Multiplayer RTS: Eyos
Game

In this side project the goal was to write a Networked Cross-platform Multi-threaded RTS with millions of units that we had to manage. This side project was to challenge us to write performant and multi-threaded code.

Github   

Performance Target: The Game

We wanted to push ourselves in a direction where we had no choice but to optimize performance to get to our goal. We designed the gameplay of the RTS to be as simple as possible, but scaled up to a million (literally).

My Contributions

Client Architecture: Entity Component System (ECS)

I was the main engine programmer and architect on the client side. I handled the graphics and the way that entities were stored.
For this I designed a efficient ECS for our needs. We needed our data to be tightly packed for cache coherency and we needed to quickly query and delete entities. As they would die quickly in a big battle.
For this I choose a tightly packed SOA style storage strategy where a single bitmask was used to identify per index which components an entity had. I was able to get away with this design because I knew that most entities in the game would have most components.



The other requirement was that the (gameplay) systems needed to be multi-threaded. As that would allow us to go for the highest performance possible. This was another requirement for the ECS, that it needed to play well with a parallel task scheduler.

For inspiration we of course looked at Unity DOTS. While ofcourse keeping in mind that we didn't nearly need the amount of abstraction that they do as we are designing the system only for this one specific game.
The main takeaways that we got from Unity DOTS was their systems and querrying API. And the sync points combined with their "CommandBuffers".
I also took inspiration from the API of Specs. Which also influenced the API for systems heavily.

struct Pos{
    float x,y,z;
};
struct Vel{
    float vX, vY, vZ;
}
struct Health{
    int value;
}

template<>
struct SystemInput<class MovementSystem> {
    // We want to get a mutable ref to position, a readonly ref to velocity, and a copy of the health component.
    using Query = Types<Pos&, const Vel&, Health>
    // Dependencies to other systems
    using Dependencies = Types<>
}

class MovementSystem : eyos::System<MovementSystem> {
    using Super = eyos::System<MovementSystem>

public:
    void Init(World& world) override;
    void Update(Super::SystemComponentQuery& query);
    void Shutdown() override;

private:
    World* world;
};

void MovementSystem::Update(Super::SystemComponentQuery& query) {
    for(auto entityProxy : query) {
        auto&&[pos, vel, health] = entityProxy;
        
        if(health.value > 0)
            pos += vel * world->time.GetDeltaTime();
    }
}