protected override void OnUpdate() { bool needPlayer = m_oldPlayerShipQuery.IsEmptyIgnoreFilter; SpawnQueues spawnQueues = default; if (sceneGlobalEntity.HasCollectionComponent <SpawnQueues>()) { spawnQueues = sceneGlobalEntity.GetCollectionComponent <SpawnQueues>(); } else { spawnQueues.playerQueue = new NativeQueue <Entity>(Allocator.Persistent); spawnQueues.aiQueue = new NativeQueue <Entity>(Allocator.Persistent); spawnQueues.newAiEntitiesToPrioritize = new NativeList <Entity>(Allocator.Persistent); spawnQueues.factionRanges = new NativeList <SpawnQueues.FactionRanges>(Allocator.Persistent); sceneGlobalEntity.AddCollectionComponent(spawnQueues); } Entities.WithStructuralChanges().WithAll <FactionTag>().ForEach((Entity entity, ref Faction faction) => { var factionFilter = new FactionMember { factionEntity = entity }; m_oldShipQuery.SetSharedComponentFilter(factionFilter); int unitsToSpawn = faction.maxFieldUnits - m_oldShipQuery.CalculateEntityCount(); unitsToSpawn = math.min(unitsToSpawn, faction.remainingReinforcements); if (needPlayer && faction.playerPrefab != Entity.Null) { var newPlayerShip = EntityManager.Instantiate(faction.playerPrefab); EntityManager.AddComponent <NewShipTag>(newPlayerShip); AddSharedComponentDataToLinkedGroup(newPlayerShip, factionFilter); if (faction.remainingReinforcements <= 0) { m_playersWithoutReinforcements.Add(newPlayerShip); } else { EntityManager.SetEnabled(newPlayerShip, false); unitsToSpawn--; faction.remainingReinforcements--; spawnQueues.playerQueue.Enqueue(newPlayerShip); } } if (unitsToSpawn > 0) { var newShipPrefab = EntityManager.Instantiate(faction.aiPrefab); EntityManager.AddComponent <NewShipTag>(newShipPrefab); AddSharedComponentDataToLinkedGroup(newShipPrefab, factionFilter); EntityManager.SetEnabled(newShipPrefab, false); var newEntities = EntityManager.Instantiate(newShipPrefab, unitsToSpawn, Allocator.TempJob); int start = spawnQueues.newAiEntitiesToPrioritize.Length; spawnQueues.newAiEntitiesToPrioritize.AddRange(newEntities); spawnQueues.factionRanges.Add(new SpawnQueues.FactionRanges { start = start, count = newEntities.Length, weight = faction.spawnWeightInverse / newEntities.Length }); newEntities.Dispose(); EntityManager.DestroyEntity(newShipPrefab); faction.remainingReinforcements -= unitsToSpawn; } m_oldShipQuery.ResetFilter(); }).Run(); EntityManager.RemoveComponent <NewShipTag>(m_newAiShipQuery); EntityManager.RemoveComponent <NewShipTag>(m_newPlayerShipQuery); foreach (var player in m_playersWithoutReinforcements) { if (!FindAndStealAiShip(player, spawnQueues)) { EntityManager.DestroyEntity(player); } } m_playersWithoutReinforcements.Clear(); }
bool FindAndStealAiShip(Entity player, SpawnQueues spawnQueues) { var factionMember = EntityManager.GetSharedComponentData <FactionMember>(player); var disabledShipsHashSet = new NativeHashSet <Entity>(1024, Allocator.TempJob); Entities.WithAll <ShipTag, Disabled>().WithNone <PlayerTag>().WithSharedComponentFilter(factionMember).ForEach((Entity entity) => { disabledShipsHashSet.Add(entity); }).Run(); if (!disabledShipsHashSet.IsEmpty) { Entity foundShip = Entity.Null; Job.WithCode(() => { var queueArray = spawnQueues.aiQueue.ToArray(Allocator.Temp); for (int i = 0; i < queueArray.Length; i++) { if (disabledShipsHashSet.Contains(queueArray[i])) { foundShip = queueArray[i]; //Todo: Is there a cleaner way to remove a random element from the queue? spawnQueues.aiQueue.Clear(); for (int j = 0; j < queueArray.Length; j++) { if (j != i) { spawnQueues.aiQueue.Enqueue(queueArray[j]); } } spawnQueues.playerQueue.Enqueue(player); return; } } }).Run(); if (foundShip == Entity.Null) { //A spawner might have it. Entities.WithAll <SpawnPointTag>().ForEach((ref SpawnPayload payload) => { if (foundShip == Entity.Null && disabledShipsHashSet.Contains(payload.disabledShip)) { foundShip = payload.disabledShip; payload.disabledShip = player; } }).Run(); } if (foundShip != Entity.Null) { EntityManager.SetEnabled(player, false); EntityManager.DestroyEntity(foundShip); disabledShipsHashSet.Dispose(); return(true); } } disabledShipsHashSet.Dispose(); //Todo: Is there a more robust way to do this? float bestHealth = 0f; Entity bestEntity = Entity.Null; Entities.WithAll <ShipTag, AiTag>().WithSharedComponentFilter(factionMember).ForEach((Entity entity, in ShipHealth health) => { if (health.health > bestHealth) { bestHealth = health.health; bestEntity = entity; } }).Run(); if (bestEntity != Entity.Null) { EntityManager.RemoveComponent <AiTag>(bestEntity); EntityManager.AddComponent <PlayerTag>(bestEntity); return(false); } return(false); }