public Task InitActorTransitionAsync(IGlobe globe, ISector sector, IActor actor,
                                             SectorTransition transition)
        {
            if (globe is null)
            {
                throw new ArgumentNullException(nameof(globe));
            }

            if (sector is null)
            {
                throw new ArgumentNullException(nameof(sector));
            }

            if (actor is null)
            {
                throw new ArgumentNullException(nameof(actor));
            }

            if (transition is null)
            {
                throw new ArgumentNullException(nameof(transition));
            }

            return(ProcessInternalAsync(globe, sector, actor, transition));
        }
示例#2
0
        public void GenerateRoomsInGrid_Transitions()
        {
            // ARRANGE
            var sectorNodeMock       = new Mock <ISectorNode>();
            var sectorNode           = sectorNodeMock.Object;
            var transition           = new SectorTransition(sectorNode);
            var availableTransitions = new[] { transition };

            var randomMock = new Mock <IRoomGeneratorRandomSource>();

            randomMock.Setup(x => x.RollRoomMatrixPositions(It.IsAny <int>(), It.IsAny <int>()))
            .Returns(new[] { new OffsetCoords(0, 0) });
            randomMock.Setup(x => x.RollTransitions(It.IsAny <IEnumerable <SectorTransition> >()))
            .Returns(new[] { transition });
            randomMock.Setup(x => x.RollRoomSize(It.IsAny <int>(), It.IsAny <int>(), It.IsIn <int>(1)))
            .Returns <int, int, int>((min, max, count) => { return(new[] { new Size(0, 0) }); });
            var random = randomMock.Object;

            var generator = new RoomGenerator(random);

            var expectedTransitions = new[] { transition };

            // ACT
            var factRooms = generator.GenerateRoomsInGrid(1, 1, 1, availableTransitions);

            // ASSERT
            factRooms.ElementAt(0).Transitions.Should().BeEquivalentTo(expectedTransitions);
        }
示例#3
0
        public void DetectTest_OneInSingleTransition_ReturnsThisTransition()
        {
            // ARRANGE

            var actorNodeMock = new Mock <IGraphNode>();
            var actorNode     = actorNodeMock.Object;

            var sectorNodeMock = new Mock <ISectorNode>();
            var sectorNode     = sectorNodeMock.Object;

            var transition = new SectorTransition(sectorNode);

            var testedTrasitions = new Dictionary <IGraphNode, SectorTransition>
            {
                { actorNode, transition }
            };

            var testedNodes = new[] { actorNode };

            var expectedTransition = transition;

            // ACT
            var factTransition = TransitionDetection.Detect(testedTrasitions, testedNodes);

            // ASSERT
            factTransition.Should().Be(expectedTransition);
        }
