Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more

EnTT: Gaming meets modern C++

Build Status Coverage Try online Documentation Gitter chat Discord channel Donate

EnTT is a header-only, tiny and easy to use library for game programming and much more written in modern C++.
Among others, it's used in Minecraft by Mojang, the ArcGIS Runtime SDKs by Esri and the amazing Ragdoll.
If you don't see your project in the list, please open an issue, submit a PR or add the #entt tag to your topics! πŸ‘


Do you want to keep up with changes or do you have a question that doesn't require you to open an issue?
Join the gitter channel and the discord server, meet other users like you. The more we are, the better for everyone.
Don't forget to check the FAQs and the wiki too. Your answers may already be there.

Do you want to support EnTT? Consider becoming a sponsor. Many thanks to these people and special thanks to:

mojang imgly

Table of Contents

Introduction

The entity-component-system (also known as ECS) is an architectural pattern used mostly in game development. For further details:

This project started off as a pure entity-component system. Over time the codebase has grown as more and more classes and functionalities were added.
Here is a brief, yet incomplete list of what it offers today:

  • Statically generated integer identifiers for types (assigned either at compile-time or at runtime).
  • A constexpr utility for human readable resource names.
  • A minimal configuration system built using the monostate pattern.
  • An incredibly fast entity-component system based on sparse sets, with its own pay for what you use policy to adjust performance and memory usage according to the users' requirements.
  • Views and groups to iterate entities and components and allow different access patterns, from perfect SoA to fully random.
  • A lot of facilities built on top of the entity-component system to help the users and avoid reinventing the wheel (dependencies, snapshot, handles, support for reactive systems and so on).
  • The smallest and most basic implementation of a service locator ever seen.
  • A built-in, non-intrusive and macro-free runtime reflection system.
  • Static polymorphism made simple and within everyone's reach.
  • A cooperative scheduler for processes of any type.
  • All that is needed for resource management (cache, loaders, handles).
  • Delegates, signal handlers (with built-in support for collectors) and a tiny event dispatcher for immediate and delayed events to integrate in loops.
  • A general purpose event emitter as a CRTP idiom based class template.
  • And much more! Check out the wiki.

Consider this list a work in progress as well as the project. The whole API is fully documented in-code for those who are brave enough to read it.

It is also known that EnTT is used in Minecraft.
Given that the game is available literally everywhere, I can confidently say that the library has been sufficiently tested on every platform that can come to mind.

Code Example

#include <entt/entt.hpp>

struct position {
    float x;
    float y;
};

struct velocity {
    float dx;
    float dy;
};

void update(entt::registry &registry) {
    auto view = registry.view<const position, velocity>();

    // use a callback
    view.each([](const auto &pos, auto &vel) { /* ... */ });

    // use an extended callback
    view.each([](const auto entity, const auto &pos, auto &vel) { /* ... */ });

    // use a range-for
    for(auto [entity, pos, vel]: view.each()) {
        // ...
    }

    // use forward iterators and get only the components of interest
    for(auto entity: view) {
        auto &vel = view.get<velocity>(entity);
        // ...
    }
}

int main() {
    entt::registry registry;

    for(auto i = 0u; i < 10u; ++i) {
        const auto entity = registry.create();
        registry.emplace<position>(entity, i * 1.f, i * 1.f);
        if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
    }

    update(registry);
}

Motivation

I started developing EnTT for the wrong reason: my goal was to design an entity-component system to beat another well known open source solution both in terms of performance and possibly memory usage.
In the end, I did it, but it wasn't very satisfying. Actually it wasn't satisfying at all. The fastest and nothing more, fairly little indeed. When I realized it, I tried hard to keep intact the great performance of EnTT and to add all the features I wanted to see in my own library at the same time.

Nowadays, EnTT is finally what I was looking for: still faster than its competitors, lower memory usage in the average case, a really good API and an amazing set of features. And even more, of course.

Performance

The proposed entity-component system is incredibly fast to iterate entities and components, this is a fact. Some compilers make a lot of optimizations because of how EnTT works, some others aren't that good. In general, if we consider real world cases, EnTT is somewhere between a bit and much faster than many of the other solutions around, although I couldn't check them all for obvious reasons.

If you are interested, you can compile the benchmark test in release mode (to enable compiler optimizations, otherwise it would make little sense) by setting the ENTT_BUILD_BENCHMARK option of CMake to ON, then evaluate yourself whether you're satisfied with the results or not.

Honestly I got tired of updating the README file whenever there is an improvement.
There are already a lot of projects out there that use EnTT as a basis for comparison (this should already tell you a lot). Many of these benchmarks are completely wrong, many others are simply incomplete, good at omitting some information and using the wrong function to compare a given feature. Certainly there are also good ones but they age quickly if nobody updates them, especially when the library they are dealing with is actively developed.

The choice to use EnTT should be based on its carefully designed API, its set of features and the general performance, not because some single benchmark shows it to be the fastest tool available.

In the future I'll likely try to get even better performance while still adding new features, mainly for fun.
If you want to contribute and/or have suggestions, feel free to make a PR or open an issue to discuss your idea.

Build Instructions

Requirements

To be able to use EnTT, users must provide a full-featured compiler that supports at least C++17.
The requirements below are mandatory to compile the tests and to extract the documentation:

  • CMake version 3.7 or later.
  • Doxygen version 1.8 or later.

Alternatively, Bazel is also supported as a build system (credits to zaucy who offered to maintain it).
In the documentation below I'll still refer to CMake, this being the official build system of the library.

If you are looking for a C++14 version of EnTT, check out the git tag cpp14.

Library

EnTT is a header-only library. This means that including the entt.hpp header is enough to include the library as a whole and use it. For those who are interested only in the entity-component system, consider to include the sole entity/registry.hpp header instead.
It's a matter of adding the following line to the top of a file:

#include <entt/entt.hpp>

Use the line below to include only the entity-component system instead:

#include <entt/entity/registry.hpp>

Then pass the proper -I argument to the compiler to add the src directory to the include paths.

Documentation

The documentation is based on doxygen. To build it:

$ cd build
$ cmake .. -DENTT_BUILD_DOCS=ON
$ make

The API reference will be created in HTML format within the directory build/docs/html. To navigate it with your favorite browser:

$ cd build
$ your_favorite_browser docs/html/index.html

The same version is also available online for the latest release, that is the last stable tag. If you are looking for something more pleasing to the eye, consider reading the nice-looking version available on docsforge: same documentation, much more pleasant to read.
Moreover, there exists a wiki dedicated to the project where users can find all related documentation pages.

Tests

To compile and run the tests, EnTT requires googletest.
cmake will download and compile the library before compiling anything else. In order to build the tests, set the CMake option ENTT_BUILD_TESTING to ON.

To build the most basic set of tests:

  • $ cd build
  • $ cmake -DENTT_BUILD_TESTING=ON ..
  • $ make
  • $ make test

Note that benchmarks are not part of this set.

Packaging Tools

EnTT is available for some of the most known packaging tools. In particular:

  • Conan, the C/C++ Package Manager for Developers.

  • vcpkg, Microsoft VC++ Packaging Tool.
    You can download and install EnTT in just a few simple steps:

    $ git clone https://github.com/Microsoft/vcpkg.git
    $ cd vcpkg
    $ ./bootstrap-vcpkg.sh
    $ ./vcpkg integrate install
    $ vcpkg install entt
    

    The EnTT port in vcpkg is kept up to date by Microsoft team members and community contributors.
    If the version is out of date, please create an issue or pull request on the vcpkg repository.

  • Homebrew, the missing package manager for macOS.
    Available as a homebrew formula. Just type the following to install it:

    brew install skypjack/entt/entt
    
  • build2, build toolchain for developing and packaging C and C++ code.
    In order to use the entt package in a build2 project, add the following line or a similar one to the manifest file:

    depends: entt ^3.0.0
    

    Also check that the configuration refers to a valid repository, so that the package can be found by build2:

    Both can be used with bpkg add-repo or added in a project repositories.manifest. See the official documentation for more details.

Consider this list a work in progress and help me to make it longer.

EnTT in Action

EnTT is widely used in private and commercial applications. I cannot even mention most of them because of some signatures I put on some documents time ago. Fortunately, there are also people who took the time to implement open source projects based on EnTT and did not hold back when it came to documenting them.

Here you can find an incomplete list of games, applications and articles that can be used as a reference.

If you know of other resources out there that are about EnTT, feel free to open an issue or a PR and I'll be glad to add them to the list.

Contributors

Requests for features, PRs, suggestions ad feedback are highly appreciated.

If you find you can help and want to contribute to the project with your experience or you do want to get part of the project for some other reason, feel free to contact me directly (you can find the mail in the profile).
I can't promise that each and every contribution will be accepted, but I can assure that I'll do my best to take them all as soon as possible.

If you decide to participate, please see the guidelines for contributing before to create issues or pull requests.
Take also a look at the contributors list to know who has participated so far.

License

Code and documentation Copyright (c) 2017-2021 Michele Caini.
Colorful logo Copyright (c) 2018-2021 Richard Caseres.

Code released under the MIT license.
Documentation released under CC BY 4.0.
All logos released under CC BY-SA 4.0.

