Skip to main content
The ECS (Entity Component System) surface lets you create entities, attach and remove components, query the store, and assert on entity state — all within the live Hytale ECS. This is the foundation for testing any game logic that touches entities or components.

@EcsTest

Annotate a test method with @EcsTest to receive an EcsTestContext and automatically get the "ecs" tag. Tests marked with @EcsTest are scheduled on the world thread and have full access to the ECS store and command buffer.
import com.frotty27.hrtk.api.annotation.EcsTest;
import com.frotty27.hrtk.api.context.EcsTestContext;

@EcsTest
void testCreateEntity(EcsTestContext ctx) {
    Object ref = ctx.createEntity();
    HytaleAssert.assertNotNull(ref);
}
Use IsolationStrategy.SNAPSHOT on your suite when your ECS tests mutate state. The snapshot captures the store before the suite and restores it after, so your tests do not pollute the live server.

EcsTestContext Methods

MethodDescription
getStore()Get the ECS store
getCommandBuffer()Get a command buffer for deferred operations
createEntity()Create a new empty entity, returns a reference
flush()Execute all deferred command buffer operations
putComponent(ref, type, component)Attach a component to an entity
removeComponent(ref, type)Remove a component from an entity
getComponent(ref, type)Get a component (returns null if absent)
hasComponent(ref, type)Check if entity has a component
waitTicks(n)Wait for N world ticks
awaitCondition(supplier, maxTicks)Poll each tick until non-null or timeout
findEntities(componentType)Find all entities with a given component
countEntities(componentType)Count entities with a given component

EcsAssert Methods

MethodDescription
assertHasComponent(store, ref, type)Assert entity has the component
assertNotHasComponent(store, ref, type)Assert entity lacks the component
assertGetComponent(store, ref, type)Assert component exists and return it
assertRefValid(ref)Assert entity reference is non-null
assertRefInvalid(ref)Assert entity reference is null

Examples

@EcsTest
@Order(1)
void testPutComponent(EcsTestContext ctx) {
    Object ref = ctx.createEntity();
    ctx.putComponent(ref, TransformComponent.getComponentType(),
                     new TransformComponent());
    ctx.flush();
    HytaleAssert.assertTrue(
        ctx.hasComponent(ref, TransformComponent.getComponentType())
    );
}
@EcsTest
@Order(2)
void testAssertGetComponent(EcsTestContext ctx) {
    Object ref = ctx.createEntity();
    ctx.putComponent(ref, TransformComponent.getComponentType(),
                     new TransformComponent());
    ctx.flush();

    Object component = EcsAssert.assertGetComponent(
        ctx.getStore(), ref, TransformComponent.getComponentType()
    );
    HytaleAssert.assertNotNull("Retrieved component", component);
}
@EcsTest
@Order(3)
void testRemoveComponent(EcsTestContext ctx) {
    Object ref = ctx.createEntity();
    ctx.putComponent(ref, TransformComponent.getComponentType(),
                     new TransformComponent());
    ctx.flush();

    ctx.removeComponent(ref, TransformComponent.getComponentType());
    ctx.flush();

    EcsAssert.assertNotHasComponent(
        ctx.getStore(), ref, TransformComponent.getComponentType()
    );
}
@EcsTest
void testFindEntities(EcsTestContext ctx) {
    Object ref = ctx.createEntity();
    ctx.putComponent(ref, TransformComponent.getComponentType(),
                     new TransformComponent());
    ctx.flush();

    List<?> found = ctx.findEntities(TransformComponent.getComponentType());
    HytaleAssert.assertNotEmpty(found);

    int count = ctx.countEntities(TransformComponent.getComponentType());
    HytaleAssert.assertGreaterThan(0, count);
}

How EcsAssert Works Internally

Because hrtk-api cannot compile against Hytale server classes directly, all ECS assertions use reflection. EcsAssert.assertHasComponent() calls store.getComponent(ref, componentType) via Method.invoke(). This means:
  • The store parameter is actually a Store<EntityStore> at runtime
  • The ref parameter is a Ref<EntityStore>
  • The componentType is a ComponentType<EntityStore, T>
You pass them as Object in the API, but they must be the correct Hytale types at runtime.
The reflection-based approach is an intentional design choice. It allows hrtk-api to remain a compile-only dependency with no runtime coupling to HytaleServer.jar.

Next Steps