HyCodeYourTale

Systems

Systems

Systémy v ECS architektuře Hytale - logika operující nad komponentami.

---

Co je Systém?

Systém obsahuje logiku a operuje nad entitami s určitými komponentami. Na rozdíl od komponent (data), systémy obsahují behavior.

Komponenta = DATA (co entita má)
Systém = LOGIKA (co entita dělá)

---

Typy Systémů

EntityEventSystem

Reaguje na ECS eventy (BreakBlockEvent, DeathEvent, atd.)

public class BlockBreakSystem extends EntityEventSystem {

public BlockBreakSystem() {
super(BreakBlockEvent.class);
}

@Override
public void handle(
int i,
@Nonnull ArchetypeChunk chunk,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer,
@Nonnull BreakBlockEvent event
) {
if (event.getBlockType() == BlockType.EMPTY) return;

Ref ref = chunk.getReferenceTo(i);
Player player = store.getComponent(ref, Player.getComponentType());

if (player != null) {
player.sendMessage(Message.raw("Rozbil jsi blok!"));
}
}

@Nullable
@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

RefChangeSystem

Reaguje na změny komponent (přidání, změna, odebrání).

public class EnterBedSystem extends RefChangeSystem {

public static final Query QUERY =
Query.and(MountedComponent.getComponentType(), PlayerRef.getComponentType());

@Override
public ComponentType componentType() {
return MountedComponent.getComponentType();
}

@Override
public Query getQuery() {
return QUERY;
}

// Komponenta přidána
public void onComponentAdded(
@Nonnull Ref ref,
@Nonnull MountedComponent component,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer
) {
if (component.getBlockMountType() == BlockMountType.Bed) {
// Hráč si lehl do postele
onEnterBed(ref, store);
}
}

// Komponenta změněna
public void onComponentSet(
@Nonnull Ref ref,
@Nullable MountedComponent oldComponent,
@Nonnull MountedComponent newComponent,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer
) {
if (newComponent.getBlockMountType() == BlockMountType.Bed) {
onEnterBed(ref, store);
}
}

// Komponenta odebrána
public void onComponentRemoved(
@Nonnull Ref ref,
@Nonnull MountedComponent component,
@Nonnull Store store,
@Nonnull CommandBuffer commandBuffer
) {
// Hráč vstal z postele
}

private void onEnterBed(Ref ref, Store store) {
// Logika pro vstup do postele
}
}

---

Anatomie EntityEventSystem

public class MySystem extends EntityEventSystem {

// 1. Konstruktor - předej třídu eventu
public MySystem() {
super(MyEvent.class);
}

// 2. Handler - hlavní logika
@Override
public void handle(
int i, // Index v chunku
@Nonnull ArchetypeChunk chunk, // Chunk s entitami
@Nonnull Store store, // ECS store
@Nonnull CommandBuffer buffer, // Pro modifikace
@Nonnull MyEvent event // Event data
) {
// Získej referenci na entitu
Ref ref = chunk.getReferenceTo(i);

// Přístup ke komponentům
Player player = store.getComponent(ref, Player.getComponentType());
MyComponent myComp = store.getComponent(ref, MyPlugin.get().getMyComponentType());

if (player != null && myComp != null) {
// Logika
}

// Modifikace přes CommandBuffer
buffer.addComponent(ref, SomeType.getComponentType(), newComponent);
}

// 3. Query - které entity dostanou event
@Nullable
@Override
public Query getQuery() {
// Pouze entity s PlayerRef
return PlayerRef.getComponentType();

// Pro všechny entity:
// return null;
}
}

---

Query

Query filtruje které entity jsou zpracovány systémem.

Jednoduchá Query

@Override
public Query getQuery() {
// Entity s PlayerRef komponentou
return PlayerRef.getComponentType();
}

Složená Query

@Override
public Query getQuery() {
// Entity s PlayerRef A CustomComponent
return Query.and(
PlayerRef.getComponentType(),
CustomComponent.getComponentType()
);
}

Bez Query (všechny entity)

@Override
public Query getQuery() {
return null; // Všechny entity
}

---

ArchetypeChunk

Chunk v ECS je skupina entit se stejnou kombinací komponent.

@Override
public void handle(int i, ArchetypeChunk chunk, ...) {
// Index i je pozice v chunku
Ref ref = chunk.getReferenceTo(i);

// Procházení všech entit v chunku
for (int j = 0; j < chunk.size(); j++) {
Ref entityRef = chunk.getReferenceTo(j);
// Zpracuj entitu
}
}

---

CommandBuffer

Pro bezpečné modifikace během iterace.

@Override
public void handle(..., CommandBuffer commandBuffer, ...) {
Ref ref = chunk.getReferenceTo(i);

// Přidání komponenty
commandBuffer.addComponent(ref, MyType.getComponentType(), new MyComponent());

// Odebrání komponenty
commandBuffer.removeComponent(ref, MyType.getComponentType());

// Zničení entity
commandBuffer.destroyEntity(ref);
}

Proč CommandBuffer?

