[1.1.59] Writing to entity.direction modifies find_entities_filtered iteration order
Posted: Fri May 27, 2022 5:05 pm
My mod expects the order of entities in the same position to be consistent when querying find_entity() and find_entities_filtered() as long as no entities are created or destroyed. Starting with version 1.1.58, this is no longer the case, and modifications to an entity's direction will change its iteration order.
Repro1:
1. Start a new map.
2. Create two entities in the same chunk.
3. Find these entities and note the iteration order.
4. Perform a no-op write to the second entity in iteration order.
5. Check iteration order again.
Expected: iteration order is the same. This is the case in versions <= 1.1.57.
Actual: the entity whose direction field was written to becomes the first entity in iteration order. (Confirm by testing with many entities in the same position.)
Note that scripting is not necessary for any operations other than checking the iteration order. The inserters can be built by hand, and then the correct one (second in iteration order) rotated by the normal keyboard shortcut.
When there are more entities involved, the modified (whether by actual rotation or writing to direction) entity becomes the first in the new iteration order.
Alternate repro2:
1. Start a new map.
2. Create multiple entities in the same position:
3. Display iteration order of entities:
4. Write to direction of the second entity:
5. Display iteration order of entities again:
Expected: iteration order is the same. This is the case in versions <= 1.1.57.
Actual: the entity whose direction field was written to becomes the first entity in iteration order. (Confirm by testing with many entities in the same position.)
Repro1:
1. Start a new map.
2. Create two entities in the same chunk.
Code: Select all
/c game.surfaces.nauvis.create_entity{name="inserter",position={0,0}} game.surfaces.nauvis.create_entity{name="inserter",position={1,0}}
Code: Select all
/c es=game.surfaces.nauvis.find_entities_filtered{name="inserter",area={{0,0},{2,2}}} for i=1,#es do game.print(es[i].unit_number) end
Code: Select all
/c es[2].direction=es[2].direction
Code: Select all
/c es=game.surfaces.nauvis.find_entities_filtered{name="inserter",area={{0,0},{2,2}}} for i=1,#es do game.print(es[i].unit_number) end
Actual: the entity whose direction field was written to becomes the first entity in iteration order. (Confirm by testing with many entities in the same position.)
Note that scripting is not necessary for any operations other than checking the iteration order. The inserters can be built by hand, and then the correct one (second in iteration order) rotated by the normal keyboard shortcut.
When there are more entities involved, the modified (whether by actual rotation or writing to direction) entity becomes the first in the new iteration order.
Alternate repro2:
1. Start a new map.
2. Create multiple entities in the same position:
Code: Select all
/c for i=1,2 do game.player.surface.create_entity{position={2,0},force='player',name='storage-tank'} end
Code: Select all
/c local s=game.player.selected; for _, e in pairs(s.surface.find_entities_filtered{position=s.position}) do game.print(e.unit_number) end
Code: Select all
/c local s=game.player.selected; es=s.surface.find_entities_filtered{position=s.position}; es[2].direction=0
Code: Select all
/c local s=game.player.selected; for _, e in pairs(s.surface.find_entities_filtered{position=s.position}) do game.print(e.unit_number) end
Actual: the entity whose direction field was written to becomes the first entity in iteration order. (Confirm by testing with many entities in the same position.)