Sync daemon authority migration

This commit is contained in:
Meta Vens 2026-06-21 09:37:54 +01:00
commit 39a0dc8737
295 changed files with 25121 additions and 7360 deletions

View file

@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
@ -21,17 +20,20 @@ public class ClickRaycaster : MonoBehaviour
_clickCatcher = GetComponent<ClickCatcher>();
_clickCatcher.OnDown.Subscribe(pointer =>
{
RaycastHit hit;
var ray = RayCamera.ScreenPointToRay(pointer.position);
Physics.Raycast(ray, out hit, 1000, Layers.value);
if (hit.collider != null)
var clickables = new List<ClickableCollider>();
foreach (var clickable in ClickableCollider.Active)
{
//Debug.Log($"Clicked on gameobject {hit.collider.gameObject}");
var clickable = hit.collider.GetComponent<ClickableCollider>();
if (clickable != null)
clickable.Click(pointer, ray, hit);
if (clickable == null || ((1 << clickable.gameObject.layer) & Layers.value) == 0)
continue;
clickables.Add(clickable);
}
else OnClickMiss?.Invoke(pointer);
if (AetheriaYmirPhysicsBridge.Instance.TryCastClickables(clickables, ray, 1000, out var hit))
hit.Clickable.Click(pointer, ray, hit);
else
OnClickMiss?.Invoke(pointer);
});
}
}

View file

@ -3,26 +3,94 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickableCollider : MonoBehaviour
{
public event Action<ClickableCollider, PointerEventData, Ray, RaycastHit> OnClick;
private static readonly List<ClickableCollider> ActiveClickables = new List<ClickableCollider>();
public void Click(PointerEventData eventData, Ray ray, RaycastHit raycastHit) => OnClick?.Invoke(this, eventData, ray, raycastHit);
private Renderer[] _renderers;
public event Action<ClickableCollider, PointerEventData, Ray, AetheriaYmirClickableHit> OnClick;
public static IReadOnlyList<ClickableCollider> Active => ActiveClickables;
public Bounds ClickBounds
{
get
{
if (_renderers == null)
RefreshYmirBoundsSource();
if (_renderers == null || _renderers.Length == 0)
return new Bounds(transform.position, Vector3.one * 0.5f);
var firstRenderer = FirstLiveRenderer();
if (firstRenderer == null)
return new Bounds(transform.position, Vector3.one * 0.5f);
var bounds = firstRenderer.bounds;
for (var i = 0; i < _renderers.Length; i++)
{
var renderer = _renderers[i];
if (renderer == null || renderer == firstRenderer)
continue;
bounds.Encapsulate(renderer.bounds);
}
return bounds;
}
}
public void Click(PointerEventData eventData, Ray ray, AetheriaYmirClickableHit hit) => OnClick?.Invoke(this, eventData, ray, hit);
public void Clear()
{
OnClick = null;
}
public void RefreshYmirBoundsSource()
{
_renderers = GetComponentsInChildren<Renderer>();
}
private void Awake()
{
RefreshYmirBoundsSource();
}
private void OnEnable()
{
if (_renderers == null || _renderers.Length == 0)
RefreshYmirBoundsSource();
if (!ActiveClickables.Contains(this))
ActiveClickables.Add(this);
}
private void OnDisable()
{
ActiveClickables.Remove(this);
}
void Start()
{
var proto = GetComponent<Prototype>();
if(proto != null)
proto.OnReturnToPool += () => OnClick = null;
}
private Renderer FirstLiveRenderer()
{
for (var i = 0; i < _renderers.Length; i++)
{
if (_renderers[i] != null)
return _renderers[i];
}
return null;
}
}