  • Přímé modifikace během iterace mohou způsobit problémy

  • CommandBuffer shromažďuje změny a aplikuje je po dokončení iterace

  • Thread-safe
  • ---

    Registrace Systému

    @Override
    protected void setup() {
    // Registrace systémů
    getEntityStoreRegistry().registerSystem(new BlockBreakSystem());
    getEntityStoreRegistry().registerSystem(new DeathSystem());
    getEntityStoreRegistry().registerSystem(new EnterBedSystem());
    }

    ---

    Příklad: Kompletní Plugin se Systémy

    public class StatsPlugin extends JavaPlugin {

    private static StatsPlugin instance;
    private ComponentType statsType;

    public StatsPlugin(JavaPluginInit init) {
    super(init);
    }

    public static StatsPlugin get() {
    return instance;
    }

    @Override
    protected void setup() {
    instance = this;

    // Registrace komponenty
    statsType = getEntityStoreRegistry().registerComponent(
    StatsComponent.class,
    StatsComponent::new
    );

    // Registrace systémů
    getEntityStoreRegistry().registerSystem(new BlockBreakStatsSystem());
    getEntityStoreRegistry().registerSystem(new DeathStatsSystem());

    // Inicializace stats pro nové hráče
    getEventRegistry().registerGlobal(PlayerReadyEvent.class, event -> {
    Player player = event.getPlayer();
    World world = player.getWorld();

    world.execute(() -> {
    Ref ref = player.getRef();
    Store store = ref.getStore();
    store.ensureAndGetComponent(ref, statsType);
    });
    });
    }

    public ComponentType getStatsType() {
    return statsType;
    }
    }

    // Systém pro sledování rozbitých bloků
    public class BlockBreakStatsSystem extends EntityEventSystem {

    public BlockBreakStatsSystem() {
    super(BreakBlockEvent.class);
    }

    @Override
    public void handle(int i, ArchetypeChunk chunk,
    Store store, CommandBuffer buffer,
    BreakBlockEvent event) {

    if (event.getBlockType() == BlockType.EMPTY) return;

    Ref ref = chunk.getReferenceTo(i);
    StatsComponent stats = store.getComponent(ref, StatsPlugin.get().getStatsType());

    if (stats != null) {
    stats.incrementBlocksBroken();
    }
    }

    @Override
    public Query getQuery() {
    return PlayerRef.getComponentType();
    }
    }

    // Systém pro sledování smrtí
    public class DeathStatsSystem extends EntityEventSystem {

    public DeathStatsSystem() {
    super(DeathEvent.class);
    }

    @Override
    public void handle(int i, ArchetypeChunk chunk,
    Store store, CommandBuffer buffer,
    DeathEvent event) {

    Ref ref = chunk.getReferenceTo(i);
    StatsComponent stats = store.getComponent(ref, StatsPlugin.get().getStatsType());

    if (stats != null) {
    stats.incrementDeaths();
    }
    }

    @Override
    public Query getQuery() {
    return PlayerRef.getComponentType();
    }
    }

    // Komponenta
    public class StatsComponent implements Component {
    private int blocksBroken = 0;
    private int deaths = 0;

    public void incrementBlocksBroken() { blocksBroken++; }
    public void incrementDeaths() { deaths++; }

    public int getBlocksBroken() { return blocksBroken; }
    public int getDeaths() { return deaths; }

    @Override
    public Component clone() {
    StatsComponent copy = new StatsComponent();
    copy.blocksBroken = this.blocksBroken;
    copy.deaths = this.deaths;
    return copy;
    }
    }

    ---

    Thread Safety v Systémech

    Systémy jsou automaticky spouštěny na správném world threadu:

  • EntityEventSystem.handle() - běží na world threadu

  • RefChangeSystem callbacks - běží na world threadu

  • Přístup ke komponentům je bezpečný

  • Není potřeba world.execute()

---

Shrnutí

| Typ Systému | Účel | Kdy použít |
|-------------|------|------------|
| EntityEventSystem | Reakce na ECS eventy | BreakBlockEvent, DeathEvent |
| RefChangeSystem | Reakce na změny komponent | Sledování přidání/odebrání komponent |

| Třída | Účel |
|-------|------|
| Query | Filtrování entit |
| ArchetypeChunk | Skupina entit se stejnými komponentami |
| CommandBuffer | Bezpečné modifikace během iterace |
| Store | Přístup ke komponentám |
| Ref | Reference na entitu |

Last updated: 20. ledna 2026