Coder Social home page Coder Social logo

skypjack / entt Goto Github PK

View Code? Open in Web Editor NEW
9.5K 177.0 833.0 34.63 MB

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

Home Page: https://github.com/skypjack/entt/wiki

License: MIT License

CMake 0.50% C++ 99.09% C 0.04% Shell 0.03% Python 0.29% Starlark 0.06%
header-only modern-cpp cpp entity-component-system game-development game-programming architectural-patterns game-engine gamedev cpp17

entt's Introduction

EnTT: Gaming meets modern C++

Build Status Coverage Try online Documentation Vcpkg port Conan Center Gitter chat Discord channel

EnTT has been a dream so far, we haven't found a single bug to date and it's super easy to work with

-- Every EnTT User Ever

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 or making a donation via PayPal.
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:

  • Built-in RTTI system mostly similar to the standard one.
  • A constexpr utility for human-readable resource names.
  • Minimal configuration system built using the monostate pattern.
  • Incredibly fast entity-component system with its own pay for what you use policy, unconstrained component types with optional pointer stability and hooks for storage customization.
  • 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.
  • General purpose execution graph builder for optimal scheduling.
  • 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 few homemade containers, like a sparse set based hash map.
  • A cooperative scheduler for processes of any type.
  • All that is needed for resource management (cache, loaders, handles).
  • Delegates, signal handlers and a tiny event dispatcher.
  • 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.
Please, do note that all tools are also DLL-friendly now and run smoothly across boundaries.

One thing known to most is that EnTT is also 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 library 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.

Benchmark

For what it's worth, you'll never see me trying to make other projects look bad or offer dubious comparisons just to make this library seem cooler.
I leave this activity to others, if they enjoy it (and it seems that some people actually like it). I prefer to make better use of my time.

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.

There are also 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.
Out of all of them, this seems like the most up-to-date project and also covers a certain number of libraries. I can't say exactly whether EnTT is used correctly or not. However, even if used poorly, it should still give the reader an idea of where it's going to operate.

Integration

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.

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.

CMake

To use EnTT from a CMake project, just link an existing target to the EnTT::EnTT alias.
The library offers everything you need for locating (as in find_package), embedding (as in add_subdirectory), fetching (as in FetchContent) or using it in many of the ways that you can think of and that involve CMake.
Covering all possible cases would require a treaty and not a simple README file, but I'm confident that anyone reading this section also knows what it's about and can use EnTT from a CMake project without problems.

Natvis support

