Documentation
  • 🏠Home
    • Parallel-Origin Documentation
  • Server
    • Introduction
    • Database
    • Entity Component System
    • Networking
    • Physics
    • Workflow
  • Client
    • Introduction
    • Internal Database
    • Entity Component System
    • Networking
    • User Interface
    • Workflow
  • Core
    • Introduction
    • Shared Components
    • Shared Networking
    • Shared Utils
    • Workflow
Powered by GitBook
On this page
  • Introduction
  • Usages
  • Example
Edit on GitHub
  1. Server

Entity Component System

Everything important about the ECS.

PreviousDatabaseNextNetworking

Last updated 1 year ago

Introduction

The is part of the basic server architecture. It manages game entities, allows them to be created from compositions of different components and allows us to easily iterate over them to execute logic on them. It is the way we express and deal with game-entities. And the best... it is incredibly efficient and fast! For this, the server uses , an ECS written by the same team and one of the fastest (if not the fastest without bragging).

For more information on how exactly an ECS works, check out the and .

Usages

So where is it used and how? Well... everywhere. The whole world and the main part of the server is expressed as ECS. Already in it starts, there the world is created in which all game entities will live.

Program.cs
_world = World.Create();

And shortly after that a , which contain the world logic and process game entities. This group is processed every few frames, it is ... it IS the game loop.

var systems = new Arch.System.Group(
 
        // Reactive Systems
        new ReactiveGroup(_world),
        new StartCommandBufferSystem(_world),
        new InitialisationSystem(_world),

        // Commands, triggering logic between entities mostly 
        new CommandGroup(_world),
        
        // UI & Interacting
        new InteractionGroup(_world),

        // Environment group ( Chunks, terrain generation... )
        new EnvironmentGroup(_world, _entityPrototyper, _biomeGeoTiff),

        // Behaviour like ai and animations
        new BehaviourGroup(_world),

        // Movement & Combat
        new MovementGroup(_world),
        new CombatGroup(_world),

        // Phyics  & Activity group
        new PhysicsGroup(_world),
        new ActivityGroup(_world, _entityPrototyper),

        // Networking group & Network Commands
        new NetworkingGroup(_world, _entityPrototyper, Network),

        // Database group
        new DatabaseGroup(_world, _gameDbContext),
        new IntervallGroup(10.0f, new DebugSystem(_world, Network)),

        // End of the frame
        new ClearTrackedAnimationsSystem(_world),
        new DestroySystem(_world)
);
systems.Initialize();

Each group can contain multiple systems and each system can contain multiple queries that execute logic on entities.

Program.cs
// Spawn in players
for (var index = 0; index < accounts.Count; index++)
{
    // Get account & character
    var acc = accounts[index]; 
    acc.ToEcs(); // Converts it to a game-entity by a extension-method               
}
EnvironmentSystems.cs
var newEntity = _prototyperHierarchy.Clone(choosedEntity.Type);   // Creates an entity
ref var entityTransform = ref newEntity.Get<NetworkTransform>();
ref var entityRotation = ref newEntity.Get<NetworkRotation>();

entityTransform.Pos = noiseGeocordinates.Geocoordinates;
entityRotation.Value = RandomExtensions.QuaternionStanding();

The creation of entities is often abstracted, in the example above once using an extension method and below using a prototyper.

Example

[Query]
[None(typeof(Prefab), typeof(Dead))]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Move([Data] in float elapsedTime, in Entity entity, ref NetworkTransform transform, ref Movement movement)
{
   // Use the passed entity to modify its data to make it move
}

Don't worry, I left out some code in the method. Because the most important thing is the method signature. This method acts as a query. It will be executed for all game entities that match the filters of the method. The best thing to do is to browse here how exactly this works.

So the method above will be executed for all entities that:

  • Without a prefab component

  • Without a dead component

  • With a NetworkTransform component

  • With a Movement component

In this case, the method is called, passing the entity being iterated over with its requested components. And the game-time.

And if we have the entity, its transform and its movement. We can easily move the entity a little bit each time it is called. Pretty simple, isn't it?

Each of these groups is called and processed in order. Each group in turn contains several systems or further groups. Each group has a task, e.g. there is the in there, which makes sure that for entities of each frame the movement is calculated and set correctly or the which takes care of the interval saving and other entity database operations. However, groups and systems do not necessarily have to target entities.

So we have the world and the groups/systems with queries that execute logic on entities. What is still missing? Exactly, the entities themselves. They are created in many different places. For example, at the start, after the accounts are loaded, they are .

Or when creating new areas and chunks in the world.

Let's take a quick look at the within the to see what such a system and a query looks like.

ECS (Entity Component System)
Arch
Arch
repo
wiki
Program.cs
group of systems is created
part of game loop
MovementGroup
DatabaseGroup
converted to player entities in the world
here
MovementSystem
MovementGroup