This (likely) outputs:
false
true
true
true
User likely expects true all around.
struct ComponentA;
struct ComponentB;
static void Test(World world)
{
for (var i = 0; i < 2; i++)
{
var e = world.Spawn()
.Add<ComponentA>()
.Add<ComponentB>();
using (world.Lock())
{
world.Stream<ComponentA>()
.For((in entity, ref _) => entity.Remove<ComponentA>());
world.Stream<ComponentB>()
.Query
.Batch()
.Remove<ComponentB>()
.Submit();
}
Console.WriteLine(e.Has<ComponentA>()); // false
Console.WriteLine(e.Has<ComponentB>()); // true
}
}
Theory - not a bug, but a footgun and might need some architectural rework.
What happens is that the batch takes note of the archetypes, not the entities.
When you create the entity, there are 2 archetypes: A (Has)first, and then it's directly moved into AB. Query matches archetype AB.
After the Query1's Stream.For has pushed all the commands, none are executed yet. Stream.Batch takes note to remove B from all current archetypes in Query 2, which is at that time only AB.
Then at end of scope, the commands are caught up (processed) in order, and before the batch command, AB is completely empty (all entities were moved into new 3rd archetype B, which the query and batch didn't know about at the time).
Maybe I want to change it so not the archetypes, but the query is noted with each batch.
But there are other things - e.g. when adding components - where this behaviour might then be surprising. (maybe... lots of maybes)
If the lock weren't there, then when the Stream.For has finished, all changes are caught up and the batch would operate on a query that knows the old AB and the newly created B archetype.
If the order were reversed, then everything is moved into archetype A, but Query 1 doesn't care about that because it notes down commands directly for the entities, and for them "remove" is still legal.
This (likely) outputs:
false
true
true
true
User likely expects true all around.
Theory - not a bug, but a footgun and might need some architectural rework.
What happens is that the batch takes note of the archetypes, not the entities.
When you create the entity, there are 2 archetypes: A (Has)first, and then it's directly moved into AB. Query matches archetype AB.
After the Query1's Stream.For has pushed all the commands, none are executed yet. Stream.Batch takes note to remove B from all current archetypes in Query 2, which is at that time only AB.
Then at end of scope, the commands are caught up (processed) in order, and before the batch command, AB is completely empty (all entities were moved into new 3rd archetype B, which the query and batch didn't know about at the time).
Maybe I want to change it so not the archetypes, but the query is noted with each batch.
But there are other things - e.g. when adding components - where this behaviour might then be surprising. (maybe... lots of maybes)
If the lock weren't there, then when the Stream.For has finished, all changes are caught up and the batch would operate on a query that knows the old AB and the newly created B archetype.
If the order were reversed, then everything is moved into archetype A, but Query 1 doesn't care about that because it notes down commands directly for the entities, and for them "remove" is still legal.