Skip to content

Latest commit

ย 

History

66 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

GServerECS - Entity Component System Framework for Java Game Server

Java Maven Maven Central License

GServerECS is an open-source ECS framework designed and developed specifically for game servers, implemented in Java. This framework provides complete ECS architecture support, including runtime component addition/removal, system execution order control, on-the-fly and deferred loading of entities/components, and other key features.

This framework is designed for game server scenarios. A single process can create multiple EcsWorld instances, each corresponding to a game room (Room) or scene (Scene). Each EcsWorld is designed to be non-thread-safe and should only be used within a single thread. Cross-thread calls are not supported.

If this project has helped you, please feel free to give it a starโญ to show your support~ This will help more people discover it ๐Ÿ˜Š

๐ŸŒŸ Key Features

Core Functionality

  • Entity Management: Entity creation, destruction, and lifecycle management
  • Component System: Support for dynamic component addition/removal with type safety
  • System Execution: Flexible system update mechanism with multiple execution modes
  • Entity Prototypes: Component-based entity prototype system

Advanced Features

  • System Groups: Support for system group management, facilitating complex logic organization
  • Execution Order Control: Precise control of system execution order through annotations
  • Deferred Commands: Support for deferred execution of entity operation commands
  • Entity Factories: Factory pattern for entity creation, simplifying entity instantiation
  • Auto-scanning: Automatic discovery and registration of systems, components, and factories based on package scanning
  • Parallel Update: Process entity updates within a single logic system across multiple threads via the @ParallelUpdate annotation

๐Ÿ“‹ System Requirements

  • Java: Version 21 or higher
  • Maven: Version 3.6 or higher
  • Dependencies:
    • Log4j2 (2.25.3)
    • Disruptor (3.4.4)
    • JUnit 5 (for testing)

๐Ÿš€ Quick Start

1. Add Dependency

See the Maven Central badge above for the latest version, or visit Maven Central to copy the dependency snippet.

<dependency>
    <groupId>top.kgame</groupId>
    <artifactId>kgame-lib-ecs</artifactId>
    <version><!-- use the version shown on Maven Central --></version>
</dependency>

2. Create Components

public class PositionComponent implements EcsComponent {
    public float x, y, z;
}

public class HealthComponent implements EcsComponent {
    public int currentHealth;
    public int maxHealth;
}

3. Create Systems

@SystemGroup(GameSystemGroup.class) 
// Systems without @SystemGroup annotation belong to top-level systems, 
// at the same level as SystemGroups, all scheduled directly by EcsWorld
public class MovementSystem extends EcsOneComponentUpdateSystem<PositionComponent> {
    
    @Override
    protected void update(Entity entity, PositionComponent position) {
        // Update position logic
        position.x += 1.0f;
    }
}

4. Create Entity Factory

// EntityFactory implementations are automatically scanned and registered
public class PlayerFactory extends BaseEntityFactory {

    @Override
    protected Collection<EcsComponent> generateComponent() {
      return List.of(new PositionComponent(), new HealthComponent());
    }
    
    @Override
    public int typeId() {
        return 1; // Factory type ID, must be unique within the same EcsWorld
    }
}

5. Create System Group

public class GameSystemGroup extends EcsSystemGroup {
    // System group implementation
    @Override
    protected void onStart() {

    }

    @Override
    protected void onStop() {
  
    }
}

6. Use ECS World

public class Game {
    private EcsWorld world;
    
    public void init() {
        // Create ECS world, specify package names to scan
        world = EcsWorld.generateInstance("com.example.game");
        // Can set custom context
        world.setContext(this);
    }
    
    public void update(long currentTime) {
        // Update ECS world
        // Note: Timestamp must be strictly increasing, must be greater than the last passed time
        world.update(currentTime);
    }
    
    public void createPlayer() {
        // Create player entity through factory
        Entity player = world.createEntity(PlayerFactory.class);
    }
    
    public void cleanup() {
        world.close();
    }
}

7. Entity Operations

// Get component
PositionComponent position = entity.getComponent(PositionComponent.class);

// Check component
if (entity.hasComponent(HealthComponent.class)) {
    // Handle logic
}

// Add component
entity.addComponent(new HealthComponent());

// Remove component
entity.removeComponent(PositionComponent.class);

// Destroy entity
world.requestDestroyEntity(entity);

