Search Unity

A weird Error inside an IJobChunk

Discussion in 'Entity Component System' started by Opeth001, Oct 9, 2019.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    Hello Guys,
    im facing a weird Error from 2 days now :( any suggestion is welcome

    it seems like im having a structural change or something like this.
    the error is happening when the PlayersSkinsManagerSystem executes this line:
    PostUpdateCommands.AddComponent(entity, new PlayerSkinPrefabIndex { value = indexRef});


    Code (CSharp):
    1.  
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using Unity.Mathematics;
    7. using Unity.Physics;
    8. using Unity.Transforms;
    9. using UnityEngine;
    10. using UnityEngine.Jobs;
    11. using Unity.Physics.Systems;
    12. using CWBR.ClientAndServer.Components;
    13. using Utils._Math;
    14.  
    15. namespace CWBR.ClientAndServer.Systems
    16. {
    17.     // Move Players using on their Inputs
    18.     //[DisableAutoCreation]
    19.     [UpdateInGroup(typeof(SimulationSystemGroup))]
    20.     public class [B][SIZE=5]PlayersMovementSystem [/SIZE][/B]: JobComponentSystem
    21.     {
    22.         private EntityQuery m_Group;
    23.  
    24.  
    25.         protected override void OnCreate()
    26.         {
    27.             //this.Enabled = false;
    28.             // Cached access to a set of ComponentData based on a specific query
    29.             m_Group = GetEntityQuery(ComponentType.ReadOnly<MoveSpeed>(), ComponentType.ReadOnly<MouvementInput>(), ComponentType.ReadOnly<AimInput>(), typeof(Rotation), typeof(PhysicsVelocity), typeof(PhysicsMass));
    30.         }
    31.  
    32.  
    33.  
    34.         //Using Translation and Rotation Components ( Depricated )
    35.  
    36.         /// <summary>
    37.         /// IJobChunk is used to create 1 Worker thread by chunk of 16kB
    38.         /// Prevent from abusing of Thread creation
    39.         /// </summary>
    40.         [BurstCompile]
    41.         struct MouvePlayersJob : IJobChunk
    42.         {
    43.  
    44.             [ReadOnly] public float defaultMovementSpeed;
    45.             [ReadOnly] public float defaultAimMoveSpeed;
    46.             [ReadOnly] public float defaultRotationSpeed;
    47.             [ReadOnly] public float deltaTime;
    48.  
    49.             [ReadOnly] public ArchetypeChunkComponentType<MoveSpeed> MoveSpeedType;
    50.             [ReadOnly] public ArchetypeChunkComponentType<MouvementInput> MoveInputType;
    51.             [ReadOnly] public ArchetypeChunkComponentType<AimInput> AimInputType;
    52.  
    53.             public ArchetypeChunkComponentType<PhysicsMass> PhysicsMassType;
    54.             public ArchetypeChunkComponentType<Rotation> RotationType;
    55.             public ArchetypeChunkComponentType<PhysicsVelocity> PhysicsVelocityType;
    56.  
    57.  
    58.             // One Thread by Chunck
    59.             public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    60.             {
    61.  
    62.                 var chunkMoveSpeeds = chunk.GetNativeArray(MoveSpeedType);
    63.                 var chunkMoveInputs = chunk.GetNativeArray(MoveInputType);
    64.                 var chunkAimInputs = chunk.GetNativeArray(AimInputType);
    65.  
    66.                 var chunkPhysicsMass = chunk.GetNativeArray(PhysicsMassType);
    67.                 var chunkRotations = chunk.GetNativeArray(RotationType);
    68.                 var chunkPhysicsVelocities = chunk.GetNativeArray(PhysicsVelocityType);
    69.  
    70.  
    71.                 for (int i = 0; i < chunk.Count; i++)
    72.                 {
    73.                     var physicsVelocity = chunkPhysicsVelocities[chunkIndex]; [SIZE=5][COLOR=#ff4d4d][B]// Line : 73[/B][/COLOR][/SIZE]
    74.  
    75.                     // This computation dont need to run if there is no imputs and the player Completed  sync the velocity
    76.                     if (chunkMoveInputs[chunkIndex].Value.Equals(float2.zero) && chunkAimInputs[chunkIndex].Value.Equals(float2.zero))
    77.                     {
    78.                         if (physicsVelocity.Linear.Equals(float3.zero))
    79.                         {
    80.                             continue;
    81.                         }
    82.                         else
    83.                         {
    84.                             physicsVelocity.Linear.x = 0;
    85.                             physicsVelocity.Linear.z = 0;
    86.                             chunkPhysicsVelocities[chunkIndex] = physicsVelocity;
    87.                             continue;
    88.                         }
    89.                     }
    90.                    
    91.                     // Character Moving Only
    92.                     if (!chunkMoveInputs[chunkIndex].Value.Equals(float2.zero) && chunkAimInputs[chunkIndex].Value.Equals(float2.zero))
    93.                     {
    94.                         // Movement
    95.                         physicsVelocity.Linear = new float3(chunkMoveInputs[chunkIndex].Value.x, 0, chunkMoveInputs[chunkIndex].Value.y) * defaultMovementSpeed  * deltaTime * chunkMoveSpeeds[chunkIndex].value;
    96.                         physicsVelocity.Linear.y = -1;
    97.                         chunkPhysicsVelocities[chunkIndex] = physicsVelocity;
    98.  
    99.  
    100.  
    101.                         // Rotation
    102.                         var finalRotation = Quaternion.LookRotation(math.normalize(new float3(chunkMoveInputs[chunkIndex].Value.x, 0, chunkMoveInputs[chunkIndex].Value.y)), _MathUtils.float3_UP);
    103.                         // fixes the Rotation when using burst
    104.                         //finalRotation.z = 0f;
    105.                         //finalRotation.x = 0f;
    106.                         chunkRotations[chunkIndex] = new Rotation
    107.                         {
    108.                             Value = Quaternion.Slerp(chunkRotations[chunkIndex].Value, finalRotation, defaultRotationSpeed * deltaTime)
    109.                         };
    110.                        
    111.                     }
    112.                     else if (chunkMoveInputs[chunkIndex].Value.Equals(float2.zero) && !chunkAimInputs[chunkIndex].Value.Equals(float2.zero))
    113.                     {   // Character Rotating Only
    114.  
    115.                         // Rotation
    116.                         var finalRotation = Quaternion.LookRotation(math.normalize(new float3(chunkAimInputs[chunkIndex].Value.x, 0, chunkAimInputs[chunkIndex].Value.y)), _MathUtils.float3_UP);
    117.                         // fixes the Rotation when using burst
    118.                         //finalRotation.z = 0f;
    119.                         //finalRotation.x = 0f;
    120.  
    121.                         chunkRotations[chunkIndex] = new Rotation
    122.                         {
    123.                             Value = Quaternion.Slerp(chunkRotations[chunkIndex].Value, finalRotation, defaultRotationSpeed * deltaTime)
    124.                         };
    125.  
    126.                     }
    127.                     else // Character Moving and Rotating
    128.                     {
    129.                         // Movement
    130.                         physicsVelocity.Linear = new float3(chunkMoveInputs[chunkIndex].Value.x, 0, chunkMoveInputs[chunkIndex].Value.y) * defaultMovementSpeed * deltaTime * chunkMoveSpeeds[chunkIndex].value;
    131.                         chunkPhysicsVelocities[chunkIndex] = physicsVelocity;
    132.  
    133.                         // Rotation
    134.                         var finalRotation = Quaternion.LookRotation(math.normalize(new float3(chunkAimInputs[chunkIndex].Value.x, 0, chunkAimInputs[chunkIndex].Value.y)), _MathUtils.float3_UP);
    135.                      
    136.                         chunkRotations[chunkIndex] = new Rotation
    137.                         {
    138. #if SERVER_BUILD
    139.                             Value = Quaternion.Slerp(chunkRotations[chunkIndex].Value, finalRotation, ServerGameBootstrap.playerDefault_RotationSpeed * deltaTime)
    140. #elif CLIENT_BUILD
    141.                             Value = Quaternion.Slerp(chunkRotations[chunkIndex].Value, finalRotation, ClientGameBootstrap.playerDefault_RotationSpeed * deltaTime)
    142. #endif
    143.                         };
    144.                     }
    145.  
    146.  
    147.  
    148.                 }
    149.  
    150.  
    151.             }
    152.         }
    153.  
    154.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    155.         {
    156.             var moveSpeedType = GetArchetypeChunkComponentType<MoveSpeed>(true);
    157.             var moveInputType = GetArchetypeChunkComponentType<MouvementInput>(true);
    158.             var aimInputType = GetArchetypeChunkComponentType<AimInput>(true);
    159.  
    160.             var physicsMassType = GetArchetypeChunkComponentType<PhysicsMass>(false);
    161.             var rotationType = GetArchetypeChunkComponentType<Rotation>(false);
    162.             var physicsVelocityType = GetArchetypeChunkComponentType<PhysicsVelocity>(false);
    163.  
    164.             var moveJob = new MouvePlayersJob
    165.             {
    166. #if CLIENT_BUILD
    167.                 defaultAimMoveSpeed = ClientGameBootstrap.playerDefault_AimMoveSpeed,
    168.                 defaultMovementSpeed = ClientGameBootstrap.playerDefault_MovementSpeed,
    169.                 defaultRotationSpeed = ClientGameBootstrap.playerDefault_RotationSpeed,
    170.                 deltaTime = ClientGameBootstrap.SimulationDeltaTime,
    171.  
    172. #elif SERVER_BUILD
    173.                 defaultAimMoveSpeed = ServerGameBootstrap.playerDefault_AimMoveSpeed,
    174.                 defaultMovementSpeed = ServerGameBootstrap.playerDefault_MovementSpeed,
    175.                 defaultRotationSpeed = ServerGameBootstrap.playerDefault_RotationSpeed,
    176.                 deltaTime = ServerGameBootstrap.SimulationDeltaTime,
    177. #endif
    178.  
    179.  
    180.  
    181.  
    182.                 MoveInputType = moveInputType,
    183.                 MoveSpeedType = moveSpeedType,
    184.                 AimInputType = aimInputType,
    185.                 PhysicsMassType = physicsMassType,
    186.                 RotationType = rotationType,
    187.                 PhysicsVelocityType = physicsVelocityType
    188.             };
    189.  
    190.             return moveJob.Schedule(m_Group, inputDeps);
    191.         }
    192.  
    193.  
    194.  
    195.     }
    196.  
    197.  
    198. }

    Code (CSharp):
    1.  
    2. #if CLIENT_BUILD
    3.  
    4. using CWBR.Client.Components;
    5. using CWBR.Client.Mono;
    6. using Unity.Entities;
    7. using Unity.Jobs;
    8. using Unity.Mathematics;
    9. using Unity.Transforms;
    10. using UnityEngine;
    11. using Utils._Math;
    12.  
    13. /// <summary>
    14. /// Manage all Players Skins (GO) Instantiation. (it's a Pool of Skins)
    15. /// </summary>
    16. //[DisableAutoCreation]
    17. [UpdateInGroup(typeof(PresentationSystemGroup))]
    18. public class PlayersSkinsManagerSystem : ComponentSystem
    19. {
    20.     public EntityQuery m_PlayersRequireSkinsQuery;
    21.     public EntityQuery m_PlayersRequireSkinRecycleQuery;
    22.  
    23.  
    24.     public EntityQuery m_PlayersWithSkinsToMoveQuery;
    25.  
    26.     private float3 localPlayerPosition;
    27.  
    28.    
    29.  
    30.     // Delegate to reduce GC
    31.     EntityQueryBuilder.F_EDDDD<PlayerSkinId, PlayerSkinPrefabIndex, Translation, Rotation> SkinsToMoveDelegate;
    32.     EntityQueryBuilder.F_EDDD<PlayerSkinId, Translation, Rotation> linkPlayersSkinsDelegate;
    33.     EntityQueryBuilder.F_EDD<PlayerSkinId, PlayerSkinPrefabIndex> RecyclePlayersSkinsDelegate;
    34.  
    35.     #region Value to space Skins Checks Time
    36.  
    37.     float timePassedSinceLastCheck = 0f; // this value is initialized to 0.6f instead of 0 to instantly show players after game start
    38.     float timebetweenChecks = 1f;
    39.  
    40.     PlayerSkinsGameObjectPool skinsPool;
    41.  
    42.     #endregion
    43.     protected override void OnCreate()
    44.     {
    45.  
    46.         // Players with Skin To Move
    47.         m_PlayersWithSkinsToMoveQuery = GetEntityQuery( ComponentType.ReadOnly<PlayerSkinId>(), ComponentType.ReadOnly<PlayerSkinPrefabIndex>(), ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<Rotation>());
    48.        
    49.         // Players Require Skin
    50.         var m_PlayersRequireSkinsQueryDesc = new EntityQueryDesc
    51.         {
    52.             All = new ComponentType[] { ComponentType.ReadOnly<PlayerSkinId>(), ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<Rotation>() },
    53.             None = new ComponentType[] { ComponentType.ReadOnly<PlayerSkinPrefabIndex>()}
    54.         };
    55.         m_PlayersRequireSkinsQuery = GetEntityQuery(m_PlayersRequireSkinsQueryDesc);
    56.        
    57.         // Players with Skins to Recycle
    58.         m_PlayersRequireSkinRecycleQuery = GetEntityQuery(ComponentType.ReadOnly<PlayerSkinId>(), ComponentType.ReadOnly<PlayerSkinRecycleTag>(), ComponentType.ReadOnly<PlayerSkinPrefabIndex>());
    59.  
    60.  
    61.         // Skins Pool
    62.         skinsPool = new PlayerSkinsGameObjectPool();
    63.  
    64.  
    65.         // Local Functions to reduce GC
    66.         SkinsToMoveDelegate = MoveSkins;
    67.         linkPlayersSkinsDelegate = LinkSkins;
    68.         RecyclePlayersSkinsDelegate = RecycleSkins;
    69.  
    70.         this.Enabled = false;
    71.     }
    72.  
    73.    
    74.  
    75.     PlayerSkinPrefabHolder cachedSkinHolder;
    76.     /// <summary>
    77.     /// Link a Skin + animator to a Close Entity (close to the LocalPlayer)
    78.     /// </summary>
    79.     /// <param name="playerSkinId"></param>
    80.     private void LinkSkins(Entity entity, ref PlayerSkinId playerSkinId, ref Translation position, ref Rotation rotation)
    81.     {
    82.        
    83.         if(math.distance(position.Value, localPlayerPosition) - ClientGameBootstrap.playerDefault_MinimumDistanceFromLocalPlayerToShowSkins <= _MathUtils.Epsilon)
    84.         {
    85.             /*
    86.             cachedSkinHolder = skinsPool.GetSkinPrefabHolder(playerSkinId.value,out var indexRef);
    87.            
    88.             EntityManager.AddComponentObject(entity, cachedSkinHolder._transform);
    89.             EntityManager.AddComponentData(entity, new PlayerPrefabIndex { value= indexRef});
    90.             EntityManager.AddComponentData(entity, new CopyTransformToGameObject {}); */
    91.  
    92.            cachedSkinHolder = skinsPool.GetSkinPrefabHolder(playerSkinId.value,ref position.Value, ref rotation.Value, out var indexRef);
    93.            PostUpdateCommands.AddComponent(entity, new PlayerSkinPrefabIndex { value = indexRef});
    94.         }
    95.     }
    96.  
    97.     private void MoveSkins(Entity entity, ref PlayerSkinId playerSkinId, ref PlayerSkinPrefabIndex playerPrefabIndex, ref Translation position, ref Rotation rotation)
    98.     {
    99.  
    100.      
    101.         if (math.distance(position.Value, localPlayerPosition) - ClientGameBootstrap.playerDefault_MaximumDistanceFromPlayerToHideSkins <= _MathUtils.Epsilon)
    102.         {
    103.             // cachedSkinHolder = skinsPool.GetSkinPrefabHolder(playerPrefabIndex.value);
    104.             /*
    105.              EntityManager.RemoveComponent(entity, typeof(Transform));
    106.              EntityManager.RemoveComponent(entity, typeof(CopyTransformToGameObject));
    107.              skinsPool.RecycleSkin(playerSkinId.value, playerPrefabIndex.value);
    108.              EntityManager.RemoveComponent(entity, typeof(PlayerPrefabIndex));*/
    109.             //skinsPool.RecycleSkin(playerSkinId.value, playerPrefabIndex.value);
    110.             // EntityManager.RemoveComponent(entity, typeof(PlayerPrefabIndex));
    111.  
    112.  
    113.             skinsPool.MoveObject(playerPrefabIndex.value, ref position.Value, ref rotation.Value);
    114.         }
    115.         else
    116.         {
    117.             EntityManager.AddComponentData(entity, new PlayerSkinRecycleTag{});
    118.         }
    119.     }
    120.  
    121.  
    122.     private void RecycleSkins(Entity entity, ref PlayerSkinId playerSkinId, ref PlayerSkinPrefabIndex playerPrefabIndex  )
    123.     {
    124.         skinsPool.RecycleSkin(playerSkinId.value, playerPrefabIndex.value);
    125.         EntityManager.RemoveComponent(entity, typeof(PlayerSkinPrefabIndex));
    126.         EntityManager.RemoveComponent(entity, typeof(PlayerSkinRecycleTag));
    127.     }
    128.  
    129.     protected override void OnUpdate()
    130.     {
    131.         // TODO: Emplement this verification in a more elegant way
    132.         if (ClientGameManager.LocalPlayerEntity == Entity.Null)
    133.             return;
    134.  
    135.  
    136.         // Players Entities To Move their Skins GOs
    137.       //  Entities.With(m_PlayersWithSkinsToMoveQuery).ForEach(SkinsToMoveDelegate);
    138.  
    139.  
    140.  
    141.         timePassedSinceLastCheck += Time.deltaTime;
    142.  
    143.         // check if 1/2 seconde has passed since the last check
    144.         if (timePassedSinceLastCheck < timebetweenChecks)
    145.             return;
    146.         else
    147.             timePassedSinceLastCheck = 0;
    148.  
    149.         // get Local Player Positon
    150.         localPlayerPosition = EntityManager.GetComponentData<Translation>(ClientGameManager.LocalPlayerEntity).Value;
    151.  
    152.         // Link Players Entities to Skins GOs
    153.         Entities.With(m_PlayersRequireSkinsQuery).ForEach(linkPlayersSkinsDelegate);
    154.  
    155.         // Players Entities Require Skins GOs Recycle
    156.        // Entities.With(m_PlayersRequireSkinRecycleQuery).ForEach(RecyclePlayersSkinsDelegate);
    157.        
    158.     }
    159.  
    160.  
    161.  
    162.  
    163.     protected override void OnDestroy()
    164.     {
    165.         skinsPool.Dispose();
    166.     }
    167.  
    168. }
    169. #endif



    ERROR:
    IndexOutOfRangeException: Index 1 is out of range of '1' Length.
    Unity.Collections.NativeArray`1[T].FailOutOfRangeError (System.Int32 index) (at <5e35e4589c1948aa8af5b8e64eea8798>:0)
    Unity.Collections.NativeArray`1[T].CheckElementReadAccess (System.Int32 index) (at <5e35e4589c1948aa8af5b8e64eea8798>:0)
    Unity.Collections.NativeArray`1[T].get_Item (System.Int32 index) (at <5e35e4589c1948aa8af5b8e64eea8798>:0)
    CWBR.ClientAndServer.Systems.PlayersMovementSystem+MouvePlayersJob.Execute (Unity.Entities.ArchetypeChunk chunk, System.Int32 chunkIndex, System.Int32 firstEntityIndex) (at Assets/Scripts/ECS/Systems/Client&Server/PlayersMouvementSystem.cs:73)
    Unity.Entities.JobChunkExtensions+JobChunk_Process`1[T].ExecuteInternal (Unity.Entities.JobChunkExtensions+JobChunkData`1[T]& jobData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/IJobChunk.cs:183)
    Unity.Entities.JobChunkExtensions+JobChunk_Process`1[T].Execute (Unity.Entities.JobChunkExtensions+JobChunkData`1[T]& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/IJobChunk.cs:170)
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    If you using AddComponent(Entity e, ComponentType type) you should provide ComponentType. If you want to add component type and set it value you should use AddComponent<T>(Entity e, T component). It's diferent things.
     
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    by simply providing the value to AddComponent it will predict the T type.

    by writing
    Code (CSharp):
    1.  PostUpdateCommands.AddComponent<PlayerSkinPrefabIndex>(entity, new PlayerSkinPrefabIndex { value = indexRef});  
    as you suggested the VS provide a quick simplification to the
    Code (CSharp):
    1. PostUpdateCommands.AddComponent(entity, new PlayerSkinPrefabIndex { value = indexRef});
     
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    Yep generic prediction, forgot about that. Yeah in this case it'll be correct overload.
     
  5. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    The Error is weird cause it's being thrown from ECS boilerplate Code. it's pratically when i get the ArchetypeChunkComponentType Array from the Chunk and try to access it by the chunkIndex.

    Code (CSharp):
    1. [BurstCompile]
    2.         struct MouvePlayersJob : IJobChunk
    3.         {
    4.             public ArchetypeChunkComponentType<PhysicsVelocity> PhysicsVelocityType;
    5.  
    6.  
    7.             // One Thread by Chunck
    8.             public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    9.             {
    10.                 var chunkPhysicsVelocities = chunk.GetNativeArray(PhysicsVelocityType);
    11.  
    12.                 for (int i = 0; i < chunk.Count; i++)
    13.                 {
    14.                     var physicsVelocity = chunkPhysicsVelocities[chunkIndex];  // Error here
    15.                  }
    16.  
    Error:
    ERROR:
    IndexOutOfRangeException: Index 1 is out of range of '1' Length.


    the only reason that seems logic to me in this case is a structural change caused by the PostUpdateCommands.AddComponent .
     
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    I looked to your error closely and now all obvious. Your problem not relates to PostUpdateCommands.AddComponent(entity, new PlayerSkinPrefabIndex { value = indexRef}); your problem is you trying to get element outside of array bounds. In your 73 line
    var physicsVelocity = chunkPhysicsVelocities[chunkIndex]
    , it should be "i" instead of chunkIndex, and in all next places inside loop. When you get array from chunk you get it in 0-chunk.Count range, which not related to chunkIndex at all. ChunkIndex is for calculating chunk data offset in some global range (for example in array of Transforms for all archetype), arrays itself at 0 to chunk.Count. Thus you of course get out of range exception, cause your array is 1 item with index 0 and you try to access it by index 1.

    It doesn't doing any structural changes itself. All structural changes will be later at buffer playback time in barrier system.
     
    Last edited: Oct 9, 2019
    Opeth001 likes this.
  7. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,117
    XD OMG for an unkown reason i was using the chunkIndex instead of the "i" and it was working cause all of them are being part of the same Chunk until i use the PostUpdateCommands.AddComponent and add a componentData to one of this chunk Entities. which will create a second chunk with a different index.

    XD thank you it salved the problem