| name | zay-es-component |
| description | Create Zay-ES EntityComponent classes for the ECS architecture. Use when creating new components, data holders, or entity attributes. |
Creating Zay-ES Components
Components are immutable data containers for the Entity-Component-System.
Location
api/src/main/java/infinity/es/
Official Zay-ES Rules of Thumb
From the official wiki:
- Components are data only - no logic in components
- One canonical writer per component type. Multiple systems must not independently write the same component to the same entity. When multiple sources contribute deltas (e.g. damage from different weapons, prize-pickup cap bumps), use the ADR 0001 Change-entity shape: emitters create a short-lived entity carrying
ChangeTarget(target, source) + a typed *Change payload; a single canonical writer system drains those entities and applies the fold. Concrete example: EnergyChange / EnergyStatsChange records in api/src/main/java/infinity/es/ship/ are drained by EnergySystem / EnergyStatsSystem in infinity-server/src/main/java/infinity/systems/ship/. See .claude/rules/replacement-as-mutation.md and docs/adr/0001-ecs-component-model.md.
- Immutability helps threading - immutable components allow systems to run in different threads without synchronization
Requirements
- Implement
com.simsilica.es.EntityComponent
- Fields must be
private final (immutable)
- Must have no-arg constructor (serialization)
- Must have constructor with all fields
- Only getters, no setters
- Optionally implement
toString() for debugging
- Include SPDX-only
BSD-3-Clause license header
Template
package infinity.es;
import com.simsilica.es.EntityComponent;
public class MyComponent implements EntityComponent {
private final int value;
private final String name;
public MyComponent() {
}
public MyComponent(final int value, final String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[value=" + value + ", name=" + name + "]";
}
}
Common Component Patterns
Tag Component (marker, no data)
public class Player implements EntityComponent {
public Player() { }
}
Model/Type Component (with static constants)
public class Model implements EntityComponent {
private final String name;
public static final String SHIP = "Ship";
public static final String BULLET = "Bullet";
public static final String INVADER = "Invader";
public Model(String name) {
this.name = name;
}
public String getName() { return name; }
}
Decay Component (time-based removal)
public class Decay implements EntityComponent {
private final long start;
private final long delta;
public Decay(long deltaMillis) {
this.start = System.nanoTime();
this.delta = deltaMillis * 1000000;
}
public double getPercent() {
long time = System.nanoTime();
return (double)(time - start) / delta;
}
}
Position Component
public class Position implements EntityComponent {
private final Vector3f location;
public Position(Vector3f location) {
this.location = location;
}
public Vector3f getLocation() {
return location;
}
}
Existing Components Reference
Gold, Bounty - integer value components
ShapeInfo - entity visual shape
Frequency - team assignment
Dead - marks entity as dead
WeaponType - weapon configuration
Delay - time-based decay