๐Ÿ“– Annotations

GServerECS provides rich annotations to control system behavior:

System Control Annotations

@SystemGroup

  • Purpose: Marks an EcsSystem to execute updates within a specified EcsSystemGroup
  • Target: EcsSystem classes
  • Parameters: Class<? extends EcsSystemGroup> value() - System group type
  • Description: EcsSystem marked with this annotation will execute updates within the specified EcsSystemGroup. EcsSystem not marked with this annotation belong to top-level systems at the same level as EcsSystemGroup, scheduled by EcsWorld. Note: This annotation cannot be used on EcsSystemGroup classes, and nested SystemGroups are not currently supported.

@TickRate

  • Purpose: Marks system update interval time
  • Target: EcsSystem classes
  • Parameters: int value() - Update interval time (milliseconds)
  • Description: Systems marked with this annotation will execute updates after the specified time interval. Systems not marked with this annotation will execute every update cycle.

@Standalone

  • Purpose: Marks EcsSystem to always execute updates, regardless of whether there are matching entities
  • Target: EcsSystem classes
  • Parameters: None
  • Description: EcsSystem marked with this annotation will execute in every update cycle, even if no entities contain the components required by this EcsSystem. EcsSystem not marked with this annotation will only execute updates in each update cycle when there are entities containing the required components.

@After

  • Purpose: Marks EcsSystem to execute updates after specified EcsSystem within the same group
  • Target: EcsSystem classes
  • Parameters: Class<? extends EcsSystem>[] value() - Target system type array
  • Description: EcsSystem marked with this annotation will execute updates after the specified EcsSystem completes. EcsSystem with the same conditions will execute in dictionary order. Can be used in SystemGroup.

@Before

  • Purpose: Marks EcsSystem to execute updates before specified EcsSystem within the same group
  • Target: EcsSystem classes
  • Parameters: Class<? extends EcsSystem>[] value() - Target system type array
  • Description: EcsSystem marked with this annotation will execute updates before the specified EcsSystem. EcsSystem with the same conditions will execute in dictionary order. Can be used in SystemGroup.

@ParallelUpdate

  • Purpose: Marks that entity updates within a logic system may be executed in parallel across multiple threads
  • Target: EcsEntityUpdateSystem and its subclasses (such as the various EcsXxxComponentUpdateSystem). Applying it to non-EcsEntityUpdateSystem types such as EcsSystemGroup or EcsStandaloneUpdateSystem causes the framework to throw InvalidParallelUpdateAnnotationException during scanning.
  • Parameters:
    • Class<? extends ParallelUpdateExecutor> executor(): parallel executor type, default RangeParallelUpdateExecutor (contiguous slices). A built-in StrideParallelUpdateExecutor (interleaved indices) is also provided. Custom executors need a public constructor (ParallelUpdateExecutorManager), or must be pre-registered via ParallelUpdateExecutorManager#register(Class, instance).
    • int minEntityCountPerBatch(): minimum entities per batch, must be > 0 (default 256); otherwise the system throws during initialization. Caps task count so simple logic is not dominated by scheduling overhead.
  • Description: For a system marked with this annotation, matching entities are iterated and processed in parallel across multiple threads within a single update; systems themselves still execute serially in their original order, only the per-entity processing inside a system runs in parallel. The following constraints must be met:
    • The system's update logic must be thread-safe, since multiple entities are processed on different threads concurrently.
    • Do not modify entity structure directly during parallel processing (e.g. entity.addComponent, entity.removeComponent, world.requestDestroyEntity). Use deferred commands (addDelayCommand) instead. Command enqueueing is thread-safe, and the commands are executed serially on a single thread after the parallel iteration completes.
    • Avoid reading/writing cross-entity shared mutable state directly in update, unless you guarantee thread safety yourself.
@ParallelUpdate // default RangeParallelUpdateExecutor (contiguous slices)
// @ParallelUpdate(executor = StrideParallelUpdateExecutor.class, minEntityCountPerBatch = 128)
// @ParallelUpdate(executor = MyHashParallelUpdateExecutor.class)
public class MovementSystem extends EcsOneComponentUpdateSystem<PositionComponent> {
    @Override
    protected void update(EcsEntity entity, PositionComponent position) {
        // Only mutate this entity's own component data, thread-safe
        position.x += 1.0f;
        // For structural changes, use deferred commands
        // addDelayCommand(new EcsCommandAddComponent(entity, new TagComponent()), EcsCommandScope.SYSTEM);
    }
}

Entity Factory

EntityFactory implementations are automatically scanned and registered by EcsWorld. No annotation is required. Simply implement the EntityFactory interface or extend BaseEntityFactory, and the framework will automatically discover and register your factory classes.

๐Ÿ”ง Predefined System Types

GServerECS provides various predefined system base classes:

  • EcsOneComponentUpdateSystem<T>: System handling entities with a single specified component
  • EcsTwoComponentUpdateSystem<T1, T2>: System handling entities with two specified components
  • EcsThreeComponentUpdateSystem<T1, T2, T3>: System handling entities with three specified components
  • EcsFourComponentUpdateSystem<T1, T2, T3, T4>: System handling entities with four specified components
  • EcsFiveComponentUpdateSystem<T1, T2, T3, T4, T5>: System handling entities with five specified components
  • EcsStandaloneUpdateSystem: Singleton update system, not bound to entities, executes once per world update
  • EcsExcludeComponentUpdateSystem<T>: System handling entities that do not contain the specified component T
  • EcsInitializeSystem<T>: Entity initialization system, automatically adds initialization completion marker
  • EcsDestroySystem<T>: Entity destruction system, handles entities marked for destruction
  • EcsEntityUpdateSystem: Logic system base class, provides component filtering and entity query functionality

๐Ÿ“ฆ System Groups (EcsSystemGroup)

System Groups (EcsSystemGroup) are an important mechanism in GServerECS for organizing and managing system execution. A system group is itself a system that can contain multiple subsystems and execute them in a specific order.

System Group Features

  • Automatic Management: System groups automatically scan and manage all systems marked with the @SystemGroup annotation
  • Execution Order: Systems within a system group execute according to the order defined by @After and @Before annotations
  • Lifecycle: System groups have complete lifecycle management, including initialization, updates, and destruction
  • Dynamic Management: Support for adding and removing Systems at runtime

System Group Hierarchy

EcsWorld
โ”œโ”€โ”€ Top-level Systems (without @SystemGroup annotation)
โ”‚   โ”œโ”€โ”€ SystemA
โ”‚   โ””โ”€โ”€ SystemB
โ””โ”€โ”€ System Groups
    โ”œโ”€โ”€ GameSystemGroup
    โ”‚   โ”œโ”€โ”€ InputSystem
    โ”‚   โ”œโ”€โ”€ LogicSystem
    โ”‚   โ””โ”€โ”€ RenderSystem
    โ””โ”€โ”€ PhysicsSystemGroup
        โ”œโ”€โ”€ CollisionSystem
        โ””โ”€โ”€ MovementSystem

โšก Deferred Command System

GServerECS provides a complete deferred command system that allows safe execution of entity and component operations during system execution. Deferred commands execute within specified scopes, ensuring atomicity and consistency of operations.

public class MySystem extends EcsOneComponentUpdateSystem<MyComponent> {
    
    @Override
    protected void update(Entity entity, MyComponent component) {
        // Add deferred command
        addDelayCommand(new EcsCommandAddComponent(entity, new NewComponent()), 
                      EcsCommandScope.SYSTEM);
    }
}

Available Deferred Commands

GServerECS provides the following four deferred commands:

  • EcsCommandCreateEntity: Deferred entity creation
  • EcsCommandDestroyEntity: Deferred entity destruction
  • EcsCommandAddComponent: Deferred component addition
  • EcsCommandRemoveComponent: Deferred component removal

Command Scopes

Deferred commands support three scopes that control command execution timing:

  • SYSTEM: System scope, commands execute after the current System completes
  • SYSTEM_GROUP: System group scope, commands execute after the current system group completes
  • WORLD: World scope, commands execute after the current world update completes

๐ŸŽฎ Entity Operation Timing

GServerECS divides entity operations into immediate effect and deferred effect modes:

Immediate Effect Operations

  • Entity Addition: Through ecsworld.createEntity() calls
  • Component Addition/Removal: Through direct calls to entity.addComponent() and entity.removeComponent()
  • Effect Timing: Operations take effect immediately, accessible by other Systems after the current System completes

Deferred Effect Operations

