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.

  • Components does not auto-delete?

    Components does not auto-delete?

    Hi, I'm working on a ECS-based game-engine project currently, and I noticed something - regardless if I delete the storage for an already unused component/class_type/pool, all previously retrieved component's references are still intact and their memory is still allocated. I'm trying to delete the memory allocation of a component's instance when the registry's remove<Component> method is called. Am I missing something and is there a possibility to retrieve the allocated memory addresses (pointers in this case) for all created, by emplace, Components and delete them?

  • [3.9.0] swap_and_pop component removal for sorted components

    [3.9.0] swap_and_pop component removal for sorted components

    I'm trying to troubleshoot some unexpected behaviour with a sorted component pool when destroying entities. Essentially, these entities have a Distance component which is kept sorted. When beyond a certain distance threshold, the entity is marked for destruction and a system later destroys these entities.

    Because marked entities are only ever destroyed when at the end of the sorted list (and I've added some logging to confirm this is the case), the swap_and_pop destruction should theoretically just remove Distance components from the end of the pool, preserving the order of the other components. But it looks like the order gets clobbered by entity destruction.

    Specifying in_place_delete is not a viable option because it (understandably) disables the single component view specialization, even if I were to explicitly keep the component pool compacted at all times.

    We currently opted for the nuclear option of re-sorting the component pool after a destruction, but as this pool can get quite large, I'd rather avoid an extra sort.

    Am I misunderstanding something about the component swap_and_pop here?

  • Error in doc code example

    Error in doc code example

    In the Aliased properties section of this page, is 'my_type' supposed to be 'time'?:

    ... To do that, the type used upon construction must be a reference type and an lvalue is necessarily provided as an argument:

    time clock;
    registry.ctx().emplace<my_type &>(clock);
    

    Read-only aliased properties are created using const types instead:

    registry.ctx().emplace<const my_type &>(clock);
    

    ...

  • Typo in docs

    Typo in docs

    On this page of the docs there's, what I assume is, a typo:

    There exits also an overload of the resolve function to use to iterate all the reflected types at once. It returns an iterable object that can be used in a range-for loop:

    Should be:

    There exists also an overload of the resolve function to use to iterate all the reflected types at once. It returns an iterable object that can be used in a range-for loop:

  • Runtime generated components?

    Runtime generated components?

    Hello, I'm currently looking into if I can replace a custom ECS framework I built for one of my projects with Entt. The main reason I built my own is that I need to be able to generate components at runtime. My current workflow is like this: First, create a list of variable types, then initialize an instance of a component definition class that figures out the required memory size and offset/padding for each variable, it also stores constructors/destructors if necessary. Then that definition can be used by the entity manager instead of a struct to create archetypes. Is this currently possible with the Entt reflection system? And if it is not could it be easily added in?

  • pkg-config file is broken when CMAKE_INSTALL_INCLUDEDIR is absolute

    pkg-config file is broken when CMAKE_INSTALL_INCLUDEDIR is absolute

A fast entity component system (ECS) for C & C++
A fast entity component system (ECS) for C & C++

Flecs is a fast and lightweight Entity Component System with a focus on high performance game development (join the Discord!). Highlights of the frame

Jun 18, 2022
Simple tower defense game using C++ with Entity Component System (ECS)
Simple tower defense game using C++ with Entity Component System (ECS)

CubbyTower CubbyTower is a simple tower defense game using C++ with Entity Component System (ECS). The code is built on C++17 and can be compiled with

May 25, 2022
A C++14 Entity Component System

NOTICE: This project is currently in the progress of being rewritten for C++17. Check out this issue if you have any suggestions/know a good way to tr

Jun 8, 2022
A lightweight but complete ECS implementation for modern C++.
A lightweight but complete ECS implementation for modern C++.

ECS A lightweight but complete ECS implementation for modern C++. Features Cache friendly design implemented on top of an EnTT-like sparse set. Clean,

Jun 13, 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

Jun 7, 2022
Yet another component system

Yet another component system Header-only c++11 entity component system Depends on Parallel hashmap for fast pointer container Compile time type name a

Jul 14, 2021
Godex is a Godot Engine ECS library.

Godex Godex is a Godot Engine ecs library. Disclaimer: this module is still in development, open an issues to report any problem or a new discussion i

Jun 20, 2022
This is an ECS archetecture in Game implemented by C++

ECS This is an implement of the ECS archetecture in Game by C++17 ⭐ Star us on GitHub — it helps! ECS Sun Entity-Component-System Compiler compatibili

Jun 7, 2022
A faster drop-in replacement for giflib. It uses more RAM, but you get more speed.

GIFLIB-Turbo What is it? A faster drop-in replacement for GIFLIB Why did you write it? Starting in the late 80's, I was fascinated with computer graph

Jun 9, 2022
Dragon's Dice Roller aims to be a lightweight, simple, reliable and easy-to-use dice roller for RPG games.

Dragon's Dice Roller is the first and (so far the only) open source RPG dice roller written in C available on GitHub. It aims to be a lightweight, simple, reliable and easy-to-use dice roller for any kind of role-playing game.

Apr 22, 2022
Replace Minecraft entity with MMD model.

KAIMyEntity Replace Minecraft entity with MMD model. KAIMyEntitySaba 将Github项目 benikabocha/saba (https://github.com/benikabocha/saba) 魔改成一个以JNI形式Expor

Jun 15, 2022
A foobar2000 component which allows you to load and play ncm files directly.
A foobar2000 component which allows you to load and play ncm files directly.

Play NCM files directly with our favourite How to setup and build project Download foobar2000 SDK and extract into vendor/sdk Download WTL from source

Jun 7, 2022
OGRE is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.
OGRE  is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.

OGRE (Object-Oriented Graphics Rendering Engine) is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware. The class library abstracts all the details of using the underlying system libraries like Direct3D and OpenGL and provides an interface based on world objects and other intuitive classes.

Jun 20, 2022
C++ game engine inspired by quake. Modern rendering and quake mapping tool integration.

Nuake Feel free to join the discord server for updates: What is it Nuake is a game engine written from scratch by myself. It is not meant to be a end-

Jun 1, 2022
A lightweight game engine written in modern C++
A lightweight game engine written in modern C++

Halley Game Engine A lightweight game engine written in C++17. It has been used to ship Wargroove, a turn-based strategy game, on Windows, Mac (experi

Jun 19, 2022
🎨 Modern 2D/3D - Importer • Exporter • Util - Library, also called (AssetIO)
🎨 Modern 2D/3D - Importer • Exporter • Util - Library, also called (AssetIO)

Brand-new modern 3D asset importer, exporter library. This library will include common 3D utils funcs. It is written with C99 but C++ wrappers or othe

Jun 8, 2022
A library for high-performance, modern 2D graphics with SDL written in C.

SDL_gpu, a library for making hardware-accelerated 2D graphics easy. by Jonathan Dearborn SDL_gpu is licensed under the terms of the MIT License. See

Jun 17, 2022
D2DX is a complete solution to make Diablo II run well on modern PCs.

D2DX D2DX is a preservation project for running classic Diablo II/LoD on modern PCs. Version 0.99.403b Mission statement Turn the game into a well beh

Jun 22, 2022
Exploring the modern rendering landscape
Exploring the modern rendering landscape

HellTech Engine An WIP exploration of the modern rendering landscape with Vulkan 1.2+ on Windows. REQUIREMENTS: Win10+ Vulkan1.2+ dedicated GPU ( ?, p

Jun 3, 2022