When using CMake, just enable the option ENTT_INCLUDE_NATVIS and enjoy it.
Otherwise, most of the tools are covered via Natvis and all files can be found in the natvis directory, divided by module.
If you spot errors or have suggestions, any contribution is welcome!

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
    

    Or you can use the experimental feature to test the latest changes:

    vcpkg install entt[experimental] --head
    

    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.

  • bzlmod, Bazel's external dependency management system.
    To use the entt module in a bazel project, add the following to your MODULE.bazel file:

    bazel_dep(name = "entt", version = "3.12.2")

    EnTT will now be available as @entt (short for @entt//:entt) to be used in your cc_* rule deps.

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

pkg-config

EnTT also supports pkg-config (for some definition of supports at least). A suitable file called entt.pc is generated and installed in a proper directory when running CMake.
This should also make it easier to use with tools such as Meson or similar.

Documentation

The documentation is based on doxygen. To build it:

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

The API reference is created in HTML format in the build/docs/html directory. 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.
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 downloads and compiles 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.

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-2024 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.

entt's People

Contributors

alexames avatar definitelynobody avatar dnkpp avatar donutvikingchap avatar drglove avatar friflo avatar green-sky avatar indianakernick avatar innokentiy-alaytsev avatar janisozaur avatar milerius avatar mojert avatar morbo84 avatar nixaj avatar njakob avatar oortonaut avatar pgruenbacher avatar pkurth avatar qix- avatar sackhorn avatar samuel-emrys avatar skypjack avatar stefanofiorentino avatar szunhammer avatar tommitytom avatar vennor avatar w1th0utnam3 avatar widberg avatar wizardike avatar zaucy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

entt's Issues

Attach multiple components of the same type.

Is it possible to attach multiple components of the same type to an entity?

SCENARIO 1 (entity with multiple textures)
In modern OpenGL, array textures has taken over the old texture atlases. This "forces" you to use textures of same size.
If you imagine a game like Terraria, a world made up with 16x16 pixel tiles. But there are also plenty of sprites of different sizes. You would need to attach multiple Texture/Sprite/Appearance components to an entity, to make it look bigger. For example a door need an upper and lower part, both with an offset in position.

SCENARIO 2 (entity with multiple shapes)
When doing collision detection, you usually attach Shape/Hitbox components to an entity.
To describe more complex geometry of an entity's body, you need multiple shapes. For example a square and a circle with an offset in position.

These two scenarios would fit perfectly with how systems operate on components, for example a renderer just wants to iterate over the Texture components, not over entities.
I did find some similar problems other programmers had (alecmce/xember#12 and sschmid/Entitas#56), but I'm not sure if those were really "component" material.

I've been struggling with this for a week now, trying to find a good solution.
At first I just had a std::vector in TextureComponent, but it didnt feel good to abuse my CPU with cache misses. A std::array would work, but since most entities only have one texture, that also felt crazy.
In my current solution, for example; A main entity (the door) which has Physics and Sheet component. Plus two "entities" (the upper and lower part of the door) which only has a Texture component each. The sheet component is a std::vector with references to its childrens. The main entity doesnt contain any texture information at all.
The entity count will raise quickly with the current solution.

Is this something that could be added to this framework? Or do you have a better solution to my problem?

Great job on this framework. Also, I would love to put my project in the readme, once its done!

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?

Call for comments: runtime components support

Currently, being EnTT based exclusively on templates, there isn't the possibility to define components at runtime.
The main purpose would be for scripting and plugins, but who knows what other uses are out there.
See this as an example.

I've thought to the problem and I'm ready to develop a solution that fits well with the API of EnTT.
That being said, I would like also to know what are the use cases for such a feature, if any. I don't want to miss something during the development.

I'll leave the issue opened until the code is available on master.
Feel free to comment whenever you want, give suggestions and make request for related features.

a little trouble building in VS2017

I am trying to build the following sample program (from the readme) in VS2017 (debug x64) and get an internal compiler error, any thoughts?

#include "entt\entt.hpp"
#include <cstdint>

struct Position {
	float x;
	float y;
};

struct Velocity {
	float dx;
	float dy;
};

void update(entt::DefaultRegistry &registry) {
	auto view = registry.view<Position, Velocity>();

	for (auto entity : view) {
		// gets only the components that are going to be used ...

		auto &velocity = view.get<Velocity>(entity);

		velocity.dx = 0.;
		velocity.dy = 0.;

		// ...
	}
}
              
void update(std::uint64_t dt, entt::DefaultRegistry &registry) {
	registry.view<Position, Velocity>().each([dt](auto entity, auto &position, auto &velocity) {
		// gets all the components of the view at once ...

		position.x += velocity.dx * dt;
		position.y += velocity.dy * dt;

		// ...
	});
}

int main() {
	entt::DefaultRegistry registry;
	std::uint64_t dt = 16;

	for (auto i = 0; i < 10; ++i) {
		auto entity = registry.create(Position{ i * 1.f, i * 1.f });
		if (i % 2 == 0) { registry.assign<Velocity>(entity, i * .1f, i * .1f); }
	}

	update(dt, registry);
	update(registry);

	// ...
}

Error C1001 An internal error has occurred in the compiler

Error in Code Example

Hi!

I wanted to bring your attention to a potential issue in the Code Example in the README.

I am trying out entt and noticed I was getting a compilation error on the following loop:

for(auto entity: ecs.view<Position>().exclude<Velocity>()) 
{
    std::cout << (registry.has<Position>(entity)) << "/" << (registry.has<Velocity>(entity)) << std::endl;
}

Specifically, 'registry': undeclared indentifier.

Switching registry to ecs seems to make the example work as expected:

for (auto entity : ecs.view<Position>().exclude<Velocity>())
{
    std::cout << (ecs.has<Position>(entity)) << "/" << (ecs.has<Velocity>(entity)) << std::endl;
}

I only dabble in C++ so I didn't want to submit a PR for this fix in case I am missing something obvious.

[Request] Retrieve multiple components at once from entity.

Hi,
I was wondering if a method like
registery.get<ComponentA, ComponentB>(entity);
could be implemented?

The idea being you can retrieve a set of components from an entity instead of just one.
Something like:

template<typename ... Components>
std::tuple<Components...> get(std::uint32_t entity)
{
    return std::make_tuple<Components...>(/*get entity components*/);
}

Unless this can be done already with views? But I didn't see a way to get a view of only one entity.

problem with component references

Hi @skypjack,

with EnTT 2.0.1, the reference to a component returned from calls like:

auto &a1   = ecs.assign<Alberto>(e1);
auto &a1_a = ecs.template get<Alberto>(e1); // this is just another alias for a1

is no more valid after I add the same component to other entities, like in the following example:

using ECS = entt::DefaultRegistry;

(...)

int main(int argc, char*argv[]) {
    ECS ecs;
    auto e1    = ecs.create();
    auto e2    = ecs.create();
    auto e3    = ecs.create();
    auto e4    = ecs.create();
    auto &a1   = ecs.assign<Alberto>(e1);
    auto &a1_a = ecs.template get<Alberto>(e1); // this is just another alias for a1
    // add an Alberto component to entity e2
    auto &t2   = ecs.assign<Alberto>(e2);

    // address of a1_b should be same of a1 and a1_a
    auto &a1_b = ecs.template get<Alberto>(e1); // this is different from a1 and a1_a
    std::cout << "Hi, I'm Alberto E1, and my address is: " << &a1 << std::endl;
    std::cout << "Hi, I'm Alberto E1, and my address is: " << &a1_a << std::endl;
    std::cout << "Hi, I'm Alberto E1, and my address is: " << &a1_b << std::endl;

    ecs.reset();
    return 0;
}

I would expect a1, a1_a and a1_b to be referencing the same object, instead with EnTT 2.0.1 a1_b points to a different memory address.

With EnTT v1, the same code works; the following is the output I get when I run the code with v1 and v2:

[~/dev/tmp/entt_testcase/v1] $ ./sample_entt_v1
Hi, I'm Alberto E1, and my address is: 0x1015c7000
Hi, I'm Alberto E1, and my address is: 0x1015c7000
Hi, I'm Alberto E1, and my address is: 0x1015c7000
[~/dev/tmp/entt_testcase/v1] $ cd ../v2
[~/dev/tmp/entt_testcase/v2] $ ./sample_entt_v2
Hi, I'm Alberto E1, and my address is: 0x7fe429c026e0
Hi, I'm Alberto E1, and my address is: 0x7fe429c026e0
Hi, I'm Alberto E1, and my address is: 0x7fe429c02860
[1]    90293 segmentation fault  ./sample_entt_v2

Attached there is a test case (I only tried with macOS 10.12) showing the behavior described above, and also reproducing the crash I described in #13.
entt_testcase.zip

As usual, thanks for your support and for sharing this library with the community!

Call for comments: make EnTT allocator-aware

I was thinking about making EnTT allocator-aware. It's not the easiest task ever, but it could be an interesting feature.

To do that, the first thing that comes to my mind is to add an extra template parameter to the registry that is propagated down to the internal data structures if required. Moreover, I would add a reserve function to the registry to pre-allocate enough space for components and entities.
This way, users that don't want to deal with memory management can freely ignore the fact that EnTT is allocator-aware and let it use an std::allocator as it already does.

The other solution around is to define an interface for allocators that offers a few virtual member functions, then pass an opaque instance to the constructor of the registry.
I don't like that much this approach, for it looks to me much more invasive than the other one.

If anyone out there is listening, every comment is welcome as usual.

Call for comments: fewer allocations, faster destroy, slower each

A lighting call for comments about a change I'm working on.
The idea is to get rid of the available vector in the registry and replace it with an identifier that acts as an entry point of an implicit freelist within the entities vector.

Put aside the details of the internal changes that are probably not so appealing, these are the benefits:

  • Fewer allocations for obvious reasons.
  • The destroy member function gets a x4 in terms of performance (results of a preliminary test), that is an incredibly boost!

The member functions involved by this change are:

  • create: apparently it's not affected at all in terms of performance.
  • destroy: gets a x4, it's worth it definitely.
  • Registry::each: I've not yet tested it, but it could be slightly affected. However this function is already pretty slow by design and its intended use is mainly for serialization, so I wouldn't bother much for that.

As a side note, each member functions of views aren't affected at all.

From my point of view, the change is worth it. Fewer allocations and a faster destroy are something I'd like to have.

Unless someone comes with a good reason not to do it, I'm finalizing the change and merging it during the week.

The API of EnTT won't be affected at all.

Call for comments: blueprint/template

Another step towards the next version of EnTT.
The idea is to create a templating system (where template isn't intended as C++ template) with which to register predefined sets of components to assign to entities during creation.

Something along this line:

registry.blueprint<AComponent, AnotherComponent>("button");

// ...

auto entity = registry.create("button");

Doubts for which feedback would be appreciated:

  • Should it be part of the registry and thus extend its API and introduce another vector internally or could it be an external tool?

  • Runtime vs compile-time: HashedString can be used in constant expressions, otherwise they risk to introduce performance hits.
    In other terms, this has better performance at runtime:

    registry.blueprint<HashedString{"button"}, AComponent, AnotherComponent>();
    // ...
    auto entity = registry.create<HashedString {"button"}>();
    

    This one has a nicer API:

    registry.blueprint<AComponent, AnotherComponent>("button");
    // ...
    auto entity = registry.create("button");
    
  • Is there any interest in such a feature? (Actually this one should have been the first question, btw)

In any case, I can't work on it for at least a week probably. Because of this, there is enough time to discuss the best way to do it.

Thread safety info for functions.

For each function of the Registry api, it's important to know the thread-safety aspect of the function.
Please add a line to each function description in the documentation regarding this aspect.

For my particular needs, are Registry.create() and .destroy() thread safe?

Dereferencing causes data corruption

Hello there, this issue/bug might be completely my fault due to my lack of c++ knowledge so please excuse if that is the case.

I've started to run into an issue where sometimes entities in my case bullets where spawned at the wrong position. after digging into the issue I found that my player's transformation component (position, size, rotation) was sometimes, but not always, zero.

I've built the following script to reproduce the issue:

#include <glm/glm.hpp>

#include <entt/entity/registry.hpp>

using Entity = entt::DefaultRegistry::entity_type;

struct Transform {
    glm::vec3 origin;
    glm::vec3 size;
    glm::vec3 rotation;
    
    Transform(float x, float y, float width, float height, float angle = 0.0f) :
        origin(x, y, 0.0f), size(width, height, 0.0f), rotation(0.0f, 0.0f, angle)
    {}
};

struct Velocity {
    float x,y,z,w;
    
    Velocity(float x, float y, float z, float w) :
    x(x), y(y), z(z), w(w) {}
};

void update(entt::DefaultRegistry &registry, Entity main)
{
    auto &main_transform = registry.get<Transform>(main);
    
    auto child = registry.create();
    
    registry.assign<Transform>(child, 20.0f, 20.0f, 10.0f, 10.0f);
    registry.assign<Velocity>(child, 0.0f,  0.0f,  0.0f,  0.0f);
    
    if (main_transform.origin.x == 0.0f)
    {
        throw "Main tranform should still be 50.0";
    }
}

int main() {
    
    entt::DefaultRegistry registry;
    
    // create a main entity (player or whatever)
    Entity main = registry.create();
    registry.assign<Transform>(main, 50.0f, 50.0f, 100.0f, 100.0f);
    registry.assign<Velocity>(main, 0.0f,  0.0f,  0.0f,  0.0f);
    
    while(1) {
        update(registry, main);
    }
}

As you can see the transformation of the main entity gets at least for my understanding never modified. So the condition if (main_transform.origin.x == 0.0f) in the update method should never be reached, but it does.

As soon as I don't dereference the main transform:

 auto main_transform = registry.get<Transform>(main);

The issue disappears.

Thanks in advance and merry christmas :)

Persistent views aren't updated correctly during a full reset

After a full reset, persistent views contain the entities that had the components before to clear the registry.
Views aren't invalidated correctly and cannot be used anymore because of that.
Pretty rare an event, but it could happen and it's a bug.

Heap corruption if destroying entity with component containing unordered_set

Was playing around with entt for a project and started getting segfaults immediately after/during destroying entities. I ended up isolating the problem in the following code segment. Switching the unordered set to a vector seems to fix the problem and is my local band-aid, but I just wanted to give a heads-up that the heap seems to get thoroughly thrashed if components contain unordered sets - likely also other data structures, haven't checked any other than unordered_set and vector. Apologies if this issue is already known/some arcane restriction of C++ that can't be worked around.

#include <unordered_set>
#include "entt/src/entt/entt.hpp"

typedef std::uint32_t Entity;

struct Collidable {
  std::unordered_set<Entity> ignored;
  void addIgnored(Entity other) {
    ignored.insert(other);
  }
};

int main() {
  entt::Registry<Entity> registry;
  auto one = registry.create();
  for (int i=0; i<100; i++) {
    auto ent = registry.create();
    auto &collide = registry.assign<Collidable>(ent);
    collide.addIgnored(one);
  }
  std::vector<Entity> toDestroy;
  registry.view<Collidable>().each(
    [&toDestroy](auto entity, const auto &collide) {
    toDestroy.push_back(entity);
  });

  for (auto i : toDestroy) {
    registry.destroy(i);
  }
}

How would you move all entities from one registry to another?

Hello there!

I have the following use case. I'm loading levels from files in parallel, passing each thread a different instance of a registry. In the normal fork/join model, I'd like to combine/move all the entities into one registry moving forward after all levels have been loaded (I know, it seems unlikely to load all levels in memory at once but...)

Is this possible currently? How would you go about this?

Typo in Code Example

Thank you for your efforts, @skypjack !!
I admit that I have not yet used your library but I am excited about its evolution.

Meanwhile I suspect there are a typo in the sample:

Where...
auto view = ecs.view<Position, Velocity>()
Shoud be:
auto view = registry.view<Position, Velocity>()

DJuego

P.S:

I'm also interested in your event bus(eventpp) but in that field you have "competitors". ;-D

Requests for features: what's next?

I'm open to requests for features.

I have some long term tasks I'll tackle in sooner or later.
However, I'd like to have feedbacks about what you would like to see as part of the library (either in the ECS or as side tools like the signal stuff).
Let's make EnTT a better framework!!

Feel free to leave a comment here and we can discuss it.


I'll close the issue in a week probably, so don't miss the chance to contribute!!

iterators order

Hi Michele, great project. I've been using ECS for medium/large scale simulations for a while and this library has a great potential, being fast, small and easily embeddable.

I spent some time experimenting with EnTT and the only thing that feels strange is the default order in which the entities are returned in a view.
The begin() and end() iterators refer respectively to the end and beginning of the container vector, and the ++it operator goes backward.

I understand that the order of the entities/components can change at runtime, especially with the (very appropriate) swap-with-last on remove, but I believe that having iterators that reflect as much as possible the order used by the user and behaving as close as possible as the standard iterator makes the system easier to understand.

Any particular reason for the actual order (except for not storing the actual number of entities in the View)?

I can provide a patch or open a pull request if you believe that the modification makes sense.
Thanks!
Davide

Lua bindings

A common requirement for game engines is scripting (with lua in my case). As this ECS (and most other) use templates you can't bind most of the important functionality into lua.

For example, how would you bind registry.get<T>(entity); into lua?

EnTT and Unreal Engine 4

Hey,

I've ported the EntitasCSharp/Unity3D MatchOne example to EnTT/Unreal Engine 4, which can be found here under MatchOneEntt. It's a really small example and I would love to get feedback whether the places using EnTT could be improved in an idiomatic way.

In general it is quite pleasant to work with EnTT, though I do miss some features coming from Entitas-CSharp. Things like reactive systems that get triggered when a component gets added/removed from an entity for example. Also that mutltiple reactive systems can react to the same "event". Or to be more precise, to the same group of collected entities.

See both FallSystem and FillSystem reacting both to the same event and thus reducing the need for boilerplate code and components.
I get why EnTT has been architected this way, but maybe there is some kind of (opt-in) middle ground to alleviate the need for boiler plate in case one needs this?

As a new user of EnTT I accidentally used assign instead of attach when working with tags and was wondering if a clearly separate API would help reduce these kind of (user) errors. Something like addTag, removeTag, hasTag, replaceTag ...

What's especially confusing for me here is, that one mostly uses the regular API for Tags, but can't do that for replacing a tag(-component):

auto ScoreEntity = Registry.attachee<ScoreComponent>();
auto Score = Registry.get<ScoreComponent>();
Registry.attach<ScoreComponent>(ScoreEntity, Score.Value + 1);

Maybe it's ok to update components without ever telling EnTT about it?

When looking through registry.hpp there's lots of places describing undefined behaviour, e.g. when adding a component to an entity twice. The latter is clearly a user error (and sometimes hard to track), but one that I expect to happen from time to time. Wouldn't it make more sense to throw/assert by default there and not just in debug mode? So that users of EnTT have strict behaviour as a default and can opt-out if the need arises. Though to be honest I can't think of a reason why one would want a chance for undefined behaviour in the first place?

The last two things are related to Unreal Engine 4 in combination with EnTT:
UE4 defines a macro named ensure and uses it in various places deep in the engine code, making it practically impossible to not have it included in some place of the user code (resulting in compiler errors). Do you see any chance of renaming ensure to something else? :)
Also when exporting the project, the UE4 build tool fails, because of the noexcept specifier and it's (UE4) policy of disabled exception handling. That behaviour can hackishly be disabled for exported builds - but I think it's in the same category as the undefined behaviour by default described above. Would it be possible to change EnTT so that the excpetion behaviour could be selected via a macro for example?

Thanks for EnTT and looking forward to your feedback :)