Entity Destruction

  • Operation Method: Request destruction through world.requestDestroyEntity()
  • Effect Timing: Executes after the current world update completes, ensuring all Systems can process the entity

Deferred Command Operations

  • All Operations: Execute through the deferred command system (EcsCommandCreateEntity, EcsCommandDestroyEntity, EcsCommandAddComponent, EcsCommandRemoveComponent)
  • Effect Timing: Refer to the Deferred Command System section

๐Ÿงช Test Examples

The project includes comprehensive test cases demonstrating various functionality usage:

  • Component Operation Tests: Demonstrates component addition and removal operations (immediate and deferred)
  • Entity Operation Tests: Demonstrates entity creation and destruction operations (immediate and deferred)
  • System Tests: Demonstrates system execution order control, update interval functionality, and complex system combination usage
  • Resource Cleanup Tests: Demonstrates ECS world destruction and resource cleanup functionality

๐Ÿ“ Project Structure

src/
โ”œโ”€โ”€ main/java/top/kgame/lib/ecs/
โ”‚   โ”œโ”€โ”€ annotation/          # Annotation definitions
โ”‚   โ”‚   โ”œโ”€โ”€ After.java       # System execution order control (after)
โ”‚   โ”‚   โ”œโ”€โ”€ Before.java      # System execution order control (before)
โ”‚   โ”‚   โ”œโ”€โ”€ ParallelUpdate.java # Per-entity parallel update marker
โ”‚   โ”‚   โ”œโ”€โ”€ Standalone.java  # Standalone system marker
โ”‚   โ”‚   โ”œโ”€โ”€ SystemGroup.java # System group marker
โ”‚   โ”‚   โ””โ”€โ”€ TickRate.java    # System update interval
โ”‚   โ”œโ”€โ”€ command/            # Deferred command system
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommand.java # Command interface
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommandBuffer.java # Command buffer
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommandScope.java  # Command scope
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommandAddComponent.java
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommandCreateEntity.java
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCommandDestroyEntity.java
โ”‚   โ”‚   โ””โ”€โ”€ EcsCommandRemoveComponent.java
โ”‚   โ”œโ”€โ”€ core/               # Core implementation
โ”‚   โ”‚   โ”œโ”€โ”€ ComponentFilter.java      # Component filter
โ”‚   โ”‚   โ”œโ”€โ”€ ComponentFilterMode.java # Filter mode
โ”‚   โ”‚   โ”œโ”€โ”€ ComponentFilterParam.java # Filter parameter
โ”‚   โ”‚   โ”œโ”€โ”€ EcsCleanable.java         # Cleanable resource interface
โ”‚   โ”‚   โ”œโ”€โ”€ EcsComponentManager.java  # Component manager
โ”‚   โ”‚   โ”œโ”€โ”€ EcsEntityManager.java     # Entity manager
โ”‚   โ”‚   โ”œโ”€โ”€ EcsSystemManager.java     # System manager
โ”‚   โ”‚   โ”œโ”€โ”€ EntityArchetype.java      # Entity archetype
โ”‚   โ”‚   โ”œโ”€โ”€ EntityFactory.java        # Entity factory interface
โ”‚   โ”‚   โ”œโ”€โ”€ EntityQuery.java          # Entity query
โ”‚   โ”‚   โ”œโ”€โ”€ ParallelUpdateExecutor.java # Abstract parallel update executor
โ”‚   โ”‚   โ”œโ”€โ”€ ParallelUpdateExecutorManager.java # Creates and caches executors by Class
โ”‚   โ”‚   โ””โ”€โ”€ SystemScheduler.java      # System scheduler
โ”‚   โ”œโ”€โ”€ exception/          # Exception definitions
โ”‚   โ”œโ”€โ”€ extensions/         # Extension functionality
โ”‚   โ”‚   โ”œโ”€โ”€ component/      # Extension components (Initialized / Destroying)
โ”‚   โ”‚   โ”œโ”€โ”€ entity/         # Extension entity factories (BaseEntityFactory)
โ”‚   โ”‚   โ”œโ”€โ”€ parallel/       # Built-in parallel executors (Range contiguous / Stride interleaved)
โ”‚   โ”‚   โ””โ”€โ”€ system/         # Extension system base classes (N-Component / Init / Destroy, etc.)
โ”‚   โ”œโ”€โ”€ tools/              # Utility classes (scanning, sorting, ClassUtils, etc.)
โ”‚   โ”œโ”€โ”€ EcsComponent.java   # Component interface
โ”‚   โ”œโ”€โ”€ EcsEntity.java      # Entity class
โ”‚   โ”œโ”€โ”€ EcsSystem.java      # System base class
โ”‚   โ”œโ”€โ”€ EcsSystemGroup.java # System group base class
โ”‚   โ”œโ”€โ”€ EcsEntityUpdateSystem.java    # Logic system base (entity query & filter)
โ”‚   โ”œโ”€โ”€ EcsStandaloneUpdateSystem.java # Singleton update system base
โ”‚   โ””โ”€โ”€ EcsWorld.java       # ECS world
โ”œโ”€โ”€ jmh/java/top/kgame/lib/ecsjmh/  # JMH core benchmarks (-Pjmh; not in default mvn test)
โ””โ”€โ”€ test/java/top/kgame/lib/ecstest/
    โ”œโ”€โ”€ logic/              # Functional / behavioral tests (default mvn test)
    โ”‚   โ”œโ”€โ”€ common/         # Shared utility tests
    โ”‚   โ”œโ”€โ”€ component/      # Component tests
    โ”‚   โ”‚   โ”œโ”€โ”€ add/        # Component add (immediately / delay)
    โ”‚   โ”‚   โ””โ”€โ”€ remove/     # Component remove (immediately / delay)
    โ”‚   โ”œโ”€โ”€ entity/         # Entity tests
    โ”‚   โ”‚   โ”œโ”€โ”€ add/        # Entity add (immediately / delay)
    โ”‚   โ”‚   โ””โ”€โ”€ remove/     # Entity remove (immediately / delay)
    โ”‚   โ”œโ”€โ”€ schedule/       # System scheduling & system-type tests
    โ”‚   โ”œโ”€โ”€ system/         # System order & interval tests
    โ”‚   โ”œโ”€โ”€ systemgroup/    # System group tests
    โ”‚   โ”œโ”€โ”€ core/           # Core functionality tests
    โ”‚   โ”œโ”€โ”€ dispose/        # Resource cleanup tests
    โ”‚   โ”œโ”€โ”€ isolated/       # Isolated scenarios (e.g. invalid ParallelUpdate)
    โ”‚   โ””โ”€โ”€ util/           # Test utilities
    โ””โ”€โ”€ performance/        # JUnit perf suite (-Pperf; not in default mvn test)
        โ””โ”€โ”€ isolated/       # Isolated perf scenarios (archetype / lifecycle / mutation / parallelupdate / tickrate)

