예제 #1
0
        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();
        }
예제 #2
0
        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);
        }