Call for comments: "singleton mode" for tags

Well, ok, I didn't find a better name than singleton mode.
All the details are in the last comment of #62. I'm creating this issue to discuss them and to try to understand if it's one of the most wanted feature.
I'm also adding a note in the TODO list, mainly because I'm working on some other features at the moment.

Let's try to find the best way to define it in the meantime.

Who is using EnTT out there?

If you are using EnTT in a real world project, I want to let you know that there exists a dedicate section in the wiki where I'd be glad to add a link for you.
Feel free to add a comment to this issue or get in touch with me privately.

Issues compiling example on front page with MSVC++ 2017 (ver. 19.12.25835)

Hi, im very interested in this library but unfortunately i cannot compile any tests or examples because the compiler gives me a "C1001 Internal Compiler error." its probably something out of our controll but i might as well share it here

CompilerOutput.txt

Im using 64bit Windows 10.

looking at the example at the front page it seems to be this code snippet:

void update(std::uint64_t dt, entt::DefaultRegistry &registry)
{
	registry.view<Position, Velocity>().each([dt](auto entity, auto &position, auto &velocity)
	{
		// gets all the components of the view at once ...

		position.x += velocity.dx * dt;
		position.y += velocity.dy * dt;

		// ...
	});
}

Can anyone share their experience using Entt in MSVC++ ?

