/// <summary> /// Update the store with the recorded BlobAsset/UnityObject associations. /// </summary> /// <remarks> /// User don't have to call this method because <see cref="Dispose"/> will do it. /// This method can be called multiple times, on the first one will matter. /// </remarks> public void UpdateBlobStore() { var keys = m_BlobPerUnityObject.GetUniqueKeyArray(Allocator.Temp); using (keys.Item1) { for (var k = 0; k < keys.Item2; ++k) { var key = keys.Item1[k]; var valueCount = m_BlobPerUnityObject.CountValuesForKey(key); var valueArray = new NativeArray <Hash128>(valueCount, Allocator.Temp); var i = 0; if (m_BlobPerUnityObject.TryGetFirstValue(key, out var value, out var iterator)) { do { valueArray[i++] = value; }while (m_BlobPerUnityObject.TryGetNextValue(out value, ref iterator)); valueArray.Sort(); } m_BlobAssetStore.UpdateBlobAssetForUnityObject <TB>(key, valueArray); valueArray.Dispose(); } } m_BlobPerUnityObject.Clear(); }
public void NativeMultiHashMap_GetKeys() { var container = new NativeMultiHashMap <int, int>(1, Allocator.Temp); for (int i = 0; i < 30; ++i) { container.Add(i, 2 * i); container.Add(i, 3 * i); } var keys = container.GetKeyArray(Allocator.Temp); #if !NET_DOTS // Tuple is not supported by TinyBCL var(unique, uniqueLength) = container.GetUniqueKeyArray(Allocator.Temp); Assert.AreEqual(30, uniqueLength); #endif Assert.AreEqual(60, keys.Length); keys.Sort(); for (int i = 0; i < 30; ++i) { Assert.AreEqual(i, keys[i * 2 + 0]); Assert.AreEqual(i, keys[i * 2 + 1]); #if !NET_DOTS // Tuple is not supported by TinyBCL Assert.AreEqual(i, unique[i]); #endif } }
public void NativeMultiHashMap_GetUniqueKeysEmpty() { var hashMap = new NativeMultiHashMap <int, int> (1, Allocator.Temp); var keys = hashMap.GetUniqueKeyArray(Allocator.Temp); Assert.AreEqual(0, keys.Item1.Length); Assert.AreEqual(0, keys.Item2); }
protected override void OnUpdate() { // A map from entities to arrays of colliders that were not applied to the body during the first pass. m_ExtraColliders = new NativeMultiHashMap <ComparableEntity, LeafShapeData>(64, Allocator.Temp); // TODO - add custom data to Physics.Collider? // First pass. // Convert all editor shape components into colliders, and either apply them to their parent rigid body // or store them for building compound colliders in the second pass. Entities.ForEach <T>(ConvertShape); // Second pass. // Merge any leftover colliders into their parent rigid bodies, as compound colliders. if (m_ExtraColliders.Length > 0) { var keys = m_ExtraColliders.GetUniqueKeyArray(Allocator.Temp); using (keys.Item1) { for (var k = 0; k < keys.Item2; ++k) { ComparableEntity entity = keys.Item1[k]; var collider = DstEntityManager.GetComponentData <PhysicsCollider>(entity.Entity); var children = new NativeList <CompoundCollider.ColliderBlobInstance>(16, Allocator.Temp); if (collider.IsValid) { // Include the already assigned collider as a child children.Add(new CompoundCollider.ColliderBlobInstance { Collider = collider.Value, CompoundFromChild = RigidTransform.identity }); } byte customData = 0; if (m_ExtraColliders.TryGetFirstValue(entity, out var child, out var iterator)) { do { children.Add(child.ColliderBlobInstance); customData &= child.CustomFlags; // TODO: Should be |= ?? } while (m_ExtraColliders.TryGetNextValue(out child, ref iterator)); } collider.Value = CompoundCollider.Create(children); children.Dispose(); DstEntityManager.SetComponentData(entity.Entity, collider); if (customData != 0) { DstEntityManager.AddOrSetComponent(entity.Entity, new PhysicsCustomData { Value = customData }); } } } } m_ExtraColliders.Dispose(); }
public void NativeMultiHashMap_GetUniqueKeys() { var hashMap = new NativeMultiHashMap <int, int> (1, Allocator.Temp); for (int i = 0; i < 30; ++i) { hashMap.Add(i, 2 * i); hashMap.Add(i, 3 * i); } var keys = hashMap.GetUniqueKeyArray(Allocator.Temp); hashMap.Dispose(); Assert.AreEqual(30, keys.Item2); for (int i = 0; i < 30; ++i) { Assert.AreEqual(i, keys.Item1[i]); } keys.Item1.Dispose(); }
protected override void OnUpdate() { var shapeQuery = EntityManager.CreateEntityQuery(ComponentType.ReadOnly <T>()); var shapeCount = shapeQuery.CalculateEntityCount(); // A map from entities to arrays of colliders m_ExtraColliders = new NativeMultiHashMap <ComparableEntity, LeafShapeData>(shapeCount, Allocator.Temp); // Lists to store input data for deferred convex and mesh jobs const int defaultPointsPerShape = 1024; m_ConvexColliderJobs = new NativeList <ConvertConvexColliderInput>(shapeCount, Allocator.TempJob); m_ConvexColliderPoints = new NativeList <float3>(shapeCount * defaultPointsPerShape, Allocator.TempJob); m_MeshColliderJobs = new NativeList <ConvertMeshColliderInput>(shapeCount, Allocator.TempJob); m_MeshColliderVertices = new NativeList <float3>(shapeCount * defaultPointsPerShape, Allocator.TempJob); m_MeshColliderIndices = new NativeList <int>(shapeCount * defaultPointsPerShape / 2, Allocator.TempJob); // First pass. // Convert all shape authoring components into colliders, and collect them for each primary body Entities.ForEach <T>(ConvertShape); // Second pass. // Produce all convex and mesh collider blobs in parallel const int arrayLength = 5; var convexColliders = new NativeArray <KeyValuePair <Entity, LeafShapeData> >(m_ConvexColliderJobs.Length, Allocator.TempJob); var convexJob = new ProduceConvexCollidersJob { InputParameters = m_ConvexColliderJobs, AllPoints = m_ConvexColliderPoints, Output = convexColliders }.Schedule(m_ConvexColliderJobs.Length, arrayLength); var meshColliders = new NativeArray <KeyValuePair <Entity, LeafShapeData> >(m_MeshColliderJobs.Length, Allocator.TempJob); var meshJob = new ProduceMeshCollidersJob { InputParameters = m_MeshColliderJobs, AllVertices = m_MeshColliderVertices, AllIndices = m_MeshColliderIndices, Output = meshColliders }.Schedule(m_MeshColliderJobs.Length, arrayLength); JobHandle.CombineDependencies(convexJob, meshJob).Complete(); AppendLeafShapeDataToShapeMap(convexColliders, m_ExtraColliders, m_ConvexShapes); convexColliders.Dispose(); AppendLeafShapeDataToShapeMap(meshColliders, m_ExtraColliders, m_MeshShapes); meshColliders.Dispose(); // Final pass. // Assign PhysicsCollider components to rigid bodies, merging multiples into compounds as needed var keys = m_ExtraColliders.GetUniqueKeyArray(Allocator.Temp); using (keys.Item1) { for (var k = 0; k < keys.Item2; ++k) { ComparableEntity body = keys.Item1[k]; var collider = DstEntityManager.HasComponent <PhysicsCollider>(body.Entity) ? DstEntityManager.GetComponentData <PhysicsCollider>(body.Entity) : new PhysicsCollider(); var children = new NativeList <CompoundCollider.ColliderBlobInstance>(16, Allocator.Temp); // collect any existing valid shapes if (collider.IsValid) { ColliderType colliderType; unsafe { colliderType = collider.ColliderPtr->Type; } // if there is already a compound, add its leaves to the list of children if (colliderType == ColliderType.Compound) { unsafe { var existingChildren = ((CompoundCollider *)collider.ColliderPtr)->Children; for (int i = 0, count = existingChildren.Length; i < count; ++i) { children.Add(new CompoundCollider.ColliderBlobInstance { Collider = BlobAssetReference <Collider> .Create( existingChildren[i].Collider, existingChildren[i].Collider->MemorySize ), CompoundFromChild = existingChildren[i].CompoundFromChild }); } } } // otherwise add the single collider to the list of children else { children.Add( new CompoundCollider.ColliderBlobInstance { Collider = collider.Value, CompoundFromChild = RigidTransform.identity } ); } } // if collider is already valid, a shape already existed from another system var isSingleShapeOnPrimaryBody = !collider.IsValid; // collect all children found by this system if (m_ExtraColliders.TryGetFirstValue(body, out var child, out var iterator)) { do { children.Add(child.ColliderBlobInstance); isSingleShapeOnPrimaryBody &= child.LeafEntity.Equals(body.Entity); } while (m_ExtraColliders.TryGetNextValue(out child, ref iterator)); } // if there is a single shape on the primary body, use it as-is, otherwise create a compound // (assume a single leaf should still be a compound so that local offset values in authoring representation are retained) collider.Value = isSingleShapeOnPrimaryBody ? children[0].Collider : CompoundCollider.Create(children); children.Dispose(); DstEntityManager.AddOrSetComponent(body.Entity, collider); } } m_ConvexShapes.Clear(); m_ConvexColliderJobs.Dispose(); m_ConvexColliderPoints.Dispose(); m_MeshShapes.Clear(); m_MeshColliderJobs.Dispose(); m_MeshColliderVertices.Dispose(); m_MeshColliderIndices.Dispose(); }
protected override unsafe void OnUpdate() { var preSpawnsAlreadyProcessed = EntityManager.CreateEntityQuery(ComponentType.ReadOnly <PreSpawnsInitialized>()) .CalculateEntityCount(); if (preSpawnsAlreadyProcessed > 0) { // Check if an uninitialized scene has appeared with no ghosts present inside, then just mark it as initialized and continue var prespawns = m_Prespawns.ToEntityArray(Allocator.TempJob); var newScenes = m_UninitializedScenes.ToEntityArray(Allocator.TempJob); for (int j = 0; j < newScenes.Length; ++j) { for (int i = 0; i < prespawns.Length; ++i) { var scenes = EntityManager.GetSharedComponentData <SceneSection>(prespawns[i]); var sceneSystem = World.GetExistingSystem <SceneSystem>(); var sceneEntity = sceneSystem.GetSceneEntity(scenes.SceneGUID); if (sceneEntity == newScenes[j]) { UnityEngine.Debug.LogError("[" + World.Name + "] Prespawned ghosts have already been initialized, this needs to happen for all subscenes at the same time."); return; } } EntityManager.AddComponent <PreSpawnsInitialized>(newScenes[j]); } newScenes.Dispose(); prespawns.Dispose(); return; } // Handle the chunk for an entity type, then handle each entity in the chunk (prespawned entities) var prespawnChunk = m_Prespawns.CreateArchetypeChunkArray(Allocator.TempJob); var entityType = GetEntityTypeHandle(); var preSpawnedIds = GetComponentDataFromEntity <PreSpawnedGhostId>(); var subsceneMap = new NativeMultiHashMap <ulong, Entity>(32, Allocator.Temp); var subscenePadding = new NativeHashMap <ulong, int>(32, Allocator.Temp); var ghostComponents = GetComponentDataFromEntity <GhostComponent>(); // Put all known subscene hashes tracked by the prespawned ghosts into a map for sorting for (int i = 0; i < prespawnChunk.Length; ++i) { var chunk = prespawnChunk[i]; var entities = chunk.GetNativeArray(entityType); for (int j = 0; j < entities.Length; ++j) { var entity = entities[j]; var subsceneHash = EntityManager.GetSharedComponentData <SubSceneGhostComponentHash>(entity).Value; subsceneMap.Add(subsceneHash, entity); } } var subsceneArray = subsceneMap.GetUniqueKeyArray(Allocator.Temp); // Figure out scene id padding or how many IDs were used by the previous scenes in the sorted list, continue // where it left off so each ghost in a scene starts of at the ID+1 of last ghost in the previous scene var scenePadding = 0; for (int i = 0; i < subsceneArray.Item2; ++i) { subscenePadding.Add(subsceneArray.Item1[i], scenePadding); scenePadding += subsceneMap.CountValuesForKey(subsceneArray.Item1[i]); } var PostUpdateCommands = new EntityCommandBuffer(Allocator.Temp); var serverSystems = World.GetExistingSystem <ServerSimulationSystemGroup>(); var ghostTypes = GetComponentDataFromEntity <GhostTypeComponent>(); var ghostPrefabBufferFromEntity = GetBufferFromEntity <GhostPrefabBuffer>(true); var prefabEntity = GetSingletonEntity <GhostPrefabCollectionComponent>(); var ghostReceiveSystem = World.GetExistingSystem <GhostReceiveSystem>(); var ghostSendSystem = World.GetExistingSystem <GhostSendSystem>(); var ghostCollectionSystem = World.GetExistingSystem <GhostCollectionSystem>(); DynamicBuffer <GhostPrefabBuffer> prefabList = ghostPrefabBufferFromEntity[prefabEntity]; int highestPrespawnId = -1; var spawnedGhosts = new NativeList <SpawnedGhostMapping>(1024, Allocator.Temp); for (int i = 0; i < prespawnChunk.Length; ++i) { var chunk = prespawnChunk[i]; var entities = chunk.GetNativeArray(entityType); for (int j = 0; j < entities.Length; ++j) { var entity = entities[j]; var ghostTypeComponent = ghostTypes[entity]; int ghostType; for (ghostType = 0; ghostType < prefabList.Length; ++ghostType) { if (ghostTypes[prefabList[ghostType].Value] == ghostTypeComponent) { break; } } if (ghostType >= prefabList.Length) { UnityEngine.Debug.LogError("Failed to look up ghost type for entity"); return; } // Check if this entity has already been handled if (ghostComponents[entity].ghostId != 0) { UnityEngine.Debug.LogWarning(entity + " already has ghostId=" + ghostComponents[entity].ghostId + " prespawn=" + preSpawnedIds[entity].Value); continue; } // Modfy the entity to its proper version if (EntityManager.HasComponent <GhostPrefabMetaDataComponent>(prefabList[ghostType].Value)) { ref var ghostMetaData = ref EntityManager.GetComponentData <GhostPrefabMetaDataComponent>(prefabList[ghostType].Value).Value.Value; if (serverSystems != null) { for (int rm = 0; rm < ghostMetaData.RemoveOnServer.Length; ++rm) { var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(ghostMetaData.RemoveOnServer[rm])); PostUpdateCommands.RemoveComponent(entity, rmCompType); } } else { for (int rm = 0; rm < ghostMetaData.RemoveOnClient.Length; ++rm) { var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(ghostMetaData.RemoveOnClient[rm])); PostUpdateCommands.RemoveComponent(entity, rmCompType); } // FIXME: should disable instead of removing once we have a way of doing that without structural changes if (ghostMetaData.DefaultMode == GhostPrefabMetaData.GhostMode.Predicted) { for (int rm = 0; rm < ghostMetaData.DisableOnPredictedClient.Length; ++rm) { var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(ghostMetaData.DisableOnPredictedClient[rm])); PostUpdateCommands.RemoveComponent(entity, rmCompType); } } else if (ghostMetaData.DefaultMode == GhostPrefabMetaData.GhostMode.Interpolated) { for (int rm = 0; rm < ghostMetaData.DisableOnInterpolatedClient.Length; ++rm) { var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(ghostMetaData.DisableOnInterpolatedClient[rm])); PostUpdateCommands.RemoveComponent(entity, rmCompType); } } } } var subsceneHash = EntityManager.GetSharedComponentData <SubSceneGhostComponentHash>(entity).Value; var newId = preSpawnedIds[entity].Value + subscenePadding[subsceneHash]; if (newId > highestPrespawnId) { highestPrespawnId = newId; } // If on a server we need to allocate the ghost ID for the pre-spawned entity so runtime spawns // will happen from the right start index if (serverSystems != null) { spawnedGhosts.Add(new SpawnedGhostMapping { ghost = new SpawnedGhost { ghostId = newId, spawnTick = 0 }, entity = entity }); var ghostSystemStateComponent = new GhostSystemStateComponent { ghostId = newId, despawnTick = 0, spawnTick = 0 }; PostUpdateCommands.AddComponent(entity, ghostSystemStateComponent); } else if (ghostReceiveSystem != null) { var snapshotSize = ghostCollectionSystem.m_GhostTypeCollection[ghostType].SnapshotSize; spawnedGhosts.Add(new SpawnedGhostMapping { ghost = new SpawnedGhost { ghostId = newId, spawnTick = 0 }, entity = entity }); var newBuffer = PostUpdateCommands.SetBuffer <SnapshotDataBuffer>(entity); newBuffer.ResizeUninitialized(snapshotSize * GhostSystemConstants.SnapshotHistorySize); UnsafeUtility.MemClear(newBuffer.GetUnsafePtr(), snapshotSize * GhostSystemConstants.SnapshotHistorySize); PostUpdateCommands.SetComponent(entity, new SnapshotData { SnapshotSize = snapshotSize, LatestIndex = 0 }); } // Pre-spawned uses spawnTick = 0, if there is a reference to a ghost and it has spawnTick 0 the ref is always resolved // This works because there despawns are high priority and we never create pre-spawned ghosts after connection var ghostComponent = new GhostComponent { ghostId = newId, ghostType = ghostType, spawnTick = 0 }; PostUpdateCommands.SetComponent(entity, ghostComponent); // Mark scene as processed, as whole scene will have been loaded when this entity appeared var sceneSection = EntityManager.GetSharedComponentData <SceneSection>(entity); var sceneSystem = World.GetExistingSystem <SceneSystem>(); var sceneEntity = sceneSystem.GetSceneEntity(sceneSection.SceneGUID); PostUpdateCommands.AddComponent <PreSpawnsInitialized>(sceneEntity); } }
protected override unsafe void OnUpdate() { var preSpawnsAlreadyProcessed = EntityManager.CreateEntityQuery(ComponentType.ReadOnly <PreSpawnsInitialized>()) .CalculateEntityCount(); if (preSpawnsAlreadyProcessed > 0) { // Check if an uninitialized scene has appeared with no ghosts present inside, then just mark it as initialized and continue var prespawns = m_Prespawns.ToEntityArray(Allocator.TempJob); var newScenes = m_UninitializedScenes.ToEntityArray(Allocator.TempJob); for (int j = 0; j < newScenes.Length; ++j) { for (int i = 0; i < prespawns.Length; ++i) { var scenes = EntityManager.GetSharedComponentData <SceneSection>(prespawns[i]); var sceneSystem = World.GetExistingSystem <SceneSystem>(); var sceneEntity = sceneSystem.GetSceneEntity(scenes.SceneGUID); if (sceneEntity == newScenes[j]) { UnityEngine.Debug.LogError("[" + World.Name + "] Prespawned ghosts have already been initialized, this needs to happen for all subscenes at the same time."); return; } } EntityManager.AddComponent <PreSpawnsInitialized>(newScenes[j]); } newScenes.Dispose(); prespawns.Dispose(); return; } // Handle the chunk for an entity type, then handle each entity in the chunk (prespawned entities) var prespawnChunk = m_Prespawns.CreateArchetypeChunkArray(Allocator.TempJob); var entityType = GetEntityTypeHandle(); var preSpawnedIds = GetComponentDataFromEntity <PreSpawnedGhostId>(); var subsceneMap = new NativeMultiHashMap <ulong, Entity>(32, Allocator.Temp); var subscenePadding = new NativeHashMap <ulong, int>(32, Allocator.Temp); var ghostComponents = GetComponentDataFromEntity <GhostComponent>(); // Put all known subscene hashes tracked by the prespawned ghosts into a map for sorting for (int i = 0; i < prespawnChunk.Length; ++i) { var chunk = prespawnChunk[i]; var entities = chunk.GetNativeArray(entityType); for (int j = 0; j < entities.Length; ++j) { var entity = entities[j]; var subsceneHash = EntityManager.GetSharedComponentData <SubSceneGhostComponentHash>(entity).Value; subsceneMap.Add(subsceneHash, entity); } } var subsceneArray = subsceneMap.GetUniqueKeyArray(Allocator.Temp); // Figure out scene id padding or how many IDs were used by the previous scenes in the sorted list, continue // where it left off so each ghost in a scene starts of at the ID+1 of last ghost in the previous scene var scenePadding = 0; for (int i = 0; i < subsceneArray.Item2; ++i) { subscenePadding.Add(subsceneArray.Item1[i], scenePadding); scenePadding += subsceneMap.CountValuesForKey(subsceneArray.Item1[i]); } var PostUpdateCommands = new EntityCommandBuffer(Allocator.Temp); var serverSystems = World.GetExistingSystem <ServerSimulationSystemGroup>(); var ghostTypes = GetComponentDataFromEntity <GhostTypeComponent>(); var ghostReceiveSystem = World.GetExistingSystem <GhostReceiveSystem>(); var ghostSendSystem = World.GetExistingSystem <GhostSendSystem>(); var ghostTypeCollection = EntityManager.GetBuffer <GhostCollectionPrefabSerializer>(GetSingletonEntity <GhostCollection>()); int highestPrespawnId = -1; var spawnedGhosts = new NativeList <SpawnedGhostMapping>(1024, Allocator.Temp); // Create a lookup from ghost type component to prefab entity, used to figure out how to strip components on the client var prefabFromType = new NativeHashMap <GhostTypeComponent, Entity>(1024, Allocator.Temp); Entities.WithNone <GhostPrefabRuntimeStrip>().WithAll <Prefab>().ForEach((Entity ent, in GhostTypeComponent ghostType) => { prefabFromType.TryAdd(ghostType, ent); }).Run(); for (int i = 0; i < prespawnChunk.Length; ++i) { var chunk = prespawnChunk[i]; var entities = chunk.GetNativeArray(entityType); for (int j = 0; j < entities.Length; ++j) { var entity = entities[j]; var ghostTypeComponent = ghostTypes[entity]; if (!prefabFromType.TryGetValue(ghostTypeComponent, out var ghostPrefabEntity)) { UnityEngine.Debug.LogError("Failed to look up ghost type for entity"); return; } // Check if this entity has already been handled if (ghostComponents[entity].ghostId != 0) { UnityEngine.Debug.LogWarning(entity + " already has ghostId=" + ghostComponents[entity].ghostId + " prespawn=" + preSpawnedIds[entity].Value); continue; } // Modfy the entity to its proper version if (EntityManager.HasComponent <GhostPrefabMetaDataComponent>(ghostPrefabEntity)) { ref var ghostMetaData = ref EntityManager.GetComponentData <GhostPrefabMetaDataComponent>(ghostPrefabEntity).Value.Value; var linkedEntityGroup = EntityManager.GetBuffer <LinkedEntityGroup>(entity); if (serverSystems != null) { for (int rm = 0; rm < ghostMetaData.RemoveOnServer.Length; ++rm) { var childIndexCompHashPair = ghostMetaData.RemoveOnServer[rm]; var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(childIndexCompHashPair.StableHash)); PostUpdateCommands.RemoveComponent(linkedEntityGroup[childIndexCompHashPair.EntityIndex].Value, rmCompType); } } else { for (int rm = 0; rm < ghostMetaData.RemoveOnClient.Length; ++rm) { var childIndexCompHashPair = ghostMetaData.RemoveOnClient[rm]; var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(childIndexCompHashPair.StableHash)); PostUpdateCommands.RemoveComponent(linkedEntityGroup[childIndexCompHashPair.EntityIndex].Value, rmCompType); } // FIXME: should disable instead of removing once we have a way of doing that without structural changes if (ghostMetaData.DefaultMode == GhostPrefabMetaData.GhostMode.Predicted) { for (int rm = 0; rm < ghostMetaData.DisableOnPredictedClient.Length; ++rm) { var childIndexCompHashPair = ghostMetaData.DisableOnPredictedClient[rm]; var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(childIndexCompHashPair.StableHash)); PostUpdateCommands.RemoveComponent(linkedEntityGroup[childIndexCompHashPair.EntityIndex].Value, rmCompType); } } else if (ghostMetaData.DefaultMode == GhostPrefabMetaData.GhostMode.Interpolated) { for (int rm = 0; rm < ghostMetaData.DisableOnInterpolatedClient.Length; ++rm) { var childIndexCompHashPair = ghostMetaData.DisableOnInterpolatedClient[rm]; var rmCompType = ComponentType.ReadWrite(TypeManager.GetTypeIndexFromStableTypeHash(childIndexCompHashPair.StableHash)); PostUpdateCommands.RemoveComponent(linkedEntityGroup[childIndexCompHashPair.EntityIndex].Value, rmCompType); } } } }
protected virtual int SetUpInventoryItems(InventoryGroupWrapper inventoryGroup, int itemCount, Entity owner) { var foodList = new NativeList <ItemHashValue>(Allocator.Temp); var potionList = new NativeList <ItemHashValue>(Allocator.Temp); var treasureList = new NativeList <ItemHashValue>(Allocator.Temp); var weaponList = new NativeList <ItemHashValue>(Allocator.Temp); var magicWeaponList = new NativeList <ItemHashValue>(Allocator.Temp); var helmetList = new NativeList <ItemHashValue>(Allocator.Temp); var chestList = new NativeList <ItemHashValue>(Allocator.Temp); var bootsList = new NativeList <ItemHashValue>(Allocator.Temp); var itemCounter = 0; this.Entities.With(this._itemsGroup).ForEach((Entity itemEntity, ref ItemComponent itemComponent, ref PickedUpComponent pickedUpComponent) => { if (pickedUpComponent.Owner != owner) { return; } itemCounter++; var item = ItemsManagerComponent.Instance.ItemsStoreComponent.Items[itemComponent.StoreIndex]; switch (item.ItemType) { case ItemType.Food: foodList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case ItemType.Potion: potionList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case ItemType.Treasure: treasureList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case ItemType.Gear: switch (item.GearType) { case GearType.Helmet: helmetList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case GearType.Chest: chestList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case GearType.Weapon: weaponList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case GearType.Boots: bootsList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; case GearType.Magic: magicWeaponList.Add( new ItemHashValue { Entity = itemEntity, ItemComponent = itemComponent }); break; } break; } }); if (itemCounter != this.LastItemsCount || this.LastOwnerEntity != owner) { this.LastItemsCount = itemCounter; this.LastOwnerEntity = owner; for (var i = inventoryGroup.Grid.transform.childCount - 1; i >= 0; i--) { GameObject.Destroy(inventoryGroup.Grid.transform.GetChild(i).gameObject); } var itemsHashMap = new NativeMultiHashMap <int, ItemHashValue>(foodList.Length + potionList.Length + treasureList.Length, Allocator.Temp); for (var i = 0; i < foodList.Length; i++) { itemsHashMap.Add(this.GetItemHash(foodList[i]), foodList[i]); } for (var i = 0; i < potionList.Length; i++) { itemsHashMap.Add(this.GetItemHash(potionList[i]), potionList[i]); } for (var i = 0; i < treasureList.Length; i++) { itemsHashMap.Add(this.GetItemHash(treasureList[i]), treasureList[i]); } if (itemsHashMap.Length > 0) { var iterator = new NativeMultiHashMapIterator <int>(); var(keys, keysLength) = itemsHashMap.GetUniqueKeyArray(Allocator.Temp); for (var keyI = 0; keyI < keysLength; keyI++) { if (!itemsHashMap.TryGetFirstValue(keys[keyI], out var hashValue, out iterator)) { continue; } var button = this.AddInventoryButton(hashValue, inventoryGroup); var itemsCount = 1; while (itemsHashMap.TryGetNextValue(out hashValue, ref iterator)) { itemsCount++; } if (itemsCount > 1) { button.Amount.text = itemsCount.ToString(); } else { button.Amount.text = string.Empty; } } keys.Dispose(); } itemsHashMap.Dispose(); for (var i = 0; i < weaponList.Length; i++) { this.AddInventoryButton(weaponList[i], inventoryGroup); } for (var i = 0; i < magicWeaponList.Length; i++) { this.AddInventoryButton(magicWeaponList[i], inventoryGroup); } for (var i = 0; i < helmetList.Length; i++) { this.AddInventoryButton(helmetList[i], inventoryGroup); } for (var i = 0; i < chestList.Length; i++) { this.AddInventoryButton(chestList[i], inventoryGroup); } for (var i = 0; i < bootsList.Length; i++) { this.AddInventoryButton(bootsList[i], inventoryGroup); } } foodList.Dispose(); potionList.Dispose(); treasureList.Dispose(); weaponList.Dispose(); magicWeaponList.Dispose(); helmetList.Dispose(); chestList.Dispose(); bootsList.Dispose(); return(itemCounter); }