public void RemoveEntityClearsListAfterCommit()
        {
            var e = new RuntimeEntityService(Mock.Of <IEventDispatcher>(), Mock.Of <ILogger>());

            var entity = e.CreateEntity(new IComponent[0]);

            e.CommitAdded();
            e.RemoveEntity(entity);
            e.CommitRemoved();

            e.RemovedEntities.Should().BeEmpty();
        }
        public void RemoveEntityRemovesFromListAfterCommit()
        {
            var e = new RuntimeEntityService(Mock.Of <IEventDispatcher>(), Mock.Of <ILogger>());

            var entity = e.CreateEntity(new IComponent[0]);

            e.CommitAdded();
            e.RemoveEntity(entity);
            e.CommitRemoved();

            e.Entities.Should().NotContain(entity);
            e.GetEntity(entity.Id).Should().BeNull();
        }
Exemplo n.º 3
0
        public Task <EngineTickResult> Tick(EngineTickInput input)
        {
            if (_state != States.Idle)
            {
                throw new InvalidOperationException($"RuntimeEngine cannot Tick() while while in state `{_state}`");
            }

            _state = States.Updating;

            var tick = new Task <EngineTickResult>(() =>
            {
                // Clear the "RemovedEntities" list from last frame.
                EntityService.CommitRemoved();

                // TODO: This is probably not deterministic. Update order is not guaranteeed for multithreaded bursts
                // Also this many loops is nasty.
                foreach (var updateBurst in SystemUpdateScheduler.UpdateBursts)
                {
                    foreach (var sys in updateBurst.Systems)
                    {
                        foreach (var commandHandler in sys.CommandHandlers)
                        {
                            foreach (var command in input.Commands)
                            {
                                if (commandHandler.CanHandle(command))
                                {
                                    commandHandler.OnCommand(command);
                                }
                            }
                        }
                    }
                }

                // Update all systems
                foreach (var updateBurst in SystemUpdateScheduler.UpdateBursts)
                {
                    // Lock the entity access gate if this is a multi-threaded burst.
                    AddEntityAccessGate.IsLocked = updateBurst.Systems.Count > 1;
                    // TODO: This still won't be enough to guarantee entity ID consistency.
                    // across different machines, since entity tick is also multithreaded.

                    Parallel.ForEach(updateBurst.Systems, system =>
                    {
                        if (system.HasTick)
                        {
                            ((Triggers.IOnTick)system.System).OnTick();
                        }

                        if (system.HasEntityTick)
                        {
                            Parallel.ForEach(system.Entities,
                                             entity => { ((Triggers.IOnEntityTick)system.System).OnTick(entity); });
                        }
                    });
                }

                // Add any entities from this frame to the system manager
                if (EntityService.AddedEntities.Count > 0)
                {
                    SystemManager.AddEntities(EntityService.AddedEntities);
                }

                // Process the removal from systems of any entities that were removed in this frame.
                if (EntityService.RemovedEntities.Count > 0)
                {
                    SystemManager.RemoveEntities(EntityService.RemovedEntities);
                }

                // Gather all the events that were added during this update step
                var events = EventQueue.DequeueAll();

                _state = States.AwaitingSync;
                return(new EngineTickResult(events));
            });

            return(tick);
        }