Somehow attempting to add a null entity...
carlislefox opened this issue · 3 comments
Hi there, I'm getting the following error which is actually causing my Server to crash:
java.lang.NullPointerException
at com.badlogic.gdx.utils.ObjectSet.contains(ObjectSet.java:340)
at com.badlogic.ashley.core.EntityManager.addEntityInternal(EntityManager.java:116)
at com.badlogic.ashley.core.EntityManager.processPendingOperations(EntityManager.java:86)
at com.badlogic.ashley.core.Engine.update(Engine.java:206)
at com.foxcake.mirage.server.game.GameServerEngine.render(GameServerEngine.java:88)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.headless.HeadlessApplication.mainLoop(HeadlessApplication.java:126)
at com.badlogic.gdx.backends.headless.HeadlessApplication$1.run(HeadlessApplication.java:93)
It looks like object set is throwing a nullpointer trying to get the hash on a null reference, but this is in the addEntityInternal which means somehow I've ended up trying to add a null entity. The thing is, this happened after the server was running for an entire week, so there's some kind of edge case here that I'm missing :/
I'm wondering what would happen if a remove() was called in the same loop as an add() or something weird like that. The only ways to work around this that I can think of involve working from source and putting null checks in manually.
A null check in addEntityInternal() would prevent this from crashing but not solve the underlying issue. What do you guys think? My server fires off all of it's incoming responsive logic in runnables that are processed by a system so the entity operations are always being performed within the engine's cycle.
- Should we be null checking the Entity in in addEntityInternal to prevent logic crashes
- When a pending operation fails, should this crash the entire engine? I feel it should throw an exception then continue on. Currently if a pending operation fails, the engine will crash out and that operation is never removed from the pending operations queue, meaning every engine cycle crashes from that point onwards. I think this is a bit fragile?
Liam
Looks like a race condition issue, you probably add/remove stuff from different thread, make sure your entity manager is thread safe, add a queue for adding/removing entities, and make sure you handle the queue once you finished to tick your entities
As addition and removal is done at the end of an engine update cycle, and is deferred if it is called during a current update cycle, it would appear as though these operations are already thread-safe?
I'm 99.9% certain all of my entity addition and removal is done in the LibGDX thread anyway, but I will however now go through the laborious process of checking everything and will report back with what I find.
Just to confirm, Libgdx containers, which are the ones we use, are not thread safe.