More on Save/Restore

This is an interesting comment about save/restore functionalities.
I'm opening a new issue because I plan to offer something more and want to discuss everything with anyone interested.


Here are parts of the comment above linked:

Is there a possibility to limit it to a subrange of entities? maybe a query like the ones in a system? In my example, i might want to replicate the Position component, but only on the entities that have a NetSerialize component. A interesting thing would be to have the snapshot to only be done on an array of entity IDs. I could do a view to see all the entities that have NetSerialize, and then only run the snapshot on those.

Alternatively, i could just do more "manual" serialization by having a Serialize system that reads NetSerialize and then adds every component it can (using has()) into a binary array or similar.

There is also quite a lot of wasted space just by all the times that entity id is serialize, wich is N + N*NComponents. Do you think a way to flip the serialization around so it ends up like "Entity1-C1-C2-C3""Entity2-C1-C4" would be possible? While this would definitely be more complicated, it would provide a huge boost to space.

I will answer the questions and I will make some proposals tomorrow morning (forgive me, it is almost midnight here).
In the meantime, feel free to comment if you want.


@dbacchet (the original question was yours) @vblanco20-1 (thanks for contributing to the discussion)

Systems?

Hi,

I was wondering if it would be possible to implement systems based on views. I'm not very familiar with templates to understand how everything in this library works, so I was hoping to get an answer here.

