Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question two containers may not be the same (aliasing). (?!)

Discussion in 'Entity Component System' started by adammpolak, Jan 26, 2021.

  1. adammpolak

    adammpolak

    Joined:
    Sep 9, 2018
    Posts:
    450
    I have received this error

    - I create an array of PlayerScore entities using ToEntityArray on PlayerScoreComponent's
    - I do a .ForEach() which doesn't involve any entities/components associated with PlayerScore entities
    - I got through each entity in the PlayerScoreComponent array and compare the entity's PlayerScoreComponent NetworkId to another brought in NetworkId
    - I then Set(entity, PlayerScoreComponent)

    I am getting:
    Code (CSharp):
    1. InvalidOperationException: The writeable ComponentDataFromEntity<PlayerScoreComponent> <>c__DisplayClass_ChangeMaterialOnTriggerEnter.JobData.playerScoreComponent is the same ComponentDataFromEntity<PlayerScoreComponent> as <>c__DisplayClass_ChangeMaterialOnTriggerEnter.JobData._ComponentDataFromEntity_PlayerScoreComponent_3, two containers may not be the same (aliasing).
    I am wondering why this comes up. Is it because within a .ForEach() I am working with entities not related to the queried entities?

    Full code:

    Code (CSharp):
    1. protected override void OnUpdate()
    2.     {
    3.         // var commandBuffer = m_CommandBufferSystem.CreateCommandBuffer();
    4.  
    5.         // Need this extra variable here so that it can
    6.         // be captured by Entities.ForEach loop below
    7.         var nonTriggerMask = m_NonTriggerMask;
    8.  
    9.         //this is where we grab the data for processing
    10.         //first we grab an array of all the player score entities
    11.         var playerScoreEntities = m_PlayerScores.ToEntityArray(Allocator.TempJob);
    12.         //we will need to grab the PlayerScoreComponent from our player score entities to compare values
    13.         var playerScoreComponent = GetComponentDataFromEntity<PlayerScoreComponent>();
    14.  
    15.         //We grab the 1 HighestScore engity
    16.         var highestScoreEntities = m_HighestScore.ToEntityArray(Allocator.TempJob);
    17.         //We will need to grab the HighestScoreComponent from our highest score entity to compare values
    18.         var highestScoreComponent = GetComponentDataFromEntity<HighestScoreComponent>();
    19.  
    20.         //We are going to use this to pull the GhostOwnerComponent from the bullets in that have the DynamicBuffer of StatefulTriggerEvents
    21.         var ghostOwner = GetComponentDataFromEntity<GhostOwnerComponent>();
    22.      
    23.         //We need to dispose our entities
    24.         Entities
    25.         .WithDisposeOnCompletion(playerScoreEntities)
    26.         .WithDisposeOnCompletion(highestScoreEntities)
    27.         .WithName("ChangeMaterialOnTriggerEnter")
    28.         .ForEach((Entity e, ref DynamicBuffer<StatefulTriggerEvent> triggerEventBuffer) =>
    29.         {
    30.             for (int i = 0; i < triggerEventBuffer.Length; i++)
    31.             {
    32.                 var triggerEvent = triggerEventBuffer[i];
    33.                 var otherEntity = triggerEvent.GetOtherEntity(e);
    34.  
    35.                 // exclude other triggers and processed events
    36.                 if (triggerEvent.State == EventOverlapState.Stay || !nonTriggerMask.Matches(otherEntity))
    37.                 {
    38.                     continue;
    39.                 }
    40.  
    41.                 //this is what happens when the bullet enters
    42.                 else if (triggerEvent.State == EventOverlapState.Enter)
    43.                 {
    44.  
    45.                     //We grab the NetworkId of the bullet so we know who to assign points to
    46.                     var bulletsPlayerNetworkId = ghostOwner[e].NetworkId;
    47.  
    48.                     //We start with 0 points to add
    49.                     int pointsToAdd = 0;
    50.                     if (HasComponent<PlayerTag>(otherEntity))
    51.                     {
    52.                         //Now we check if the bullet came from the same player
    53.                         if (ghostOwner[otherEntity].NetworkId == bulletsPlayerNetworkId)
    54.                         {
    55.                             //if it is from the same player no points
    56.                             return;
    57.                         }
    58.                         pointsToAdd += 10;
    59.                     }
    60.  
    61.                     if (HasComponent<AsteroidTag>(otherEntity))
    62.                     {
    63.                         pointsToAdd += 1;
    64.                     }
    65.                  
    66.                     //After updating the points to add we check the PlayerScore entities and find the one with the
    67.                     //correct NetworkId so we can update the scores for the layer
    68.                     //If the updated score is higher than the highest score it updates the highest score
    69.                     for (int j = 0; j < playerScoreEntities.Length; j++)
    70.                     {
    71.                         var  currentPlayScoreComponent = playerScoreComponent[playerScoreEntities[j]];
    72.                         if(currentPlayScoreComponent.networkId == bulletsPlayerNetworkId)
    73.                         {
    74.                             var newPlayerScore = new PlayerScoreComponent{
    75.                                 networkId = currentPlayScoreComponent.networkId,
    76.                                 playerName = currentPlayScoreComponent.playerName,
    77.                                 currentScore = currentPlayScoreComponent.currentScore + pointsToAdd,
    78.                                 highScore = currentPlayScoreComponent.highScore
    79.                                 };
    80.                             //here we check if the player beat their own high score
    81.                             if (newPlayerScore.currentScore > newPlayerScore.highScore)
    82.                             {
    83.                                 newPlayerScore.highScore = newPlayerScore.currentScore;
    84.                             }
    85.                             //here we check if the player beat the highest score
    86.                             var currentHighScore = highestScoreComponent[highestScoreEntities[0]];
    87.                             if (newPlayerScore.highScore > currentHighScore.highestScore)
    88.                             {
    89.                                 var updatedHighestScore = new HighestScoreComponent {
    90.                                     highestScore = newPlayerScore.highScore,
    91.                                     playerName = newPlayerScore.playerName
    92.                                 };
    93.                                 SetComponent<HighestScoreComponent>(highestScoreEntities[0],  updatedHighestScore);
    94.                             }
    95.                             SetComponent<PlayerScoreComponent>(playerScoreEntities[j], newPlayerScore);
    96.                         }
    97.                     }
    98.                 }
    99.                 else
    100.                 {
    101.                     continue;
    102.                 }
    103.             }
    104.         }).Schedule();
    105.  
    106.     }
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    676
    You should either use GetComponentDataFromEntity<HighestScoreComponent> or the syntax-sugar version Get/SetComponent<HighestScoreComponent> (and the same for the PlayerScoreComponent). The error is because you have two ComponentDataFromEntity for the same component (one that you created yourself, and another one generated by the Unity code-gen).
     
  3. adammpolak

    adammpolak

    Joined:
    Sep 9, 2018
    Posts:
    450
    Sorry I am sure I am being dense but is that not what I am doing in line 13 and 18 in the example above?

    If I don't need to create one how do I use the code-gen one?
     
    Last edited: Jan 26, 2021
  4. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    676
    You are using GetComponentDataFromEntity on lines 13 and 18, then on lines 93 and 95 you are using SetComponent (which code-gens another GetComponentDataFromEntity). You should either use the ones you already got in lines 13 and 18, or delete those and only use the SetComponent version.
     
  5. adammpolak

    adammpolak

    Joined:
    Sep 9, 2018
    Posts:
    450
    I had no idea that SetComponent == GetComponentData !!! Thank you!

    I assume I HAVE to go with GetComponentData instead of SetComponent right? Because I am using GetComponentData within the .ForEach to grab data from an entity.

    (I only asked because I am wondering if there are more obvious things I am missing)
     
  6. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    676
    I would say that Get/SetComponent is the way to go with ForEach... Unless you don't like code-gen magic for some reason.

    If you only use GetComponent inside the ForEach it will code-gen properly to a read-only GeComponentDataFromEntity and if you use SetComponent it will use the non-read-only version automatically.
     
  7. adammpolak

    adammpolak

    Joined:
    Sep 9, 2018
    Posts:
    450
    This is really great thank you.

    So if I use GetComponent I am ALSO allowed to use SetComponent

    But if I use GetComponentDataArray then I cannot use SetComponent

    Much appreciated