Giter Club home page Giter Club logo

skypjack / entt Goto Github PK

View Code? Open in Web Editor NEW
9.5K 9.5K 834.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%
architectural-patterns cpp cpp17 cpp20 data-oriented data-oriented-design ecs ecs-framework entity-component-system entt game-dev game-development game-engine game-programming gamedev header-only modern-cpp no-dependencies production-ready reflection

entt's Introduction

Hi there, I'm skypjack ๐Ÿ‘‹

zak

Despite what you may have thought, I'm not Zak. Iโ€™m Michele Caini, software developer from Florence, Italy.
I'm also a freelancer, I work mainly remotely and in my free time I dedicate myself to some open source projects such as EnTT.
Oh... and I'm a father too, madly in love with my wife and son who always support me! ๐Ÿ˜

Something about me:

  • ๐Ÿ”ญ Iโ€™m currently working on Minecraft, thanks to the Microsoft Mojang Studios ๐Ÿ˜ฒ and I'm very grateful for this opportunity.
  • ๐Ÿ’ป I'm a freelancer. Don't hesitate to contact me if you want to offer a collaboration. Fond of C++, gaming and high perf.
  • ๐Ÿ“ซ Check the links in my profile. Feel free to ping me to say hello, introduce yourself and have a chat. ๐Ÿ™‚

๐Ÿ™ Support me if you like ...

Everything you can find on my GitHub profile or on my blog I do in my spare time, without any kind of income.
If you want to help me by contributing or otherwise supporting me, you can take a look at my sponsorship page.

Twitter: scaipgec GitHub skypjack

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

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.

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());
}

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.

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. :-)

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.

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.

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.

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

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.

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.

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!

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?

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 :)

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)

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 :)

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

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.

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

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?

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

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.

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.

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)

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

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?

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!

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?

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.

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)... };

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?

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

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 
}

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?

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 :)

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);
  }
}

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.

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

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.

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.

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++ ?

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

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.

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

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?

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!!

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.

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.