示例#4
0
        /// <summary> Определяет, что все указанные узлы (в них обычно стоят актёры игрока) находятся в одном узле перехода. </summary>
        /// <param name="transitions"> Доступные переходы. </param>
        /// <param name="actorNodes"> Набор проверяемых узлов. Сюда передаются узлы актеров, которые пренадлежат игроку. </param>
        /// <returns> Возвращает отработавший переход. Иначе возаращает null. </returns>
        public static SectorTransition Detect(IDictionary <IGraphNode, SectorTransition> transitions,
                                              IEnumerable <IGraphNode> actorNodes)
        {
            // Из сектора нет прямого выхода.
            // Нужно для упрощения тестов сектора или карты.
            // Дальше будут специальные переходы. Например, в результате диалога.
            if (transitions == null)
            {
                return(null);
            }

            var allExit = true;

            //Проверяем, что есть хоть один персонаж игрока.
            // Потому что, умирая, персонажи удаляются из менеджера.
            // И проверка сообщает, что нет ниодного персонажа игрока вне узлов выхода.
            var atLeastOneHuman = false;

            SectorTransition expectedTransition = null;

            foreach (var actorNode in actorNodes)
            {
                atLeastOneHuman = true;

                if (!transitions.TryGetValue(actorNode, out var transition))
                {
                    continue;
                }

                if (expectedTransition == null)
                {
                    expectedTransition = transition;
                }
                else if (expectedTransition != transition)
                {
                    allExit = false;
                    break;
                }
            }

            if (atLeastOneHuman && allExit)
            {
                return(expectedTransition);
            }

            // означает, что переход не задействован
            return(null);
        }
        private async Task ProcessInternalAsync(IGlobe globe, ISector sourceSector, IActor actor,
                                                SectorTransition transition)
        {
            var sectorNode = transition.SectorNode;

            await _semaphoreSlim.WaitAsync().ConfigureAwait(false);

            try
            {
                if (sectorNode.State != SectorNodeState.SectorMaterialized)
                {
                    await _globeExpander.ExpandAsync(sectorNode).ConfigureAwait(false);

                    globe.AddSectorNode(sectorNode);
                }

                // It was used as fallback later.
                var oldActorNode = actor.Node;

                sourceSector.ActorManager.Remove(actor);

                var targetSector = sectorNode.Sector;

                if (targetSector is null)
                {
                    throw new InvalidOperationException();
                }

                var transitionItem = new TransitionPoolItem(
                    actor.Person,
                    actor.TaskSource,
                    targetSector,
                    sourceSector,
                    oldActorNode);
                _transitionPool.Push(transitionItem);
            }
            finally
            {
                //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked.
                //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution
                _semaphoreSlim.Release();
            }
        }
示例#6
0
        private async Task ProcessInnerAsync(IGlobe globe, ISector sector, IActor actor, SectorTransition transition)
        {
            var sectorNode = transition.SectorNode;

            //TODO Разобраться с этим кодом.
            // https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/
            //Asynchronously wait to enter the Semaphore. If no-one has been granted access to the Semaphore, code execution will proceed, otherwise this thread waits here until the semaphore is released
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
            await _semaphoreSlim.WaitAsync();

#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
            try
            {
                if (sectorNode.State != SectorNodeState.SectorMaterialized)
                {
                    await _globeExpander.ExpandAsync(sectorNode).ConfigureAwait(false);

                    globe.AddSectorNode(sectorNode);
                }

                // It was used as fallback later.
                var oldActorNode = actor.Node;

                try
                {
                    sector.ActorManager.Remove(actor);
                }
                catch (InvalidOperationException exception)
                {
                    // Пока ничего не делаем
                    Console.WriteLine(exception);
                    Console.WriteLine(sector.GetHashCode());
                    Console.WriteLine(actor);
                }

                var nextSector = sectorNode.Sector;

                var transitionItem =
                    new TransitionPoolItem(actor.Person, actor.TaskSource, nextSector, sector, oldActorNode);
                _transitionPool.Push(transitionItem);
            }
            finally
            {
                //When the task is ready, release the semaphore. It is vital to ALWAYS release the semaphore when we are ready, or else we will end up with a Semaphore that is forever locked.
                //This is why it is important to do the Release within a try...finally clause; program execution may crash or take a different path, this way you are guaranteed execution
                _semaphoreSlim.Release();
            }
        }
示例#7
0
 public void MoveToOtherSector(ISector sector, SectorTransition sectorTransition)
 {
     BeginTransitionToOtherSector?.Invoke(this, EventArgs.Empty);
     sector.UseTransition(this, sectorTransition);
 }
示例#8
0
 public void UseTransition(IActor actor, SectorTransition transition)
 {
     DoActorExit(actor, transition);
 }
示例#9
0
        private void DoActorExit([NotNull] IActor actor, [NotNull] SectorTransition roomTransition)
        {
            var e = new TransitionUsedEventArgs(actor, roomTransition);

            TrasitionUsed?.Invoke(this, e);
        }
 public TransitionUsedEventArgs(IActor actor, SectorTransition transition)
 {
     Actor      = actor ?? throw new ArgumentNullException(nameof(actor));
     Transition = transition ?? throw new ArgumentNullException(nameof(transition));
 }