Owner
Michele Caini
I'm a freelancer and a senior software engineer. What else?
Michele Caini
Comments
  • Call for comments: signals on component creation/destruction

    Call for comments: signals on component creation/destruction

    Ok, people is asking this and I tried to figure out if it's possible. Probably, I found a nice way to add signalling stuff to the registry in a way that is in policy with the whole framework: pay only for what you use.. It means that there will be no performance hits for those components that aren't (let me say) observed. On the other side, it will be possible to be notified about creation and destruction of specific components if required.

    I've still to review the whole idea and try to implement it. However, I'd like to have feedbacks about it.

    Is it a feature in which you could be interested? Any suggestion, comment or request?

    As a side note, it would unlock other features like implicit blueprints (when component A is attached, attach also B and C silently) and so on.

    Let me know, feedbacks are appreciated!! I'll close the issue probably in a couple of days.

    Thank you.

  • Member function for on_construct() without instance?

    Member function for on_construct() without instance?

    Would it be possible to add an overload for the on_construct()-family of methods on the sinks to allow for a member function of the underlying component type, without an instance of the member function's type?

    Here's a visual example:

    struct some_component {
        int i = 0;
    
        void init() {
            cout << "I've init'd: " << i << endl;
        }
    };
    
    registry.on_construct<some_component>().connect<&some_component::init>();
    

    In the above pseudo-code, we don't use a static function nor do we use a member function with a point/reference to a specific instance. Instead, we use a pointer to a member function of the component itself to call, with this being the pointer to the newly created component itself.

    This would greatly clean up some of the glue code in some parts of the engine, as right now I am either passing lambdas or creating stubs to do pretty much exactly this.

    For context, I could be using constructors and destructors, but given the inherently POD-like structures, default move constructors, et al, I'm writing my components in a way they can be re-used via init() and destroy() member methods (where a call to destroy() could, in theory, be followed by init() assuming all of the non-default POD properties have been set prior). I fully realize this isn't a design requirement by ENTT but it seems like a clean approach for my use-case.

    Would love to hear your thoughts, or why this might not be a good idea. :)

  • [POC] Annotated meta-data

    [POC] Annotated meta-data

    The purpose of annotated meta-data is to provide better runtime-introspection abilities with less code. Annotations are just properties created with reusable function or functional object.

    https://github.com/Innokentiy-Alaytsev/entt/tree/runtime-annotations

    I've implemented one of the functions I think is useful. I've renamed the concept from 'decoration' to 'annotation' - I think the new word better represents the purpose. I've only implemented the function for registering meta-data without setter and getter. If you say everything is fine, I'll add implementations for annotated meta-data with setter and getter, annotated meta-type (reflect_annotated), maybe annotated meta-function (func_annotated). Also, I'll try to find a way to minimise the amount of the required code - it's very straight forward, but it may be a support burden.

  • Save/Restore

    Save/Restore

    Hi @skypjack , I've been disconnected for a few weeks, and when today I got back, had a look at the code, well... wow! already version 2.4.1 and a lot of new features (and most of those I already had custom-implemented because of need, like the Actor class)!

    I have a side question and a possible feature request: how difficult would it be to implement a save/restore functionality in the ECS? In the simulation system we are implementing, one of the main features we need to implement is the possibility to take "snapshots" of the entire system state, save them and restore at a later time. More or less a classical replay system, but with multiple restore points.

    Is it possible to implement that functionality in the Registry, with the current implementation? In case you believe is a feature that is worth incorporating, please send me a PM and we can maybe have a quick call to discuss ways of helping/accelerating the development.

  • Implemented scoped unregistering of meta-types

    Implemented scoped unregistering of meta-types

    Added an overload for entt::meta function accepting an entt::meta_chain object reference for building a chain of locally registered types. The entt::meta_chain instance will store an implicit list of types registered with it and will call entt::meta::reset() for each of them upon its desctruction.

  • discussion - empty components should not be part of the each callback

    discussion - empty components should not be part of the each callback

    skypjack was already refactoring the empty instance pools -> https://github.com/skypjack/entt/commit/e228cb66488fc6ae98365ce2f5f8db45834a92c3#diff-36792e38ee0671f0a02c94d88a91cfbb idk if that is gonna have any impact on this issue...

    but basically something like

    reg.group<Component, EmptyTag>().each([](auto id, auto comp) {});
    reg.group<Component, EmptyTag>().each([](auto comp) {});
    

    instead of

    reg.group<Component, EmptyTag>().each([](auto id, auto comp, auto tag) {});
    reg.group<Component, EmptyTag>().each([](auto comp, auto tag) {});
    

    since there's no point in having empty instance in the arguments.. This is a api breaking change though so it'd have to be part of a major release cause I'm sure everyone like me has just been including the tags in their each callbacks.

  • Some implementation Questions

    Some implementation Questions

    I have some questions about the best way to implement some things:

    1. Component Dependency: for example if i have a "Position" Component and a "Velocity" Componenet and i want to create a new Component called "Physics" to have more complex behaiviour how woud i make Position and Velocity a requirement for having a physics component. I could pass the Registry and the Entity into the Physics component constructor to add the Position and Velocity components if they dont exist but that doesnt seem to be a clean solution.

    2. Best way of implementing child entities: im kinda thinking about this too i would think that you create a "Parent" component that has a Entity handle to a child and thats it ? but what about passing information down the chain like if i change the position of the parent entity i want to inform the children that the parent moved and update their position accordingly. I would have to check in the "Position" component if it has a "Parent" component and then pass it down or is there a better way?.

    3. Getting the registry or the attached entity in the component: can you do that without having to pass it into the components that need it? im not sure about that but would it be possible to create a Component base class for those type of things and then have a specialization in the attach function but i dont know if that is possible in C++.

    4. What about baseclass Components: eg. if i have a Renderable Component and i want to subclass it to implement the draw function or something and add that to the entity and then get all of them with a view by searching all Renderables. is that possible, if not what would be a alternative?

  • Component polymorphism support feature & prototype

    Component polymorphism support feature & prototype

    Hello,

    I'd like to introduce my work on prototype feature, that adds component polymorphism support. Such thing might seem a little controversial, so I will immediately mention two things:

    • Despite not being a part of pure ECS concept, such feature can be very useful in many real world cases
    • It is enabled only for certain component types at compile time, so it will not affect performance of non-polymorphic components in any way (pay only for what you use)

    I already have working prototype in the experimental branch of my fork. Of course it requires some review and improvements, and some parts may not be made in a nicest way possible right now, but it is fully functional.

    Here is a basic example:

    struct Ticking : public entt::polymorphic {
        virtual void tick(const entt::entity) = 0;
    };
    
    class Physics : public entt::inherit<Ticking> {
        // ...
        void tick(const entt::entity e) override {
             // ...
        }
    };
    
    class AI : public entt::inherit<Ticking> {
        // ...
        void tick(const entt::entity e) override {
             // ...
        }
    };
    
    
    registry.emplace<Physics>(e); // emplace polymorphic component
    Ticking& ticking1 = registry.get<Ticking>(e); // will return Physics as Ticking
    registry.emplace<AI>(e); // emplace another polymorphic component
    Ticking& ticking2 = registry.get<Ticking>(e); // will return any of two components, because they are both inherit from Ticking, which component is returned is not defined
    
    // get iterable to iterate each component, that is inherited from Ticking, order of iteration is not defined
    for (Ticking& ticking : registry.view<entt::every<Ticking>>(e).each()) {
        // ...
    }
    
    // view can also get every component instead of one
    registry.view<entt::every<Ticking>>(e).each([](const entt::entity, entt::every<Ticking> every_ticking) {
        for(Ticking& ticking : every_ticking) // ...
    });
    
    // will remove EVERY component, that is inherited from Ticking
    registry.remove<Ticking>(e);
    

    You can try it yourself, it is already in the fork, along with some tests. I will appreciate any feedback about how to improve both the concept and the solution, and hope it will make it way into EnTT in the future.

    Now lets dive into some details:

    Problems, I try to address

    Maybe the main problem, this feature solves, is accessing components without knowing their exact type. It is sometimes can be very useful to access component as some interface/base type without knowing what exactly it is (so basically this is what polymorphism is about in general, and this feature is applying this concept to ECS).

    In the context of ECS it results in 2 main ideas: we should be able to access component by any of its base types and we also should be able to access all such components, attached to an entity, because there of course can be more than one. Example of this idea is already shown above, we create two component types, that implement Ticking interface and add both of them to an entity, and then we can just iterate all ticking components and do something with them (probably just call tick in this case).

    Additionally, to follow "pay only for what you use" rule, such polymorphic components must be treated separately and must not affect performance of other components.

    Some specs

    The basic idea is simple: component can be accessed not only by its own type, but by any of its parent types. From the example above we can see, that both Physics and AI components inherit from, and so can be accessed as reference to Ticking. Here I tried to come up with a bit more formal set of rules:

    1. We define polymorphic components separately from non-polymorphic, by inheriting from entt::polymorphic or entt::inherit<Parent1, Parent2, ...>. Polymorphic component can inherit only from other polymorphic components to keep them separate from non-polymorphic. With this requirement we can completely separate all logic at the compile time and preserve performance for non-polymorphic components.
    2. When polymorphic component is added to entity, it can then be accessed not only by its own type, but as any of its parent types. This applies both for getting it for one entity and for iterating with a view.
    3. Now for some parent type there can be several components of its child types attached to an entity. So we must be able to: 3.1. Still get one of this components, if we just need one. This operation ideally must be as fast, as getting one non-polymorphic component. Which component will be returned cannot be specified in this case, so we just return any of them. 3.2. Iterate over all components of this type, attached to an entity. Same as with one component, we must be able to use it both with get and with view. To achieve this, we pass entt::every<ParentType> instead of just ParentType to registry.get or registry.view, and get it back. Then we just iterate entt::every<ParentType> to get ParentType&. 3.3. Access with entt::every must work completely similar for one and for several components.
    4. Calling erase and remove must delete all components inherited from given type. This might seem a bit controversial, because in some cases we need to delete component of exactly this type, so maybe in the future separate method should be added to do such things.
    5. Actions insert, get_or_emplace are deleted for polymorphic components right now, and patch is also controversial one, as they deserve separate discussion. ... This list will be expanded as the discussion progresses

    Some implementation details

    Wrappers (or containers, don't know, which name is better)

    Main idea here is to store polymorphic components inside wrappers/containers (polymorphic_component_container<Component>). These wrappers are able to store component value of exactly given type and reference list to other components. They have storage for component value, list of references to other components and 2 bits for flags to store its state.

    Wrapper has methods for value construction/destruction, adding/removing references to other components from reference list and for getting reference to one component or entt::every to iterate all of them. When constructing a value, wrapper adds reference to this value into all wrappers for parent component types, when destructing - it will remove all this references. So it requires registry and entity to access those wrappers for parent types.

    Polymorphic components reference each other by pointer, so stable pointer is required, in_place_delete is true for all polymorphic types, and empty type optimization is also disabled, because wrappers are never empty.

    Changes in basic_storage

    Because polymorphic components are stored in wrappers and accessed in a slightly different way, separate basic_storage and iterator implementations are created for them. It changes implementation of get, emplace, erase and remove and also adds hidden methods for polymorphic_component_container like emplace_ref and erase_ref.

    I have also added get_as<T> (and similar) methods for all basic_storage implementations and similar as<T> methods for storage iterators. The purpose of those is resolving entt::every (and maybe some other type modifiers in the future). For non-polymorphic storage those methods are completely similar to get/operator*, they actually just call them with an extra static_assert, so no performance overhead here.

    And here comes an uglier part: emplace and erase now require registry for polymorphic storage, so right now they are just passed as an additional parameter, that is ignored for non-polymorphic component storages. Again, no performance overhead here, as the registry parameter is just optimized out, but the whole idea of such inverse dependence is pretty nasty. It is another open discussion on how to implement this in a more elegant way.

    Changes in basic_view

    Here things are simpler: I use get_as<T>/as<T> methods I have created in storage and storage iterators to just forward everything in a right way. Because all of these methods are basically same as get/operator* used before for non-polymorphic types, no overhead is expected for them.

    There is also some changes to get unwrap entt::every to get storages for required component, but these are fully resolved at compile time.

    Changes in basic_registry

    Only changes here are passing registry to emplace/erase/remove and unwrapping entt::every for views.

    Dive into polymorphic_component_container implementation

    As was said before, polymorphic_component_container aka polymorphic component wrapper can store both component value and reference list. In a very basic implementation it can be done like this (and also thinking of it in this way may help a lot):

    template<typename Component>
    struct polymorphic_component_container {
        std::optional<Component> value;
        std::vector<Component&> refs;
    };
    

    But when I came to thinking about erase implementation the following problem kicked in. When erasing component, we must also erase all components listed in refs (those are child types). When deleting component, it must delete all of its references from parent wrappers, so we must know exact types of components in refs to do it or come up with another way. My idea was to store pointer to 'deleter' function along with component reference, such deleter will be placed when reference is added and called, when it is required to erase component by its reference. So wrapper implementation should look like this:

    template<typename Component>
    struct polymorphic_component_container {
        struct component_ref {
            Component& ref;
            void* deleter;
        };
        std::optional<Component> value;
        std::vector<component_ref> refs;
    };
    

    Now lets move on to real implementation. It does not use std::vector nor std::optional. Instead it has data - buffer for component value or at least one pointer and uintptr_t pointer, which can store pointer to one reference or pointer to list, depending on wrapper state. And to store wrapper state I use a solution with some pointer hacks - I rely on memory alignment, so 2 bits of pointer are always zero and can be used to store the state (it is achieved by aligning entt::inherit by at least 4 bytes). This saves us one memory access when getting reference to the component and also sizeof(pointer) bytes of memory per wrapper, that would be otherwise added by padding. I thought it was worth it, so there is a lot of strange stuff going on inside wrapper, but if you consider this an overkill I of course will rethink it.

    Now lets look on the possible storage states: there are 2 bits, 2 flags that are mostly independent of each other, 1st flag - if wrapper has a value, 2nd flag - if wrapper has a reference list. Describing whole implementation here would take forever, I will try to do it separately, so here are some important notes:

    • There is always a value or a reference stored directly inside the wrapper, so one component reference can be always accessed without any indirection and looking into list. If nothing is stored, wrapper is deleted.
    • When wrapper has list, it stores all the references, owned by this wrapper, including reference to the value inside this wrapper (if in has one), so iterating the list does not require extra logic.
    • When wrapper contains only one reference or only value, it does not allocate a list (and also it deallocates a list, if only one reference/value remains)
    • Lists are allocated via component_ref_list_page_source to optimize many small memory allocations of the same size, required for them. Note: right now template of component_ref_list_page_source depends only on underlying allocator type, but maybe it should instead be instantiated per component type (the page size must be reduced greatly in this case).

    I am planning to clean up, and move some of this logic out of the wrapper class to abstract underlying memory layout a bit, right now the solution is messy.

    ...Implementation details are also to be expanded
  • Non-owning entt::actor

    Non-owning entt::actor

    Here I have a draft for a non-owning version of entt::basic_actor called entt::basic_handle. I really had my heart set on the name "handle" but then I realised (well actually the compiler realised πŸ˜„) that there's already entt::handle. So the alias in the forwarding header is called handle_grr because grr naming things is hard! Anyway, we can figure out a name later.

    The handle is a reference type while actor is a value type. If actor was std::vector, then handle would be std::span. This has influenced a number of design decisions. Handles are lightweight types that can be copied and moved around freely. They are intended to be a drop-in replacement for an entity-registry pair. "having 3 parameters is better than having 6".

    Mutability

    entt::registry reg;
    entt::entity e = reg.create();
    
    entt::handle h1{e, reg};
    const entt::handle h2{e, reg};
    entt::const_handle h3{e, reg};
    const entt::const_handle h4{e, reg};
    
    h1.assign<int>(); // OK
    h2.assign<int>(); // OK
    h3.assign<int>(); // Not allowed
    h4.assign<int>(); // Not allowed
    

    Implicit conversions

    void add_components(entt::handle);
    void get_components(entt::const_handle);
    
    entt::registry reg;
    entt::actor actor{reg};
    entt::handle handle{actor};
    
    add_components(actor);
    get_components(actor);
    add_components(handle);
    get_components(handle);
    

    Deduction guides

    ENTT_OPAQUE_TYPE(my_entity, entt::id_type);
    
    entt::basic_registry<my_entity> reg;
    const auto &const_reg = reg;
    my_entity e = reg.create();
    
    entt::basic_actor a1{reg};           // basic_actor<my_entity>
    const auto &a2 = a1;
    entt::basic_handle h1{a1};           // basic_handle<my_entity>
    entt::basic_handle h2{e, reg};       // basic_handle<my_entity>
    entt::basic_handle h3{e, const_reg}; // basic_handle<const my_entity>
    entt::basic_handle h4{a2};           // basic_handle<const my_entity>
    

    I have not attempted to deal with the duplication between the three classes. I wanted to keep it simple and deal with that later. Better to have all this boilerplate in the library than in user code though, right? I was thinking that it might be useful to give these classes a fuller API. Instead of just assign and remove, there could be emplace_or_replace, remove_if_exists, patch, etc. That is, all (or most) of the registry member functions that operate on a single entity could be added. That will make the duplication much worse but is a separate discussion anyway.

    I also haven't added tests for this. I kind of wanted to find a name that doesn't clash (and perhaps discuss the design a bit too) before doing that. I just realised that the examples above are probably halfway towards a test suite.

    In a couple of the constructors, I commented Does this assertion really make sense?. Would it ever make sense to construct a handle from a valid registry but a null entity? If this class is to be a drop-in replacement for an entity-registry pair then perhaps that assertion should be removed. To be clear, I'm not suggesting that it is removed from actor, just from handle. Or maybe it could be changed to ENTT_ASSERT(ref.valid(entity) || entity == null)? Or even ENTT_ASSERT(reg.valid_or_null(entity))? I think I remember suggesting valid_or_null long ago. Once again, separate discussion!

  • Basic logic operations for registry and filtering views.

    Basic logic operations for registry and filtering views.

    It just occurred to me that one could in principle enhance the registry.has<...>(...) and registry.any<...>(...) methods with all the basic logic operations. I admit XOR seems to me to be the most convenient, but in theory all apply.

    bool xorExistingComponents = registry.XOR<component1, component2, component3, ...>(entity);
    

    The holy grail would of course be able to generate views with more expressive logical conditions. But that might have other performance trade-offs.

    Also, build times may suffer...

  • [Feature Request] Make the registry work across boundaries

    [Feature Request] Make the registry work across boundaries

    This is a follow up of #182 to discuss the problem in the title.
    To sum up: on Windows, inline variables aren't guaranteed to be unique between all the TUs and thus things could break when the registry is pushed across boundaries.

    There are several solutions that could make it work when a single library is used with a main executable. However, most of them will still break in case of multiple libraries used together at once. Therefore I won't even mention these solutions.

    So far, a widely accepted proposal (discussed on gitter) is based on named components. In other terms, components that will be pushed across boundaries must be assigned a compile-time name.
    This solution can be implemented in two different ways, each with its pros and cons:

    1. Components inherit from a dedicated class template:

      struct my_component: entt::shared<"my_name"_hs> { /* ... */ };
      // or even SHARED(my_component) { /* ... */ };
      // ...
      registry.do_something<my_component>(entity);
      

      A macro can be used to ease the definition, of course. In this case, whenever a shared component is detected, the registry searches it by name instead of by identifier. A secondary macro can be used to force the behavior only on libraries and rely on direct access through identifiers in the main executable.

    2. The other way around doesn't affect component definitions, but require users to explicitly specify when to use a components in shared mode, that is by name. Something along this line:

      struct my_component { /* ... */ };
      // ...
      registry.do_something<my_component>(entity); // direct access with numeric identifier
      registry.do_something<SHARED(my_component)>(entity); // work fine across boundaries
      

      This is a bit more verbose, but users have finer control and their components are theirs. Moreover, it's clear at the call site whether a component is used in shared mode or not.

    I'm open to comment, critiques and suggestions. I won't to get rid of this limitations, because it's getting annoying, so let's discuss it and solve the problem once and forever.


    EDIT

    I tried to implement a first draft. Another possible approach is to rely on 1. and split components between shared and non-shared ones. In other terms, to have two vectors of pools. The drawback is that there are two vectors ofc. :smile:
    It would affect to an extent only those components that are pushed across boundaries.
    On the other side, this is trickier, it requires much boilerplate and it will be most probably harder to maintain.

    A trivial approach instead, probably the easiest to implement and to maintain, is to have the whole registry as shared and non-shared.
    It means that internally the registry uses always a direct access or always a name based lookup. When users are dealing with dlls on Windows, it's enough to set up a macro and have components that inherit from shared_t to provide a name. In all the other cases, the lookup by name is disabled and everything works by direct access.
    Less granular, ofc, but it requires to change only one function at a first glance.

    Comments?


    EDIT

    @ArnCarveris came up with a good idea that is a compromise between what we discusses so far, gets rid of inheritance and is safe as well.
    This edit to keep track of it (names can change in the final version):

    template<typename>
    struct shared_traits;
    
    template<>
    struct shared_traits<my_component> {
        static constexpr auto value = "my_component"_hs;
    };
    

    A few macros will be provided to ease the definition of shared components. In particular:

    •  ENTT_SHARE(my_component);
      

      To use to turn an already existing type in a shared one.

    •  ENTT_SHARED_STRUCT(my_component) { /* ... */ };
       ENTT_SHARED_CLASS(my_component) { /* ... */ };
      

      To use to define directly a type as a shared class.

    Feedback are welcome.

  • Opaque structures no longer supported by locator API

    Opaque structures no longer supported by locator API

    Recent changes to the locator API prevent the locator from being initialised with an existing service. Now, the service may only be initialised via in-place construction. Overall, the changes to the locator API are great for encapsulation and simplicity, but has made it difficult (or impossible) to register an opaque structure as a service.

    Consider the following example from the previous API, in which a shared_ptr pairs the creation and destruction of an SDL_Window (an opaque C-struct) via create/destroy functions. The shared_ptr is then assigned to the locator and the user can rest assured that the underlying type will be destroyed appropriately when the service is reset.

    std::shared_ptr<SDL_Window> window {
        SDL_CreateWindow(
            window_title,
            SDL_WINDOWPOS_CENTERED,
            SDL_WINDOWPOS_CENTERED,
            window_size.x,
            window_size.y,
            0),
        &SDL_DestroyWindow,
    };
    
    entt::service_locator<SDL_Window>::set(window);
    

    I don't believe that the new locator API can support using an opaque structure as a service type anymore, as there is no way to attach the custom create/destroy functions, unless this can be achieved in a relatively simple way via a custom allocator?

    I could create a wrapper class for the opaque type that will invoke the create/destroy functions, and register this as a service instead, but this feels more cumbersome and adds another layer of indirection.

    Do you have any thoughts on this?

  • Allow entities and components of specific entities to be disabled/enabled

    Allow entities and components of specific entities to be disabled/enabled

    It would be super helpful to be able to disable either an entity or a specific component on an entity, both without actually deleting entity or component. The entity or component continues to exist, does not get overwritten by entt during creation (retains its id and version), and might be re-enabled later.

    What

    • get<T> and try_get<T> should not return component T if it has been disabled for the given entity.
    • get<T> and try_get<T> should not return an enabled component T if the given entity is disabled.
    • A view should skip a disabled entity.
    • A disabled entity or component should be able to be deleted.

    Imagine two entities exist with components:

    Entity A -TransformComponent -RenderComponent -CollisionComponent

    Entity B -TransformComponent -RenderComponent -CollisionComponent

    If I disable Entity A, it should not be returned if I create a view on CollisionComponent.

    If I disable CollisionComponent on Entity B, only Entity A should be returned if I create a view on CollisionComponent.

    (Why you would disable CollisionComponent I have no idea. This is just to demonstrate that disabling a component applies to a specific entity, not all components of that type.)

    Nice to Have

    • Something that could return all disabled but not deleted entities and components (by type) but at worst the user could just be maintaining a list of disabled entities.
    • An alternative version/overload of view that returns all entities, enabled or not.

    How

    I'm purposefully not suggesting how an entity or component might be enabled or disabled.

    Why

    Presumably entt's own check would be far faster/efficient than the method I employed to do this. All of my components derive from a Component class, which has an enabled member. All entities get a GeneralComponent on creation. Among other things GeneralComponent does, its enabled is treated specially: to determine if the entity itself is considered enabled.

    Background

    I was working on a pathing system that has three pieces: FollowComponent, WanderComponent, and PathingComponent (and the corresponding systems). The problem is simple: the first two components must stop all work for any entities involved in cutscene scripting (unless a script specifically turns them back on). I can't simply disable the systems because they should continue to process other entities not involved in the script. I need to disable FollowComponent and WanderComponent on the entities involved in the cutscene.

    Another practical usage scenario is undo/redo in a level editor. Deleting an entity could simply disable it, and then upon save all disabled entities are ignored. Undo'ing a delete would simply re-enable said entity (presumably the undo/redo list stores the entity). The major benefit of this approach is preserving the original state of the entity after the user requests an undo. Redo would simply disable the entity again.

  • Sketch of a change to save binary size

    Sketch of a change to save binary size

    I was doing some explorations on improving binary size and found this potential change in ENTT. Basically, what's going on here is that the 'placeholder' function-level "magic static" is more expensive than it may appear to be at first.

    I analyzed a large game using ENTT, by using the SizeBench tool. Each 'placeholder' creates what is called an "atexit destructor" that ends up generating code that is unnecessary. When this magic static is first encountered, it gets constructed (thread-safe, too) which is a rad property of magic statics - but...who is responsible for destructing it? And when does that happen? That's what an atexit destructor does - it's code generated to run the destructor of the magic static (if it was ever constructed), and it runs when the module is unloaded or when exit() is used.

    Each of these 'placeholder' objects is returned as a const reference, so it's never mutated, but it still has to be destructed and that code has to be generated. If, instead, this returns nullptr in the case of not having a pool, the placeholder need not be constructer or destructed.

    There's not many callsites using assure that had to be updated to do -> instead of . for the reference-to-pointer switch, and tolerate a null return value.

    In a large game I found this to save ~200KB of binary size (almost all in the .text section, or code, a little bit in .pdata which has an entry per function in .text so it's usually correlated, and it saved some .bss in-memory read/write data pages.)

    I didn't actually run any tests after this change, and I only tested building and linking with MSVC, so consider this a sketch to see if you want to carry it forward and actually test it and ensure it's ok for all the compilers and platforms ENTT may support.

  • Component polymorphism support

    Component polymorphism support

    Adds extension, that allows to declare and work with polymorphic components. See discussion in the delated issue #859.

    Example usage (will be updated in case of changes):

    #include <entt/entity/polymorphic.hpp>
    
    struct ticking : public entt::inherit<> { // declare as polymorphic component without parents
        virtual void tick(const entt::entity) = 0;
    };
    
    class physics : public entt::inherit<ticking> { // inherit from ticking
        // ...
        void tick(const entt::entity e) override {
             // ...
        }
    };
    
    class ai : public entt::inherit<ticking> { // inherit from ticking
        // ...
        void tick(const entt::entity e) override {
             // ...
        }
    };
    
    // iterate all components, derived from ticking for given entity
    for (ticking& ticking : entt::algorithm::poly_get_all<ticking>(reg, e)) {
        ticking.tick(e);
    }
    
    // try get any component, derived from ticking for given entity
    if (ticking* ticking = entt::algorithm::poly_get_any<ticking>(reg, e); ticking != nullptr) {
        ticking->tick(e);
    }
    
    // iterate all components, derived from ticking in the registry
    entt::algorithm::poly_each<ticking>(reg, [] (entt::entity e, ticking& c) {
        ticking.tick(e);
    });
    
    // count components, derived from ticking 
    entt::algorithm::poly_count<ticking>(reg, e); // attached to entity
    entt::algorithm::poly_count<ticking>(reg); // in the registry
    
    // remove all components, derived from ticking, attached to entity
    entt::algorithm::poly_remove<ticking>(reg, e); 
    
    
  • Question: Can I infer the size of the component type when visiting storage pools?

    Question: Can I infer the size of the component type when visiting storage pools?

    Hello!

    I am trying to generically (without upfront knowledge of the component types) read the byte contents of all existing pools.

    Is this possible?

    I assume the only way I can access the pools generically is by using visit:

    auto visitor = [](entt::sparse_set& pool) {
        // Can I get the pool element size?
    };
    entity_registry_.visit(visitor);
    

    (BTW, the documentation has this example but it seems to me this is no longer possible:

    // create a copy of an entity component by component
    for(auto &&curr: registry.storage()) {
        if(auto &storage = curr.second; storage.contains(src)) {
            storage.emplace(dst, storage.get(src));
        }
    }
    

    )

EntityX - A fast, type-safe C++ Entity-Component system

EntityX - A fast, type-safe C++ Entity Component System NOTE: The current stable release 1.0.0 breaks backward compatibility with < 1.0.0. See the cha

Dec 29, 2022
apecs: A Petite Entity Component System

apecs: A Petite Entity Component System A header-only, very small entity component system with no external dependencies.

Jun 1, 2022
[WIP] Experimental C++14 multithreaded compile-time entity-component-system library.

ecst Experimental & work-in-progress C++14 multithreaded compile-time Entity-Component-System header-only library. Overview Successful development of

Dec 17, 2022
C++ single-header entity component system library

ECS This is a simple C++ header-only type-safe entity component system library. It makes heavy use of C++11 constructs, so make sure you have an up to

Dec 27, 2022
C++ entity-component system

CORGI Version 1.0.2 {#corgi_readme} CORGI is a C++ entity-component system library developed primarily for games that focus on simplicity and flexibil

Nov 6, 2022
Thoughts about entity-component-system

About Warning: This is not a complete production-ready library for entity-component-system. This is only my thoughts about how the modern entity-compo

Dec 7, 2022
Open-source node system framework, to change your algorithmic code into useful tools to create much more complicated simulations!
Open-source node system framework, to change your algorithmic code into useful tools to create much more complicated simulations!

Open-source node system framework, to change your algorithmic code into useful tools to create much more complicated simulations!

Jan 9, 2023
EyeLog Can Record And Steal Consecutive Keystrokes (and much more) That The User Enters On A Device
EyeLog Can Record And Steal Consecutive Keystrokes (and much more) That The User Enters On A Device

What This EyeLog EyeLog Is A Keylogger Can Record And Steal Consecutive Keystrokes (and much more) That The User Enters On A Device How To Setup EyeLo

Dec 28, 2021
A collection of valorant cheating codes, including offsets, world to screen and much more!

Valorant External Cheating Help Always up to date Valorant Offsets + a wide variety of noob friendly helper functions. Functions are not heaviky teste

Jun 12, 2022
rax/RAX is a C++ extension library designed to provide new, fast, and reliable cross-platform class types.

rax rax/RAX is a C++ extension library designed to provide cross-platform new, fast, and reliable class types for different fields such as work with I

May 2, 2022
Gaming Input Peripherals Device Firewall for Windows.
Gaming Input Peripherals Device Firewall for Windows.

HidHide ⚠️ Compiling a signed BETA release is in the works, please be patient! ⚠️ Introduction Microsoft Windows offers support for a wide range of hu

Jan 2, 2023
Left hand gaming keypad with a 3D printed case
Left hand gaming keypad with a 3D printed case

GameHand Left-hand gaming keypad with a 3D printed case Case files KiCAD PCB files Gerbers for PCB production JLCPCB BOM JLCPCB CPL This work is licen

Jul 22, 2022
An open source C++ entity system.

anax ARCHIVED: as I haven't maintained this library for at least a couple of years. I don't have the time or interest to work on this. Please use anot

Jan 4, 2023
Hobbyist Operating System targeting x86_64 systems. Includes userspace, Virtual File System, An InitFS (tarfs), Lua port, easy porting, a decent LibC and LibM, and a shell that supports: piping, file redirection, and more.
Hobbyist Operating System targeting x86_64 systems. Includes userspace, Virtual File System, An InitFS (tarfs), Lua port, easy porting, a decent LibC and LibM, and a shell that supports: piping, file redirection, and more.

SynnixOS Epic Hobby OS targeting x86_64 CPUs, it includes some hacked together functionality for most essential OSs although, with interactivity via Q

Oct 28, 2022
Dec 29, 2022
3D scanning is becoming more and more ubiquitous.

Welcome to the MeshLib! 3D scanning is becoming more and more ubiquitous. Robotic automation, self-driving cars and multitude of other industrial, med

Dec 31, 2022
κ²Œμž„μ΄λž‘ λ¬΄κ΄€ν•©λ‹ˆλ‹€λ§Œ λ°‹μ—… - ECS 기반 κ²Œμž„ 개발 λ°œν‘œ 자료 및 예제 μ½”λ“œ

2021-CoMu-ECS-Development κ²Œμž„μ΄λž‘ λ¬΄κ΄€ν•©λ‹ˆλ‹€λ§Œ λ°‹μ—… - ECS 기반 κ²Œμž„ 개발 λ°œν‘œ 자료 및 예제 μ½”λ“œ Contents Presentation File Quick Start For macOS or Linux or Windows Subsystem f

Dec 18, 2022
πŸ› οΈ A simple ECS library made for learning purposes (header-only)

Met ECS A simple Entity Component System library made for learning purposes. It is header-only, so just have to copy the content of the src folder and

Mar 26, 2022