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)); }
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); }
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); }
/// <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(); } }
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(); } }
public void MoveToOtherSector(ISector sector, SectorTransition sectorTransition) { BeginTransitionToOtherSector?.Invoke(this, EventArgs.Empty); sector.UseTransition(this, sectorTransition); }
public void UseTransition(IActor actor, SectorTransition transition) { DoActorExit(actor, transition); }
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)); }