Terasology icon indicating copy to clipboard operation
Terasology copied to clipboard

Entity creation within the context of `initialise()` is silently ignored without access to the entity

Open skaldarnar opened this issue 3 years ago • 0 comments

General Info

Terasology Launcher Version: n/a Terasology Version: 71a98a1bc771aa0c0b2969db6878134e5022fb28 (v5.2.0+) Operating System: Linux Mint 20.2 x86_64 Onboard / Dedicated Graphics: NVIDIA GeForce GTX 1070 Java Version: openjdk version "11.0.11" 2021-04-20

What you were trying to do

In the context of https://github.com/Terasology/LightAndShadow/pull/256 we were trying to get the Light and Shadow game entity during the initialisation of an entity system to add mandatory components to it before starting the game.

https://github.com/Terasology/LightAndShadow/blob/6b7eab6e0170e165a65f9b388b55c17f73e7e43a/src/main/java/org/terasology/module/lightandshadow/phases/authority/PhaseSystem.java#L39-L43

The respective call to GameEntitySystem#getGameEntity() is supposed to fetch the respective entity if it exists, or create it otherwise.

https://github.com/Terasology/LightAndShadow/blob/ad522934014b3296b725a4b97442fdd793aa3f83/src/main/java/org/terasology/module/lightandshadow/systems/GameEntitySystem.java#L33-L45

What actually happened

Later during testing we figured out that the entity is actually not created. We verified this by looking at entity dumps created with dumpEntities from the in-game console. The entity creation within the context of initialise() is silently ignored.

For debugging purposes we then tried to print out the entity.toFullDescription(), which suddenly caused an an error.

The entity creation itself within the context of initialise() should already throw an exception, not only if the entity is also accessed. Actions like entity creation should not silently be ignored.

How to reproduce

Entity creation is silently ignored:

  1. Create or entity within the context of initialise() in an entity system
  2. Create an entity dump in-game and check whether that entity exists (it should not)
  3. :question: entity creation is silently ignored

Access to entity throws exception:

  1. Create or entity within the context of initialise() in an entity system
  2. Access the entity within the context of initialise(), e.g., by getting and printing entity.getId()
  3. :x: game crashes with IllegalStateException

Log details

12:46:22.476 [main] ERROR o.t.e.c.m.loadProcesses.LoadEntities - Entity created before load: {
  "id": 1,
  "parentPrefab": "LightAndShadow:gameEntity",
  "LightAndShadow:Phase": {
    "currentPhase": "IDLE"
  }
}
12:46:22.478 [main] ERROR o.t.engine.core.modes.StateLoading - Error while loading org.terasology.engine.core.modes.loadProcesses.LoadEntities@66e17bf2
java.lang.IllegalStateException: Entity creation detected during component system initialisation, game load aborting
	at org.terasology.engine.core.modes.loadProcesses.LoadEntities.step(LoadEntities.java:40)
	at org.terasology.engine.core.modes.StateLoading.update(StateLoading.java:257)
	at org.terasology.engine.core.TerasologyEngine.tick(TerasologyEngine.java:499)
	at org.terasology.engine.core.TerasologyEngine.mainLoop(TerasologyEngine.java:459)
	at org.terasology.engine.core.TerasologyEngine.runMain(TerasologyEngine.java:435)
	at org.terasology.engine.core.TerasologyEngine.run(TerasologyEngine.java:401)
	at org.terasology.engine.Terasology.call(Terasology.java:206)
	at org.terasology.engine.Terasology.call(Terasology.java:69)
	at picocli.CommandLine.executeUserObject(CommandLine.java:1933)
	at picocli.CommandLine.access$1200(CommandLine.java:145)
	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2332)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2326)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2291)
	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2159)
	at picocli.CommandLine.execute(CommandLine.java:2058)
	at org.terasology.engine.Terasology.main(Terasology.java:138)

Workaround

I think using the postBegin hook is the correct place to do these kind of initialization.

https://github.com/Terasology/LightAndShadow/blob/13cc215483d2b0bac25217c38ae201c28fd26720/src/main/java/org/terasology/module/lightandshadow/phases/authority/PhaseSystem.java#L39-L45

Additional Infos / Context

Creating entities in initialise() is forbidden.

The game will crash if a system tries to access an entity within the context of initialise(), e.g., entity.getId().

However, the entity creation is silently ignored if it happened within the context of initialise() and there is no immediate access to it. This leads to hard-to-debug situations where entities are seemingy missing for no reason, i.e., creation did not throw errors but they are nowhere to be found in an entity dump.

skaldarnar avatar Dec 18 '21 11:12 skaldarnar