Struct component

Synopsis

#include <include/flecs/addons/cpp/component.hpp>

template <typename T>
struct component : untyped_component

Description

No description yet.

Mentioned in

Methods

componentRegister a component
on_addRegister on_add hook.
on_removeRegister on_remove hook.
on_setRegister on_set hook.

Source

Lines 337-477 in include/flecs/addons/cpp/component.hpp.

template <typename T>
struct component : untyped_component {
    /** Register a component.
     * If the component was already registered, this operation will return a handle
     * to the existing component.
     * 
     * @param world The world for which to register the component.
     * @param name Optional name (overrides typename).
     * @param allow_tag If true, empty types will be registered with size 0.
     * @param id Optional id to register component with.
     */
    component(
        flecs::world_t *world, 
        const char *name = nullptr, 
        bool allow_tag = true, 
        flecs::id_t id = 0) 
    {
        const char *n = name;
        bool implicit_name = false;
        if (!n) {
            n = _::type_name<T>();

            /* Keep track of whether name was explicitly set. If not, and the 
            * component was already registered, just use the registered name.
            *
            * The registered name may differ from the typename as the registered
            * name includes the flecs scope. This can in theory be different from
            * the C++ namespace though it is good practice to keep them the same */
            implicit_name = true;
        }

        if (_::cpp_type<T>::registered(world)) {
            /* Obtain component id. Because the component is already registered,
             * this operation does nothing besides returning the existing id */
            id = _::cpp_type<T>::id_explicit(world, name, allow_tag, id);

            ecs_cpp_component_validate(world, id, n,
                _::cpp_type<T>::size(),
                _::cpp_type<T>::alignment(),
                implicit_name);
        } else {
            /* If component is registered from an existing scope, ignore the
             * namespace in the name of the component. */
            if (implicit_name && (ecs_get_scope(world) != 0)) {
                const char *last_elem = strrchr(n, ':');
                if (last_elem) {
                    name = last_elem + 1;
                }
            }

            /* Find or register component */
            id = ecs_cpp_component_register(world, id, n, _::symbol_name<T>(),
                ECS_SIZEOF(T), ECS_ALIGNOF(T), implicit_name);

            /* Initialize static component data */
            id = _::cpp_type<T>::id_explicit(world, name, allow_tag, id);

            /* Initialize lifecycle actions (ctor, dtor, copy, move) */
            if (_::cpp_type<T>::size()) {
                _::register_lifecycle_actions<T>(world, id);
            }
        }

        m_world = world;
        m_id = id;
    }

    /** Register on_add hook. */
    template <typename Func>
    component<T>& on_add(Func&& func) {
        using Invoker = typename _::each_invoker<
            typename std::decay<Func>::type, T>;
        flecs::type_hooks_t h = get_hooks();
        ecs_assert(h.on_add == nullptr, ECS_INVALID_OPERATION, 
            "on_add hook is already set");
        BindingCtx *ctx = get_binding_ctx(h);
        h.on_add = Invoker::run_add;
        ctx->on_add = FLECS_NEW(Invoker)(FLECS_FWD(func));
        ctx->free_on_add = reinterpret_cast<ecs_ctx_free_t>(
            _::free_obj<Invoker>);
        ecs_set_hooks_id(m_world, m_id, &h);
        return *this;
    }

    /** Register on_remove hook. */
    template <typename Func>
    component<T>& on_remove(Func&& func) {
        using Invoker = typename _::each_invoker<
            typename std::decay<Func>::type, T>;
        flecs::type_hooks_t h = get_hooks();
        ecs_assert(h.on_remove == nullptr, ECS_INVALID_OPERATION, 
            "on_remove hook is already set");
        BindingCtx *ctx = get_binding_ctx(h);
        h.on_remove = Invoker::run_remove;
        ctx->on_remove = FLECS_NEW(Invoker)(FLECS_FWD(func));
        ctx->free_on_remove = reinterpret_cast<ecs_ctx_free_t>(
            _::free_obj<Invoker>);
        ecs_set_hooks_id(m_world, m_id, &h);
        return *this;
    }

    /** Register on_set hook. */
    template <typename Func>
    component<T>& on_set(Func&& func) {
        using Invoker = typename _::each_invoker<
            typename std::decay<Func>::type, T>;
        flecs::type_hooks_t h = get_hooks();
        ecs_assert(h.on_set == nullptr, ECS_INVALID_OPERATION, 
            "on_set hook is already set");
        BindingCtx *ctx = get_binding_ctx(h);
        h.on_set = Invoker::run_set;
        ctx->on_set = FLECS_NEW(Invoker)(FLECS_FWD(func));
        ctx->free_on_set = reinterpret_cast<ecs_ctx_free_t>(
            _::free_obj<Invoker>);
        ecs_set_hooks_id(m_world, m_id, &h);
        return *this;
    }

private:
    using BindingCtx = _::component_binding_ctx;

    BindingCtx* get_binding_ctx(flecs::type_hooks_t& h){        
        BindingCtx *result = static_cast<BindingCtx*>(h.binding_ctx);
        if (!result) {
            result = FLECS_NEW(BindingCtx);
            h.binding_ctx = result;
            h.binding_ctx_free = reinterpret_cast<ecs_ctx_free_t>(
                _::free_obj<BindingCtx>);
        }
        return result;
    }

    flecs::type_hooks_t get_hooks() {
        const flecs::type_hooks_t* h = ecs_get_hooks_id(m_world, m_id);
        if (h) {
            return *h;
        } else {
            return {};
        }
    }
};