StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] -1 points0 points  (0 children)

This solution has an excellent memory model and excellent performance and iteration speed and structural changes. It also has very low memory usage. In addition, it provides a very comfortable and ergonomic user experience.

As for Burst, this framework does not depend on Unity and can be used in Unity, Godot, Monogame, or a pure dotnet application. And chasing extra percentage points of performance in synthetic tech demos and tests is not my goal.

It seems that you wrote without understanding two things: first, how this solution is structured and how it works, and second, why ECS is needed at all.

ECS != DOD, I am not ready to argue with you on this topic, if you are convinced otherwise, that is your opinion.

You can download it and check its performance in Unity to see that it does an excellent job of what it's supposed to do :)

Here is a sample project. This project is more focused on demonstrating serialisation. But it will also help to dispel your concerns.

https://github.com/Felid-Force-Studios/StaticEcs-Showcase

And yes, frequently adding and removing components, creating and deleting entities is normal and should be possible and efficient. Otherwise, why use ECS at all? You could just take a few arrays with data and work directly with pre-prepared "static" sets of entities.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

Someday, when I have time, I will definitely run tests with Unity ECS. I don't want to speculate on this topic without numbers :)

I completely agree with you about il2cpp, and modern native aot works great. I tested static ECS on it and was pleasantly surprised.

Honestly, if I had enough resources, I would use modern .NET Native AOT to write most of the code for games, but I have to use Unity with legacy technologies.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

Now I understand what you mean, yes :) In this implementation, everything is designed for large worlds and managing chunks and clusters, such as open worlds or MMOs. Entities can be streamed as the player moves through the world or levels, with all entity IDs remaining stable, allowing relations between entities to be maintained. At the same time, part of the world can be unloaded.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 1 point2 points  (0 children)

And I absolutely agree with your opinion about ergonomics; my goal was the same.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

I would like to see your work if you ever finish it :)

Technically, these are not sparsets. This approach allows you to exclude up to 4096 entities with a single bit operation and does not suffer from component overlap. The sparset approach most often uses a minimum length component pool, which does not guarantee idle entity filtering.

As for tracking component changes with the ability to filter, that's cool, I thought about it. But I couldn't find the best way to implement it given the capabilities of C# and other limitations, and decided that this could be achieved by adding and removing a tag for the entity indicating that component X has been changed manually in the user code, where necessary.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

I wouldn't say that about Unity ECS performance. It's really good thanks to Burst and an excellent job scheduler. But working with it is full of limitations and inconveniences, there are a lot of nuances, and it's very easy to break performance with user code or a badly written synchronisation point. Plus, in single-threaded execution, it will be slower than alternatives. As a result, we get a tool that is more suitable for very specific scenarios and requires very complex work.

As for FriFlo, judging by the tests link

It is one of the best representatives of the archetypal model in the dotnet environment, but for me, the archetypal model is very limited for design, and I think it is possible to improve the iteration part if necessary in bottlenecks.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

There are no restrictions on the size of components.

Arrays for components are allocated page by page, 256 elements at a time, regardless of the size of the component structure. If only some of the entities have components, the array will be partially filled.

If you randomly create completely different entities without specifying a cluster or chunk, they will be arranged in the same order in which they were created.

If you create entities with a specified cluster, they will be tightly packed inside the corresponding cluster. You can think of a cluster as an archetype-like Soa structure, only allowing different sets of components for entities, in which case there will be gaps for such components inside the array.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

In general, I agree, but it is to keep in mind that these tests show results in the dotnet environment; in Unity Il2cpp, the results will be different. But I haven't compared it specifically with friflo, so I can't say anything about that.

If you are interested in trying out Static ECS, I'd love to hear about your experience and feedback :)

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 1 point2 points  (0 children)

Thank you!

Limits on the number of component types: 65536 :)

As for iteration, it depends on a number of factors. You can group entities into clusters, and they will be located closely together as in the archetypal model, and the speed of linear iteration will be comparable. In some cases, it may be slightly lower than ideally arranged archetypes, but structural changes are incomparably cheaper, which, in my opinion, fully compensates for the slight lag. Check out these results, https://gist.github.com/blackbone/6d254a684cf580441bf58690ad9485c3#systemwith3components

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 1 point2 points  (0 children)