View file

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GameCult.Aetheria.EveRuntime;
using GameCult.Aetheria.State.Unity;
using GameCult.Eve.Surface;
using GameCult.Eve.UnityUIToolkit;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
@ -34,6 +33,28 @@ public class InputDisplayLayout : MonoBehaviour
private string _captureActionName = "";
private int _captureBindingIndex = -1;
private string _captureBindingLabel = "";
private readonly AetheriaEveUnitySurfaceChrome _surfaceChrome = new AetheriaEveUnitySurfaceChrome
{
RootAlignItems = Align.Center,
RootJustifyContent = Justify.Center,
RootPaddingLeft = 24f,
RootPaddingRight = 24f,
RootPaddingTop = 24f,
RootPaddingBottom = 24f,
RootBackgroundColor = new Color(0f, 0f, 0f, 0.72f),
Width = 1080f,
MinWidth = 0f,
MaxWidth = 1080f,
MaxHeight = 900f,
FlexGrow = 1f,
PaddingLeft = 20f,
PaddingRight = 20f,
PaddingTop = 20f,
PaddingBottom = 20f,
BorderRadius = 0f,
BorderWidth = 0f,
BackgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.96f)
};
public InputActionAsset Input
{
@ -51,7 +72,6 @@ public class InputDisplayLayout : MonoBehaviour
private void Start()
{
EnsureInputAsset();
EnsureSurfaceDocument();
EnsureCaptureAction();
HideLegacyChildren();
RenderSurface();
@ -60,7 +80,6 @@ public class InputDisplayLayout : MonoBehaviour
private void OnEnable()
{
EnsureInputAsset();
EnsureSurfaceDocument();
EnsureCaptureAction();
HideLegacyChildren();
RenderSurface();
@ -76,7 +95,7 @@ public class InputDisplayLayout : MonoBehaviour
if (_surfaceDocument != null)
{
_surfaceDocument.rootVisualElement.Clear();
AetheriaEveUnitySurfaceHost.Hide(_surfaceDocument);
}
}
@ -90,7 +109,7 @@ public class InputDisplayLayout : MonoBehaviour
if (_surfaceDocument != null)
{
Destroy(_surfaceDocument.gameObject);
AetheriaEveUnitySurfaceHost.DestroyDocument(_surfaceDocument);
_surfaceDocument = null;
}
}
@ -106,20 +125,6 @@ public class InputDisplayLayout : MonoBehaviour
Input = _ownedInput.asset;
}
private void EnsureSurfaceDocument()
{
if (_surfaceDocument != null)
{
return;
}
var host = new GameObject("Aetheria Input Surface");
host.transform.SetParent(transform, false);
host.layer = gameObject.layer;
_surfaceDocument = host.AddComponent<UIDocument>();
_surfaceDocument.sortingOrder = 1000;
}
private void HideLegacyChildren()
{
for (var index = 0; index < transform.childCount; index++)
@ -159,38 +164,17 @@ public class InputDisplayLayout : MonoBehaviour
}
EnsureInputAsset();
EnsureSurfaceDocument();
EnsureCaptureAction();
var document = ToEveSurfaceDocument(
AetheriaRuntimeInputSettingsSurfaceBuilder.Build(ProjectSurfaceState()));
var document = AetheriaRuntimeInputSettingsSurfaceBuilder.Build(ProjectSurfaceState());
var root = _surfaceDocument.rootVisualElement;
root.Clear();
root.style.flexGrow = 1;
root.style.justifyContent = Justify.Center;
root.style.alignItems = Align.Center;
root.style.paddingLeft = 24;
root.style.paddingRight = 24;
root.style.paddingTop = 24;
root.style.paddingBottom = 24;
root.style.backgroundColor = new Color(0f, 0f, 0f, 0.72f);
var shell = new VisualElement();
shell.style.flexDirection = FlexDirection.Column;
shell.style.width = 1080;
shell.style.maxWidth = 1080;
shell.style.maxHeight = 900;
shell.style.flexGrow = 1;
shell.style.paddingLeft = 20;
shell.style.paddingRight = 20;
shell.style.paddingTop = 20;
shell.style.paddingBottom = 20;
shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.96f);
root.Add(shell);
var lowerer = new EveUiToolkitSurfaceLowerer();
shell.Add(lowerer.Lower(document, HandleSurfaceCommand));
_surfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
transform,
_surfaceDocument,
"Aetheria Input Surface",
document,
HandleSurfaceCommand,
_surfaceChrome);
}
private AetheriaRuntimeInputSettingsSurfaceState ProjectSurfaceState()
@ -312,59 +296,59 @@ public class InputDisplayLayout : MonoBehaviour
private void HandleSurfaceCommand(EveSurfaceCommandRequest request)
{
switch (request.Command)
if (!AetheriaRuntimeInputSettingsSurfaceCommands.TryRead(request, out var command))
{
case var command when string.Equals(command, AetheriaRuntimeInputSettingsCommands.Refresh, StringComparison.Ordinal):
Debug.LogWarning($"Unknown input-settings command: {request?.Command}");
return;
}
switch (command.Kind)
{
case AetheriaRuntimeInputSettingsCommandKind.Refresh:
RenderSurface();
return;
case var command when string.Equals(command, AetheriaRuntimeInputSettingsCommands.CancelCapture, StringComparison.Ordinal):
case AetheriaRuntimeInputSettingsCommandKind.CancelCapture:
ClearCapture();
RenderSurface();
return;
case var command when string.Equals(command, AetheriaRuntimeInputSettingsCommands.BeginCapture, StringComparison.Ordinal):
BeginCapture(request.Payload);
case AetheriaRuntimeInputSettingsCommandKind.BeginCapture:
BeginCapture(command);
return;
case var command when string.Equals(command, AetheriaRuntimeInputSettingsCommands.ToggleActionBar, StringComparison.Ordinal):
ToggleActionBarInput(request.Payload);
case AetheriaRuntimeInputSettingsCommandKind.ToggleActionBar:
ToggleActionBarInput(command);
return;
default:
Debug.LogWarning($"Unknown input-settings command: {request.Command}");
Debug.LogWarning($"Unknown input-settings command: {request?.Command}");
return;
}
}
private void BeginCapture(IReadOnlyDictionary<string, string> payload)
private void BeginCapture(AetheriaRuntimeInputSettingsSurfaceCommand command)
{
if (payload == null ||
!payload.TryGetValue("actionName", out var actionName) ||
!payload.TryGetValue("bindingIndex", out var bindingIndexText) ||
!int.TryParse(bindingIndexText, NumberStyles.Integer, CultureInfo.InvariantCulture, out var bindingIndex))
if (string.IsNullOrWhiteSpace(command.ActionName) || command.BindingIndex < 0)
{
Debug.LogWarning("Input capture requested without a valid action name and binding index.");
return;
}
_captureActionName = actionName;
_captureBindingIndex = bindingIndex;
_captureBindingLabel = payload.TryGetValue("bindingLabel", out var bindingLabel)
? bindingLabel ?? actionName
: actionName;
_captureActionName = command.ActionName;
_captureBindingIndex = command.BindingIndex;
_captureBindingLabel = string.IsNullOrWhiteSpace(command.BindingLabel)
? command.ActionName
: command.BindingLabel;
_captureAction?.Enable();
RenderSurface();
}
private void ToggleActionBarInput(IReadOnlyDictionary<string, string> payload)
private void ToggleActionBarInput(AetheriaRuntimeInputSettingsSurfaceCommand command)
{
if (payload == null ||
!payload.TryGetValue("inputPath", out var inputPath) ||
!payload.TryGetValue("enabled", out var enabledText) ||
!bool.TryParse(enabledText, out var enabled))
if (string.IsNullOrWhiteSpace(command.InputPath))
{
Debug.LogWarning("Action-bar toggle requested without a valid input path and enabled state.");
return;
}
ActionGameManager.CommitRuntimeActionBarInput(inputPath, enabled);
ActionGameManager.RequestRuntimeActionBarInput(command.InputPath, command.Enabled);
RenderSurface();
}
@ -394,7 +378,7 @@ public class InputDisplayLayout : MonoBehaviour
}
action.ApplyBindingOverride(_captureBindingIndex, inputPath);
ActionGameManager.CommitRuntimeInputBindingOverride(action.name, _captureBindingIndex, inputPath);
ActionGameManager.RequestRuntimeInputBindingOverride(action.name, _captureBindingIndex, inputPath);
ClearCapture();
RenderSurface();
}
@ -406,33 +390,4 @@ public class InputDisplayLayout : MonoBehaviour
_captureBindingLabel = "";
}
private static EveSurfaceDocument ToEveSurfaceDocument(AetheriaRuntimeSurfaceDocument document)
{
return new EveSurfaceDocument(
"surface-state",
"gamecult.eve.surface.v1",
document.ProviderId,
document.ProviderKind,
document.Title,
document.Version,
document.UpdatedAtUtc,
new EveSurfaceTree(
document.Surface.Id,
ToEveSurfaceComponent(document.Surface.Root),
document.Surface.Styles
.Select(style => new EveStyleToken(style.Name, style.Value))
.ToArray()),
document.Commands
.Select(command => new EveCommandTemplate(command.Command, command.Label, command.Transport))
.ToArray());
}
private static EveSurfaceComponent ToEveSurfaceComponent(AetheriaRuntimeSurfaceComponent component)
{
return new EveSurfaceComponent(
component.Id,
component.Kind,
new Dictionary<string, string>(component.Props, StringComparer.Ordinal),
component.Children.Select(ToEveSurfaceComponent).ToArray());
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -6,9 +6,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GameCult.Aetheria.EveRuntime;
using GameCult.Aetheria.State.Unity;
using GameCult.Eve.Surface;
using GameCult.Eve.UnityUIToolkit;
using TMPro;
using UniRx;
using UniRx.Triggers;
@ -24,14 +24,6 @@ using int2 = Unity.Mathematics.int2;
public class InventoryPanel : MonoBehaviour, IPointerClickHandler
{
private const string DropdownSurfaceType = "surface-state";
private const string DropdownSurfaceSchema = "gamecult.eve.surface.v1";
private const string DropdownSurfaceProviderId = "aetheria";
private const string DropdownSurfaceProviderKind = "inventory.panel";
private const string DropdownSurfaceId = "aetheria.inventory.panel.dropdown";
private const string CloseDropdownSurfaceCommand = "aetheria.inventory.panel.dropdown.close";
private const string SaveLoadoutCommand = "aetheria.inventory.panel.dropdown.save_loadout";
public ConfirmationDialog Dialog;
public RectTransform DragParent;
public bool Flip;
@ -92,6 +84,19 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
private InventoryCell _clickCell;
private float _clickTime;
private readonly Dictionary<string, Action> _dropdownCommands = new Dictionary<string, Action>(StringComparer.Ordinal);
private readonly AetheriaEveUnitySurfaceChrome _dropdownSurfaceChrome = new AetheriaEveUnitySurfaceChrome
{
RootAlignItems = UIE.Align.FlexStart,
RootJustifyContent = UIE.Justify.FlexStart,
RootPaddingTop = 0f,
Width = 420f,
MinWidth = 0f,
MaxWidth = 520f,
PaddingLeft = 18f,
PaddingRight = 18f,
PaddingTop = 18f,
PaddingBottom = 18f
};
private UIE.UIDocument _dropdownSurfaceDocument;
private bool _hud;
@ -133,7 +138,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
{
if(_displayedEntity is Ship ship)
{
if (GameManager.CommitDockedCurrentShip(ship))
if (GameManager.RequestDockedCurrentShip(ship))
Current.targetGraphic.color = ToggleEnabledColor;
}
else
@ -157,7 +162,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
Dialog.AddField("Name", () => entityName, s => entityName = s);
Dialog.Show(() =>
{
GameManager.CommitEntityName(_displayedEntity, entityName);
GameManager.RequestEntityName(_displayedEntity, entityName);
Title.text = _displayedEntity.Name;
});
Dialog.MoveToCursor();
@ -182,55 +187,22 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
var price = blueprint.Price(GameManager.ItemManager);
return ($"{template.Name} - {price:n0}", () =>
{
if (GameManager.CommitRuntimeLoadoutRestore(template, out var entity))
if (GameManager.RequestRuntimeLoadoutRestore(template, out var entity) && entity != null)
Display(entity);
}, price < GameManager.Credits);
}, true);
}
private void RenderDropdownSurface()
{
BuildDropdownCommands();
var document = ResolveDropdownSurfaceDocument();
document.gameObject.SetActive(true);
var root = document.rootVisualElement;
root.Clear();
root.style.flexGrow = 1;
root.style.position = UIE.Position.Absolute;
root.style.left = 0;
root.style.top = 0;
root.style.right = 0;
root.style.bottom = 0;
root.style.alignItems = UIE.Align.FlexStart;
root.style.justifyContent = UIE.Justify.FlexStart;
root.pickingMode = UIE.PickingMode.Ignore;
var shell = new UIE.VisualElement();
shell.style.width = 420;
shell.style.maxWidth = 520;
shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.94f);
shell.style.borderTopLeftRadius = 8;
shell.style.borderTopRightRadius = 8;
shell.style.borderBottomLeftRadius = 8;
shell.style.borderBottomRightRadius = 8;
shell.style.paddingLeft = 18;
shell.style.paddingRight = 18;
shell.style.paddingTop = 18;
shell.style.paddingBottom = 18;
shell.style.borderLeftWidth = 1;
shell.style.borderRightWidth = 1;
shell.style.borderTopWidth = 1;
shell.style.borderBottomWidth = 1;
shell.style.borderLeftColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderRightColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderTopColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderBottomColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.pickingMode = UIE.PickingMode.Position;
root.Add(shell);
var lowerer = new EveUiToolkitSurfaceLowerer();
shell.Add(lowerer.Lower(BuildDropdownSurfaceDefinition(), HandleDropdownSurfaceCommand));
_dropdownSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
transform,
_dropdownSurfaceDocument,
"Aetheria Inventory Dropdown Surface",
AetheriaRuntimeInventoryDropdownSurfaceBuilder.Build(ProjectDropdownSurfaceState()),
HandleDropdownSurfaceCommand,
_dropdownSurfaceChrome);
}
private void BuildDropdownCommands()
@ -243,7 +215,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
{
if (entityEntry.entity != _displayedEntity)
{
var equipmentCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}.equipment";
var equipmentCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityEquipmentCommand(entityEntry.entityIndex);
_dropdownCommands[equipmentCommand] = () => Display(entityEntry.entity);
}
@ -251,27 +223,29 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
.Where(bay => bay != _displayedCargo)
.Select((bay, bayIndex) => (bay, bayIndex)))
{
var bayCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}.bay_{bayEntry.bayIndex}";
var bayCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityBayCommand(
entityEntry.entityIndex,
bayEntry.bayIndex);
_dropdownCommands[bayCommand] = () => Display(bayEntry.bay);
}
}
else if (entityEntry.entity != _displayedEntity)
{
var entityCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}";
var entityCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityCommand(entityEntry.entityIndex);
_dropdownCommands[entityCommand] = () => Display(entityEntry.entity);
}
}
if (GameManager.DockingBay != null && _displayedCargo != GameManager.DockingBay)
{
_dropdownCommands["aetheria.inventory.panel.dropdown.docking_bay"] = () => Display(GameManager.DockingBay);
_dropdownCommands[AetheriaRuntimeInventoryDropdownSurfaceBuilder.DockingBay] = () => Display(GameManager.DockingBay);
}
if (_displayedEntity != null)
{
_dropdownCommands[SaveLoadoutCommand] = () =>
_dropdownCommands[AetheriaRuntimeInventoryDropdownSurfaceBuilder.SaveLoadout] = () =>
{
GameManager.QueueRuntimeLoadoutTemplateCommit(EntityConstructionBlueprintProjector.CaptureBlueprint(_displayedEntity));
GameManager.RequestLoadoutTemplateSave(EntityConstructionBlueprintProjector.CaptureBlueprint(_displayedEntity));
};
}
@ -281,14 +255,10 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
if (blueprint == null)
continue;
var price = blueprint.Price(GameManager.ItemManager);
if (price >= GameManager.Credits)
continue;
var restoreCommand = $"aetheria.inventory.panel.dropdown.loadout_{loadoutEntry.templateIndex}";
var restoreCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.LoadoutCommand(loadoutEntry.templateIndex);
_dropdownCommands[restoreCommand] = () =>
{
if (GameManager.CommitRuntimeLoadoutRestore(loadoutEntry.template, out var entity))
if (GameManager.RequestRuntimeLoadoutRestore(loadoutEntry.template, out var entity) && entity != null)
Display(entity);
};
}
@ -296,20 +266,27 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
private void HandleDropdownSurfaceCommand(EveSurfaceCommandRequest request)
{
if (string.Equals(request.Command, CloseDropdownSurfaceCommand, StringComparison.Ordinal))
if (!AetheriaRuntimeInventoryDropdownSurfaceCommands.TryRead(request, out var command))
{
Debug.LogWarning($"Unknown inventory dropdown command: {request?.Command}");
return;
}
if (command.Kind == AetheriaRuntimeInventoryDropdownCommandKind.Close)
{
HideDropdownSurface();
return;
}
if (_dropdownCommands.TryGetValue(request.Command, out var action))
if (command.Kind == AetheriaRuntimeInventoryDropdownCommandKind.Select &&
_dropdownCommands.TryGetValue(command.Command, out var action))
{
action();
HideDropdownSurface();
return;
}
Debug.LogWarning($"Unknown inventory dropdown command: {request.Command}");
Debug.LogWarning($"Unknown inventory dropdown command: {request?.Command}");
}
private void HideDropdownSurface()
@ -317,217 +294,125 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
if (_dropdownSurfaceDocument == null)
return;
_dropdownSurfaceDocument.rootVisualElement.Clear();
_dropdownSurfaceDocument.gameObject.SetActive(false);
AetheriaEveUnitySurfaceHost.Hide(_dropdownSurfaceDocument);
}
private UIE.UIDocument ResolveDropdownSurfaceDocument()
private AetheriaRuntimeInventoryDropdownSurfaceState ProjectDropdownSurfaceState()
{
if (_dropdownSurfaceDocument != null)
return _dropdownSurfaceDocument;
var host = new GameObject("Aetheria Inventory Dropdown Surface");
host.transform.SetParent(transform, false);
var document = host.AddComponent<UIE.UIDocument>();
document.sortingOrder = 1000;
host.SetActive(false);
_dropdownSurfaceDocument = document;
return document;
}
private EveSurfaceDocument BuildDropdownSurfaceDefinition()
{
var children = new List<EveSurfaceComponent>
{
Card(
$"{DropdownSurfaceId}.summary",
"Inventory Actions",
Metric(
$"{DropdownSurfaceId}.current",
"Current View",
Title?.text ?? "None"),
Text(
$"{DropdownSurfaceId}.note",
"Gameplay still owns entity and cargo selection plus loadout restore. This surface just kills the old context-menu shell."))
};
var groups = new List<AetheriaRuntimeInventoryDropdownGroup>();
foreach (var entityEntry in GameManager.AvailableEntities().Select((entity, entityIndex) => (entity, entityIndex)))
{
var buttons = new List<EveSurfaceComponent>();
var equipmentCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}.equipment";
var options = new List<AetheriaRuntimeInventoryDropdownOption>();
var equipmentCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityEquipmentCommand(entityEntry.entityIndex);
if (_dropdownCommands.ContainsKey(equipmentCommand))
{
buttons.Add(Button(
$"{DropdownSurfaceId}.entity_{entityEntry.entityIndex}.equipment",
options.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.entity_{entityEntry.entityIndex}.equipment",
"Equipment",
equipmentCommand));
}
foreach (var bayEntry in entityEntry.entity.CargoBays.Select((bay, bayIndex) => (bay, bayIndex)))
{
var bayCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}.bay_{bayEntry.bayIndex}";
var bayCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityBayCommand(
entityEntry.entityIndex,
bayEntry.bayIndex);
if (_dropdownCommands.ContainsKey(bayCommand))
{
buttons.Add(Button(
$"{DropdownSurfaceId}.entity_{entityEntry.entityIndex}.bay_{bayEntry.bayIndex}",
options.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.entity_{entityEntry.entityIndex}.bay_{bayEntry.bayIndex}",
$"Bay {bayEntry.bayIndex + 1}",
bayCommand));
}
}
var entityCommand = $"aetheria.inventory.panel.dropdown.entity_{entityEntry.entityIndex}";
var entityCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.EntityCommand(entityEntry.entityIndex);
if (_dropdownCommands.ContainsKey(entityCommand))
{
buttons.Add(Button(
$"{DropdownSurfaceId}.entity_{entityEntry.entityIndex}.select",
options.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.entity_{entityEntry.entityIndex}.select",
entityEntry.entity.Name,
entityCommand));
}
if (buttons.Count > 0)
if (options.Count > 0)
{
children.Add(Card(
$"{DropdownSurfaceId}.entity_{entityEntry.entityIndex}.card",
groups.Add(new AetheriaRuntimeInventoryDropdownGroup(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.entity_{entityEntry.entityIndex}.card",
entityEntry.entity.Name,
ButtonColumn($"{DropdownSurfaceId}.entity_{entityEntry.entityIndex}.options", buttons.ToArray())));
options));
}
}
if (_dropdownCommands.ContainsKey("aetheria.inventory.panel.dropdown.docking_bay"))
if (_dropdownCommands.ContainsKey(AetheriaRuntimeInventoryDropdownSurfaceBuilder.DockingBay))
{
children.Add(Card(
$"{DropdownSurfaceId}.dockingBay.card",
groups.Add(new AetheriaRuntimeInventoryDropdownGroup(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.dockingBay.card",
"Docking Bay",
ButtonColumn(
$"{DropdownSurfaceId}.dockingBay.options",
Button(
$"{DropdownSurfaceId}.dockingBay.select",
new[]
{
new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.dockingBay.select",
GameManager.DockingBay.Name,
"aetheria.inventory.panel.dropdown.docking_bay"))));
AetheriaRuntimeInventoryDropdownSurfaceBuilder.DockingBay)
}));
}
var loadoutChildren = new List<EveSurfaceComponent>();
if (_dropdownCommands.ContainsKey(SaveLoadoutCommand))
var loadoutOptions = new List<AetheriaRuntimeInventoryDropdownOption>();
if (_dropdownCommands.ContainsKey(AetheriaRuntimeInventoryDropdownSurfaceBuilder.SaveLoadout))
{
loadoutChildren.Add(Button(
$"{DropdownSurfaceId}.loadouts.save",
loadoutOptions.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.loadouts.save",
"Save Loadout",
SaveLoadoutCommand));
AetheriaRuntimeInventoryDropdownSurfaceBuilder.SaveLoadout));
}
foreach (var loadoutEntry in GameManager.LoadoutTemplates.Select((template, templateIndex) => (template, templateIndex)))
{
var restoreCommand = $"aetheria.inventory.panel.dropdown.loadout_{loadoutEntry.templateIndex}";
var restoreCommand = AetheriaRuntimeInventoryDropdownSurfaceBuilder.LoadoutCommand(loadoutEntry.templateIndex);
var blueprint = GameManager.CreateEntityConstructionBlueprint(loadoutEntry.template);
if (blueprint == null)
{
loadoutChildren.Add(Text(
$"{DropdownSurfaceId}.loadouts.unavailable_{loadoutEntry.templateIndex}",
$"{loadoutEntry.template.Name} - unavailable"));
loadoutOptions.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.loadouts.unavailable_{loadoutEntry.templateIndex}",
$"{loadoutEntry.template.Name} - unavailable",
""));
continue;
}
var price = blueprint.Price(GameManager.ItemManager);
if (_dropdownCommands.ContainsKey(restoreCommand))
{
loadoutChildren.Add(Button(
$"{DropdownSurfaceId}.loadouts.restore_{loadoutEntry.templateIndex}",
loadoutOptions.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.loadouts.restore_{loadoutEntry.templateIndex}",
$"{loadoutEntry.template.Name} - {price:n0}",
restoreCommand));
}
else
{
loadoutChildren.Add(Text(
$"{DropdownSurfaceId}.loadouts.locked_{loadoutEntry.templateIndex}",
$"{loadoutEntry.template.Name} - {price:n0} (unavailable)"));
loadoutOptions.Add(new AetheriaRuntimeInventoryDropdownOption(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.loadouts.locked_{loadoutEntry.templateIndex}",
$"{loadoutEntry.template.Name} - {price:n0} (unavailable)",
""));
}
}
if (loadoutChildren.Count > 0)
if (loadoutOptions.Count > 0)
{
children.Add(Card(
$"{DropdownSurfaceId}.loadouts.card",
groups.Add(new AetheriaRuntimeInventoryDropdownGroup(
$"{AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId}.loadouts.card",
"Loadouts",
ButtonColumn($"{DropdownSurfaceId}.loadouts.options", loadoutChildren.ToArray())));
loadoutOptions));
}
children.Add(ButtonRow(
$"{DropdownSurfaceId}.actions",
Button($"{DropdownSurfaceId}.close", "Close", CloseDropdownSurfaceCommand)));
return new EveSurfaceDocument(
DropdownSurfaceType,
DropdownSurfaceSchema,
DropdownSurfaceProviderId,
DropdownSurfaceProviderKind,
"Inventory Dropdown",
version: 1,
DateTime.UtcNow.ToString("O"),
new EveSurfaceTree(
DropdownSurfaceId,
Node(
$"{DropdownSurfaceId}.root",
"surface",
Array.Empty<(string Key, string Value)>(),
children.ToArray()),
Array.Empty<EveStyleToken>()),
_dropdownCommands
.Select(pair => new EveCommandTemplate(pair.Key, pair.Key.Split('.').Last(), "unity-uitoolkit"))
.Append(new EveCommandTemplate(CloseDropdownSurfaceCommand, "Close", "unity-uitoolkit"))
.ToArray());
return new AetheriaRuntimeInventoryDropdownSurfaceState(
Title?.text ?? "None",
groups,
DateTime.UtcNow.ToString("O"));
}
private static EveSurfaceComponent Card(
string id,
string title,
params EveSurfaceComponent[] children)
{
return Node(id, "card", new[] { ("title", title) }, children);
}
private static EveSurfaceComponent Metric(string id, string label, string value)
{
return Node(id, "metric", new[] { ("label", label), ("value", value) });
}
private static EveSurfaceComponent Text(string id, string value)
{
return Node(id, "text", new[] { ("value", value) });
}
private static EveSurfaceComponent Button(string id, string label, string command)
{
return Node(id, "control.button", new[] { ("label", label), ("command", command) });
}
private static EveSurfaceComponent ButtonRow(
string id,
params EveSurfaceComponent[] children)
{
return Node(id, "row", Array.Empty<(string Key, string Value)>(), children);
}
private static EveSurfaceComponent ButtonColumn(
string id,
params EveSurfaceComponent[] children)
{
return Node(id, "column", Array.Empty<(string Key, string Value)>(), children);
}
private static EveSurfaceComponent Node(
string id,
string kind,
IEnumerable<(string Key, string Value)> props,
params EveSurfaceComponent[] children)
{
return new EveSurfaceComponent(
id,
kind,
props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal),
children ?? Array.Empty<EveSurfaceComponent>());
}
private void Update()
private void Update()
{
if (_displayedEntity != null && TemperatureDisplay)
{
@ -747,24 +632,21 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
var item = itemDragObject.Item;
if (!(item is EquippableItem equippableItem)) return;
var placementPosition = v + itemDragObject.OriginCellOffset;
if (entity.ItemFits(equippableItem, placementPosition))
//foreach (var cell in _dragCells) cell.gameObject.SetActive(false);
FakeItem = item;
FakeOccupancy = _displayedHullShape.Inset(GetItemShape(equippableItem), placementPosition, item.Rotation);
RefreshCells();
GameManager.RegisterDragTarget(drag =>
{
//foreach (var cell in _dragCells) cell.gameObject.SetActive(false);
FakeItem = item;
FakeOccupancy = _displayedHullShape.Inset(GetItemShape(item), placementPosition, item.Rotation);
//Debug.Log("Entity Drag Callback");
FakeOccupancy = null;
var success = RequestDraggedItemToEntity(drag, entity, placementPosition);
if (!success)
ShowUnableToMoveItemDialog();
RefreshCells();
GameManager.RegisterDragTarget(drag =>
{
//Debug.Log("Entity Drag Callback");
FakeOccupancy = null;
var success = CommitDraggedItemToEntity(drag, entity, placementPosition);
if (!success)
ShowUnableToMoveItemDialog();
RefreshCells();
// TODO: SFX: Equip
return success;
});
}
// TODO: SFX: Equip
return success;
});
});
cell.PointerExitTrigger.OnPointerExitAsObservable()
.Subscribe(data =>
@ -786,22 +668,22 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
// Debug.Log($"Clicked at pos {data.position}, normalized {point}");
if (_displayedHullShape[int2(v.x - 1, v.y)] && point.x < ThermalToggleRegionSize)
{
if (GameManager.CommitHullConductivityToggle(entity, int2(v.x - 1, v.y), 0))
if (GameManager.RequestHullConductivityToggle(entity, int2(v.x - 1, v.y), 0))
RefreshCells(new []{v,int2(v.x - 1, v.y)});
}
if (_displayedHullShape[int2(v.x + 1, v.y)] && point.x > 1 - ThermalToggleRegionSize)
{
if (GameManager.CommitHullConductivityToggle(entity, int2(v.x, v.y), 0))
if (GameManager.RequestHullConductivityToggle(entity, int2(v.x, v.y), 0))
RefreshCells(new []{v,int2(v.x + 1, v.y)});
}
if (_displayedHullShape[int2(v.x, v.y - 1)] && point.y < ThermalToggleRegionSize)
{
if (GameManager.CommitHullConductivityToggle(entity, int2(v.x, v.y - 1), 1))
if (GameManager.RequestHullConductivityToggle(entity, int2(v.x, v.y - 1), 1))
RefreshCells(new []{v,int2(v.x, v.y - 1)});
}
if (_displayedHullShape[int2(v.x, v.y + 1)] && point.y > 1 - ThermalToggleRegionSize)
{
if (GameManager.CommitHullConductivityToggle(entity, int2(v.x, v.y), 1))
if (GameManager.RequestHullConductivityToggle(entity, int2(v.x, v.y), 1))
RefreshCells(new []{v,int2(v.x, v.y + 1)});
}
});
@ -950,23 +832,20 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
if (!(GameManager.DragObject is ItemDragObject itemDragObject)) return;
var item = itemDragObject.Item;
var placementPosition = v + itemDragObject.OriginCellOffset;
if (cargo.ItemFits(item, placementPosition))
//foreach (var cell in _dragCells) cell.gameObject.SetActive(false);
FakeItem = item;
FakeOccupancy = cargo.InteriorShape.Inset(GetItemShape(item), placementPosition, item.Rotation);
RefreshCells();
GameManager.RegisterDragTarget(drag =>
{
//foreach (var cell in _dragCells) cell.gameObject.SetActive(false);
FakeItem = item;
FakeOccupancy = cargo.InteriorShape.Inset(GetItemShape(item), placementPosition, item.Rotation);
RefreshCells();
GameManager.RegisterDragTarget(drag =>
{
//Debug.Log("Inventory Drag Callback");
FakeOccupancy = null;
var success = CommitDraggedItemToCargo(drag, cargo, placementPosition);
if (!success)
ShowUnableToMoveItemDialog();
// TODO: SFX: Drop
return success;
});
}
//Debug.Log("Inventory Drag Callback");
FakeOccupancy = null;
var success = RequestDraggedItemToCargo(drag, cargo, placementPosition);
if (!success)
ShowUnableToMoveItemDialog();
// TODO: SFX: Drop
return success;
});
});
cell.PointerExitTrigger.OnPointerExitAsObservable()
.Subscribe(data =>
@ -1150,7 +1029,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
var c = float3(1);
if (TryGetTypedHardpointType(item, out var typedHardpoint))
c = HardpointData.GetColor(typedHardpoint);
c = HardpointData.GetColor(typedHardpoint).ToUnityFloat3();
if(!highlight)
c *= .7071f;
@ -1224,18 +1103,18 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
return ActionGameManager.RuntimeCatalog?.FindItem(item?.ItemKey ?? "");
}
private bool CommitDraggedItemToEntity(DragObject drag, Entity destination, int2 destinationPosition)
private bool RequestDraggedItemToEntity(DragObject drag, Entity destination, int2 destinationPosition)
{
switch (drag)
{
case EquippedItemDragObject equippedItemDragObject:
return GameManager.CommitEquippedItemEquip(
return GameManager.RequestEquippedItemEquip(
equippedItemDragObject.OriginEntity,
equippedItemDragObject.EquippedItem,
destination,
destinationPosition);
case ItemInstanceDragObject itemInstanceDragObject when itemInstanceDragObject.Item is EquippableItem equippableItem:
return GameManager.CommitCargoItemEquip(
return GameManager.RequestCargoItemEquip(
itemInstanceDragObject.OriginInventory,
destination,
equippableItem,
@ -1245,18 +1124,18 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
}
}
private bool CommitDraggedItemToCargo(DragObject drag, EquippedCargoBay destination, int2 destinationPosition)
private bool RequestDraggedItemToCargo(DragObject drag, EquippedCargoBay destination, int2 destinationPosition)
{
switch (drag)
{
case EquippedItemDragObject equippedItemDragObject:
return GameManager.CommitEquippedItemStore(
return GameManager.RequestEquippedItemStore(
equippedItemDragObject.OriginEntity,
equippedItemDragObject.EquippedItem,
destination,
destinationPosition);
case ItemInstanceDragObject itemInstanceDragObject:
return GameManager.CommitCargoItemTransfer(
return GameManager.RequestCargoItemTransfer(
itemInstanceDragObject.OriginInventory,
destination,
itemInstanceDragObject.Item,
@ -1279,7 +1158,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler
{
if (_dropdownSurfaceDocument != null)
{
Destroy(_dropdownSurfaceDocument.gameObject);
AetheriaEveUnitySurfaceHost.DestroyDocument(_dropdownSurfaceDocument);
_dropdownSurfaceDocument = null;
}
}

View file

@ -1,12 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
/* 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 System.Collections.Generic;
using System.Linq;
using GameCult.Aetheria.EveRuntime;
using GameCult.Aetheria.State.Unity;
using GameCult.Eve.Surface;
using GameCult.Eve.UnityUIToolkit;
using UnityEngine;
using UnityEngine.UIElements;
@ -21,12 +22,6 @@ public class MenuPanel : MonoBehaviour
public bool RequireDock;
}
private const string MenuTabsSurfaceType = "surface-state";
private const string MenuTabsSurfaceSchema = "gamecult.eve.surface.v1";
private const string MenuTabsSurfaceProviderId = "aetheria";
private const string MenuTabsSurfaceProviderKind = "runtime.menu";
private const string MenuTabsSurfaceId = "aetheria.runtime_menu.tabs";
public ActionGameManager GameManager;
public RectTransform TabButtons;
[SerializeField] private MenuTabBinding[] TabBindings = Array.Empty<MenuTabBinding>();
@ -36,6 +31,7 @@ public class MenuPanel : MonoBehaviour
private readonly Dictionary<MenuTab, MenuTabBinding> _tabs = new Dictionary<MenuTab, MenuTabBinding>();
private MenuTabBinding _current;
private UIDocument _tabSurfaceDocument;
private readonly AetheriaEveUnitySurfaceChrome _tabSurfaceChrome = new AetheriaEveUnitySurfaceChrome();
public MenuTab CurrentTab { get; private set; }
@ -95,7 +91,7 @@ public class MenuPanel : MonoBehaviour
{
if (_tabSurfaceDocument != null)
{
Destroy(_tabSurfaceDocument.gameObject);
AetheriaEveUnitySurfaceHost.DestroyDocument(_tabSurfaceDocument);
_tabSurfaceDocument = null;
}
}
@ -108,61 +104,34 @@ public class MenuPanel : MonoBehaviour
if (TabButtons != null)
TabButtons.gameObject.SetActive(false);
var document = ResolveTabSurfaceDocument();
document.gameObject.SetActive(true);
var root = document.rootVisualElement;
root.Clear();
root.style.flexGrow = 1;
root.style.position = Position.Absolute;
root.style.left = 0;
root.style.top = 0;
root.style.right = 0;
root.style.bottom = 0;
root.style.alignItems = Align.Center;
root.style.justifyContent = Justify.FlexStart;
root.style.paddingTop = 16;
root.pickingMode = PickingMode.Ignore;
var shell = new VisualElement();
shell.style.minWidth = 420;
shell.style.maxWidth = 760;
shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.94f);
shell.style.borderTopLeftRadius = 8;
shell.style.borderTopRightRadius = 8;
shell.style.borderBottomLeftRadius = 8;
shell.style.borderBottomRightRadius = 8;
shell.style.paddingLeft = 16;
shell.style.paddingRight = 16;
shell.style.paddingTop = 12;
shell.style.paddingBottom = 12;
shell.style.borderLeftWidth = 1;
shell.style.borderRightWidth = 1;
shell.style.borderTopWidth = 1;
shell.style.borderBottomWidth = 1;
shell.style.borderLeftColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderRightColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderTopColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderBottomColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.pickingMode = PickingMode.Position;
root.Add(shell);
var lowerer = new EveUiToolkitSurfaceLowerer();
shell.Add(lowerer.Lower(BuildTabSurfaceDefinition(), HandleTabSurfaceCommand));
_tabSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
transform,
_tabSurfaceDocument,
"Aetheria Runtime Menu Tabs Surface",
AetheriaRuntimeMenuTabsSurfaceBuilder.Build(ProjectTabSurfaceState()),
HandleTabSurfaceCommand,
_tabSurfaceChrome);
}
private void HandleTabSurfaceCommand(EveSurfaceCommandRequest request)
{
if (!AetheriaRuntimeMenuTabsSurfaceCommands.TryRead(request, out var command))
{
Debug.LogWarning($"Unknown runtime menu tab command: {request?.Command}");
return;
}
foreach (var tab in _tabs.Keys)
{
if (string.Equals(request.Command, GetTabCommand(tab), StringComparison.Ordinal))
if (command.Kind == AetheriaRuntimeMenuTabCommandKind.SelectTab &&
string.Equals(command.TabKey, TabKey(tab), StringComparison.Ordinal))
{
ShowTab(tab);
return;
}
}
Debug.LogWarning($"Unknown runtime menu tab command: {request.Command}");
Debug.LogWarning($"Unknown runtime menu tab command: {request?.Command}");
}
private void HideTabSurface()
@ -170,68 +139,21 @@ public class MenuPanel : MonoBehaviour
if (_tabSurfaceDocument == null)
return;
_tabSurfaceDocument.rootVisualElement.Clear();
_tabSurfaceDocument.gameObject.SetActive(false);
AetheriaEveUnitySurfaceHost.Hide(_tabSurfaceDocument);
}
private UIDocument ResolveTabSurfaceDocument()
{
if (_tabSurfaceDocument != null)
return _tabSurfaceDocument;
var host = new GameObject("Aetheria Runtime Menu Tabs Surface");
host.transform.SetParent(transform, false);
var document = host.AddComponent<UIDocument>();
document.sortingOrder = 1000;
host.SetActive(false);
_tabSurfaceDocument = document;
return document;
}
private EveSurfaceDocument BuildTabSurfaceDefinition()
private AetheriaRuntimeMenuTabsSurfaceState ProjectTabSurfaceState()
{
var visibleTabs = ResolveVisibleTabs();
var commands = visibleTabs
.Select(tabBinding => new EveCommandTemplate(
GetTabCommand(tabBinding.Tab),
GetTabLabel(tabBinding),
"unity-uitoolkit"))
.ToArray();
var buttons = visibleTabs
.Select(tabBinding =>
{
var label = GetTabLabel(tabBinding);
if (tabBinding.Tab == CurrentTab)
label = $"{label} *";
return Button(
$"{MenuTabsSurfaceId}.{tabBinding.Tab.ToString().ToLowerInvariant()}",
label,
GetTabCommand(tabBinding.Tab));
})
.ToArray();
return new EveSurfaceDocument(
MenuTabsSurfaceType,
MenuTabsSurfaceSchema,
MenuTabsSurfaceProviderId,
MenuTabsSurfaceProviderKind,
"Runtime Menu Tabs",
version: 1,
DateTime.UtcNow.ToString("O"),
new EveSurfaceTree(
MenuTabsSurfaceId,
Node(
$"{MenuTabsSurfaceId}.root",
"surface",
Array.Empty<(string Key, string Value)>(),
Text(
$"{MenuTabsSurfaceId}.current",
$"Current: {CurrentTab}"),
ButtonRow($"{MenuTabsSurfaceId}.tabs", buttons)),
Array.Empty<EveStyleToken>()),
commands);
return new AetheriaRuntimeMenuTabsSurfaceState(
TabKey(CurrentTab),
visibleTabs
.Select(tabBinding => new AetheriaRuntimeMenuTabSurfaceEntry(
TabKey(tabBinding.Tab),
GetTabLabel(tabBinding),
tabBinding.Tab == CurrentTab))
.ToArray(),
DateTime.UtcNow.ToString("O"));
}
private MenuTabBinding[] ResolveVisibleTabs()
@ -250,42 +172,12 @@ public class MenuPanel : MonoBehaviour
: tabBinding.Label;
}
private static string GetTabCommand(MenuTab tab)
private static string TabKey(MenuTab tab)
{
return $"aetheria.runtime_menu.tab.{tab.ToString().ToLowerInvariant()}";
return tab.ToString().ToLowerInvariant();
}
private static EveSurfaceComponent Text(string id, string value)
{
return Node(id, "text", new[] { ("value", value) });
}
private static EveSurfaceComponent Button(string id, string label, string command)
{
return Node(id, "control.button", new[] { ("label", label), ("command", command) });
}
private static EveSurfaceComponent ButtonRow(
string id,
params EveSurfaceComponent[] children)
{
return Node(id, "row", Array.Empty<(string Key, string Value)>(), children);
}
private static EveSurfaceComponent Node(
string id,
string kind,
IEnumerable<(string Key, string Value)> props,
params EveSurfaceComponent[] children)
{
return new EveSurfaceComponent(
id,
kind,
props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal),
children ?? Array.Empty<EveSurfaceComponent>());
}
// void Start()
// void Start()
// {
// ShowTab(MenuTab.Inventory);
// }

View file

@ -100,7 +100,7 @@ public class SectorMap : MonoBehaviour
if (!_revealedZones.Contains(zone))
{
var zoneInstance = ZonePrototype.Instantiate<SectorZoneUI>();
zoneInstance.Clickable.OnClick += (clickableCollider, data, ray, hit) => ZoneClicked.OnNext(zone);
zoneInstance.Clickable.OnClick += (_, _, _, _) => ZoneClicked.OnNext(zone);
if(zone == _currentPlayerLocation)
MarkPlayerLocation(zoneInstance);
_zoneInstances[zone] = zoneInstance;
@ -111,7 +111,7 @@ public class SectorMap : MonoBehaviour
{
zoneInstance.Primary.sharedMaterial = _factionMaterials[zone.Owner].primaryMaterial;
zoneInstance.Secondary.sharedMaterial = _factionMaterials[zone.Owner].secondaryMaterial;
if(zone == ActionGameManager.CurrentGalaxy.HomeZones[zone.Owner])
if(zone == ActionGameManager.ObservedGalaxy.HomeZones[zone.Owner])
zoneInstance.Secondary.transform.localScale = Vector3.one * 4;
}
else
@ -119,7 +119,7 @@ public class SectorMap : MonoBehaviour
zoneInstance.Secondary.gameObject.SetActive(false);
}
var isOnCriticalPath = ActionGameManager.CurrentGalaxy.ExitPath?.Contains(zone) ?? false;
var isOnCriticalPath = ActionGameManager.ObservedGalaxy.ExitPath?.Contains(zone) ?? false;
foreach (var adjacentZone in zone.AdjacentZones)
{
// If the adjacent zone is in the set already revealed, then show the link
@ -128,7 +128,7 @@ public class SectorMap : MonoBehaviour
_revealedLinks.Contains((adjacentZone, zone))))
{
var link = LinkPrototype.Instantiate<Transform>();
var critical = isOnCriticalPath && (ActionGameManager.CurrentGalaxy.ExitPath?.Contains(adjacentZone) ?? false);
var critical = isOnCriticalPath && (ActionGameManager.ObservedGalaxy.ExitPath?.Contains(adjacentZone) ?? false);
linksToReveal.Add((zone.Position, adjacentZone.Position, link, critical));
if (zone.Owner != null && zone.Owner.HasSameKey(adjacentZone.Owner))
link.GetComponent<MeshRenderer>().sharedMaterial = _factionMaterials[zone.Owner].linkMaterial;
@ -151,7 +151,7 @@ public class SectorMap : MonoBehaviour
zoneTextTransform.pivot = new Vector2(sign(linkDirection.x)/2+.5f,sign(linkDirection.y)/2+.5f);
zoneTextTransform.localPosition = new Vector3(-linkDirection.x * LabelDistance, -linkDirection.y * LabelDistance, -1);
if (zone == ActionGameManager.CurrentGalaxy.Entrance)
if (zone == ActionGameManager.ObservedGalaxy.Entrance)
{
var iconInstance = IconPrototype.Instantiate<MeshRenderer>();
iconInstance.material.mainTexture = EntranceIcon;
@ -161,7 +161,7 @@ public class SectorMap : MonoBehaviour
iconTransform.localPosition = new Vector3(-linkDirection.x * IconDistance, -linkDirection.y * IconDistance);
}
if (zone == ActionGameManager.CurrentGalaxy.Exit)
if (zone == ActionGameManager.ObservedGalaxy.Exit)
{
var iconInstance = IconPrototype.Instantiate<MeshRenderer>();
iconInstance.material.mainTexture = ExitIcon;
@ -171,8 +171,8 @@ public class SectorMap : MonoBehaviour
iconTransform.localPosition = new Vector3(-linkDirection.x * IconDistance, -linkDirection.y * IconDistance);
}
var homeMega = ActionGameManager.CurrentGalaxy.HomeZones.Keys
.FirstOrDefault(m => ActionGameManager.CurrentGalaxy.HomeZones[m] == zone);
var homeMega = ActionGameManager.ObservedGalaxy.HomeZones.Keys
.FirstOrDefault(m => ActionGameManager.ObservedGalaxy.HomeZones[m] == zone);
if (homeMega != null)
{
var backgroundInstance = IconBackgroundPrototype.Instantiate<MeshRenderer>();
@ -195,8 +195,8 @@ public class SectorMap : MonoBehaviour
iconTransform.localPosition = new Vector3(-linkDirection.x * IconDistance, -linkDirection.y * IconDistance);
}
var bossMega = ActionGameManager.CurrentGalaxy.BossZones.Keys
.FirstOrDefault(m => ActionGameManager.CurrentGalaxy.BossZones[m] == zone);
var bossMega = ActionGameManager.ObservedGalaxy.BossZones.Keys
.FirstOrDefault(m => ActionGameManager.ObservedGalaxy.BossZones[m] == zone);
if (bossMega != null)
{
var backgroundInstance = IconBackgroundPrototype.Instantiate<MeshRenderer>();
@ -268,12 +268,12 @@ public class SectorMap : MonoBehaviour
public void Start()
{
if (ActionGameManager.CurrentGalaxy == null)
if (ActionGameManager.ObservedGalaxy == null)
{
gameObject.SetActive(false);
return;
}
foreach (var mega in ActionGameManager.CurrentGalaxy.Factions)
foreach (var mega in ActionGameManager.ObservedGalaxy.Factions)
{
var influenceTexture = new RenderTexture(1024, 1024, 0, RenderTextureFormat.RHalf);
var influenceRenderer = InfluenceRendererPrototype.Instantiate<MeshRenderer>();
@ -300,22 +300,22 @@ public class SectorMap : MonoBehaviour
legendElement.Label.text = mega.ShortName;
}
SectorRenderer.material.SetFloat("CloudAmplitude", ActionGameManager.CurrentGalaxy.Background.CloudAmplitude);
SectorRenderer.material.SetFloat("CloudExponent", ActionGameManager.CurrentGalaxy.Background.CloudExponent);
SectorRenderer.material.SetFloat("NoisePosition", ActionGameManager.CurrentGalaxy.Background.NoisePosition);
SectorRenderer.material.SetFloat("NoiseAmplitude", ActionGameManager.CurrentGalaxy.Background.NoiseAmplitude);
SectorRenderer.material.SetFloat("NoiseOffset", ActionGameManager.CurrentGalaxy.Background.NoiseOffset);
SectorRenderer.material.SetFloat("NoiseGain", ActionGameManager.CurrentGalaxy.Background.NoiseGain);
SectorRenderer.material.SetFloat("NoiseLacunarity", ActionGameManager.CurrentGalaxy.Background.NoiseLacunarity);
SectorRenderer.material.SetFloat("NoiseFrequency", ActionGameManager.CurrentGalaxy.Background.NoiseFrequency);
SectorRenderer.material.SetFloat("CloudAmplitude", ActionGameManager.ObservedGalaxy.Background.CloudAmplitude);
SectorRenderer.material.SetFloat("CloudExponent", ActionGameManager.ObservedGalaxy.Background.CloudExponent);
SectorRenderer.material.SetFloat("NoisePosition", ActionGameManager.ObservedGalaxy.Background.NoisePosition);
SectorRenderer.material.SetFloat("NoiseAmplitude", ActionGameManager.ObservedGalaxy.Background.NoiseAmplitude);
SectorRenderer.material.SetFloat("NoiseOffset", ActionGameManager.ObservedGalaxy.Background.NoiseOffset);
SectorRenderer.material.SetFloat("NoiseGain", ActionGameManager.ObservedGalaxy.Background.NoiseGain);
SectorRenderer.material.SetFloat("NoiseLacunarity", ActionGameManager.ObservedGalaxy.Background.NoiseLacunarity);
SectorRenderer.material.SetFloat("NoiseFrequency", ActionGameManager.ObservedGalaxy.Background.NoiseFrequency);
}
private void RenderInfluence()
{
// Render Influence Textures
foreach (var mega in ActionGameManager.CurrentGalaxy.Factions)
foreach (var mega in ActionGameManager.ObservedGalaxy.Factions)
{
foreach (var zone in ActionGameManager.CurrentGalaxy.Zones)
foreach (var zone in ActionGameManager.ObservedGalaxy.Zones)
{
if(_zoneInstances.ContainsKey(zone))
{

View file

@ -2,8 +2,9 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GameCult.Aetheria.EveRuntime;
using GameCult.Aetheria.State.Unity;
using GameCult.Eve.Surface;
using GameCult.Eve.UnityUIToolkit;
using UniRx;
using UnityEngine;
using UnityEngine.EventSystems;
@ -15,13 +16,6 @@ using float2 = Unity.Mathematics.float2;
public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IScrollHandler
{
private const string ZoneDetailsSurfaceType = "surface-state";
private const string ZoneDetailsSurfaceSchema = "gamecult.eve.surface.v1";
private const string ZoneDetailsSurfaceProviderId = "aetheria";
private const string ZoneDetailsSurfaceProviderKind = "sector.map";
private const string ZoneDetailsSurfaceId = "aetheria.sector_map.zone_details";
private const string CloseZoneDetailsCommand = "aetheria.sector_map.zone_details.close";
public ClickRaycaster Raycaster;
public Canvas Canvas;
public SectorMap Map;
@ -51,6 +45,19 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
private float _sectorBackgroundDepth;
private float _sectorCameraDepth;
private UIDocument _zoneDetailsSurfaceDocument;
private readonly AetheriaEveUnitySurfaceChrome _zoneDetailsSurfaceChrome = new AetheriaEveUnitySurfaceChrome
{
RootAlignItems = Align.FlexEnd,
RootPaddingTop = 24f,
RootPaddingRight = 24f,
Width = 360f,
MinWidth = 0f,
MaxWidth = 420f,
PaddingLeft = 18f,
PaddingRight = 18f,
PaddingTop = 18f,
PaddingBottom = 18f
};
private float2 _position = float2(0.5f);
private float _viewSize = .5f;
@ -86,59 +93,30 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
private void RenderZoneDetailsSurface(GalaxyZone zone)
{
var document = ResolveZoneDetailsSurfaceDocument();
document.gameObject.SetActive(true);
var root = document.rootVisualElement;
root.Clear();
root.style.flexGrow = 1;
root.style.position = Position.Absolute;
root.style.left = 0;
root.style.top = 0;
root.style.right = 0;
root.style.bottom = 0;
root.style.alignItems = Align.FlexEnd;
root.style.justifyContent = Justify.FlexStart;
root.style.paddingTop = 24;
root.style.paddingRight = 24;
root.pickingMode = PickingMode.Ignore;
var shell = new VisualElement();
shell.style.width = 360;
shell.style.maxWidth = 420;
shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.94f);
shell.style.borderTopLeftRadius = 8;
shell.style.borderTopRightRadius = 8;
shell.style.borderBottomLeftRadius = 8;
shell.style.borderBottomRightRadius = 8;
shell.style.paddingLeft = 18;
shell.style.paddingRight = 18;
shell.style.paddingTop = 18;
shell.style.paddingBottom = 18;
shell.style.borderLeftWidth = 1;
shell.style.borderRightWidth = 1;
shell.style.borderTopWidth = 1;
shell.style.borderBottomWidth = 1;
shell.style.borderLeftColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderRightColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderTopColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.style.borderBottomColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
shell.pickingMode = PickingMode.Position;
root.Add(shell);
var lowerer = new EveUiToolkitSurfaceLowerer();
shell.Add(lowerer.Lower(BuildZoneDetailsSurfaceDefinition(zone), HandleZoneDetailsSurfaceCommand));
_zoneDetailsSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
transform,
_zoneDetailsSurfaceDocument,
"Aetheria Sector Zone Details Surface",
AetheriaRuntimeZoneDetailsSurfaceBuilder.Build(ProjectZoneDetailsSurfaceState(zone)),
HandleZoneDetailsSurfaceCommand,
_zoneDetailsSurfaceChrome);
}
private void HandleZoneDetailsSurfaceCommand(EveSurfaceCommandRequest request)
{
if (string.Equals(request.Command, CloseZoneDetailsCommand, StringComparison.Ordinal))
if (!AetheriaRuntimeZoneDetailsSurfaceCommands.TryRead(request, out var command))
{
Debug.LogWarning($"Unknown sector-map zone details command: {request?.Command}");
return;
}
if (command.Kind == AetheriaRuntimeZoneDetailsCommandKind.Close)
{
HideZoneDetailsSurface();
return;
}
Debug.LogWarning($"Unknown sector-map zone details command: {request.Command}");
Debug.LogWarning($"Unknown sector-map zone details command: {request?.Command}");
}
private void HideZoneDetailsSurface()
@ -146,27 +124,12 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
if (_zoneDetailsSurfaceDocument == null)
return;
_zoneDetailsSurfaceDocument.rootVisualElement.Clear();
_zoneDetailsSurfaceDocument.gameObject.SetActive(false);
AetheriaEveUnitySurfaceHost.Hide(_zoneDetailsSurfaceDocument);
}
private UIDocument ResolveZoneDetailsSurfaceDocument()
private AetheriaRuntimeZoneDetailsSurfaceState ProjectZoneDetailsSurfaceState(GalaxyZone zone)
{
if (_zoneDetailsSurfaceDocument != null)
return _zoneDetailsSurfaceDocument;
var host = new GameObject("Aetheria Sector Zone Details Surface");
host.transform.SetParent(transform, false);
var document = host.AddComponent<UIDocument>();
document.sortingOrder = 1000;
host.SetActive(false);
_zoneDetailsSurfaceDocument = document;
return document;
}
private EveSurfaceDocument BuildZoneDetailsSurfaceDefinition(GalaxyZone zone)
{
var density = saturate(ActionGameManager.CurrentGalaxy.Background.CloudDensity(zone.Position) / 2);
var density = saturate(ActionGameManager.ObservedGalaxy.Background.CloudDensity(zone.Position) / 2);
var radius = GameManager.Settings.ZoneSettings.ZoneRadius.Evaluate(density);
var mass = GameManager.Settings.ZoneSettings.ZoneMass.Evaluate(density);
var otherFactions = zone.Factions
@ -175,135 +138,44 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToArray();
var children = new List<EveSurfaceComponent>
{
Card(
$"{ZoneDetailsSurfaceId}.card",
zone.Name,
Metric($"{ZoneDetailsSurfaceId}.owner", "Owner", zone.Owner?.Name ?? "None"),
Metric($"{ZoneDetailsSurfaceId}.mass", "Mass", ActionGameManager.RuntimePlayerSettings.Format(mass)),
Metric($"{ZoneDetailsSurfaceId}.radius", "Radius", ActionGameManager.RuntimePlayerSettings.Format(radius)))
};
if (otherFactions.Length > 0)
{
children.Add(Text(
$"{ZoneDetailsSurfaceId}.factions",
$"Factions Present: {string.Join(", ", otherFactions)}"));
}
if (zone.Contents == null)
{
children.Add(Text(
$"{ZoneDetailsSurfaceId}.unvisited",
"Has not been visited."));
}
else
{
var runtimeZone = zone.Contents;
children.Add(Card(
$"{ZoneDetailsSurfaceId}.contents",
"Contents",
Metric(
$"{ZoneDetailsSurfaceId}.planets",
"Planets",
runtimeZone.PlanetInstances.Values.Count(body => !(body is GasGiant)).ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.belts",
"Asteroid Belts",
runtimeZone.AsteroidBelts.Count.ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.giants",
"Gas Giants",
runtimeZone.PlanetInstances.Values.Count(body => body is GasGiant && !(body is Sun)).ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.stars",
"Stars",
runtimeZone.PlanetInstances.Values.Count(body => body is Sun).ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.stations",
"Stations",
runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Station)).ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.turrets",
"Turrets",
runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Turret)).ToString()),
Metric(
$"{ZoneDetailsSurfaceId}.ships",
"Ships",
runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Ship)).ToString())));
return new AetheriaRuntimeZoneDetailsSurfaceState(
zone.Name,
zone.Owner?.Name ?? "None",
ActionGameManager.RuntimePlayerSettings.Format(mass),
ActionGameManager.RuntimePlayerSettings.Format(radius),
otherFactions,
hasContents: false,
planets: "",
asteroidBelts: "",
gasGiants: "",
stars: "",
stations: "",
turrets: "",
ships: "",
updatedAtUtc: DateTime.UtcNow.ToString("O"));
}
children.Add(ButtonRow(
$"{ZoneDetailsSurfaceId}.actions",
Button($"{ZoneDetailsSurfaceId}.close", "Close", CloseZoneDetailsCommand)));
return new EveSurfaceDocument(
ZoneDetailsSurfaceType,
ZoneDetailsSurfaceSchema,
ZoneDetailsSurfaceProviderId,
ZoneDetailsSurfaceProviderKind,
var runtimeZone = zone.Contents;
return new AetheriaRuntimeZoneDetailsSurfaceState(
zone.Name,
version: 1,
DateTime.UtcNow.ToString("O"),
new EveSurfaceTree(
ZoneDetailsSurfaceId,
Node(
$"{ZoneDetailsSurfaceId}.root",
"surface",
Array.Empty<(string Key, string Value)>(),
children.ToArray()),
Array.Empty<EveStyleToken>()),
new[]
{
new EveCommandTemplate(CloseZoneDetailsCommand, "Close", "unity-uitoolkit")
});
zone.Owner?.Name ?? "None",
ActionGameManager.RuntimePlayerSettings.Format(mass),
ActionGameManager.RuntimePlayerSettings.Format(radius),
otherFactions,
hasContents: true,
planets: runtimeZone.PlanetInstances.Values.Count(body => !(body is GasGiant)).ToString(),
asteroidBelts: runtimeZone.AsteroidBelts.Count.ToString(),
gasGiants: runtimeZone.PlanetInstances.Values.Count(body => body is GasGiant && !(body is Sun)).ToString(),
stars: runtimeZone.PlanetInstances.Values.Count(body => body is Sun).ToString(),
stations: runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Station)).ToString(),
turrets: runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Turret)).ToString(),
ships: runtimeZone.Entities.Count(entity => HasHullType(entity, HullType.Ship)).ToString(),
updatedAtUtc: DateTime.UtcNow.ToString("O"));
}
private static EveSurfaceComponent Card(
string id,
string title,
params EveSurfaceComponent[] children)
{
return Node(id, "card", new[] { ("title", title) }, children);
}
private static EveSurfaceComponent Metric(string id, string label, string value)
{
return Node(id, "metric", new[] { ("label", label), ("value", value) });
}
private static EveSurfaceComponent Text(string id, string value)
{
return Node(id, "text", new[] { ("value", value) });
}
private static EveSurfaceComponent Button(string id, string label, string command)
{
return Node(id, "control.button", new[] { ("label", label), ("command", command) });
}
private static EveSurfaceComponent ButtonRow(
string id,
params EveSurfaceComponent[] children)
{
return Node(id, "row", Array.Empty<(string Key, string Value)>(), children);
}
private static EveSurfaceComponent Node(
string id,
string kind,
IEnumerable<(string Key, string Value)> props,
params EveSurfaceComponent[] children)
{
return new EveSurfaceComponent(
id,
kind,
props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal),
children ?? Array.Empty<EveSurfaceComponent>());
}
// private IEnumerator AnimatePath()
// private IEnumerator AnimatePath()
// {
// var pathZones = ActionGameManager.CurrentSector.ExitPath;
// LegendPanel.SetActive(false);
@ -358,7 +230,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
{
if (_zoneDetailsSurfaceDocument != null)
{
Destroy(_zoneDetailsSurfaceDocument.gameObject);
AetheriaEveUnitySurfaceHost.DestroyDocument(_zoneDetailsSurfaceDocument);
_zoneDetailsSurfaceDocument = null;
}
}

File diff suppressed because it is too large Load diff