legion icon indicating copy to clipboard operation
legion copied to clipboard

Crash when deleting entities from a deserialized world (entity not found)

Open thebracket opened this issue 4 years ago • 4 comments

I've been using Legion in my Nox Futura Rust port. It's generally excellent, but I've run into a bug. I didn't think you'd want to help me go through 13k lines of code, so I made a repo with a reproduction of the issue: https://github.com/thebracket/legion-serialize-bug-demo

It uses the serialization code from the example, wrapped in some functions. This is working great with 30k entities in NF, loading nice and fast and all the queries/systems work with the loaded data. I know that Entity references in serialized data aren't done yet, so I've been using an identity tag (with a unique id) on entities I need to reference - with a view to replacing it with entity references at a later date. That's also been working well.

The bug: when you try to delete a deserialized entity, you get a crash. Legion appears to be unable to find the entity (even though it hands it to you and it looks ok, and referencing its components works fine) and crashes on an unwrap call. I've included full backtraces and example usage in the linked repo.

The example:

In works_fine:

  1. Inserts 3 trees into the world. They have TreeTag, IdentityTag(usize) tags (the identity is incremented per tree) and a Position component.
  2. It runs a query to filter to tree id # 1 and prints it.
  3. Runs a query with entities to find tree # 1 and deletes it via a command buffer.
  4. Searches for tree # 1 again to show that its actually gone.

That works great.

In crashes():

  1. Inserts 3 trees into the world. They have TreeTag, IdentityTag(usize) tags (the identity is incremented per tree) and a Position component.
  2. It runs a query to filter to tree id # 1 and prints it.
  3. Saves the world to a RON file, and re-loads it.
  4. Finds tree # 1 and prints it again to prove that its there.
  5. Runs a query with entities to find tree # 1 and deletes it via a command buffer.
  6. It crashed!

Hopefully, I've just done something wrong in my copy/paste serialization code?

Thanks for taking the time to look at it. Legion is awesome.

thebracket avatar Jul 15 '20 14:07 thebracket

I also tried to work around it, instead of deleting the entity add a PendingDelete tag. The call to add the tag fails with the same error. It looks like the entity added from deserializing is somehow invalid, but I haven't learned enough about Legion's innards to find the issue yet.

thebracket avatar Jul 15 '20 14:07 thebracket

If it helps, I simplified the repro to not have the identity and filtering. It still crashes, so the tag/filter apparently isn't related to the issue: https://github.com/thebracket/legion-serialize-bug-demo/tree/no_identity

thebracket avatar Jul 15 '20 15:07 thebracket

Aha! I'm really not sure why this works, but a band-aid fix is in the branch https://github.com/thebracket/legion-serialize-bug-demo/tree/nasty-fix

Adding the following to the very end of deserialize_world makes the project not crash:

let mut new_world = universe.create_world();
new_world.move_from(deserialized_world);
new_world

That's kind of a nasty thing to do, but it works!

thebracket avatar Jul 15 '20 15:07 thebracket

I'll try and find the time to take a proper look at this soon, but from the description it sounds like the world is not properly recording the locations of the new entities upon deserialization. The entity will still be found by queries, but anything which tries to index to that entity (such as deleting the entity or using get_component) will think the entity does not exist.

TomGillen avatar Jul 16 '20 07:07 TomGillen