2021-01-14 03:20:27 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2026-06-21 09:37:54 +01:00
|
|
|
using GameCult.Aetheria.EveRuntime;
|
2026-06-21 09:54:15 +01:00
|
|
|
using GameCult.Aetheria.State.Verse;
|
2026-06-16 21:45:56 +01:00
|
|
|
using GameCult.Eve.Surface;
|
2021-01-14 23:47:08 +00:00
|
|
|
using TMPro;
|
2021-01-14 03:20:27 +00:00
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.UI;
|
2026-06-16 21:45:56 +01:00
|
|
|
using UnityEngine.UIElements;
|
2021-01-19 01:22:56 +00:00
|
|
|
using Unity.Mathematics;
|
|
|
|
|
using static Unity.Mathematics.math;
|
2021-01-14 03:20:27 +00:00
|
|
|
|
|
|
|
|
public class TradeMenu : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
public ActionGameManager GameManager;
|
2021-01-19 01:22:56 +00:00
|
|
|
public ConfirmationDialog Dialog;
|
2026-06-16 21:45:56 +01:00
|
|
|
public UnityEngine.UI.Button NewFilterButton;
|
2021-01-14 23:47:08 +00:00
|
|
|
public Prototype FilterPrototype;
|
2021-01-14 03:20:27 +00:00
|
|
|
public SizeFilter MinimumSizeFilter;
|
|
|
|
|
public SizeFilter MaximumSizeFilter;
|
|
|
|
|
public Spreadsheet Spreadsheet;
|
2021-01-14 23:47:08 +00:00
|
|
|
public TextMeshProUGUI TargetCargoLabel;
|
2026-06-16 21:45:56 +01:00
|
|
|
public UnityEngine.UI.Button FoldoutButton;
|
2025-07-18 00:21:33 +01:00
|
|
|
public TextMeshProUGUI CreditsLabel;
|
2021-01-14 03:20:27 +00:00
|
|
|
|
2021-01-14 23:47:08 +00:00
|
|
|
private EquippedCargoBay _targetCargo;
|
|
|
|
|
private (ItemFilter filter, HardpointType type) _hardpointFilter;
|
2021-01-17 02:45:52 +00:00
|
|
|
private (ItemFilter filter, SimpleCommodityCategory type) _commodityFilter;
|
|
|
|
|
private (ItemFilter filter, CompoundCommodityCategory type) _compoundCommodityFilter;
|
2026-06-14 08:59:33 +01:00
|
|
|
private List<BehaviorFilter> _behaviorFilters = new List<BehaviorFilter>();
|
2026-06-16 21:45:56 +01:00
|
|
|
private UIDocument _cargoSelectorSurfaceDocument;
|
2026-06-16 22:24:48 +01:00
|
|
|
private UIDocument _filterSurfaceDocument;
|
|
|
|
|
private UIDocument _rowActionSurfaceDocument;
|
2026-06-16 23:09:42 +01:00
|
|
|
private UIDocument _tradeItemSurfaceDocument;
|
2026-06-21 09:37:54 +01:00
|
|
|
private readonly AetheriaEveUnitySurfaceChrome _cargoSelectorSurfaceChrome = PanelChrome(360f, 420f, Align.FlexEnd);
|
|
|
|
|
private readonly AetheriaEveUnitySurfaceChrome _filterSurfaceChrome = PanelChrome(420f, 520f, Align.FlexStart);
|
|
|
|
|
private readonly AetheriaEveUnitySurfaceChrome _rowActionSurfaceChrome = PanelChrome(320f, 360f, Align.FlexStart);
|
|
|
|
|
private readonly AetheriaEveUnitySurfaceChrome _tradeItemSurfaceChrome = PanelChrome(420f, 520f, Align.FlexStart);
|
2026-06-21 21:36:35 +01:00
|
|
|
private AetheriaRuntimeTradeCargoSelectorSurfaceProjection _cargoSelectorSurfaceProjection;
|
2026-06-21 21:32:57 +01:00
|
|
|
private AetheriaRuntimeTradeFilterSurfaceProjection _filterSurfaceProjection;
|
2026-06-21 21:28:39 +01:00
|
|
|
private Action[] _rowActionCallbacks = Array.Empty<Action>();
|
|
|
|
|
private AetheriaRuntimeTradeRowActionSurfaceProjection _rowActionSurfaceProjection;
|
2021-01-14 23:47:08 +00:00
|
|
|
|
2021-03-20 04:20:17 +00:00
|
|
|
public EquippedCargoBay Inventory { get; set; }
|
|
|
|
|
|
2021-01-14 03:20:27 +00:00
|
|
|
private void OnEnable()
|
|
|
|
|
{
|
2026-06-21 19:19:50 +01:00
|
|
|
if (!GameManager.TryGetObservedDockingBay(out var dockingBay)) return;
|
|
|
|
|
_targetCargo = dockingBay;
|
2021-01-14 23:47:08 +00:00
|
|
|
TargetCargoLabel.text = "Docking Bay";
|
2026-06-16 21:45:56 +01:00
|
|
|
HideCargoSelectorSurface();
|
2026-06-16 22:24:48 +01:00
|
|
|
HideFilterSurface();
|
|
|
|
|
HideRowActionSurface();
|
2026-06-16 23:09:42 +01:00
|
|
|
HideTradeItemDetailsSurface();
|
2025-07-18 00:21:33 +01:00
|
|
|
UpdateCreditsLabel();
|
2021-03-20 04:20:17 +00:00
|
|
|
|
|
|
|
|
MinimumSizeFilter.Width.onEndEdit.RemoveAllListeners();
|
2021-01-14 23:47:08 +00:00
|
|
|
MinimumSizeFilter.Width.onEndEdit.AddListener(_ => Populate());
|
2021-03-20 04:20:17 +00:00
|
|
|
|
|
|
|
|
MinimumSizeFilter.Height.onEndEdit.RemoveAllListeners();
|
2021-01-14 23:47:08 +00:00
|
|
|
MinimumSizeFilter.Height.onEndEdit.AddListener(_ => Populate());
|
2021-03-20 04:20:17 +00:00
|
|
|
|
|
|
|
|
MaximumSizeFilter.Width.onEndEdit.RemoveAllListeners();
|
2021-01-14 23:47:08 +00:00
|
|
|
MaximumSizeFilter.Width.onEndEdit.AddListener(_ => Populate());
|
2021-03-20 04:20:17 +00:00
|
|
|
|
|
|
|
|
MaximumSizeFilter.Height.onEndEdit.RemoveAllListeners();
|
2021-01-14 23:47:08 +00:00
|
|
|
MaximumSizeFilter.Height.onEndEdit.AddListener(_ => Populate());
|
2026-06-16 22:24:48 +01:00
|
|
|
|
|
|
|
|
NewFilterButton.onClick.RemoveAllListeners();
|
2021-01-14 23:47:08 +00:00
|
|
|
NewFilterButton.onClick.AddListener(() =>
|
|
|
|
|
{
|
2026-06-16 22:24:48 +01:00
|
|
|
RenderFilterSurface();
|
2021-01-14 23:47:08 +00:00
|
|
|
});
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Populate()
|
|
|
|
|
{
|
2026-06-14 02:19:14 +01:00
|
|
|
var columns = new List<(string name, int size, Func<TradeRow, Func<string>> output, Func<TradeRow, IComparable> sortKey)>();
|
2021-01-14 23:47:08 +00:00
|
|
|
|
|
|
|
|
columns.Add(("Name", 3,
|
2026-06-21 20:12:50 +01:00
|
|
|
x => () => x.Item is CraftedItemInstance && !string.IsNullOrWhiteSpace(x.TierColorHex) ?
|
|
|
|
|
$"<color=#{x.TierColorHex}>{x.Name}" :
|
2026-06-14 02:19:14 +01:00
|
|
|
x.Name,
|
|
|
|
|
x => x.Name));
|
2021-01-14 23:47:08 +00:00
|
|
|
if(_hardpointFilter.filter==null)
|
|
|
|
|
columns.Add(("Type", 2,
|
2021-03-20 04:20:17 +00:00
|
|
|
x => () =>
|
2021-01-17 02:45:52 +00:00
|
|
|
{
|
2026-06-14 03:52:20 +01:00
|
|
|
if (x.TryGetTypedSimpleCommodityCategory(out _))
|
|
|
|
|
return x.TypedItem.SimpleCommodityCategory;
|
|
|
|
|
if (x.TryGetTypedCompoundCommodityCategory(out _))
|
|
|
|
|
return x.TypedItem.CompoundCommodityCategory;
|
2026-06-14 02:19:14 +01:00
|
|
|
if (x.TryGetTypedHardpoint(out var hardpointType)) return Enum.GetName(typeof(HardpointType), hardpointType);
|
2021-01-17 02:45:52 +00:00
|
|
|
return "None";
|
2026-06-14 02:19:14 +01:00
|
|
|
},
|
|
|
|
|
x =>
|
2021-01-17 02:45:52 +00:00
|
|
|
{
|
2026-06-14 03:52:20 +01:00
|
|
|
if (x.TryGetTypedSimpleCommodityCategory(out var simpleCategory))
|
|
|
|
|
return (int)simpleCategory;
|
2021-01-17 02:45:52 +00:00
|
|
|
var offset = Enum.GetValues(typeof(SimpleCommodityCategory)).Length;
|
2026-06-14 03:52:20 +01:00
|
|
|
if(x.TryGetTypedCompoundCommodityCategory(out var compoundCategory))
|
|
|
|
|
return (int)compoundCategory + offset;
|
2021-01-17 02:45:52 +00:00
|
|
|
offset += Enum.GetValues(typeof(CompoundCommodityCategory)).Length;
|
2026-06-14 02:19:14 +01:00
|
|
|
if (x.TryGetTypedHardpoint(out var hardpointType)) return (int) hardpointType + offset;
|
2021-01-17 02:45:52 +00:00
|
|
|
return 0;
|
|
|
|
|
}));
|
2021-01-14 23:47:08 +00:00
|
|
|
columns.Add(("Mass", 1,
|
2026-06-14 02:19:14 +01:00
|
|
|
x => () => ActionGameManager.RuntimePlayerSettings.Format(x.Mass),
|
|
|
|
|
x => x.Mass));
|
2021-01-17 02:45:52 +00:00
|
|
|
columns.Add(("Price", 1,
|
2026-06-14 02:19:14 +01:00
|
|
|
x => () => x.Price.ToString("N0"),
|
|
|
|
|
x => x.Price));
|
2021-01-14 23:47:08 +00:00
|
|
|
columns.Add(("Size", 1,
|
2026-06-14 02:19:14 +01:00
|
|
|
x => () => $"{x.ShapeWidth}x{x.ShapeHeight}",
|
|
|
|
|
x => x.ShapeWidth * x.ShapeHeight));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
2021-03-20 04:20:17 +00:00
|
|
|
var items = Inventory.Cargo.Keys
|
2026-06-13 23:36:21 +01:00
|
|
|
.Where(PassesTypedTradeFilters)
|
2026-06-21 20:12:50 +01:00
|
|
|
.Select(item => new TradeRow(item, FindTypedTradeItem(item), ProjectTradeItem(item)));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
|
|
|
|
if (MinimumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
items = items.Where(i =>
|
2026-06-14 02:19:14 +01:00
|
|
|
!(MinimumSizeFilter.Width.text.Length > 0 && i.ShapeWidth < int.Parse(MinimumSizeFilter.Width.text) ||
|
|
|
|
|
MinimumSizeFilter.Height.text.Length > 0 && i.ShapeHeight < int.Parse(MinimumSizeFilter.Height.text)));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
|
|
|
|
if (MaximumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
items = items.Where(i =>
|
2026-06-14 02:19:14 +01:00
|
|
|
!(MaximumSizeFilter.Width.text.Length > 0 && i.ShapeWidth > int.Parse(MaximumSizeFilter.Width.text) ||
|
|
|
|
|
MaximumSizeFilter.Height.text.Length > 0 && i.ShapeHeight > int.Parse(MaximumSizeFilter.Height.text)));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
2021-01-17 02:45:52 +00:00
|
|
|
if(_commodityFilter.filter != null)
|
2026-06-14 03:52:20 +01:00
|
|
|
items = items.Where(i => i.TryGetTypedSimpleCommodityCategory(out var category) && category == _commodityFilter.type);
|
2021-01-17 02:45:52 +00:00
|
|
|
|
|
|
|
|
if(_compoundCommodityFilter.filter != null)
|
2026-06-14 03:52:20 +01:00
|
|
|
items = items.Where(i => i.TryGetTypedCompoundCommodityCategory(out var category) && category == _compoundCommodityFilter.type);
|
2021-01-17 02:45:52 +00:00
|
|
|
|
2021-01-14 23:47:08 +00:00
|
|
|
if (_hardpointFilter.filter != null)
|
2026-06-14 02:19:14 +01:00
|
|
|
items = items.Where(i => i.TryGetTypedHardpoint(out var hardpointType) && hardpointType == _hardpointFilter.type);
|
2021-01-14 23:47:08 +00:00
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
foreach (var behaviorFilter in _behaviorFilters)
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
items = items.Where(i => HasTypedBehavior(i.TypedItem, behaviorFilter));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
2026-06-14 10:17:33 +01:00
|
|
|
foreach (var field in behaviorFilter.Metadata.DisplayFields)
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 10:17:33 +01:00
|
|
|
if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Number)
|
2021-03-20 04:20:17 +00:00
|
|
|
columns.Add((field.Name, 1, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
var value = GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2026-06-14 04:13:52 +01:00
|
|
|
return () => ActionGameManager.RuntimePlayerSettings.Format((float)value);
|
2026-06-14 02:19:14 +01:00
|
|
|
}, x =>
|
2026-06-16 19:55:50 +01:00
|
|
|
{
|
|
|
|
|
return (float)GetTypedBehaviorNumber(x, behaviorFilter, field);
|
|
|
|
|
}));
|
|
|
|
|
else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Temperature)
|
|
|
|
|
columns.Add((field.Name, 1, x =>
|
|
|
|
|
{
|
|
|
|
|
var value = GetTypedBehaviorNumber(x, behaviorFilter, field);
|
|
|
|
|
return () => ActionGameManager.RuntimePlayerSettings.FormatTemperature((float)value);
|
|
|
|
|
}, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
return (float)GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2021-01-14 23:47:08 +00:00
|
|
|
}));
|
2026-06-14 10:17:33 +01:00
|
|
|
else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.Integer)
|
2021-03-20 04:20:17 +00:00
|
|
|
columns.Add((field.Name, 1, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
var value = GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2026-06-14 04:13:52 +01:00
|
|
|
return () => ((int)value).ToString();
|
2026-06-14 02:19:14 +01:00
|
|
|
}, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
return (int)GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2021-01-14 23:47:08 +00:00
|
|
|
}));
|
2026-06-14 10:17:33 +01:00
|
|
|
else if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.PerformanceStat)
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2021-03-20 04:20:17 +00:00
|
|
|
columns.Add((field.Name, 1, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
var value = GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2026-06-14 04:13:52 +01:00
|
|
|
return () => ActionGameManager.RuntimePlayerSettings.Format((float)value);
|
2026-06-14 02:19:14 +01:00
|
|
|
}, x =>
|
2021-01-14 23:47:08 +00:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
return (float)GetTypedBehaviorNumber(x, behaviorFilter, field);
|
2021-01-14 23:47:08 +00:00
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
columns.Add(("Owned", 1,
|
2021-03-20 04:20:17 +00:00
|
|
|
x => () =>
|
2021-01-17 02:45:52 +00:00
|
|
|
{
|
2026-06-14 02:19:14 +01:00
|
|
|
if (x.IsHull)
|
2026-06-21 18:19:42 +01:00
|
|
|
return CountAvailablePlayerShips(x.ItemKey).ToString();
|
2026-06-14 02:19:14 +01:00
|
|
|
if(x.Item is SimpleCommodity)
|
2026-06-14 23:09:49 +01:00
|
|
|
return (_targetCargo.ItemsOfType.ContainsKey(x.ItemKey) ? _targetCargo.ItemsOfType[x.ItemKey].Cast<SimpleCommodity>().Sum(s=>s.Quantity) : 0).ToString();
|
|
|
|
|
return (_targetCargo.ItemsOfType.ContainsKey(x.ItemKey) ? _targetCargo.ItemsOfType[x.ItemKey].Count : 0).ToString();
|
2021-01-17 02:45:52 +00:00
|
|
|
},
|
2026-06-14 02:19:14 +01:00
|
|
|
x =>
|
2021-01-17 02:45:52 +00:00
|
|
|
{
|
2026-06-14 02:19:14 +01:00
|
|
|
if (x.IsHull)
|
2026-06-21 18:19:42 +01:00
|
|
|
return CountAvailablePlayerShips(x.ItemKey);
|
2026-06-14 02:19:14 +01:00
|
|
|
if(x.Item is SimpleCommodity)
|
2026-06-14 23:09:49 +01:00
|
|
|
return _targetCargo.ItemsOfType.ContainsKey(x.ItemKey) ? _targetCargo.ItemsOfType[x.ItemKey].Cast<SimpleCommodity>().Sum(s=>s.Quantity) : 0;
|
|
|
|
|
return _targetCargo.ItemsOfType.ContainsKey(x.ItemKey) ? _targetCargo.ItemsOfType[x.ItemKey].Count : 0;
|
2021-01-17 02:45:52 +00:00
|
|
|
}));
|
2021-01-14 23:47:08 +00:00
|
|
|
|
|
|
|
|
Spreadsheet.ShowData(
|
|
|
|
|
columns.Select(x => x.name).ToArray(),
|
|
|
|
|
columns.Select(x => x.size).ToArray(),
|
|
|
|
|
items.Select(i => new SpreadsheetEntryRow
|
|
|
|
|
{
|
|
|
|
|
Columns = columns.Select(x => new SpreadsheetEntryColumn
|
|
|
|
|
{
|
|
|
|
|
Output = x.output(i),
|
2026-06-14 02:19:14 +01:00
|
|
|
SortKey = x.sortKey(i)
|
2021-01-14 23:47:08 +00:00
|
|
|
}).ToArray(),
|
2026-06-16 23:09:42 +01:00
|
|
|
OnClick = () => RenderTradeItemDetailsSurface(i.TypedItem),
|
2021-01-14 23:47:08 +00:00
|
|
|
OnDoubleClick = () =>
|
|
|
|
|
{
|
2026-06-14 02:19:14 +01:00
|
|
|
switch (i.Item)
|
2021-01-17 02:45:52 +00:00
|
|
|
{
|
2021-03-20 04:20:17 +00:00
|
|
|
case CraftedItemInstance c:
|
|
|
|
|
Buy(c);
|
2021-01-19 01:22:56 +00:00
|
|
|
break;
|
2021-03-20 04:20:17 +00:00
|
|
|
case SimpleCommodity s:
|
2021-01-19 01:22:56 +00:00
|
|
|
Buy(s, 1);
|
|
|
|
|
break;
|
2021-01-17 02:45:52 +00:00
|
|
|
}
|
2021-01-19 01:22:56 +00:00
|
|
|
|
2021-01-14 23:47:08 +00:00
|
|
|
Populate();
|
2021-01-19 01:22:56 +00:00
|
|
|
},
|
|
|
|
|
OnRightClick = () =>
|
|
|
|
|
{
|
2026-06-14 02:19:14 +01:00
|
|
|
if (i.Item is SimpleCommodity s)
|
2021-01-19 01:22:56 +00:00
|
|
|
{
|
2026-06-16 22:24:48 +01:00
|
|
|
RenderRowActionSurface(
|
|
|
|
|
$"Buying {i.Name}",
|
|
|
|
|
("Buy Quantity", () => ShowBuyQuantityDialog(i.Name, i.Price, s)));
|
2021-01-19 01:22:56 +00:00
|
|
|
}
|
2021-01-14 03:20:27 +00:00
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
}
|
2026-06-13 23:36:21 +01:00
|
|
|
|
|
|
|
|
private bool PassesTypedTradeFilters(ItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
var typedItem = FindTypedTradeItem(item);
|
|
|
|
|
if (typedItem == null)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MinimumSizeFilter.gameObject.activeSelf &&
|
|
|
|
|
(MinimumSizeFilter.Width.text.Length > 0 && typedItem.ShapeWidth < int.Parse(MinimumSizeFilter.Width.text) ||
|
|
|
|
|
MinimumSizeFilter.Height.text.Length > 0 && typedItem.ShapeHeight < int.Parse(MinimumSizeFilter.Height.text)))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MaximumSizeFilter.gameObject.activeSelf &&
|
|
|
|
|
(MaximumSizeFilter.Width.text.Length > 0 && typedItem.ShapeWidth > int.Parse(MaximumSizeFilter.Width.text) ||
|
|
|
|
|
MaximumSizeFilter.Height.text.Length > 0 && typedItem.ShapeHeight > int.Parse(MaximumSizeFilter.Height.text)))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_hardpointFilter.filter != null &&
|
|
|
|
|
!string.Equals(typedItem.HardpointType, _hardpointFilter.type.ToString(), StringComparison.Ordinal))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
return _behaviorFilters.All(filter => HasTypedBehavior(typedItem, filter));
|
2026-06-13 23:36:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeCatalogItem FindTypedTradeItem(ItemInstance item)
|
|
|
|
|
{
|
2026-06-15 00:49:54 +01:00
|
|
|
return ActionGameManager.RuntimeCatalog?.FindItem(item?.ItemKey ?? "");
|
2026-06-13 23:36:21 +01:00
|
|
|
}
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-21 20:17:54 +01:00
|
|
|
private AetheriaRuntimeTradeItemProjection ProjectTradeItem(ItemInstance item)
|
2026-06-21 20:12:50 +01:00
|
|
|
{
|
|
|
|
|
var typedItem = FindTypedTradeItem(item);
|
|
|
|
|
return AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem(
|
|
|
|
|
typedItem,
|
|
|
|
|
ProjectTradeItemCommit(item),
|
2026-06-21 20:17:54 +01:00
|
|
|
GameManager.ObservedTradeValueSettings());
|
2026-06-21 20:12:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeLoadoutItemCommit? ProjectTradeItemCommit(ItemInstance item)
|
|
|
|
|
{
|
|
|
|
|
if (item is not CraftedItemInstance crafted)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var durability = item is EquippableItem equippable ? equippable.Durability : 1f;
|
|
|
|
|
return AetheriaRuntimeDaemonTradeItemQueries.CraftedItemCommit(
|
|
|
|
|
item.ItemKey,
|
|
|
|
|
crafted.Quality,
|
|
|
|
|
durability);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 10:17:33 +01:00
|
|
|
private static double GetTypedBehaviorNumber(TradeRow row, BehaviorFilter behaviorFilter, AetheriaRuntimeBehaviorFieldMetadata field)
|
2026-06-14 04:13:52 +01:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
var payload = FindTypedBehaviorPayload(row.TypedItem, behaviorFilter);
|
2026-06-14 10:17:33 +01:00
|
|
|
var payloadField = payload?.Fields.FirstOrDefault(candidate => candidate.Key == field.Key);
|
2026-06-14 04:13:52 +01:00
|
|
|
if (payloadField == null)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 10:17:33 +01:00
|
|
|
if (field.ValueKind == AetheriaRuntimeBehaviorFieldValueKind.PerformanceStat)
|
2026-06-14 04:13:52 +01:00
|
|
|
{
|
|
|
|
|
return payloadField.Value.Children.Count > 1
|
|
|
|
|
? payloadField.Value.Children[1].NumberValue
|
|
|
|
|
: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return payloadField.Value.NumberValue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
private static AetheriaRuntimeBehaviorPayload FindTypedBehaviorPayload(AetheriaRuntimeCatalogItem typedItem, BehaviorFilter behaviorFilter)
|
2026-06-14 04:13:52 +01:00
|
|
|
{
|
|
|
|
|
if (typedItem == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
return typedItem.BehaviorPayloads.FirstOrDefault(payload => TypedBehaviorMatches(payload, behaviorFilter));
|
2026-06-14 04:13:52 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
private static bool HasTypedBehavior(AetheriaRuntimeCatalogItem typedItem, BehaviorFilter behaviorFilter)
|
2026-06-14 04:13:52 +01:00
|
|
|
{
|
2026-06-14 08:59:33 +01:00
|
|
|
return typedItem?.BehaviorPayloads.Any(payload => TypedBehaviorMatches(payload, behaviorFilter)) ?? false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool TypedBehaviorMatches(AetheriaRuntimeBehaviorPayload payload, BehaviorFilter behaviorFilter)
|
|
|
|
|
{
|
2026-06-14 10:17:33 +01:00
|
|
|
return AetheriaRuntimeBehaviorMetadataCatalog.IsKindOrDescendant(payload.Kind, behaviorFilter.Kind);
|
2026-06-14 04:13:52 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-14 08:59:33 +01:00
|
|
|
private sealed class BehaviorFilter
|
|
|
|
|
{
|
2026-06-14 10:17:33 +01:00
|
|
|
public BehaviorFilter(ItemFilter filter, AetheriaRuntimeBehaviorMetadata metadata)
|
2026-06-14 08:59:33 +01:00
|
|
|
{
|
|
|
|
|
Filter = filter ?? throw new ArgumentNullException(nameof(filter));
|
2026-06-14 10:17:33 +01:00
|
|
|
Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
|
2026-06-14 08:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ItemFilter Filter { get; }
|
2026-06-14 10:17:33 +01:00
|
|
|
public AetheriaRuntimeBehaviorMetadata Metadata { get; }
|
|
|
|
|
public string Kind => Metadata.Kind;
|
2026-06-14 08:59:33 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-14 02:19:14 +01:00
|
|
|
private sealed class TradeRow
|
|
|
|
|
{
|
2026-06-21 20:12:50 +01:00
|
|
|
public TradeRow(
|
|
|
|
|
ItemInstance item,
|
|
|
|
|
AetheriaRuntimeCatalogItem typedItem,
|
|
|
|
|
AetheriaRuntimeTradeItemProjection tradeProjection)
|
2026-06-14 02:19:14 +01:00
|
|
|
{
|
|
|
|
|
Item = item;
|
|
|
|
|
TypedItem = typedItem;
|
2026-06-21 20:12:50 +01:00
|
|
|
TradeProjection = tradeProjection;
|
2026-06-14 02:19:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ItemInstance Item { get; }
|
|
|
|
|
|
|
|
|
|
public AetheriaRuntimeCatalogItem TypedItem { get; }
|
|
|
|
|
|
2026-06-21 20:12:50 +01:00
|
|
|
public AetheriaRuntimeTradeItemProjection TradeProjection { get; }
|
|
|
|
|
|
2026-06-14 23:09:49 +01:00
|
|
|
public string ItemKey => Item?.ItemKey ?? "";
|
|
|
|
|
|
2026-06-14 03:52:20 +01:00
|
|
|
public string Name => !string.IsNullOrWhiteSpace(TypedItem?.Name) ? TypedItem.Name : "Unknown Item";
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-14 03:52:20 +01:00
|
|
|
public float Mass => TypedItem != null ? (float)TypedItem.Mass : 0f;
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-21 20:12:50 +01:00
|
|
|
public int Price => TradeProjection.Price;
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-21 20:12:50 +01:00
|
|
|
public string TierColorHex => TradeProjection.TierColorHex;
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-14 03:52:20 +01:00
|
|
|
public int ShapeWidth => TypedItem != null && TypedItem.ShapeWidth > 0 ? TypedItem.ShapeWidth : 0;
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-14 03:52:20 +01:00
|
|
|
public int ShapeHeight => TypedItem != null && TypedItem.ShapeHeight > 0 ? TypedItem.ShapeHeight : 0;
|
2026-06-14 02:19:14 +01:00
|
|
|
|
2026-06-14 03:52:20 +01:00
|
|
|
public bool IsHull => !string.IsNullOrWhiteSpace(TypedItem?.HullType);
|
|
|
|
|
|
|
|
|
|
public bool TryGetTypedSimpleCommodityCategory(out SimpleCommodityCategory category)
|
|
|
|
|
{
|
|
|
|
|
category = SimpleCommodityCategory.Minerals;
|
|
|
|
|
return !string.IsNullOrWhiteSpace(TypedItem?.SimpleCommodityCategory) &&
|
|
|
|
|
Enum.TryParse(TypedItem.SimpleCommodityCategory, true, out category);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool TryGetTypedCompoundCommodityCategory(out CompoundCommodityCategory category)
|
|
|
|
|
{
|
|
|
|
|
category = CompoundCommodityCategory.Wearables;
|
|
|
|
|
return !string.IsNullOrWhiteSpace(TypedItem?.CompoundCommodityCategory) &&
|
|
|
|
|
Enum.TryParse(TypedItem.CompoundCommodityCategory, true, out category);
|
|
|
|
|
}
|
2026-06-14 02:19:14 +01:00
|
|
|
|
|
|
|
|
public bool TryGetTypedHardpoint(out HardpointType hardpointType)
|
|
|
|
|
{
|
|
|
|
|
hardpointType = HardpointType.Hull;
|
|
|
|
|
return !string.IsNullOrWhiteSpace(TypedItem?.HardpointType) &&
|
|
|
|
|
Enum.TryParse(TypedItem.HardpointType, true, out hardpointType);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-18 00:21:33 +01:00
|
|
|
|
|
|
|
|
private void UpdateCreditsLabel()
|
|
|
|
|
{
|
|
|
|
|
if (CreditsLabel != null)
|
|
|
|
|
{
|
|
|
|
|
CreditsLabel.text = GameManager.Credits.ToString("N0");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-14 03:20:27 +00:00
|
|
|
|
2021-03-20 04:20:17 +00:00
|
|
|
private void Buy(CraftedItemInstance item)
|
2021-01-19 01:22:56 +00:00
|
|
|
{
|
2026-06-14 04:02:54 +01:00
|
|
|
var typedItem = FindTypedTradeItem(item);
|
|
|
|
|
if (typedItem == null)
|
|
|
|
|
{
|
|
|
|
|
ShowUnableToBuy("Missing typed trade row!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var price = GetTypedTradePrice(item, typedItem);
|
2026-06-16 02:57:45 +01:00
|
|
|
var isShipHull = !string.IsNullOrWhiteSpace(typedItem?.HullType);
|
|
|
|
|
if (isShipHull &&
|
|
|
|
|
!string.Equals(typedItem.HullType, nameof(HullType.Ship), StringComparison.Ordinal))
|
2021-01-19 01:22:56 +00:00
|
|
|
{
|
2026-06-16 02:57:45 +01:00
|
|
|
ShowUnableToBuy("Unsupported hull purchase!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-07-18 00:21:33 +01:00
|
|
|
|
2026-06-21 13:51:26 +01:00
|
|
|
GameManager.RequestTradePurchase(Inventory, _targetCargo, item, price, isShipHull);
|
2026-06-16 02:57:45 +01:00
|
|
|
|
2021-01-19 01:22:56 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-20 04:20:17 +00:00
|
|
|
private void Buy(SimpleCommodity simpleCommodity, int quantity)
|
2021-01-19 01:22:56 +00:00
|
|
|
{
|
2026-06-14 04:02:54 +01:00
|
|
|
var typedItem = FindTypedTradeItem(simpleCommodity);
|
|
|
|
|
if (typedItem == null)
|
|
|
|
|
{
|
|
|
|
|
ShowUnableToBuy("Missing typed trade row!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var price = typedItem.Price;
|
2026-06-21 13:51:26 +01:00
|
|
|
GameManager.RequestTradePurchase(Inventory, _targetCargo, simpleCommodity, quantity, price);
|
2026-06-16 02:57:45 +01:00
|
|
|
|
2021-01-19 01:22:56 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-14 04:02:54 +01:00
|
|
|
private int GetTypedTradePrice(CraftedItemInstance item, AetheriaRuntimeCatalogItem typedItem)
|
|
|
|
|
{
|
2026-06-21 20:12:50 +01:00
|
|
|
return AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem(
|
|
|
|
|
typedItem,
|
|
|
|
|
ProjectTradeItemCommit(item),
|
2026-06-21 20:17:54 +01:00
|
|
|
GameManager.ObservedTradeValueSettings()).Price;
|
2026-06-14 04:02:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ShowUnableToBuy(string reason)
|
|
|
|
|
{
|
|
|
|
|
Dialog.Clear();
|
|
|
|
|
Dialog.Title.text = $"Unable to buy: {reason}";
|
|
|
|
|
Dialog.Show();
|
|
|
|
|
Dialog.MoveToCursor();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 22:24:48 +01:00
|
|
|
private void ShowBuyQuantityDialog(string itemName, int price, SimpleCommodity simpleCommodity)
|
|
|
|
|
{
|
|
|
|
|
int quantity = 1;
|
|
|
|
|
Dialog.Clear();
|
|
|
|
|
Dialog.Title.text = $"Buying {itemName}";
|
|
|
|
|
Dialog.AddField(
|
|
|
|
|
"Quantity",
|
|
|
|
|
() => quantity,
|
2026-06-21 13:16:34 +01:00
|
|
|
q => quantity = q);
|
2026-06-16 22:24:48 +01:00
|
|
|
Dialog.Show(() =>
|
|
|
|
|
{
|
|
|
|
|
Buy(simpleCommodity, quantity);
|
|
|
|
|
Populate();
|
|
|
|
|
});
|
|
|
|
|
Dialog.MoveToCursor();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 23:09:42 +01:00
|
|
|
private void RenderTradeItemDetailsSurface(AetheriaRuntimeCatalogItem item)
|
|
|
|
|
{
|
|
|
|
|
if (item == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
_tradeItemSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
|
|
|
|
|
transform,
|
|
|
|
|
_tradeItemSurfaceDocument,
|
|
|
|
|
"Aetheria Trade Item Details Surface",
|
|
|
|
|
AetheriaRuntimeTradeItemDetailsSurfaceBuilder.Build(ProjectTradeItemDetailsSurfaceState(item)),
|
|
|
|
|
HandleTradeItemDetailsSurfaceCommand,
|
|
|
|
|
_tradeItemSurfaceChrome,
|
|
|
|
|
sortingOrder: 1003);
|
2026-06-16 23:09:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleTradeItemDetailsSurfaceCommand(EveSurfaceCommandRequest request)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
if (!AetheriaRuntimeTradeItemDetailsSurfaceCommands.TryRead(request, out var command))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"Unknown trade item details command: {request?.Command}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.Kind == AetheriaRuntimeTradeItemDetailsCommandKind.Close)
|
2026-06-16 23:09:42 +01:00
|
|
|
{
|
|
|
|
|
HideTradeItemDetailsSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
Debug.LogWarning($"Unknown trade item details command: {request?.Command}");
|
2026-06-16 23:09:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HideTradeItemDetailsSurface()
|
|
|
|
|
{
|
|
|
|
|
if (_tradeItemSurfaceDocument == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.Hide(_tradeItemSurfaceDocument);
|
2026-06-16 23:09:42 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private AetheriaRuntimeTradeItemDetailsSurfaceState ProjectTradeItemDetailsSurfaceState(AetheriaRuntimeCatalogItem item)
|
2026-06-16 23:09:42 +01:00
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
var durability = "";
|
|
|
|
|
var thermalRange = "";
|
|
|
|
|
var behaviorSections = Array.Empty<AetheriaRuntimeTradeItemSection>();
|
2026-06-16 23:09:42 +01:00
|
|
|
if (!string.IsNullOrWhiteSpace(item.HardpointType))
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
durability = ActionGameManager.RuntimePlayerSettings.Format((float)item.Durability);
|
|
|
|
|
thermalRange = FormatTemperatureRange(item);
|
|
|
|
|
behaviorSections = ProjectTradeItemBehaviorSections(item).ToArray();
|
2026-06-16 23:09:42 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
return new AetheriaRuntimeTradeItemDetailsSurfaceState(
|
|
|
|
|
item.Name,
|
|
|
|
|
item.Description ?? "",
|
|
|
|
|
ActionGameManager.RuntimeCatalog?.GetManufacturer(item)?.Name ?? "GameCult",
|
|
|
|
|
ActionGameManager.RuntimePlayerSettings.Format((float)item.Mass),
|
|
|
|
|
item.Price,
|
|
|
|
|
durability,
|
|
|
|
|
thermalRange,
|
|
|
|
|
behaviorSections,
|
|
|
|
|
DateTime.UtcNow.ToString("O"));
|
2026-06-16 23:09:42 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private IEnumerable<AetheriaRuntimeTradeItemSection> ProjectTradeItemBehaviorSections(AetheriaRuntimeCatalogItem item)
|
2026-06-16 23:09:42 +01:00
|
|
|
{
|
|
|
|
|
foreach (var behavior in item.BehaviorPayloads ?? Array.Empty<AetheriaRuntimeBehaviorPayload>())
|
|
|
|
|
{
|
|
|
|
|
if (string.Equals(behavior.Kind, AetheriaRuntimeBehaviorKinds.StatModifier, StringComparison.Ordinal))
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
var statReference = AetheriaRuntimeBehaviorValueReader.ReadStatReference(FindTypedBehaviorField(behavior, 1)?.Value);
|
|
|
|
|
var modifier = AetheriaRuntimeBehaviorValueReader.ReadPerformanceStat(FindTypedBehaviorField(behavior, 2)?.Value);
|
|
|
|
|
var modifierType = AetheriaRuntimeBehaviorValueReader.ReadEnum(
|
|
|
|
|
FindTypedBehaviorField(behavior, 3)?.Value,
|
|
|
|
|
StatModifierType.Constant);
|
|
|
|
|
yield return new AetheriaRuntimeTradeItemSection(
|
|
|
|
|
$"{AetheriaRuntimeTradeItemDetailsSurfaceBuilder.SurfaceId}.behavior.{behavior.Kind}.stat_modifier",
|
2026-06-16 23:09:42 +01:00
|
|
|
"Stat Modifier",
|
2026-06-21 09:37:54 +01:00
|
|
|
new[]
|
|
|
|
|
{
|
|
|
|
|
new AetheriaRuntimeTradeItemMetric(
|
|
|
|
|
$"{AetheriaRuntimeTradeItemDetailsSurfaceBuilder.SurfaceId}.behavior.{behavior.Kind}.target",
|
|
|
|
|
$"{statReference.Target.SplitCamelCase()}:{statReference.Stat.SplitCamelCase()}",
|
|
|
|
|
$"{(modifierType == StatModifierType.Constant ? "+" : "x")}{ActionGameManager.RuntimePlayerSettings.Format(modifier.Min)}")
|
|
|
|
|
});
|
2026-06-16 23:09:42 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var metadata = AetheriaRuntimeBehaviorMetadataCatalog.Get(behavior.Kind);
|
|
|
|
|
if (metadata == null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var fields = metadata.DisplayFields
|
2026-06-21 09:37:54 +01:00
|
|
|
.Select(field => ProjectTradeItemBehaviorMetric(behavior, field))
|
2026-06-16 23:09:42 +01:00
|
|
|
.Where(metric => metric != null)
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
if (fields.Length == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
yield return new AetheriaRuntimeTradeItemSection(
|
|
|
|
|
$"{AetheriaRuntimeTradeItemDetailsSurfaceBuilder.SurfaceId}.behavior.{behavior.Kind}",
|
2026-06-16 23:09:42 +01:00
|
|
|
behavior.Kind.FormatTypeName(),
|
|
|
|
|
fields);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private AetheriaRuntimeTradeItemMetric ProjectTradeItemBehaviorMetric(
|
2026-06-16 23:09:42 +01:00
|
|
|
AetheriaRuntimeBehaviorPayload behavior,
|
|
|
|
|
AetheriaRuntimeBehaviorFieldMetadata field)
|
|
|
|
|
{
|
|
|
|
|
var payloadField = FindTypedBehaviorField(behavior, field.Key);
|
|
|
|
|
if (payloadField == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
string value;
|
|
|
|
|
switch (field.ValueKind)
|
|
|
|
|
{
|
|
|
|
|
case AetheriaRuntimeBehaviorFieldValueKind.Number:
|
|
|
|
|
value = ActionGameManager.RuntimePlayerSettings.Format((float)payloadField.Value.NumberValue);
|
|
|
|
|
break;
|
|
|
|
|
case AetheriaRuntimeBehaviorFieldValueKind.Temperature:
|
|
|
|
|
value = ActionGameManager.RuntimePlayerSettings.FormatTemperature((float)payloadField.Value.NumberValue);
|
|
|
|
|
break;
|
|
|
|
|
case AetheriaRuntimeBehaviorFieldValueKind.Integer:
|
|
|
|
|
value = ((int)payloadField.Value.NumberValue).ToString();
|
|
|
|
|
break;
|
|
|
|
|
case AetheriaRuntimeBehaviorFieldValueKind.PerformanceStat:
|
2026-06-21 09:37:54 +01:00
|
|
|
value = ActionGameManager.RuntimePlayerSettings.Format(AetheriaRuntimeBehaviorValueReader.ReadPerformanceStat(payloadField.Value).Min);
|
2026-06-16 23:09:42 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
return new AetheriaRuntimeTradeItemMetric(
|
|
|
|
|
$"{AetheriaRuntimeTradeItemDetailsSurfaceBuilder.SurfaceId}.behavior.{behavior.Kind}.{field.Key}",
|
2026-06-16 23:09:42 +01:00
|
|
|
field.Name.SplitCamelCase(),
|
|
|
|
|
value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string FormatTemperatureRange(AetheriaRuntimeCatalogItem item)
|
|
|
|
|
{
|
|
|
|
|
if (item.MaximumTemperature > item.MinimumTemperature)
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
$"{ActionGameManager.RuntimePlayerSettings.FormatTemperature((float)item.MinimumTemperature)} to " +
|
|
|
|
|
$"{ActionGameManager.RuntimePlayerSettings.FormatTemperature((float)item.MaximumTemperature)}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "No typed thermal range";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static AetheriaRuntimeBehaviorField FindTypedBehaviorField(AetheriaRuntimeBehaviorPayload behavior, int? key)
|
|
|
|
|
{
|
|
|
|
|
return key == null
|
|
|
|
|
? null
|
|
|
|
|
: behavior.Fields.FirstOrDefault(field => field.Key == key.Value);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 03:20:27 +00:00
|
|
|
void Start()
|
|
|
|
|
{
|
2021-01-14 23:47:08 +00:00
|
|
|
FoldoutButton.onClick.AddListener(() =>
|
|
|
|
|
{
|
2026-06-16 21:45:56 +01:00
|
|
|
RenderCargoSelectorSurface();
|
2021-01-14 23:47:08 +00:00
|
|
|
});
|
2021-01-14 03:20:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2026-06-16 21:45:56 +01:00
|
|
|
|
2026-06-16 22:24:48 +01:00
|
|
|
private void RenderFilterSurface()
|
|
|
|
|
{
|
2026-06-21 21:32:57 +01:00
|
|
|
_filterSurfaceProjection = ProjectTradeFilterSurface();
|
2026-06-16 22:24:48 +01:00
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
_filterSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
|
|
|
|
|
transform,
|
|
|
|
|
_filterSurfaceDocument,
|
|
|
|
|
"Aetheria Trade Filter Surface",
|
2026-06-21 21:32:57 +01:00
|
|
|
AetheriaRuntimeTradeInteractionSurfaceBuilder.BuildFilter(_filterSurfaceProjection.State),
|
2026-06-21 09:37:54 +01:00
|
|
|
HandleFilterSurfaceCommand,
|
|
|
|
|
_filterSurfaceChrome,
|
|
|
|
|
sortingOrder: 1001);
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleFilterSurfaceCommand(EveSurfaceCommandRequest request)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
if (!AetheriaRuntimeTradeInteractionSurfaceCommands.TryReadFilter(request, out var command))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"Unknown trade filter command: {request?.Command}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.Kind == AetheriaRuntimeTradeInteractionCommandKind.Close)
|
2026-06-16 22:24:48 +01:00
|
|
|
{
|
|
|
|
|
HideFilterSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
if (command.Kind == AetheriaRuntimeTradeInteractionCommandKind.Select &&
|
2026-06-21 21:32:57 +01:00
|
|
|
_filterSurfaceProjection?.TryResolve(command.Command, out var selection) == true)
|
2026-06-16 22:24:48 +01:00
|
|
|
{
|
2026-06-21 21:32:57 +01:00
|
|
|
ExecuteTradeFilterSelection(selection);
|
2026-06-16 22:24:48 +01:00
|
|
|
HideFilterSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
Debug.LogWarning($"Unknown trade filter command: {request?.Command}");
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HideFilterSurface()
|
|
|
|
|
{
|
|
|
|
|
if (_filterSurfaceDocument == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.Hide(_filterSurfaceDocument);
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 21:32:57 +01:00
|
|
|
private AetheriaRuntimeTradeFilterSurfaceProjection ProjectTradeFilterSurface()
|
|
|
|
|
{
|
|
|
|
|
var options = new List<AetheriaRuntimeTradeFilterOption>();
|
|
|
|
|
options.AddRange(((HardpointType[])Enum.GetValues(typeof(HardpointType)))
|
|
|
|
|
.Where(type => _hardpointFilter.filter == null || type != _hardpointFilter.type)
|
|
|
|
|
.Select(type => new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.Hardpoint,
|
|
|
|
|
type.ToString(),
|
|
|
|
|
type.ToString().FormatTypeName())));
|
|
|
|
|
options.AddRange(((SimpleCommodityCategory[])Enum.GetValues(typeof(SimpleCommodityCategory)))
|
|
|
|
|
.Where(type => _commodityFilter.filter == null || type != _commodityFilter.type)
|
|
|
|
|
.Select(type => new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.SimpleCommodity,
|
|
|
|
|
type.ToString(),
|
|
|
|
|
type.ToString().FormatTypeName())));
|
|
|
|
|
options.AddRange(((CompoundCommodityCategory[])Enum.GetValues(typeof(CompoundCommodityCategory)))
|
|
|
|
|
.Where(type => _compoundCommodityFilter.filter == null || type != _compoundCommodityFilter.type)
|
|
|
|
|
.Select(type => new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.CompoundCommodity,
|
|
|
|
|
type.ToString(),
|
|
|
|
|
type.ToString().FormatTypeName())));
|
|
|
|
|
options.AddRange(AetheriaRuntimeBehaviorMetadataCatalog.All
|
|
|
|
|
.Where(option => _behaviorFilters.All(filter => filter.Kind != option.Kind))
|
|
|
|
|
.OrderBy(option => option.Kind, StringComparer.Ordinal)
|
|
|
|
|
.Select(option => new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.Behavior,
|
|
|
|
|
option.Kind,
|
|
|
|
|
option.Kind.FormatTypeName())));
|
2026-06-16 22:24:48 +01:00
|
|
|
|
2026-06-21 21:32:57 +01:00
|
|
|
if (!MinimumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
{
|
|
|
|
|
options.Add(new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.MinimumSize,
|
|
|
|
|
"minimum",
|
|
|
|
|
"Minimum Size"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!MaximumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
{
|
|
|
|
|
options.Add(new AetheriaRuntimeTradeFilterOption(
|
|
|
|
|
AetheriaRuntimeTradeFilterSelectionKind.MaximumSize,
|
|
|
|
|
"maximum",
|
|
|
|
|
"Maximum Size"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AetheriaRuntimeTradeInteractionSurfaceBuilder.ProjectFilters(
|
2026-06-21 09:37:54 +01:00
|
|
|
BuildFilterSummary(),
|
2026-06-21 21:32:57 +01:00
|
|
|
options,
|
2026-06-21 09:37:54 +01:00
|
|
|
DateTime.UtcNow.ToString("O"));
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 21:32:57 +01:00
|
|
|
private void ExecuteTradeFilterSelection(AetheriaRuntimeTradeFilterSelection selection)
|
|
|
|
|
{
|
|
|
|
|
switch (selection.Kind)
|
|
|
|
|
{
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.Hardpoint:
|
|
|
|
|
if (Enum.TryParse(selection.Token, out HardpointType hardpointType))
|
|
|
|
|
{
|
|
|
|
|
ApplyHardpointFilter(hardpointType);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.SimpleCommodity:
|
|
|
|
|
if (Enum.TryParse(selection.Token, out SimpleCommodityCategory simpleCategory))
|
|
|
|
|
{
|
|
|
|
|
ApplySimpleCommodityFilter(simpleCategory);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.CompoundCommodity:
|
|
|
|
|
if (Enum.TryParse(selection.Token, out CompoundCommodityCategory compoundCategory))
|
|
|
|
|
{
|
|
|
|
|
ApplyCompoundCommodityFilter(compoundCategory);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.Behavior:
|
|
|
|
|
var metadata = AetheriaRuntimeBehaviorMetadataCatalog.All
|
|
|
|
|
.FirstOrDefault(option => string.Equals(option.Kind, selection.Token, StringComparison.Ordinal));
|
|
|
|
|
if (metadata != null)
|
|
|
|
|
{
|
|
|
|
|
ApplyBehaviorFilter(metadata);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.MinimumSize:
|
|
|
|
|
EnableMinimumSizeFilter();
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeFilterSelectionKind.MaximumSize:
|
|
|
|
|
EnableMaximumSizeFilter();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RenderRowActionSurface(string title, params (string Label, Action Action)[] actions)
|
|
|
|
|
{
|
2026-06-21 21:28:39 +01:00
|
|
|
_rowActionCallbacks = actions
|
|
|
|
|
.Select(action => action.Action)
|
|
|
|
|
.ToArray();
|
|
|
|
|
_rowActionSurfaceProjection = AetheriaRuntimeTradeInteractionSurfaceBuilder.ProjectRowActions(
|
|
|
|
|
title,
|
|
|
|
|
actions.Select((action, index) => new AetheriaRuntimeTradeRowActionOption(index, action.Label)),
|
|
|
|
|
DateTime.UtcNow.ToString("O"));
|
2026-06-16 22:24:48 +01:00
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
_rowActionSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
|
|
|
|
|
transform,
|
|
|
|
|
_rowActionSurfaceDocument,
|
|
|
|
|
"Aetheria Trade Row Action Surface",
|
2026-06-21 21:28:39 +01:00
|
|
|
AetheriaRuntimeTradeInteractionSurfaceBuilder.BuildRowActions(_rowActionSurfaceProjection.State),
|
2026-06-21 09:37:54 +01:00
|
|
|
HandleRowActionSurfaceCommand,
|
|
|
|
|
_rowActionSurfaceChrome,
|
|
|
|
|
sortingOrder: 1002);
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleRowActionSurfaceCommand(EveSurfaceCommandRequest request)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
if (!AetheriaRuntimeTradeInteractionSurfaceCommands.TryReadRowAction(request, out var command))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"Unknown trade row action command: {request?.Command}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.Kind == AetheriaRuntimeTradeInteractionCommandKind.Close)
|
2026-06-16 22:24:48 +01:00
|
|
|
{
|
|
|
|
|
HideRowActionSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
if (command.Kind == AetheriaRuntimeTradeInteractionCommandKind.Select &&
|
2026-06-21 21:28:39 +01:00
|
|
|
_rowActionSurfaceProjection?.TryResolve(command.Command, out var selection) == true &&
|
|
|
|
|
selection.Index >= 0 &&
|
|
|
|
|
selection.Index < _rowActionCallbacks.Length)
|
2026-06-16 22:24:48 +01:00
|
|
|
{
|
2026-06-21 21:28:39 +01:00
|
|
|
_rowActionCallbacks[selection.Index]?.Invoke();
|
2026-06-16 22:24:48 +01:00
|
|
|
HideRowActionSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
Debug.LogWarning($"Unknown trade row action command: {request?.Command}");
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HideRowActionSurface()
|
|
|
|
|
{
|
|
|
|
|
if (_rowActionSurfaceDocument == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.Hide(_rowActionSurfaceDocument);
|
2026-06-16 22:24:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyHardpointFilter(HardpointType hardpointType)
|
|
|
|
|
{
|
|
|
|
|
EnsureHardpointFilter();
|
|
|
|
|
ClearCommodityFilters();
|
|
|
|
|
_hardpointFilter.filter.Label.text = $"Hardpoint: {Enum.GetName(typeof(HardpointType), hardpointType)}";
|
|
|
|
|
_hardpointFilter.type = hardpointType;
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplySimpleCommodityFilter(SimpleCommodityCategory category)
|
|
|
|
|
{
|
|
|
|
|
EnsureCommodityFilter();
|
|
|
|
|
ClearHardpointFilter();
|
|
|
|
|
ClearCompoundCommodityFilter();
|
|
|
|
|
_commodityFilter.filter.Label.text = $"Simple Commodity: {Enum.GetName(typeof(SimpleCommodityCategory), category)}";
|
|
|
|
|
_commodityFilter.type = category;
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyCompoundCommodityFilter(CompoundCommodityCategory category)
|
|
|
|
|
{
|
|
|
|
|
EnsureCompoundCommodityFilter();
|
|
|
|
|
ClearHardpointFilter();
|
|
|
|
|
ClearCommodityFilter();
|
|
|
|
|
_compoundCommodityFilter.filter.Label.text = $"Compound Commodity: {Enum.GetName(typeof(CompoundCommodityCategory), category)}";
|
|
|
|
|
_compoundCommodityFilter.type = category;
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyBehaviorFilter(AetheriaRuntimeBehaviorMetadata metadata)
|
|
|
|
|
{
|
|
|
|
|
var matchingType = _behaviorFilters.FirstOrDefault(filter =>
|
|
|
|
|
AetheriaRuntimeBehaviorMetadataCatalog.IsKindOrDescendant(filter.Kind, metadata.Kind) ||
|
|
|
|
|
AetheriaRuntimeBehaviorMetadataCatalog.IsKindOrDescendant(metadata.Kind, filter.Kind));
|
|
|
|
|
if (matchingType?.Filter != null)
|
|
|
|
|
{
|
|
|
|
|
matchingType.Filter.DisableButton.onClick.Invoke();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var filter = FilterPrototype.Instantiate<ItemFilter>();
|
|
|
|
|
filter.Label.text = metadata.Kind.FormatTypeName();
|
|
|
|
|
var behaviorFilter = new BehaviorFilter(filter, metadata);
|
|
|
|
|
filter.OnDisable += () =>
|
|
|
|
|
{
|
|
|
|
|
_behaviorFilters.Remove(behaviorFilter);
|
|
|
|
|
Populate();
|
|
|
|
|
};
|
|
|
|
|
_behaviorFilters.Add(behaviorFilter);
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnableMinimumSizeFilter()
|
|
|
|
|
{
|
|
|
|
|
MinimumSizeFilter.gameObject.SetActive(true);
|
|
|
|
|
MinimumSizeFilter.OnDisable += () => Populate();
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnableMaximumSizeFilter()
|
|
|
|
|
{
|
|
|
|
|
MaximumSizeFilter.gameObject.SetActive(true);
|
|
|
|
|
MaximumSizeFilter.OnDisable += () => Populate();
|
|
|
|
|
Populate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureHardpointFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_hardpointFilter.filter != null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_hardpointFilter.filter = FilterPrototype.Instantiate<ItemFilter>();
|
|
|
|
|
_hardpointFilter.filter.OnDisable += () =>
|
|
|
|
|
{
|
|
|
|
|
_hardpointFilter.filter = null;
|
|
|
|
|
Populate();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureCommodityFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_commodityFilter.filter != null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_commodityFilter.filter = FilterPrototype.Instantiate<ItemFilter>();
|
|
|
|
|
_commodityFilter.filter.OnDisable += () =>
|
|
|
|
|
{
|
|
|
|
|
_commodityFilter.filter = null;
|
|
|
|
|
Populate();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureCompoundCommodityFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_compoundCommodityFilter.filter != null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_compoundCommodityFilter.filter = FilterPrototype.Instantiate<ItemFilter>();
|
|
|
|
|
_compoundCommodityFilter.filter.OnDisable += () =>
|
|
|
|
|
{
|
|
|
|
|
_compoundCommodityFilter.filter = null;
|
|
|
|
|
Populate();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ClearHardpointFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_hardpointFilter.filter == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_hardpointFilter.filter.GetComponent<Prototype>().ReturnToPool();
|
|
|
|
|
_hardpointFilter.filter = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ClearCommodityFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_commodityFilter.filter == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_commodityFilter.filter.GetComponent<Prototype>().ReturnToPool();
|
|
|
|
|
_commodityFilter.filter = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ClearCompoundCommodityFilter()
|
|
|
|
|
{
|
|
|
|
|
if (_compoundCommodityFilter.filter == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_compoundCommodityFilter.filter.GetComponent<Prototype>().ReturnToPool();
|
|
|
|
|
_compoundCommodityFilter.filter = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ClearCommodityFilters()
|
|
|
|
|
{
|
|
|
|
|
ClearCommodityFilter();
|
|
|
|
|
ClearCompoundCommodityFilter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string BuildFilterSummary()
|
|
|
|
|
{
|
|
|
|
|
var activeFilters = new List<string>();
|
|
|
|
|
if (_hardpointFilter.filter != null)
|
|
|
|
|
{
|
|
|
|
|
activeFilters.Add($"Gear: {Enum.GetName(typeof(HardpointType), _hardpointFilter.type)}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_commodityFilter.filter != null)
|
|
|
|
|
{
|
|
|
|
|
activeFilters.Add($"Simple: {Enum.GetName(typeof(SimpleCommodityCategory), _commodityFilter.type)}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_compoundCommodityFilter.filter != null)
|
|
|
|
|
{
|
|
|
|
|
activeFilters.Add($"Compound: {Enum.GetName(typeof(CompoundCommodityCategory), _compoundCommodityFilter.type)}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
activeFilters.AddRange(_behaviorFilters.Select(filter => $"Behavior: {filter.Kind.FormatTypeName()}"));
|
|
|
|
|
|
|
|
|
|
if (MinimumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
{
|
|
|
|
|
activeFilters.Add("Minimum size active");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MaximumSizeFilter.gameObject.activeSelf)
|
|
|
|
|
{
|
|
|
|
|
activeFilters.Add("Maximum size active");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return activeFilters.Count == 0
|
|
|
|
|
? "No active filters"
|
|
|
|
|
: string.Join(" | ", activeFilters);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-16 21:45:56 +01:00
|
|
|
private void RenderCargoSelectorSurface()
|
|
|
|
|
{
|
2026-06-21 21:36:35 +01:00
|
|
|
_cargoSelectorSurfaceProjection = ProjectTradeCargoSelectorSurface();
|
2026-06-16 21:45:56 +01:00
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
_cargoSelectorSurfaceDocument = AetheriaEveUnitySurfaceHost.RenderRuntime(
|
|
|
|
|
transform,
|
|
|
|
|
_cargoSelectorSurfaceDocument,
|
|
|
|
|
"Aetheria Trade Cargo Selector Surface",
|
2026-06-21 21:36:35 +01:00
|
|
|
AetheriaRuntimeTradeCargoSelectorSurfaceBuilder.Build(_cargoSelectorSurfaceProjection.State),
|
2026-06-21 09:37:54 +01:00
|
|
|
HandleCargoSelectorSurfaceCommand,
|
|
|
|
|
_cargoSelectorSurfaceChrome);
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleCargoSelectorSurfaceCommand(EveSurfaceCommandRequest request)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
if (!AetheriaRuntimeTradeCargoSelectorSurfaceCommands.TryRead(request, out var command))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"Unknown trade cargo selector command: {request?.Command}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.Kind == AetheriaRuntimeTradeCargoSelectorCommandKind.Close)
|
2026-06-16 21:45:56 +01:00
|
|
|
{
|
|
|
|
|
HideCargoSelectorSurface();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
if (command.Kind == AetheriaRuntimeTradeCargoSelectorCommandKind.Select &&
|
2026-06-21 21:36:35 +01:00
|
|
|
_cargoSelectorSurfaceProjection?.TryResolve(command.Command, out var selection) == true)
|
2026-06-16 21:45:56 +01:00
|
|
|
{
|
2026-06-21 21:36:35 +01:00
|
|
|
ApplyCargoSelection(selection);
|
2026-06-16 21:45:56 +01:00
|
|
|
HideCargoSelectorSurface();
|
|
|
|
|
Populate();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
Debug.LogWarning($"Unknown trade cargo selector command: {request?.Command}");
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HideCargoSelectorSurface()
|
|
|
|
|
{
|
|
|
|
|
if (_cargoSelectorSurfaceDocument == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.Hide(_cargoSelectorSurfaceDocument);
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private static AetheriaEveUnitySurfaceChrome PanelChrome(float width, float maxWidth, Align alignItems)
|
2026-06-16 21:45:56 +01:00
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
return new AetheriaEveUnitySurfaceChrome
|
|
|
|
|
{
|
|
|
|
|
RootAlignItems = alignItems,
|
|
|
|
|
RootJustifyContent = Justify.FlexStart,
|
|
|
|
|
RootPaddingTop = 16f,
|
|
|
|
|
RootPaddingLeft = alignItems == Align.FlexStart ? 16f : 0f,
|
|
|
|
|
RootPaddingRight = alignItems == Align.FlexEnd ? 16f : 0f,
|
|
|
|
|
Width = width,
|
|
|
|
|
MinWidth = 0f,
|
|
|
|
|
MaxWidth = maxWidth,
|
|
|
|
|
PaddingLeft = 18f,
|
|
|
|
|
PaddingRight = 18f,
|
|
|
|
|
PaddingTop = 18f,
|
|
|
|
|
PaddingBottom = 18f
|
|
|
|
|
};
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 21:36:35 +01:00
|
|
|
private AetheriaRuntimeTradeCargoSelectorSurfaceProjection ProjectTradeCargoSelectorSurface()
|
2026-06-16 21:45:56 +01:00
|
|
|
{
|
2026-06-21 21:36:35 +01:00
|
|
|
var targets = new List<AetheriaRuntimeTradeCargoProjectionOption>();
|
|
|
|
|
if (GameManager.TryGetObservedDockingBay(out var dockingBay))
|
|
|
|
|
{
|
|
|
|
|
targets.Add(new AetheriaRuntimeTradeCargoProjectionOption(
|
|
|
|
|
AetheriaRuntimeTradeCargoTargetKind.DockingBay,
|
|
|
|
|
"Docking Bay",
|
|
|
|
|
isCurrent: _targetCargo == dockingBay));
|
|
|
|
|
}
|
2026-06-16 21:45:56 +01:00
|
|
|
|
2026-06-21 21:36:35 +01:00
|
|
|
targets.AddRange(GameManager.ObservedAvailableEntities()
|
|
|
|
|
.OfType<Ship>()
|
|
|
|
|
.Where(ship => ship.IsPlayerShip)
|
|
|
|
|
.SelectMany((ship, shipIndex) => ship.CargoBays.Select((cargoBay, bayIndex) =>
|
|
|
|
|
new AetheriaRuntimeTradeCargoProjectionOption(
|
|
|
|
|
AetheriaRuntimeTradeCargoTargetKind.ShipBay,
|
|
|
|
|
$"{ship.Name} Bay {bayIndex + 1}",
|
|
|
|
|
shipIndex,
|
|
|
|
|
bayIndex,
|
|
|
|
|
_targetCargo == cargoBay))));
|
|
|
|
|
|
|
|
|
|
return AetheriaRuntimeTradeCargoSelectorSurfaceBuilder.Project(
|
2026-06-21 09:37:54 +01:00
|
|
|
TargetCargoLabel.text ?? "",
|
|
|
|
|
targets,
|
|
|
|
|
DateTime.UtcNow.ToString("O"));
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 21:36:35 +01:00
|
|
|
private void ApplyCargoSelection(AetheriaRuntimeTradeCargoSelection selection)
|
|
|
|
|
{
|
|
|
|
|
switch (selection.Kind)
|
|
|
|
|
{
|
|
|
|
|
case AetheriaRuntimeTradeCargoTargetKind.DockingBay:
|
|
|
|
|
if (GameManager.TryGetObservedDockingBay(out var dockingBay))
|
|
|
|
|
{
|
|
|
|
|
_targetCargo = dockingBay;
|
|
|
|
|
TargetCargoLabel.text = selection.Label;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
case AetheriaRuntimeTradeCargoTargetKind.ShipBay:
|
|
|
|
|
var ships = GameManager.ObservedAvailableEntities()
|
|
|
|
|
.OfType<Ship>()
|
|
|
|
|
.Where(ship => ship.IsPlayerShip)
|
|
|
|
|
.ToArray();
|
|
|
|
|
if (selection.ShipIndex >= 0 &&
|
|
|
|
|
selection.ShipIndex < ships.Length &&
|
|
|
|
|
selection.BayIndex >= 0 &&
|
|
|
|
|
selection.BayIndex < ships[selection.ShipIndex].CargoBays.Count)
|
|
|
|
|
{
|
|
|
|
|
_targetCargo = ships[selection.ShipIndex].CargoBays[selection.BayIndex];
|
|
|
|
|
TargetCargoLabel.text = selection.Label;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-21 18:19:42 +01:00
|
|
|
private int CountAvailablePlayerShips(string itemKey)
|
|
|
|
|
{
|
2026-06-21 19:28:00 +01:00
|
|
|
return GameManager.ObservedAvailableEntities()
|
2026-06-21 18:19:42 +01:00
|
|
|
.OfType<Ship>()
|
|
|
|
|
.Count(ship => ship.IsPlayerShip && ship.Hull?.ItemKey == itemKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDisable()
|
2026-06-16 21:45:56 +01:00
|
|
|
{
|
|
|
|
|
HideCargoSelectorSurface();
|
2026-06-16 22:24:48 +01:00
|
|
|
HideFilterSurface();
|
|
|
|
|
HideRowActionSurface();
|
2026-06-16 23:09:42 +01:00
|
|
|
HideTradeItemDetailsSurface();
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
{
|
|
|
|
|
if (_cargoSelectorSurfaceDocument != null)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.DestroyDocument(_cargoSelectorSurfaceDocument);
|
2026-06-16 21:45:56 +01:00
|
|
|
_cargoSelectorSurfaceDocument = null;
|
|
|
|
|
}
|
2026-06-16 22:24:48 +01:00
|
|
|
|
|
|
|
|
if (_filterSurfaceDocument != null)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.DestroyDocument(_filterSurfaceDocument);
|
2026-06-16 22:24:48 +01:00
|
|
|
_filterSurfaceDocument = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_rowActionSurfaceDocument != null)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.DestroyDocument(_rowActionSurfaceDocument);
|
2026-06-16 22:24:48 +01:00
|
|
|
_rowActionSurfaceDocument = null;
|
|
|
|
|
}
|
2026-06-16 23:09:42 +01:00
|
|
|
|
|
|
|
|
if (_tradeItemSurfaceDocument != null)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
AetheriaEveUnitySurfaceHost.DestroyDocument(_tradeItemSurfaceDocument);
|
2026-06-16 23:09:42 +01:00
|
|
|
_tradeItemSurfaceDocument = null;
|
|
|
|
|
}
|
2026-06-16 21:45:56 +01:00
|
|
|
}
|
2021-01-14 03:20:27 +00:00
|
|
|
}
|