Aetheria/Assets/Scripts/Gameplay/ActionGameManager.cs
2026-07-05 21:29:34 +01:00

430 lines
17 KiB
C#

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using Cinemachine;
using GameCult.Aetheria.State.Verse;
using GameCult.Mesh;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.UI;
using float2 = Unity.Mathematics.float2;
using float3 = Unity.Mathematics.float3;
public class ActionGameManager : MonoBehaviour
{
private AetheriaDaemonObserver _daemonObserver;
private AetheriaUnityPilotCommandSender _pilotCommands;
private AetheriaUnityObservedEntityRestorer _observedEntityRestorer;
private AetheriaUnityCurrentEntityBinder _currentEntityBinder;
private AetheriaUnityObservedZoneContextFactory _observedZoneContextFactory;
private AetheriaUnityPilotFrameController _pilotFrameController;
private AetheriaUnityPilotOperationController _pilotOperationController;
private AetheriaUnityObservedFrameApplier _observedFrameApplier;
private AetheriaUnityEntityBlueprintMaterializer _entityBlueprintMaterializer;
private AetheriaUnityMenuShell _menuShell;
private AetheriaUnityGameplayInputShell _gameplayInputShell;
private AetheriaUnityCockpitHudShell _cockpitHudShell;
private AetheriaUnityGameplayLoopShell _gameplayLoopShell;
private AetheriaUnityGameplayBootShell _gameplayBootShell;
private AetheriaUnityGameplaySceneWiring _sceneWiring;
private AetheriaClientState _gameplayState;
private AetheriaClientState GameplayState =>
_gameplayState ??= AetheriaUnityRuntimeClientProvider.RuntimeState("unity-action-game-manager");
private AetheriaUnityPilotCommandSender PilotCommands =>
_pilotCommands ??= new AetheriaUnityPilotCommandSender(
() => AetheriaUnityRuntimeClientProvider.Control("unity-pilot-commands"),
() => Time.unscaledTime);
private AetheriaUnityObservedEntityRestorer ObservedEntityRestorer =>
_observedEntityRestorer ??= new AetheriaUnityObservedEntityRestorer(
_presentationEntityIndex,
ItemManager,
EntityBlueprintMaterializer.MaterializeObservedEntity,
_loadoutItemFactory.CreateLoadoutItem,
Debug.LogWarning);
private AetheriaUnityObservedZoneContextFactory ObservedZoneContextFactory =>
_observedZoneContextFactory ??= new AetheriaUnityObservedZoneContextFactory(
ItemManager,
Settings.PlanetSettings,
() => ObservedGalaxy,
Debug.LogWarning,
PlayMusic);
private AetheriaUnityCurrentEntityBinder CurrentEntityBinder =>
_currentEntityBinder ??= new AetheriaUnityCurrentEntityBinder
{
ZoneRenderer = ZoneRenderer,
DeathPost = DeathPost,
GameplayUI = GameplayUI,
CurrentEntityPresentation = _currentEntityPresentation,
TargetPresentation = _targetPresentation,
GetCurrentEntity = () => CurrentEntity,
ResolveDockParent = ResolveDockParentFromCurrentDocking,
SetCurrentEntity = entity => CurrentEntity = entity,
GetViewDirection = () => _viewDirection,
SetViewDirection = direction => _viewDirection = direction,
ResolveZoneRender = () => ResolveDaemonObserver()?.LastRenderView?.ZoneRender,
ApplyActionBarBindings = _ => _actionBarPresentation?.ApplyLocalBindings(),
EnablePlayerInput = EnablePlayerInput,
DisablePlayerInput = DisablePlayerInput,
PlayMusic = PlayMusic,
UpdateTargetPanel = target => CockpitHudShell.UpdateTarget(target, CurrentEntity)
};
private AetheriaUnityPilotFrameController PilotFrameController =>
_pilotFrameController ??= new AetheriaUnityPilotFrameController(direction => _viewDirection = direction)
{
ZoneRenderer = ZoneRenderer,
Input = Input,
TargetPresentation = _targetPresentation,
PilotCommands = PilotCommands,
HeatstrokePost = HeatstrokePost,
SevereHeatstrokePost = SevereHeatstrokePost,
Sensitivity = Sensitivity
};
private AetheriaUnityPilotOperationController PilotOperationController =>
_pilotOperationController ??= new AetheriaUnityPilotOperationController(
() => PilotCommands,
_presentationEntityIndex,
() => _viewDirection,
() => CurrentEntity);
private AetheriaUnityObservedFrameApplier ObservedFrameApplier =>
_observedFrameApplier ??= new AetheriaUnityObservedFrameApplier(
ResolveDaemonObserver,
ObservedZoneContextFactory.ResolveGalaxyZone,
() => Zone,
zone => Zone = zone,
_presentationEntityIndex,
ObservedEntityRestorer,
ObservedZoneContextFactory,
() => ZoneRenderer,
() => CurrentEntity,
entity => CurrentEntityBinder.RestoreBinding(entity),
Debug.LogWarning);
private AetheriaUnityEntityBlueprintMaterializer EntityBlueprintMaterializer =>
_entityBlueprintMaterializer ??= new AetheriaUnityEntityBlueprintMaterializer(_loadoutItemFactory);
private AetheriaUnityMenuShell MenuShell =>
_menuShell ??= new AetheriaUnityMenuShell
{
MainMenu = MainMenu,
HelpScreen = HelpScreen,
InputDisplayLayout = InputDisplayLayout,
UiRoot = UiRoot,
Menu = Menu,
GameplayUI = GameplayUI,
ResolveCurrentEntity = () => CurrentEntity,
IsCurrentEntityUndocked = IsCurrentEntityObservedUndocked,
ResolveObservedTarget = entity => _targetPresentation.GetObservedTarget(entity),
SetPaused = paused => GameplayLoopShell.Paused = paused,
EnablePlayerInput = EnablePlayerInput,
DisablePlayerInput = DisablePlayerInput,
UpdatePlayerPanel = () => CockpitHudShell.UpdatePlayer(CurrentEntity),
UpdateTargetPanel = target => CockpitHudShell.UpdateTarget(target, CurrentEntity)
};
private AetheriaUnityGameplayInputShell GameplayInputShell =>
_gameplayInputShell ??= new AetheriaUnityGameplayInputShell
{
RuntimePlayerSettings = RuntimePlayerSettings,
InputDisplayLayout = InputDisplayLayout,
Dialog = Dialog,
MainMenu = MainMenu,
Menu = Menu,
MenuMap = MenuMap,
GameplayUI = GameplayUI,
ActionBar = ActionBar,
ActionBarSlot = ActionBarSlot,
ZoneRenderer = ZoneRenderer,
MenuShell = MenuShell,
DragSession = _dragSession,
ActionBarPresentation = _actionBarPresentation,
PilotOperationController = PilotOperationController,
ResolveCurrentEntity = () => CurrentEntity,
SetInput = input => Input = input
};
private AetheriaUnityCockpitHudShell CockpitHudShell =>
_cockpitHudShell ??= new AetheriaUnityCockpitHudShell
{
ShipPanel = ShipPanel,
TargetShipPanel = TargetShipPanel,
SchematicDisplay = SchematicDisplay,
TargetSchematicDisplay = TargetSchematicDisplay,
TargetIndicator = TargetIndicator
};
private AetheriaUnityGameplayLoopShell GameplayLoopShell =>
_gameplayLoopShell ??= new AetheriaUnityGameplayLoopShell
{
ResolveCurrentEntity = () => CurrentEntity,
IsCurrentEntityUndocked = IsCurrentEntityObservedUndocked,
ApplyLatestZoneRender = () => ObservedFrameApplier.ApplyLatestZoneRender(),
CurrentEntityPresentation = _currentEntityPresentation,
PilotFrameController = PilotFrameController,
TargetPresentation = _targetPresentation
};
private AetheriaUnityGameplayBootShell GameplayBootShell =>
_gameplayBootShell ??= new AetheriaUnityGameplayBootShell
{
Settings = Settings,
ZoneRenderer = ZoneRenderer,
CockpitHudShell = CockpitHudShell,
Log = Debug.Log
};
private AetheriaUnityGameplaySceneWiring SceneWiring =>
_sceneWiring ??= new AetheriaUnityGameplaySceneWiring
{
ZoneRenderer = ZoneRenderer,
DockCamera = DockCamera,
FollowCamera = FollowCamera,
Menu = Menu,
TradeMenu = TradeMenu,
GameplayUI = GameplayUI,
Inventory = Inventory,
ShipPanel = ShipPanel,
TargetShipPanel = TargetShipPanel,
SchematicDisplay = SchematicDisplay,
TargetSchematicDisplay = TargetSchematicDisplay,
Crosshairs = Crosshairs,
LockIndicator = LockIndicator,
HitMarker = HitMarker,
HitMarkerDuration = HitMarkerDuration,
TargetShieldsBackground = TargetShieldsBackground,
TargetShieldsIcon = TargetShieldsIcon,
ShieldColor = ShieldColor,
NoShieldColor = NoShieldColor,
ShieldIcon = ShieldIcon,
NoShieldIcon = NoShieldIcon,
HostileTargetIndicator = HostileTargetIndicator,
FriendlyTargetIndicator = FriendlyTargetIndicator,
ViewDot = ViewDot,
TargetIndicator = TargetIndicator,
TargetHitpointsFill = TargetHitpointsFill,
TargetVisibilityFill = TargetVisibilityFill,
VisibilityToTargetFill = VisibilityToTargetFill,
TargetShieldsFill = TargetShieldsFill,
MainMenu = MainMenu
};
private readonly AetheriaUnityPresentationEntityIndex _presentationEntityIndex = new AetheriaUnityPresentationEntityIndex();
private static RuntimePlayerSettings RuntimePlayerSettings
=> AetheriaUnityRuntimeClientProvider.PlayerSettings;
public GameSettings Settings;
//public string StarterShipTemplate = "Longinus";
public float2 Sensitivity;
[Header("Postprocessing")]
public Volume DeathPost;
public Volume HeatstrokePost;
public Volume SevereHeatstrokePost;
[Header("Scene Links")]
public GameObject UiRoot;
public GameObject HelpScreen;
public InputDisplayLayout InputDisplayLayout;
public Transform ActionBar;
public ActionBarSlot ActionBarSlot;
public ZoneRenderer ZoneRenderer;
public CinemachineVirtualCamera DockCamera;
public CinemachineVirtualCamera FollowCamera;
[Header("Menu UI")]
public MainMenu MainMenu;
public MenuPanel Menu;
public MapRenderer MenuMap;
public TradeMenu TradeMenu;
public InventoryMenu Inventory;
public InventoryPanel ShipPanel;
public InventoryPanel TargetShipPanel;
public ConfirmationDialog Dialog;
[Header("Gameplay UI")]
public CanvasGroup GameplayUI;
public Prototype HostileTargetIndicator;
public Prototype FriendlyTargetIndicator;
public PlaceUIElementWorldspace ViewDot;
public Prototype LockIndicator;
public PlaceUIElementWorldspace[] Crosshairs;
public GameObject HitMarker;
public float HitMarkerDuration;
public SchematicDisplay SchematicDisplay;
public SchematicDisplay TargetSchematicDisplay;
[Header("Target Indicator")]
public PlaceUIElementWorldspace TargetIndicator;
public Image TargetHitpointsFill;
public Image TargetVisibilityFill;
public Image VisibilityToTargetFill;
public Image TargetShieldsBackground;
public Image TargetShieldsFill;
public Image TargetShieldsIcon;
public Color ShieldColor;
public Color NoShieldColor;
public Sprite ShieldIcon;
public Sprite NoShieldIcon;
//public PlayerInput Input;
// private CinemachineFramingTransposer _transposer;
// private CinemachineComposer _composer;
private Entity _currentEntity;
// private ShipInput _shipInput;
private float3 _viewDirection;
private readonly AetheriaUnityCurrentEntityPresentation _currentEntityPresentation = new AetheriaUnityCurrentEntityPresentation();
private readonly AetheriaUnityTargetPresentation _targetPresentation = new AetheriaUnityTargetPresentation();
public AetheriaInput Input { get; private set; }
private Entity CurrentEntity
{
get => _currentEntity;
set => _currentEntity = value;
}
private ItemManager ItemManager { get; set; }
private AetheriaUnityLoadoutItemFactory _loadoutItemFactory;
private Galaxy ObservedGalaxy { get; set; }
private Zone Zone { get; set; }
private readonly AetheriaUnityDragSession _dragSession = new AetheriaUnityDragSession();
private readonly AetheriaUnityActionBarPresentation _actionBarPresentation = new AetheriaUnityActionBarPresentation();
private void OnDisable()
{
_gameplayInputShell?.Dispose();
AetheriaUnityRuntimeClientProvider.Dispose();
}
void Start()
{
var boot = GameplayBootShell.Boot();
ItemManager = boot.ItemManager;
_loadoutItemFactory = boot.LoadoutItemFactory;
ObservedGalaxy = boot.ObservedGalaxy;
SceneWiring.ConfigureCurrentEntityPresentation(_currentEntityPresentation, boot.RuntimeCatalog);
SceneWiring.ConfigureTargetPresentation(
_targetPresentation,
boot.RuntimeCatalog,
_presentationEntityIndex);
SceneWiring.ConfigureInventoryDragSession(_dragSession);
SceneWiring.ConfigureActionBarPresentation(
_actionBarPresentation,
GameplayInputShell,
boot.RuntimeCatalog,
Settings,
() => CurrentEntity,
() => AetheriaUnityRuntimeClientProvider.Control("unity-action-bar"));
SceneWiring.ConfigureRuntimeInputScreenShell(MenuShell);
SceneWiring.ConfigurePresentationEntityIndex(_presentationEntityIndex);
// TODO: Process Stories
GameplayInputShell.Bootstrap();
StartGame();
}
private void EnablePlayerInput()
{
GameplayInputShell.EnablePlayerInput();
}
private void DisablePlayerInput()
{
GameplayInputShell.DisablePlayerInput();
}
private void StartGame()
{
ObservedFrameApplier.ApplyLatestZoneRender();
}
private bool IsCurrentEntityObservedUndocked()
{
var docking = CurrentDockingSnapshot();
if (CurrentEntity == null ||
docking == null ||
docking.CurrentEntityIndex != CurrentEntity.DaemonEntityIndex)
{
return false;
}
if (_presentationEntityIndex.TryGetRecordKeyForPresentationEntity(CurrentEntity, out var currentEntityKey) &&
!string.IsNullOrWhiteSpace(docking.CurrentEntityKey) &&
!string.Equals(docking.CurrentEntityKey, currentEntityKey, StringComparison.Ordinal))
{
return false;
}
return !docking.IsDocked;
}
private Entity ResolveDockParentFromCurrentDocking(Entity currentEntity)
{
var docking = CurrentDockingSnapshot();
if (currentEntity == null ||
docking == null ||
!docking.IsDocked ||
docking.CurrentEntityIndex != currentEntity.DaemonEntityIndex ||
string.IsNullOrWhiteSpace(docking.DockParentEntityKey))
{
return null;
}
if (_presentationEntityIndex.TryGetRecordKeyForPresentationEntity(currentEntity, out var currentEntityKey) &&
!string.IsNullOrWhiteSpace(docking.CurrentEntityKey) &&
!string.Equals(docking.CurrentEntityKey, currentEntityKey, StringComparison.Ordinal))
{
return null;
}
return _presentationEntityIndex.TryGetPresentationEntityByRecordKey(docking.DockParentEntityKey, out var dockParent)
? dockParent
: null;
}
private AetheriaRuntimeCurrentDockingDocument CurrentDockingSnapshot()
{
try
{
return GameplayState.CurrentDocking.Latest();
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to read Aetheria current docking for gameplay manager: {ex.Message}");
return null;
}
}
// public void ToggleEditMode()
// {
// _editMode = !_editMode;
// FollowCamera.gameObject.SetActive(!_editMode);
// TopDownCamera.gameObject.SetActive(_editMode);
// }
public void PlayMusic(MusicType type)
{
// TODO: SFX: Music
}
void Update()
{
GameplayLoopShell.Tick(Time.deltaTime, Time.time);
}
private AetheriaDaemonObserver ResolveDaemonObserver()
{
if (_daemonObserver != null)
{
return _daemonObserver;
}
_daemonObserver = FindAnyObjectByType<AetheriaDaemonObserver>();
return _daemonObserver;
}
private void LateUpdate()
{
GameplayLoopShell.LateTick();
}
}