| name | sio2-system |
| description | Create server-side game systems using SiO2 AbstractGameSystem (via the project's BaseInfinitySystem wrapper). Use when building systems that process entities, handle game logic, or manage server-side state. |
Creating Game Systems (SiO2)
Server-side systems process entities each frame using the SiO2 framework. The project wraps SiO2's AbstractGameSystem with infinity.systems.BaseInfinitySystem, which adds a requireSystem(Class<T>) helper — a non-null lookup that throws IllegalStateException with a greppable message if the dependency isn't registered. Use it for mandatory deps; fall back to raw getSystem(...) only for optional deps that legitimately may be absent (test fixtures, minimal harnesses).
Location
infinity-server/src/main/java/infinity/systems/
Official Zay-ES Rules of Thumb
From the wiki:
- Components are data only - systems contain the logic
- Two systems should not produce the same component type for the same entities (project further restricts via Replacement-as-Mutation — one canonical writer per component type, see
.claude/rules/replacement-as-mutation.md)
- You're not forced into a particular 'system' model - query entities when you want them
Requirements
- Extend
infinity.systems.BaseInfinitySystem (which extends com.simsilica.sim.AbstractGameSystem)
- Get
EntityData via requireSystem(EntityData.class) in initialize()
- Create
EntitySet queries for needed components
- CRITICAL: Release all EntitySets in terminate() - memory leak otherwise
- Use
applyChanges() pattern in update()
- Include SPDX-only
BSD-3-Clause license header
Template
package infinity.systems;
import com.simsilica.es.Entity;
import com.simsilica.es.EntityData;
import com.simsilica.es.EntityId;
import com.simsilica.es.EntitySet;
import com.simsilica.sim.SimTime;
import infinity.systems.BaseInfinitySystem;
public class MySystem extends BaseInfinitySystem {
private EntityData ed;
private EntitySet entities;
@Override
protected void initialize() {
ed = requireSystem(EntityData.class);
entities = ed.getEntities(Component1.class, Component2.class);
}
@Override
protected void terminate() {
entities.release();
entities = null;
}
@Override
public void update(final SimTime time) {
if (entities.applyChanges()) {
for (final Entity e : entities.getAddedEntities()) {
handleAdded(e);
}
for (final Entity e : entities.getChangedEntities()) {
handleChanged(e);
}
for (final Entity e : entities.getRemovedEntities()) {
handleRemoved(e);
}
}
for (final Entity e : entities) {
process(e, time);
}
}
private void handleAdded(final Entity e) {
}
private void handleChanged(final Entity e) {
}
private void handleRemoved(final Entity e) {
}
private void process(final Entity e, final SimTime time) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
}
Common System Patterns (from Wiki)
Decay System Pattern
Time-based entity removal:
public class DecaySystem extends BaseInfinitySystem {
private EntityData ed;
private EntitySet decays;
@Override
protected void initialize() {
ed = requireSystem(EntityData.class);
decays = ed.getEntities(Decay.class);
}
@Override
protected void terminate() {
decays.release();
decays = null;
}
@Override
public void update(SimTime time) {
decays.applyChanges();
for (Entity e : decays) {
Decay decay = e.get(Decay.class);
if (decay.getPercent() >= 1.0) {
ed.removeEntity(e.getId());
}
}
}
}
Movement System Pattern
@Override
public void update(SimTime time) {
bullets.applyChanges();
for (Entity e : bullets) {
Position position = e.get(Position.class);
Speed speed = e.get(Speed.class);
e.set(new Position(
position.getLocation().add(0, time.getTpf() * speed.getSpeed(), 0)
));
}
}
Collision System Pattern
public class CollisionSystem extends BaseInfinitySystem {
private EntitySet attackers;
private EntitySet defenders;
@Override
protected void initialize() {
ed = requireSystem(EntityData.class);
attackers = ed.getEntities(Attack.class, CollisionShape.class, Position.class);
defenders = ed.getEntities(Defense.class, CollisionShape.class, Position.class);
}
@Override
public void update(SimTime time) {
attackers.applyChanges();
defenders.applyChanges();
for (Entity attacker : attackers) {
for (Entity defender : defenders) {
if (hasCollision(attacker, defender)) {
handleCollision(attacker, defender);
}
}
}
}
}
Getting Other Systems
OtherSystem other = requireSystem(OtherSystem.class);
OtherSystem maybeOther = getSystem(OtherSystem.class);
Publishing Events
import com.simsilica.event.EventBus;
EventBus.publish(EventType.MY_EVENT, new MyEvent(data));
Using Filters
import com.simsilica.es.Filters;
EntitySet ships = ed.getEntities(
Filters.fieldEquals(Model.class, "name", Model.SHIP),
Model.class,
Position.class
);
Existing Systems Reference
AvatarSystem - player ship management
DeathSystem - death/respawn handling
DelaySystem - timed component removal
ContactSystem - collision handling