Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding components within inline query affects references to current components #210

Closed
mk1024 opened this issue Mar 22, 2024 · 2 comments
Closed
Labels
wontfix This will not be worked on

Comments

@mk1024
Copy link

mk1024 commented Mar 22, 2024

Background
I'm using Arch (1.2.8 via NuGet) as the backbone of my game. Aside from typical components like Position, Velocity or Physics there is also a Player component. When the PlayerSystem detects a certain state for a player, it triggers an animation by adding an animation component. When the animation has finished, the component is removed. This worked perfectly with one player.
Recently, I added support for multiple entities with player components and noticed a strange behavior within inline queries. There are no parallel queries, threads or tasks used.

Issue
Whenever I use entity.Add(...) or entity.AddOrGet(...) within an inline query update method, the referenced components are getting randomly changed.
In the example below a and b should be equal, but b always is the index of another player. If I comment out the .Add(...) call, everything works as expected.

Example (simplified)

private readonly QueryDescription _query = new QueryDescription().WithAll<Player>();

public override void Update(in GameTime gameTime)
{
    var playerUpdate = new PlayerUpdate(this);
    World.InlineEntityQuery<PlayerUpdate, Player>(in _query, ref playerUpdate);
}

private readonly struct PlayerUpdate(PlayerSystem system)
    : IForEachWithEntity<Player>
{
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Update(Entity entity, ref Player player)
        {
            var a = player.Index; // returns current index
            entity.Add(new ScaleAnimation { ... });
            // the following method gives the same result:
            // ref var animation = ref entity.AddOrGet<ScaleAnimation>();
            var b = player.Index; // returns index of other component
        }
}
@genaray genaray added the wontfix This will not be worked on label Mar 26, 2024
@genaray
Copy link
Owner

genaray commented Mar 26, 2024

Thanks for your post! However, the behavior you describe is "intentional". The structural modification of an entity copies it into a new archetype. Its slot is taken by another entity. Since you use ref to access its components in exactly this slot, the values also change because they are overwritten.

This is the disadvantage of the inline query. However, the source generator or custom enumeration or the standard queries can be used to override this behavior.

@genaray genaray closed this as completed Mar 26, 2024
@mk1024
Copy link
Author

mk1024 commented Mar 28, 2024

Thanks for the clarification.

My simple fix was to add components only at the end of each Update call and not use the referenced components after that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

No branches or pull requests

2 participants