I imagine something like this would be useful:

template<class ECS, typename... Components>
class System<ECS, Components...>
{
public:

	using pool_type = typename ECS::pool_type;
	using entity_type = typename ECS::entity_type;


	System(ECS ecs) : m_ecs(ecs) {};
	virtual ~System() {};

	void run() {
		for (entity_type entity : m_ecs.view<Components...>())
		{
			process(entity);
		}
	}

	virtual inline void process(entity_type entity) = 0;

private:

	ECS m_ecs;

};

Then this would be used for each system like:

class MovementSystem : public System<ECS, Position, Velocity> ...

then in the game loop you'd just loop though all the systems and call run() or something like that.

Code above obviously doesn't work, just trying to give an example.

The program crashes when nothing abnormal happens

'The program has unexpectedly finished' with this minimal code:

int main (void) {
  struct Pos { float x, y; };
  auto registry = entt::DefaultRegistry<Pos>{};
  auto entity = registry.create<Pos>();
  return 0;
}

And no, with this addition of code to the end:

#ifndef NDEBUG
  registry.reset();
#endif

It seems to me that this confusing behavior, depending on the NDEBUG definition, looks bad, as well as this part of the code:

~SparseSet() noexcept {
  assert(empty());
}

Runtime hashed string?

Would be useful to have a run-time hashed string constructor. I already have this requirement and currently just have a copy of the hash function used. Obviously, this is a maintenance risk if you were to ever change that hashing function.

EDIT: To clarify, I am aware that if I have a char array with a predetermined size e.g char name[32] I can construct a HashedString at run-time but It would be nice to have the option to pass a std::string for example.

Version 1.0.0 versus latest 2.0.0 and more stringent component requirements?

I had a working entt based small project using entt version 1.0.0 (Jun 2017 approx.).

I upgraded to entt 2.0.0 and had to make minor changes to my code to get it to compile;

  1. header location changed from
     #include <registry.hpp>
to
     #include <entt/entity/registry.hpp>
  1. simplified from
using ECS = entt::DefaultRegistry<
 component::Body,
 component::Collideable,
 component::Particle,
 component::Renderable
>;

to

using ECS = entt::DefaultRegistry;

All compiled fine. Version 1.0.0 runs fine but version 2.0.0 fails. When version 2.0.0 ran I saw with gdb backtrace that an assert gives false and halts run in line 320 of registry.hpp.

Is the new version more stringent on the components? I have a suspect component defined as

