Skip to content

Instantly share code, notes, and snippets.

@Syjgin
Last active January 20, 2022 06:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Syjgin/c686d1e4261f4bb725c530c8a523946e to your computer and use it in GitHub Desktop.
Save Syjgin/c686d1e4261f4bb725c530c8a523946e to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using Components;
using PlatformMode;
namespace Dialogues.PopupQueue
{
public class PopupQueue
{
private readonly Stack<IPopupQueueElement> _visibleElements = new();
private readonly Queue<IPopupQueueElement> _elementsToDisplay = new();
private GameScene _currentMode;
private PopupQueueOperation _lastOperation;
private readonly Dictionary<PopupQueueElementType, bool> _elementExists = new();
public PopupQueueElementType Init(GameScene scene) //необязательно, просто в нашем случае окна ведут себя по-разному в зависимости от текущей сцены
{
_visibleElements.Clear();
_elementsToDisplay.Clear();
_elementExists.Clear();
foreach (var popupType in (PopupQueueElementType[]) Enum.GetValues(typeof(PopupQueueElementType)))
{
_elementExists[popupType] = false;
}
_currentMode = scene;
switch (_currentMode)
{
case GameScene.Menu:
ShowMainMenu();
return PopupQueueElementType.MainMenuPopup;
case GameScene.Flying:
return PopupQueueElementType.NoPopup;
case GameScene.Platform:
return PopupQueueElementType.Platform;
default:
return PopupQueueElementType.NoPopup;
}
}
public bool TryCloseCurrentElement(bool force = false)
{
return TryEnqueueElement(new NoPopupQueueElement(force));
}
public bool TryEnqueueElement(IPopupQueueElement element)
{
if (!IsElementAllowedHere(element.ElementType)) //опять же, способ добавить специфичную для сцены логику, но не обязательно
return false;
var isElementDenied = GetCurrentElement().DenyNextElementTypes.Contains(element.ElementType) && !element.IsIgnoreDenyElements;
switch (element.OpenOperation)
{
case PopupQueueOperation.OverlapPrevious:
if (_elementExists[element.ElementType])
return false;
if (isElementDenied)
{
_elementsToDisplay.Enqueue(element);
return false;
}
Enqueue(element.OpenOperation, element);
return true;
case PopupQueueOperation.HidePrevious:
if (_elementExists[element.ElementType])
return false;
if (isElementDenied)
{
return false;
}
Enqueue(element.OpenOperation, element);
return true;
case PopupQueueOperation.MergePrevious:
if (isElementDenied)
{
_elementsToDisplay.Enqueue(element);
return false;
}
if (GetCurrentElement().ElementType == element.ElementType)
{
_visibleElements.Pop();
}
Enqueue(element.OpenOperation, element);
return true;
case PopupQueueOperation.BringFromForeground:
if (isElementDenied)
return false;
switch (_currentMode)
{
case GameScene.Menu:
if (_visibleElements.Peek().ElementType == PopupQueueElementType.MainMenuPopup)
{
return false;
}
break;
case GameScene.Flying:
if (_visibleElements.Count == 0)
{
ShowMainMenu();
return true;
}
break;
case GameScene.Platform:
if (_visibleElements.Count > 0)
{
var topElement = _visibleElements.Peek();
if (topElement.ElementType == PopupQueueElementType.Platform)
{
ShowMainMenu();
return true;
}
}
break;
default:
break;
}
if (_visibleElements.Count > 0)
{
var removedElement = _visibleElements.Pop();
_elementExists[removedElement.ElementType] = false;
}
_lastOperation = PopupQueueOperation.BringFromForeground;
return true;
default:
return false;
}
}
public bool TryEnqueuePreviousElement()
{
if (_elementsToDisplay.Count == 0) return false;
var newDisplayedElement = _elementsToDisplay.Peek();
var result = TryEnqueueElement(newDisplayedElement);
if(result)
_elementsToDisplay.Dequeue();
return result;
}
public PopupQueueOperation GetLastOperation()
{
return _lastOperation;
}
public IPopupQueueElement GetCurrentElement()
{
return _visibleElements.Count > 0 ? _visibleElements.Peek() : new NoPopupQueueElement();
}
private bool IsElementAllowedHere(PopupQueueElementType elementType)
{
if (elementType == PopupQueueElementType.NoPopup)
return true;
switch (_currentMode)
{
case GameScene.Menu:
return elementType is PopupQueueElementType.ConfirmPopup
or PopupQueueElementType.MainMenuPopup or PopupQueueElementType.SavesPopup
or PopupQueueElementType.SettingsPopup or PopupQueueElementType.AboutPopup;
case GameScene.Flying:
return elementType != PopupQueueElementType.Platform &&
elementType != PopupQueueElementType.Building &&
elementType != PopupQueueElementType.AboutPopup;
case GameScene.Platform:
{
var current = GetCurrentElement();
switch (current)
{
case BuildingDialogueDefinition buildingDialogueDefinition when buildingDialogueDefinition.Building.Building.BuildingType == BuildingType.Airship && elementType == PopupQueueElementType.AirshipPopup:
case PlatformDialogueDefinition platformDialogueDefinition when platformDialogueDefinition.Platform.CurrentBuildingId == StaticPlatform.CrewNacelle:
return true;
default:
return elementType != PopupQueueElementType.AboutPopup && elementType != PopupQueueElementType.AirshipPopup;
}
}
default:
throw new ArgumentOutOfRangeException();
}
}
private void Enqueue(PopupQueueOperation operation, IPopupQueueElement element)
{
var previous = GetCurrentElement();
_visibleElements.Push(element);
_elementExists[element.ElementType] = true;
if (operation == PopupQueueOperation.HidePrevious && !previous.CanBeHidden)
{
_lastOperation = PopupQueueOperation.OverlapPrevious;
return;
}
_lastOperation = operation;
}
private void ShowMainMenu()
{
Enqueue(PopupQueueOperation.OverlapPrevious,new MainMenuPopupDefinition());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment