/entt

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

Primary LanguageC++MIT LicenseMIT

EnTT: Gaming meets modern C++

GitHub version LoC Build Status Build status Coverage Status Gitter chat Donate

Patreon

Table of Contents

Introduction

EnTT is a header-only, tiny and easy to use entity-component system (and much more) written in modern C++ and even used by Mojang in Minecraft.
The entity-component-system (also known as ECS) is an architectural pattern used mostly in game development. For further details:

A long time ago, the sole entity-component system was part of the project. After a while the codebase has grown and more and more classes have become part of the repository.
Here is a brief, yet incomplete list of what it offers today:

  • Statically generated integer identifiers for types (assigned either at compile-time or at runtime).
  • A constexpr utility for human readable resource identifiers.
  • A minimal configuration system built on top of the monostate pattern.
  • An incredibly fast entity-component system based on sparse sets, with its own views and a pay for what you use policy to adjust performance and memory usage according to users' requirements.
  • A lot of facilities built on top of the entity-component system to help developers and avoid reinventing the wheel (ie dependencies, snapshot, actor class for those who aren't confident with the architecture and so on).
  • The smallest and most basic implementation of a service locator ever seen.
  • A built-in, non-intrusive and macro-free runtime reflection system.
  • A cooperative scheduler for processes of any type.
  • All what is needed for resource management (cache, loaders, handles).
  • Delegates, signal handlers (with built-in support for collectors) and a tiny event dispatcher for immediate and delayed events to integrate in loops.
  • A general purpose event emitter as a CRTP idiom based class template.
  • And much more! Check out the wiki.

Consider it a work in progress. The whole API is also fully documented in-code for those who are brave enough to read it.

Currently, EnTT is tested on Linux, Microsoft Windows and OS X. It has proven to work also on both Android and iOS.
Most likely it will not be problematic on other systems as well, but has not been sufficiently tested so far.

Code Example

#include <entt/entt.hpp>
#include <cstdint>

struct position {
    float x;
    float y;
};

struct velocity {
    float dx;
    float dy;
};

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

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

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

        vel.dx = 0.;
        vel.dy = 0.;

        // ...
    }
}

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

        pos.x += vel.dx * dt;
        pos.y += vel.dy * dt;

        // ...
    });
}

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

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

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

    // ...
}

Motivation

I started working on EnTT because of the wrong reason: my goal was to design an entity-component system that beated another well known open source solution in terms of performance and used (possibly) less memory in the average case.
In the end, I did it, but it wasn't much satisfying. Actually it wasn't satisfying at all. The fastest and nothing more, fairly little indeed. When I realized it, I tried hard to keep intact the great performance of EnTT and to add all the features I wanted to see in my own library at the same time.

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

Performance

As it stands right now, EnTT is just fast enough for my requirements if compared to my first choice (it was already amazingly fast actually).
Below is a comparison between the two (both of them compiled with GCC 7.3.0 on a Dell XPS 13 out of the mid 2014):

Benchmark EntityX (compile-time) EnTT
Create 1M entities 0.0147s 0.0046s
Destroy 1M entities 0.0053s 0.0045s
1M entities, one component 0.0012s 1.9e-07s
1M entities, two components 0.0012s 3.8e-07s
1M entities, two components
Half of the entities have all the components
0.0009s 3.8e-07s
1M entities, two components
One of the entities has all the components
0.0008s 1.0e-06s
1M entities, five components 0.0010s 7.0e-07s
1M entities, ten components 0.0011s 1.2e-06s
1M entities, ten components
Half of the entities have all the components
0.0010s 1.2e-06s
1M entities, ten components
One of the entities has all the components
0.0008s 1.2e-06s
Sort 150k entities, one component
Arrays are in reverse order
- 0.0036s
Sort 150k entities, enforce permutation
Arrays are in reverse order
- 0.0005s
Sort 150k entities, one component
Arrays are almost sorted, std::sort
- 0.0035s
Sort 150k entities, one component
Arrays are almost sorted, insertion sort
- 0.0007s

Note: The default version of EntityX (master branch) wasn't added to the comparison because it's already much slower than its compile-time counterpart.

Pretty interesting, aren't them? In fact, these benchmarks are the same used by EntityX to show how fast it is. To be honest, they aren't so good and these results shouldn't be taken much seriously (they are completely unrealistic indeed).
The proposed entity-component system is incredibly fast to iterate entities, this is a fact. The compiler can make a lot of optimizations because of how EnTT works, even more when components aren't used at all. This is exactly the case for these benchmarks. On the other hand and if we consider real world cases, EnTT is in the middle between a bit and much faster than the other solutions around when users also access the components and not just the entities, although it is not as fast as reported by these benchmarks.
This is why they are completely wrong and cannot be used to evaluate any of the entity-component systems.

If you decide to use EnTT, choose it because of its API, features and performance, not because there is a benchmark somewhere that makes it seem the fastest.

Probably I'll try to get out of EnTT more features and even better performance in the future, mainly for fun.
If you want to contribute and/or have any suggestion, feel free to make a PR or open an issue to discuss your idea.

Build Instructions

Requirements

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

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

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

Library

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

#include <entt/entt.hpp>

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

#include <entt/entity/registry.hpp>

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

Documentation

The documentation is based on doxygen. To build it:

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

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

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

It's also available online for the latest version.
Finally, there exists a wiki dedicated to the project where users can find all related documentation pages.

Tests

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

To build the most basic set of tests:

  • $ cd build
  • $ cmake ..
  • $ make
  • $ make test

Note that benchmarks are not part of this set.

Packaging Tools

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

  • vcpkg, Microsoft VC++ Packaging Tool.
  • Homebrew, the missing package manager for macOS.
    Available as a homebrew formula. Just type the following to install it:
    brew install skypjack/entt/entt
    

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

EnTT in Action

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

Here you can find and 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

EnTT was written initially as a faster alternative to other well known and open source entity-component systems. Nowadays this library is moving its first steps. Much more will come in the future and hopefully I'm going to work on it for a long time.
Requests for features, PR, suggestions ad feedback are highly appreciated.

If you find you can help me and want to contribute to the project with your experience or you do want to get part of the project for some other reasons, 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 seriously.

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-2018 Michele Caini.
Logo Copyright (c) 2018 Richard Caseres.

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

Support

Patreon

Become a patron and get access to extra content, help me spend more time on the projects you love and create new ones for you. Your support will help me to continue the work done so far and make it more professional and feature-rich every day.
It takes very little to become a patron and thus help the software you use every day. Don't miss the chance.

Donation

Developing and maintaining EnTT takes some time and lots of coffee. I'd like to add more and more functionalities in future and turn it in a full-featured solution.
If you want to support this project, you can offer me an espresso. I'm from Italy, we're used to turning the best coffee ever in code. If you find that it's not enough, feel free to support me the way you prefer.
Take a look at the donation button at the top of the page for more details or just click here.

Hire me

If you start using EnTT and need help, if you want a new feature and want me to give it the highest priority, if you have any other reason to contact me: do not hesitate. I'm available for hiring.
Feel free to take a look at my profile and contact me by mail.