#include <SFML/Graphics.hpp>

#include <iostream>

namespace component {

struct Body {
  Body(const sf::Vector2f &position, const sf::Vector2f &direction, float rotationd = 0.0)
    : position(position), direction(direction), rotationd(rotationd) {}

  sf::Vector2f position;
  sf::Vector2f direction;
  float rotation = 0.0, rotationd;
};

}; // namespace component

Is there something improper with this constructor as it relates to entt 2.0.0?

Towards EnTT v2.5/v3

Road to EnTT v2.5/v3 (it depends on the types of changes).
Here is a list of the new features and major changes planned for the next version.

  • Performance improvements for multi component standard views
  • Serialization/Deserialization
  • Spaces (not sure about this actually)
  • ...

Changes are merged on master step by step. They could also be breaking ones in terms of API.
Please, keep on using the latest tag if you want to switch to the new version at once.

C1001 internal compiler error in VS2017

For Visual Studio 2017 (compiler version Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25019 for x64), the uniform initialization of the pool tuple in the ComponentPool constructor:

explicit ComponentPool(size_type dim = 4098) noexcept
    : pools{Pool<Component>{dim}, Pool<Components>{dim}...}
{
    assert(!(dim < 0));
}

results in the internal compiler error

1>main.cpp(12): fatal error C1001: An internal error has occurred in the compiler.
1>(compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\yyaction.cpp', line 7249)
1> To work around this problem, try simplifying or changing the program near the locations listed above.

A temporary workaround is to replace the uniform initialization with a standard initialization:

: pools(Pool<Component>{dim}, Pool<Components>{dim}...)

The line can be found here. I reported it as a compiler bug in the Visual Studio Developer Community.

Call for comments: get rid of single instance components (aka tags)

I plan to get rid of single instance components. It is not a final decision yet, but I'm taking it seriously into consideration.

The reason is that they are useful sometimes (usually because of a design flaw in the client indeed), but one can easily work around the lack at application level.
As an example, in case EnTT was allocation-aware, a proper allocator that asserts on the second assignment would be enough. Another solution is that the system aimed to tag the entity is the same that stores the tag and refers it later, other than provide the identifier to those that are interested.

BTW, there is no reason for them to live in the Registry. On the other side, they are source of troubles when it comes to extend EnTT to offer save/restore functionalities and some other features.

What about if I get rid of them? Comments are appreciated.

Trouble with Visual Studio 2017 debug mode.

Hi! Thank you for EnTT. I want to notify this.

OS: Windows 10 x64

I have build successfully your library and the Code Example with MinGW Builds. And i get:

single component view
0,0
1,1
2,2
3,3
4,4
5,5
6,6
7,7
8,8
9,9
multi component view
0,0 - 0,0
2,2 - 0.2,0.2
4,4 - 0.4,0.4
6,6 - 0.6,0.6
8,8 - 0.8,0.8
single component view
9,9
1,1
2,2
3,3
7,7
5,5
6,6
multi component view

Process returned 0 (0x0)   execution time : 0.016 s
Press any key to continue.

Too I have build successfully your library and the Code Example with Visual Studio 2017. And i get the same result in release mode. However when i run in debug mode an exception is thrown:

	for (auto entity : ecs.view<Position, Velocity>()) {

The exception is produced in vector file "c:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.10.25017\include\vector"

 #if _ITERATOR_DEBUG_LEVEL == 2
	void _Compat(const _Myiter& _Right) const
		{	// test for compatible iterator pair
		if (this->_Getcont() != _Right._Getcont())
			{
			_DEBUG_ERROR("vector iterators incompatible"); <-----HERE
			}
		}

Thanks again!

DJuego

Call for comments: debugging tools.

I was wondering if some debugging tools could help the development of applications that use EnTT (or any other entity-component system in general).
I've my idea based on my own experiences of what could be useful. However, feedbacks from users that used EnTT in a real world scenario would be really useful!!

If you have any suggestion, feel free to leave a comment.
I cannot guarantee everything will be implemented, but I'll take in consideration each comment for sure!!

I'll close this issue at the end of the week.
Thank you very much for your help.

VS2017 parsing issue

Today is a busy day, I kind of feel sorry opening another issue.

I'm also running into an Issue with VS2017, until know I've been building with gcc and XCode. I've spent the last few days fixing issues to be able to run my application on WIndows. The last issue I was not able to resolve looks like a parsing issue in the view.hpp.

It's weird because I can see that the entt tests run successfully on the CI Service with VS.

It seems to be only one line VS struggles with inside the reset method.

void reset() {
    using accumulator_type = size_type[];
    auto probe = [this](auto sz, auto &pool) { return pool.size() < sz ? (view = &pool, pool.size()) : sz; };
    size_type sz = std::max({ std::get<pool_type<Component> &>(pools).size()... }) + std::size_t{1};  // This line here.
    accumulator_type accumulator = { sz, (sz = probe(sz, std::get<pool_type<Component> &>(pools)))... };
        (void)accumulator;
}

This is line 517:

size_type sz = std::max({ std::get<pool_type<Component> &>(pools).size()... }) + std::size_t{1};

Here is the error output:

/src\entt\entity\view.hpp(517): error C2062: type 'unknown-type' unexpected
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ';' before '{'
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ')' before ';'
/src\entt\entity\view.hpp(517): error C3520: 'Component': parameter pack must be expanded in this context
/src\entt\entity\view.hpp(517): error C2228: left of '.size' must have class/struct/union
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ';' before '...'
/src\entt\entity\view.hpp(517): error C2059: syntax error: '...'
/src\entt\entity\view.hpp(517): error C2059: syntax error: ')'
/src\entt\entity\view.hpp(517): error C2059: syntax error: '>'
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ';' before '{'
/src\entt\entity\view.hpp(517): error C3520: 'Component': parameter pack must be expanded in this context
/src\entt\entity\view.hpp(517): error C2228: left of '.size' must have class/struct/union
/src\entt\entity\view.hpp(517): error C2059: syntax error: '...'
/src\entt\entity\view.hpp(517): error C2059: syntax error: ')'
/src\entt\entity\view.hpp(517): error C2059: syntax error: ':'
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ';' before '{'
/src\entt\entity\view.hpp(517): error C2143: syntax error: missing ';' before '}'

Thanks in Advance.
PS: I love the signal stuff, I've been able to implement it :)

Guidelines

The current ECS guideline offers a starting point with samples and user cases. I definitely think it would be a good idea to create guidelines for other EnTT features (signals, event bus, scheduler, event dispatcher, ... similar to the current ECS guideline (registry and views).

That would greatly improve the appeal of the library for newcomers.
Of course, a list of documented methods is essential/necessary for reference. However It is not enough. (IMHO).

Obviously, it is a work in the medium and long term... but I believe it brings more added value than many other features. And it helps publicize the power of EnTT.

DJuego

Making `snapshot` const?

It would be really great if the Registry's snapshot function could be marked const, but something that gets in the way of that is the following line which gets a view into the registry for a particular component. Since view calls ensure, which is non-const, the Registry member variable of the snapshot class can't be marked const. Do you think there might be a way around this? Would be nice to have, but not particularly important.

accumulator_type accumulator = { 0, (get(archive, registry.template view<Component>()), 0)... };

Expose size() member for View class?

Hello, I just started to use this library and have a simple question. I would like to assert at runtime there is only one entity in my registry with a certain component. To do this, I would like to write the following statement
assert(1 == view.size());

At this point I found there is no size() member on a View. It has a size type, but no member function for counting the number of entities.

I noticed that PersistentView has a size member.

My intuitive understanding is, the semantics of a "size" member function for a "view" would be the number of entities in the view with all the components. My question, is there a semantic reason for not having a size() member function on View?

If it's a performance reason, would a different function (ie: count) providing these semantics be palatable?

Call for comments: get rid of some member functions

Currently, we have three different versions of the Registry::create member function:

  • Plain:
    entity_type create() noexcept;
    
  • Default initialized components:
    template<typename... Component>
    entity_type create() noexcept;
    
  • Initialized components:
    template<typename... Component>
    entity_type create(Component &&... components) noexcept;
    

Honestly, it's pretty annoying to maintain all of them and more than once I've been in trouble because they were a problem while trying to figure out how to develop other features.
It would help getting rid of the last two versions and replace them with a new version of assign that accepts initialized components (to create more components all at once).


I'm sure this issue will attract a lot of - no, please - and I'll end up leaving the functions where they are, but asking does not cost anything. :-)

Call for comments: single instance components (aka tags)

So far, tags and components have no requirements and a type can be used both as a component and as a tag.
This is also the reason for which their APIs are slightly different. As an example, to assign a tag we must use attach and to replace it we have to use set.
This approach could be error-prone, mainly because it happens that users use a tag as if it's a component or viceversa and the bugs that arise from this are quite subtle.

A possible solution would be to completely separate the two APIs. Sort of assign vs assignTag, replace vs replaceTag and so on.
However, this is still error-prone and internally it's hard to say sometimes if a type is a tag or a component for the registry. Something similar is true also for the clients.
Consider the following line:

auto type = registry.component<MyTag>();

It works and that's all. Put errors like this one all around a codebase and pretty annoying bugs are for free.

A more (let me say) type-safe approach would be to force users to define tags as derived classes like this:

struct MyTag: SingleInstanceComponent<MyTag> {
    // ...
};

This way tags and components can share exactly the same API (replace, assign and so on, no exceptions). Sfinae will do the rest.
Moreover, the registry would know at all times what kind of object it is working with. It means compile-time errors if an user uses a tag as if it's a component or viceversa. It means more chances for optimizations. And so on.
Drawbacks? The base class from which to inherit. I tried to avoid it so far for I'm not a fan of forcing users to do something. Anyway, single instance components probably is worth it.

Any comment? Could it be a viable solution?

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.

VS2017 15.5.3 compilation error when using views (C++17)

Getting a compilation error when using views with entt (commit 9761b6e) in sparse_set.hpp

Error C2664 'void std::swap(std::exception_ptr &,std::exception_ptr &) noexcept': cannot convert argument 1 from '<COMPONENT_NAME>' to 'std::exception_ptr &' at sparse_set.hpp line 621
with <COMPONENT_NAME> the name of a component class.

entt::Entity is just
using Entity = std::uint32_t
one line above
using DefaultRegistry = Registry<std::uint32_t>;
in registery.hpp
(unless this is source of issue?)

Full output: https://pastebin.com/ViUaP9u3

Resource loader - function does not take 0 arguments.

Having this error when trying to use the resource loader.

Thought it was my code to begin with but I took a copy of the example loader in comments:

struct MyResource {};

struct MyLoader : entt::ResourceLoader<MyLoader, MyResource> {
	std::shared_ptr<MyResource> load(int) const {
		return std::make_shared<MyResource>();
	}
};

And I try and use it:

entt::ResourceCache<MyResource> cache;
cache.load<MyLoader>("test");

I get the compile time error of C2660 'MyLoader::load': function does not take 0 arguments

Retrieve all active entities from the registry

Correct me if im wrong, std::vector<entity_type> available and std::vector<entity_type> entities
are both private properties and there seems to be no class method in the registry to simply retrieve all active entities.

I would really love to see a way to iterate over all entities.

for(auto entity : registry.all())
{
    // something 
}

Rename "ensure" to "assure"

I'm creating a new issue to track for the renaming of ensure/assure mentioned in #61

The last two things are related to Unreal Engine 4 in combination with EnTT:
UE4 defines a macro named ensure and uses it in various places deep in the engine code, making it practically impossible to not have it included in some place of the user code (resulting in compiler errors). Do you see any chance of renaming ensure to something else? :)

Put them in the TODO list. Is assure fine for UE4? Any other suggestion?

That sounds fine to me and I've also assured that there's also no macro defined with that name.

Call for comments: spaces

I've been fascinated for a while by the idea of having spaces implemented directly within EnTT.
Actually, more than once I found myself saying - uff, if only I had spaces here, it would be easier to do this.

However I postponed the implementation because:

  • I didn't want them to be part of the registry, because not all users want them and find them useful - in other terms, I don't want to introduce spaces and thus to affect performance of the registry in any case.
  • I didn't want them to not be part of the registry, because I wasn't able to find a way to make it work properly (mainly to keep spaces in sync with a registry isn't for free).

Finally, perhaps I found a way to implement spaces and give them a minimal API that just works.
The goal is to not add a duplicated set of functions from the registry, only to add boilerplate all around the codebase.

Not exactly the same, but here is an example of what it will look like probably:

template<typename Entity>
struct Space {
   Space(Registry<Entity> &registry);

    // iterate all the entities, false positive (invalid entities) are possible
    iterator_type begin() const noexcept;
    iterator_type end() const noexcept;

    // create an entity and assign it directly to the space
    entity_type create();

    // assign an entitiy to the registry
    void assign(entity_type entity);

    // iterate entities using a standard view internally, invoke the function for each entity
    // invalid entities are filtered out an never returned through func (lazy clean of a space)
    template<typename... Component, typename Func>
    void view(Func func);

    // iterate entities using a persistent view internally, invoke the function for each entity
    // invalid entities are filtered out an never returned through func (lazy clean of a space)
    template<typename... Component, typename Func>
    void persistent(Func func);

    operator const registry_type & () const noexcept;
    operator registry_type & () noexcept;
};

Minimal, clean, does the job. Users cannot do everything with the sole space, they must work together with the registry. On the other side, spaces won't affect the performance of a registry in case one doesn't use them.
Moreover, spaces won't have dedicated views. They offer only two each-like functions under the names view and persistent.
Finally, users can create how many spaces they want at runtime this way. They don't have a name or an identity. Consider a space as a partition of a registry.


Any feedback or suggestion is really appreciated. Questions are good as well.
I still have some doubts, but I prefer not to influence you. :-)

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.

Upcoming changes

Here is the discussion mentioned in #10 to talk about upcoming features.
The plan is to clean up the API (some methods are simply redundant) and to make it more user-friendly if possible. Moreover, performance on multi components views should be improved significantly.

Let's make a list of changes and discuss about it:

  • Remove copy, it's syntactic sugar for:

    registry.accomodate<Position>(to, registry.get<Position>(from));
    

    accomodate creates the component if to has not it, otherwise it overwrites the existent component. One can safely use it wherever copy has been used. Finally, entity wide versions of copy is useless and error-prone and the burden to maintain it doesn't worth the price.
    replace can also be removed, but probably it's the sole function that make sense along with accomodate.

  • Remove clone, it cannot be implemented correctly. Users should not clone an entity as a whole for they don't know to what components the entity is bound. clone should rather be a high level functionality that picks components up selectively.

  • Remove swap, it's syntactic sugar for:

    std::swap(std::get<Position>(e1), std::get<Position>(e2));
    

    Moreover, it's confusing what should be the expected behavior. It could either swap the sole components between entities or the entities with all their data within the entity list. The result isn't the same.

  • Remove the requirement of declaring components at compile-time. This:

    Registry<Position, Velocity> registry;
    // ...
    auto entity = registry.create<Velocity>();
    // ...
    

    Becomes this:

    Registry registry;
    // ...
    auto entity = registry.create<Velocity>();
    // ...
    

    The main advantage should be in terms of compilation time for large projects. The registry is included in each and every file that uses a component. On the other side, a component is included only in a few files that work with it.
    The price to pay is a slightly slower assign function. Iterations shouldn't be affected by this change.

  • Rework the way multi components views are treated and bring the performance down to the ones of single components views.
    The price to pay is probably slightly slower assign and remove functions.

  • Largely improve the sort functionalities, both versions.

  • Introduce entity version. It will make reuse of IDs easier and safer. Entities will be represented by opaque numbers that contain both the id and the version. The system will verify the latter at each use. valid will use the version of the entity to compute a result.

  • ...

Any comment and suggestion is welcome, feel free to participate and post here your thoughts.

Error in VS2015

Hi, i have C2610 error in VS 2015 on this lines:
/*! @brief Default copy assignment operator. @return This hashed string. /
constexpr HashedString & operator=(const HashedString &) noexcept = default;
/
! @brief Default move assignment operator. @return This hashed string. */
constexpr HashedString & operator=(HashedString &&) noexcept = default;

In hashed_string.hpp.

Fix: comment constexpr for VS 2015(using define _MSC_VER>1900)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.