โฑ JMH Core Benchmarks

Reference JMH numbers for the EcsWorld.update hot path (AverageTime; lower is better). Results vary by machine and load โ€” use them as an order-of-magnitude guide. For change impact, compare before/after on the same machine via the script.

Environment: JDK 21.0.6 ยท JMH 1.37 ยท Forks=3 ยท Warmup 3ร—1s ยท Measurement 5ร—1s ยท Windows

Benchmark Entities Score ยฑ Error Unit
WorldUpdateBenchmark.update 1,000 37.154 ยฑ 1.018 us/op
WorldUpdateBenchmark.update 10,000 410.430 ยฑ 3.563 us/op
ParallelWorldUpdateBenchmark.update 2,000 206.805 ยฑ 16.509 us/op
ParallelWorldUpdateBenchmark.update 8,000 870.761 ยฑ 97.554 us/op

Reproduce:

# Core JMH only (not part of default mvn test)
mvn -Pjmh test-compile exec:exec

# Or via the script (labels / diffs)
python scripts/run_performance_tests.py --profile core --label local

For the broader JUnit performance suite, see scripts/run_performance_tests.py --profile full. Default mvn test neither runs nor compiles performance tests / JMH (enabled only via -Pperf / -Pjmh).

๐Ÿ“‹ Subsequent Development Plan

  • Multi-thread Support (In Progress)
  • Entity-Component Framework Independent of System (Not Started)

๐Ÿ“„ License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

๐Ÿ”— Related Links

๐Ÿ“ž Contact

For questions or suggestions, please contact us through:


About

An Entity-Component-System framework for Java game servers

Topics

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages