From 8ccbf27c091d97076f5d04d4baae58a837641e9a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 21 Jun 2026 20:21:37 +0100 Subject: [PATCH] Project item tiers through runtime queries --- Aetheria.State.Verify/Program.cs | 67 ++++++++++++++++++++ Assets/Scripts/Gameplay/ActionGameManager.cs | 5 -- Assets/Scripts/UI/Menu/InventoryMenu.cs | 17 +++-- Assets/Scripts/Zone Display/ZoneRenderer.cs | 11 +++- 4 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 7815f31fd..74d5b7a87 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -50,6 +50,7 @@ RequireTradeCargoSelectorUseEveSurface(root); RequireTradeFilterAndRowActionsUseEveSurface(root); RequireTradeItemDetailsUseEveSurface(root); RequireTradeItemValuesUseRuntimeQueries(root); +RequireItemTierProjectionUsesRuntimeQueries(root); RequireInventoryDropdownUseEveSurface(root); RequireNoDeadPopupShells(root); RequirePlayerSettingsEveSurface(root); @@ -4859,6 +4860,72 @@ static void RequireTradeItemValuesUseRuntimeQueries(string root) } } +static void RequireItemTierProjectionUsesRuntimeQueries(string root) +{ + var actionGameManagerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); + var inventoryMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "InventoryMenu.cs"); + var zoneRendererPath = Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs"); + var tradeQueriesPath = Path.Combine( + root, + "Packages", + "org.gamecult.aetheria.state", + "Runtime", + "AetheriaRuntimeDaemonTradeItemQueries.cs"); + + var actionGameManager = File.Exists(actionGameManagerPath) + ? File.ReadAllText(actionGameManagerPath) + : throw new InvalidOperationException("Cannot verify item tier projection; ActionGameManager.cs is missing."); + var inventoryMenu = File.Exists(inventoryMenuPath) + ? File.ReadAllText(inventoryMenuPath) + : throw new InvalidOperationException("Cannot verify item tier projection; InventoryMenu.cs is missing."); + var zoneRenderer = File.Exists(zoneRendererPath) + ? File.ReadAllText(zoneRendererPath) + : throw new InvalidOperationException("Cannot verify item tier projection; ZoneRenderer.cs is missing."); + var tradeQueries = File.Exists(tradeQueriesPath) + ? File.ReadAllText(tradeQueriesPath) + : throw new InvalidOperationException("Cannot verify item tier projection; runtime trade item queries are missing."); + + if (actionGameManager.Contains("ObservedItemTier(", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "ActionGameManager still exposes item tier projection as a Unity ItemManager bridge."); + } + + var forbiddenUnityTierSymbols = new[] + { + "GameManager.ObservedItemTier", + "ItemManager.GetTier(", + "GameManager.ItemManager.GetTier" + }; + var hits = new[] { inventoryMenuPath, zoneRendererPath } + .SelectMany(path => File.ReadLines(path) + .Select((line, index) => new { Path = path, LineNumber = index + 1, Line = line })) + .Where(line => forbiddenUnityTierSymbols.Any(symbol => line.Line.Contains(symbol, StringComparison.Ordinal))) + .Select(line => $"{Path.GetRelativePath(root, line.Path)}:{line.LineNumber}: {line.Line.Trim()}") + .ToArray(); + + if (hits.Length > 0) + { + throw new InvalidOperationException( + "Unity UI/rendering still projects item tiers through ItemManager instead of shared runtime queries: " + + string.Join("; ", hits)); + } + + if (!inventoryMenu.Contains("FormatItemTier(", StringComparison.Ordinal) || + !inventoryMenu.Contains("AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem(", StringComparison.Ordinal) || + !inventoryMenu.Contains("tradeProjection.TierName", StringComparison.Ordinal) || + !inventoryMenu.Contains("tradeProjection.Upgrades", StringComparison.Ordinal) || + !zoneRenderer.Contains("AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem(", StringComparison.Ordinal) || + !zoneRenderer.Contains("tradeProjection.TierColorHex", StringComparison.Ordinal) || + !tradeQueries.Contains("public string TierName { get; }", StringComparison.Ordinal) || + !tradeQueries.Contains("public string TierColorHex { get; }", StringComparison.Ordinal) || + !tradeQueries.Contains("public int Upgrades { get; }", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Item tier labels and pickup colors must be projected through shared runtime trade item query results."); + } +} + static void RequireInventoryDropdownUseEveSurface(string root) { var inventoryPanelPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "InventoryPanel.cs"); diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index ae8201aa3..0bec9967d 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -560,11 +560,6 @@ public class ActionGameManager : MonoBehaviour .ToArray()); } - public (RarityTier tier, int upgrades) ObservedItemTier(CraftedItemInstance item) - { - return ItemManager.GetTier(item); - } - private readonly (float2 direction, string name)[] _directions = { (new float2(0, 1), "Front"), (new float2(1, 0), "Right"), diff --git a/Assets/Scripts/UI/Menu/InventoryMenu.cs b/Assets/Scripts/UI/Menu/InventoryMenu.cs index ec680364c..832940236 100644 --- a/Assets/Scripts/UI/Menu/InventoryMenu.cs +++ b/Assets/Scripts/UI/Menu/InventoryMenu.cs @@ -508,8 +508,7 @@ public class InventoryMenu : MonoBehaviour if (item is EquippableItem equippableItem) { - var (itemTier, upgrades) = GameManager.ObservedItemTier(equippableItem); - tier = $"{itemTier.Name}{new string('+', upgrades)}"; + tier = FormatItemTier(typedItem, equippableItem); durability = $"{(int)(equippableItem.Durability / GetMaxDurability(typedItem, equippableItem) * 100)}%"; thermalRange = FormatTemperatureRange(typedItem); behaviorSections = ProjectCargoItemBehaviorSections(typedItem, equippableItem).ToArray(); @@ -713,8 +712,18 @@ public class InventoryMenu : MonoBehaviour private string BuildEquippedItemTitle(EquippedItem item, AetheriaRuntimeCatalogItem typedItem) { - var (tier, upgrades) = GameManager.ObservedItemTier(item.EquippableItem); - return $"{typedItem?.Name ?? "Unknown Item"} ({tier.Name}{new string('+', upgrades)})"; + return $"{typedItem?.Name ?? "Unknown Item"} ({FormatItemTier(typedItem, item.EquippableItem)})"; + } + + private string FormatItemTier(AetheriaRuntimeCatalogItem typedItem, EquippableItem item) + { + var tradeProjection = AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem( + typedItem, + ToRuntimeLoadoutItem(item), + GameManager.ObservedTradeValueSettings()); + return tradeProjection.HasTier + ? $"{tradeProjection.TierName}{new string('+', tradeProjection.Upgrades)}" + : ""; } private static string FormatCurrentItemStat(PerformanceStat stat, EquippableItem item) diff --git a/Assets/Scripts/Zone Display/ZoneRenderer.cs b/Assets/Scripts/Zone Display/ZoneRenderer.cs index 273073a69..c2c1747b8 100644 --- a/Assets/Scripts/Zone Display/ZoneRenderer.cs +++ b/Assets/Scripts/Zone Display/ZoneRenderer.cs @@ -768,7 +768,16 @@ public class ZoneRenderer : MonoBehaviour itemPickup.ScanLabel.text = typedItem?.Name ?? "Unknown Item"; if (item is CraftedItemInstance craftedItemInstance) { - var c = ItemManager.GetTier(craftedItemInstance).tier.Color.ToColor(); + var tradeProjection = AetheriaRuntimeDaemonTradeItemQueries.ProjectTradeItem( + typedItem, + AetheriaRuntimeDaemonTradeItemQueries.CraftedItemCommit( + craftedItemInstance.ItemKey, + craftedItemInstance.Quality, + item is EquippableItem equippable ? equippable.Durability : 1f), + ActionGameManager.Instance?.ObservedTradeValueSettings()); + var c = Color.white; + if (!ColorUtility.TryParseHtmlString($"#{tradeProjection.TierColorHex}", out c)) + c = Color.white; c.a = 0; itemPickup.ScanLabel.color = c; }