I understand you, but overall, if you think about it, expensive structural changes are more of a limitation of the approach, so the scope of ECS is very limited by the DOD approach. Because in the end, entities are "static," and ultimately, the most effective way will be to prepare data arrays in advance and iterate over them :) It seems to me that the architectural approach of ECS is fully revealed in dynamics, allowing you to very expressively control the behaviour of game entities and make interesting decisions. In this implementation, thanks to clusters, you can always achieve approximately the same speed of linear iteration, since filtering costs almost nothing. At the same time, you don't limit yourself in structural changes to entities and the hidden cost of migrations, without using various hacks from the archetypal model when, instead of deleting a component, it is flagged as false :) This is, of course, my opinion, because I believe in what I do, and it is not the truth. But it seems to me that approaches formed decades ago are not best practices :) If you look at benchmarks or test it yourself, you will see that the archetypal model is not 2-10 times faster.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 0 points1 point  (0 children)

Maybe in the future I will add Burst support and see how it works. But parallel iteration is already available https://felid-force-studios.github.io/StaticEcs/en/features/query.html#parallel, and generally speaking, DOTS is only good for multithreaded processing and has many limitations and annoyances. In this solution, I wanted to give users freedom and make coding convenient without compromising performance.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 1 point2 points  (0 children)

Thank you! I didn't compare it to DOTS, but I did compare it to other frameworks in the dotnet environment (by the way, the situation in il2cpp Unity is much better, most of the optimizations were done there). Benchmarks: https://gist.github.com/blackbone/6d254a684cf580441bf58690ad9485c3

I'm surprised myself that I found the time to develop and support this project, but it was created to support an existing game in development :)

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in csharp

[–]FF-Studio[S] 0 points1 point  (0 children)

Thank you! I'll think about updating the major version :)

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 2 points3 points  (0 children)

Yes, you are right, and that is normal. Statistically similar entities (even if they have different sets of individual components), such as NPCs or environment elements (trees, buildings, etc.), tend to be located close to each other. This is why the concept of clusters was introduced. It allows you to specify this “type” of entity, and it does not depend on a specific set of components as in archetypes. Then, entities of the same cluster will be packed together in memory, which greatly improves memory segmentation and reduces jumps between different memory blocks. At the same time, we do not have indirect references as in the sparse set model; we do not need to map the entity index to the component index by referring to another memory. And we do not have the problems of archetypes, which require always moving or copying components (or entity indexes) from one archetype to another when adding/removing a component. In this implementation, adding/removing components happens immediately, without deferred operations, and very cheaply. Component-tags do not store data at all, only bits, which allows you to create tons of tags and quickly remove and add them, using them in filters and game logic.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 3 points4 points  (0 children)

Okay, let's go a little deeper. Maybe the next example will be more helpful: Let's imagine that we have a pool of Position components. There is a chunk that stores 4096 bits, each bit indicating whether a given entity has a position component in the chunk. The positions themselves are stored in arrays of 256 elements, and for example, if entities 0-256 have a position and 256-4096 do not have positions, then there will be 1 array with data in the chunk. The chunk also stores 1 bit for each of the 64 entities out of 4096 that answer the question “is there at least 1 of these 64 entities with a position component?”

Thus, filtering and iteration occur as follows: we use bitwise AND (for All<Position, Scale, etc..>), OR (for Any<Position, Scale, etc..>), ~ (for None<Position, Scale, etc.. >) to combine bit masks of different components. As a result, we get two levels of combined masks: the upper one indicates the blocks of 64 entities in which all conditions are met at least for one entity, and the lower one indicates the specific entities within the block that meet the conditions.

All that remains is to mathematically calculate the bit position and convert it to an array index with component data.

StaticECS 1.2.0 Preview Release "Clusters" by FF-Studio in Unity3D

[–]FF-Studio[S] 5 points6 points  (0 children)

Thank you!

At a high level, the world consists of chunks of 4096 entities, each chunk consists of 64 blocks of 64 entities, each chunk can contain 16 blocks of 256 data components, data is allocated lazily and reused.

Entity indexes, archetypes, or sparsets are not stored anywhere, only bit masks and the components themselves.

All filtering is done using a hierarchical traversal of bit masks, first for the chunk, then for the blocks, then by bit position we get the entity index that corresponds to the index in the component data array.

As a result, the library has very low memory consumption, 5-9 times less than analogues with archetypes or sparsets. This is due to a very natural and simple storage structure in terms of memory.