Entity System (ECS)
This section covers Hytale’s Entity-Component-System (ECS) architecture, which provides efficient data access and flexible composition for game objects.
What is ECS?
Section titled “What is ECS?”The Entity-Component-System architecture separates game objects into three core concepts:
- Entities - Lightweight references (IDs) to game objects
- Components - Data containers attached to entities
- Systems - Logic processors that operate on components
This separation provides:
- Efficient memory layout and cache-friendly data access
- Flexible composition without deep inheritance hierarchies
- Clean separation between data and logic
Architecture Overview
Section titled “Architecture Overview”Store<ECS_TYPE>├── ComponentRegistry<ECS_TYPE> - Type registration and system management├── Archetype[] - Component type combinations│ └── ArchetypeChunk[] - Entity storage per archetype│ ├── Ref<ECS_TYPE>[] - Entity references│ └── Component<ECS_TYPE>[][] - Component data arrays├── Resource<ECS_TYPE>[] - Global resources (via ResourceType)└── ISystem<ECS_TYPE>[] - Logic processorsGetting Started
Section titled “Getting Started”- Component System - Learn about creating and using components
- Entity Stats - Health, stamina, mana, and custom attributes
- Physics System - Physics simulation and collision
- Player Management - Player data and persistence
Quick Example
Section titled “Quick Example”// Get the EntityStore from a world, then get the underlying StoreEntityStore entityStore = world.getEntityStore();Store<EntityStore> store = entityStore.getStore();
// Create an entity using a HolderHolder<EntityStore> holder = EntityStore.REGISTRY.newHolder();holder.addComponent(positionType, new PositionComponent(0, 64, 0));holder.addComponent(velocityType, new VelocityComponent());holder.addComponent(healthType, new HealthComponent(100));
Ref<EntityStore> entity = store.addEntity(holder, AddReason.SPAWN);
// Get a component from an entity using ComponentType (not Class)PositionComponent pos = store.getComponent(entity, positionType);
// Iterate over entities with specific components using forEachChunkstore.forEachChunk(positionType, (archetypeChunk, commandBuffer) -> { for (int i = 0; i < archetypeChunk.size(); i++) { Ref<EntityStore> ref = archetypeChunk.getReferenceTo(i); PositionComponent position = archetypeChunk.getComponent(i, positionType); VelocityComponent velocity = archetypeChunk.getComponent(i, velocityType); if (position != null && velocity != null) { // Process entities with both components position.add(velocity); } }});Core Concepts
Section titled “Core Concepts”Entity References (Ref)
Section titled “Entity References (Ref)”Entities are referenced through lightweight Ref objects that track validity:
public class Ref<ECS_TYPE> { public static final Ref<?>[] EMPTY_ARRAY = new Ref[0];
@Nonnull private final Store<ECS_TYPE> store; private volatile int index; private volatile transient int hashCode; private volatile Throwable invalidatedBy;
public Ref(@Nonnull Store<ECS_TYPE> store) { this(store, Integer.MIN_VALUE); }
public Ref(@Nonnull Store<ECS_TYPE> store, int index) { this.store = store; this.index = index; this.hashCode = this.hashCode0(); }
@Nonnull public Store<ECS_TYPE> getStore() { return this.store; }
public int getIndex() { return this.index; }
public void validate() { if (this.index == Integer.MIN_VALUE) { throw new IllegalStateException("Invalid entity reference!", this.invalidatedBy); } }
public boolean isValid() { return this.index != Integer.MIN_VALUE; }}Component Types
Section titled “Component Types”Components must implement the Component interface which extends Cloneable:
public interface Component<ECS_TYPE> extends Cloneable { @Nonnull public static final Component[] EMPTY_ARRAY = new Component[0];
@Nullable public Component<ECS_TYPE> clone();
@Nullable default public Component<ECS_TYPE> cloneSerializable() { return this.clone(); }}Components are accessed through ComponentType<ECS_TYPE, T> objects registered with the ComponentRegistry, not by their Class directly.
Systems
Section titled “Systems”Systems process entities with specific component combinations. The base interface is ISystem:
public interface ISystem<ECS_TYPE> { public static final ISystem[] EMPTY_ARRAY = new ISystem[0];
default public void onSystemRegistered() {}
default public void onSystemUnregistered() {}
@Nullable default public SystemGroup<ECS_TYPE> getGroup() { return null; }
@Nonnull default public Set<Dependency<ECS_TYPE>> getDependencies() { return Collections.emptySet(); }}Resources
Section titled “Resources”Resources are global data accessible across the store, implementing the Resource interface:
public interface Resource<ECS_TYPE> extends Cloneable { public static final Resource[] EMPTY_ARRAY = new Resource[0];
@Nullable public Resource<ECS_TYPE> clone();}Resources are accessed via ResourceType and retrieved using store.getResource(resourceType).
Archetypes
Section titled “Archetypes”An Archetype represents a specific combination of component types. Entities with the same archetype are stored together in ArchetypeChunk for cache-efficient iteration:
// Create an archetype with specific component typesArchetype<EntityStore> archetype = Archetype.of(positionType, velocityType);
// Add or remove component types from archetypesArchetype<EntityStore> withHealth = Archetype.add(archetype, healthType);Archetype<EntityStore> withoutVelocity = Archetype.remove(archetype, velocityType);Next Steps
Section titled “Next Steps”- Read the Component System guide for detailed documentation
- Learn about Entity Stats for health and attributes
- Understand the Physics System for movement and collision