From 898751e6e541fbf7325018a64279d1a2ed847dd5 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 14 Jun 2026 04:47:02 +0100 Subject: [PATCH] Use typed cargo geometry in cargo bays --- .voidbot/state/aetheria.cc | Bin 63708 -> 65004 bytes Assets/Scripts/ServerShared/Entity.cs | 105 ++++++++++++++++------- Assets/Scripts/UI/Menu/InventoryPanel.cs | 16 ++-- docs/aetheria-perfect-machine-map.md | 25 ++++-- 4 files changed, 97 insertions(+), 49 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 90fe1661fa9db6fab98539c9cff1756ef694afcf..8a695c28c005f938aa9334df686884cbc2abd76f 100644 GIT binary patch delta 1736 zcmah~J!~9B6vn=j@gW67AlOzg8c_ftzC9nY%{eK6ghV!i;Mfs`yYcSq?%>&(_0H`5 zScn4=3YTaAiHd?h5n{l)iY5q(G&E7VK#HKWF;oh6FeXZ5-lzfM*Y$+Vug`U z3G{Pl_D3wGa)d8T8 zOd@2n&Jf0=t>sfy6Rw-an7bX+N+1USX8Et+_KM}eG$m;iGe9GvNO)9rGI}TvGCKNS zNLgEniA#OzE)d*Rwn)aT<;WvUVd+5AO~RE(I!l-n2E4RLA~UY4K|(#`Q5iEJ%}+#> z#hoHh%B3RML&DEr8y1T>&cYXpa7hKfdF>qKFehS$9zkWGTh;6n!mdkV1^CGn@`Sq% zn2;G)gxgg~HzA6-ehiOyrJ{_X*o<0*iAaMGF%n?l4ai9uR!|7ViFlp3<_IVY1Evyr zBoYcHVF)eC4XvdL1Ok1fjCCLpd(IBF|5*g$sf(3{Ho*Fy=>COlY`I3-1pZ_CZ&3yRQYaxH!$f$gYxpPt!G%HL6g~jmbezk; zAsm;9FF)3MYYV;dXgH#O+uj*ZW49ndjp$6{Zh#R;1=GxF8HG#_p3QwEdE zm(!|me`qbove)H1E3)yImhWZ<9Ed%<4QW2)yP?}2ztiZH+g*2&0K!b+8k9wQ; z|5ly$(brBq(q-p_3siYXx|oB!QlJj(CWB<{1r&GidlVW2 zp&Xs%%1qFe2=a=%X@b}XM*`7XwK-W|&v`;|5Swu#y~}SezO)3JLA+C_3GM}MmH^mT zBu4M``mA*yu$I|pK&-~7U~cQVm%_`w<(a6iH74|>!)R>g;`E7=xwX&LS3gxakhku6 zSbul;#>?B*ajLKvn2F#^i?j-qU!i?xsiyQRTdL|ByZa_1ylQt4lzut;#DgF7cJ3Ui zR0f6g_0q&>_B21O_ex`M&3vCB2BE1KH|DiGn H&9D9gm)?Nl delta 896 zcmZWo&r4KM6h@zj8dj8(v=B}Nw#m_PMx8XGR063sHnngOT;DtM-o-cfPWRq7VjD4N z(K0RsMFr6>h!(>90pYrhM2m`uT8J*%sL>{f&U^D_2wGk4ch8USeBZf0emh@wo%NUP zJ^8|9zL+hHk1yP7%h*GEo%UV(ohCYwOHk?DY9ht41nKG+Xy18iPjw7h{o!u!jZ%Q% zqd>)7uzw!(mkd@QW#IHa#J%Af3nPR;h90Uc#93FEU_L64%R+-f zEyEfYKA3r-v8fUUqit$m+l8Rbq~+MqfklsrYHv#)6@ zNC8?K{m5?IF4}Kb57&Qv3_1_K!5Sw%F2-;7>r3DF9Xo%i&+_e)nS3dCW^!a?vM`d( z74r+v4fFLA`)vDteY#_Cv%ay@+ufc1i2Q`zbdINcKb9+`|Kn{}<9#e=cb$GKold*I bC!1lTqe{#px3K1}_@&yDUDR9yHAlmAER diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 9c46c29af..f96cf66ee 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using GameCult.Aetheria.State.Unity; using UniRx; using Unity.Mathematics; using static Unity.Mathematics.math; @@ -1367,8 +1368,8 @@ public class EquippedCargoBay : EquippedItem public readonly Dictionary> ItemsOfType = new Dictionary>(); - public new readonly CargoBayData Data; - + public Shape InteriorShape { get; } + public float Mass { get; private set; } public float ThermalMass { get; private set; } public string Name { get; } @@ -1377,7 +1378,7 @@ public class EquippedCargoBay : EquippedItem { get { - var unoccupied = new Shape(Data.InteriorShape.Width, Data.InteriorShape.Height); + var unoccupied = new Shape(InteriorShape.Width, InteriorShape.Height); foreach (var v in unoccupied.AllCoordinates) unoccupied[v] = Occupancy[v.x, v.y] == null; return unoccupied; @@ -1386,25 +1387,29 @@ public class EquippedCargoBay : EquippedItem public EquippedCargoBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity) { - Data = ItemManager.GetData(EquippableItem) as CargoBayData; + var typedCargoBay = ItemManager.GetRuntimeItem(EquippableItem); + InteriorShape = ToShape( + typedCargoBay?.InteriorShapeWidth ?? 1, + typedCargoBay?.InteriorShapeHeight ?? 1, + typedCargoBay?.InteriorShapeCells); Name = name; - Mass = Data.Mass; - ThermalMass = Data.Mass * Data.SpecificHeat; + Mass = ItemManager.GetMass(EquippableItem); + ThermalMass = ItemManager.GetThermalMass(EquippableItem); - Occupancy = new ItemInstance[Data.InteriorShape.Width,Data.InteriorShape.Height]; + Occupancy = new ItemInstance[InteriorShape.Width, InteriorShape.Height]; } // Check whether the given item will fit when its origin is placed at the given coordinate public bool ItemFits(ItemInstance item, int2 cargoCoord) { - var itemData = ItemManager.GetData(item); + var itemShape = GetItemShape(item); // Check every cell of the item's shape - foreach (var i in itemData.Shape.Coordinates) + foreach (var i in itemShape.Coordinates) { // If there is an item already occupying that space, it won't fit - var itemCargoCoord = cargoCoord + itemData.Shape.Rotate(i, item.Rotation); - if (!Data.InteriorShape[itemCargoCoord] || (Occupancy[itemCargoCoord.x, itemCargoCoord.y] != null && Occupancy[itemCargoCoord.x, itemCargoCoord.y] != item)) return false; + var itemCargoCoord = cargoCoord + itemShape.Rotate(i, item.Rotation); + if (!InteriorShape[itemCargoCoord] || (Occupancy[itemCargoCoord.x, itemCargoCoord.y] != null && Occupancy[itemCargoCoord.x, itemCargoCoord.y] != item)) return false; } return true; @@ -1425,7 +1430,7 @@ public class EquippedCargoBay : EquippedItem public bool TryFindSpace(SimpleCommodity item, out List positions) { positions = new List(); - var itemData = ItemManager.GetData(item); + var maxStack = GetMaxStack(item); var remainingQuantity = item.Quantity; // For simple commodities, search for existing item stacks to add to @@ -1434,10 +1439,10 @@ public class EquippedCargoBay : EquippedItem if (item.Data != cargoItem.Data) continue; var cargoCommodity = (SimpleCommodity) cargoItem; - if (cargoCommodity.Quantity >= itemData.MaxStack) continue; + if (cargoCommodity.Quantity >= maxStack) continue; // Subtract remaining space in existing stack from remaining quantity - remainingQuantity -= min(itemData.MaxStack - cargoCommodity.Quantity, remainingQuantity); + remainingQuantity -= min(maxStack - cargoCommodity.Quantity, remainingQuantity); positions.Add(Cargo[cargoItem]); // If we've moved all of the items into existing stacks, no need to search for empty space! @@ -1446,7 +1451,7 @@ public class EquippedCargoBay : EquippedItem // TODO: Try alternate item rotations / use Shape.FitsWithin // Search all the space in the cargo bay for an empty space where the item fits - foreach (var cargoCoord in Data.InteriorShape.Coordinates) + foreach (var cargoCoord in InteriorShape.Coordinates) { if (ItemFits(item, cargoCoord)) { @@ -1462,7 +1467,7 @@ public class EquippedCargoBay : EquippedItem public bool TryFindSpace(CraftedItemInstance item, out int2 position) { // Search all the space in the cargo bay for an empty space where the item fits - foreach (var cargoCoord in Data.InteriorShape.Coordinates) + foreach (var cargoCoord in InteriorShape.Coordinates) { if (ItemFits(item, cargoCoord)) { @@ -1512,12 +1517,13 @@ public class EquippedCargoBay : EquippedItem // Returns true only when ALL of the items are successfully stored public bool TryStore(SimpleCommodity item, int2 cargoCoord) { - var itemData = ItemManager.GetData(item); + var itemShape = GetItemShape(item); + var maxStack = GetMaxStack(item); if (ItemFits(item, cargoCoord)) { - foreach (var p in itemData.Shape.Coordinates) + foreach (var p in itemShape.Coordinates) { - var pos = cargoCoord + itemData.Shape.Rotate(p, item.Rotation); + var pos = cargoCoord + itemShape.Rotate(p, item.Rotation); Occupancy[pos.x, pos.y] = item; } Cargo[item] = cargoCoord; @@ -1528,18 +1534,18 @@ public class EquippedCargoBay : EquippedItem } else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data == item.Data) { - if (cargoCommodity.Quantity + item.Quantity <= itemData.MaxStack) + if (cargoCommodity.Quantity + item.Quantity <= maxStack) { cargoCommodity.Quantity += item.Quantity; } else { - var quantityTransferred = itemData.MaxStack - cargoCommodity.Quantity; + var quantityTransferred = maxStack - cargoCommodity.Quantity; item.Quantity -= quantityTransferred; - cargoCommodity.Quantity = itemData.MaxStack; + cargoCommodity.Quantity = maxStack; - Mass += itemData.Mass * quantityTransferred; - ThermalMass += itemData.Mass * itemData.SpecificHeat * quantityTransferred; + Mass += GetUnitMass(item) * quantityTransferred; + ThermalMass += GetUnitThermalMass(item) * quantityTransferred; return false; } } @@ -1558,10 +1564,10 @@ public class EquippedCargoBay : EquippedItem { if (!ItemFits(item, cargoCoord)) return false; - var itemData = ItemManager.GetData(item); - foreach (var p in itemData.Shape.Coordinates) + var itemShape = GetItemShape(item); + foreach (var p in itemShape.Coordinates) { - var pos = cargoCoord + itemData.Shape.Rotate(p, item.Rotation); + var pos = cargoCoord + itemShape.Rotate(p, item.Rotation); Occupancy[pos.x, pos.y] = item; } Cargo[item] = cargoCoord; @@ -1583,10 +1589,9 @@ public class EquippedCargoBay : EquippedItem ItemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!"); return null; } - var itemData = ItemManager.GetData(item); if(quantity >= item.Quantity) { - foreach(var v in Data.InteriorShape.Coordinates) + foreach(var v in InteriorShape.Coordinates) if (Occupancy[v.x, v.y] == item) Occupancy[v.x, v.y] = null; @@ -1602,8 +1607,8 @@ public class EquippedCargoBay : EquippedItem } item.Quantity -= quantity; - Mass -= itemData.Mass * quantity; - ThermalMass -= itemData.Mass * itemData.SpecificHeat * quantity; + Mass -= GetUnitMass(item) * quantity; + ThermalMass -= GetUnitThermalMass(item) * quantity; return new SimpleCommodity{Data = item.Data, Quantity = quantity, Rotation = item.Rotation}; } @@ -1614,8 +1619,7 @@ public class EquippedCargoBay : EquippedItem ItemManager.Log("Attempted to remove item from a cargo bay that it wasn't even in! Something went wrong here!"); return; } - var itemData = ItemManager.GetData(item); - foreach(var v in Data.InteriorShape.Coordinates) + foreach(var v in InteriorShape.Coordinates) if (Occupancy[v.x, v.y] == item) Occupancy[v.x, v.y] = null; @@ -1635,6 +1639,41 @@ public class EquippedCargoBay : EquippedItem if (item is CraftedItemInstance craftedItem) Remove(craftedItem); } + + private Shape GetItemShape(ItemInstance item) + { + var typedItem = ItemManager.GetRuntimeItem(item); + return ToShape(typedItem?.ShapeWidth ?? 1, typedItem?.ShapeHeight ?? 1, typedItem?.ShapeCells); + } + + private int GetMaxStack(SimpleCommodity item) + { + var typedItem = ItemManager.GetRuntimeItem(item); + return typedItem != null && typedItem.MaxStack > 0 ? typedItem.MaxStack : 1; + } + + private float GetUnitMass(ItemInstance item) + { + var typedItem = ItemManager.GetRuntimeItem(item); + return typedItem != null ? (float)typedItem.Mass : 0f; + } + + private float GetUnitThermalMass(ItemInstance item) + { + var typedItem = ItemManager.GetRuntimeItem(item); + return typedItem != null ? (float)(typedItem.Mass * typedItem.SpecificHeat) : 0f; + } + + private static Shape ToShape(int width, int height, IReadOnlyList cells) + { + var shape = new Shape(Math.Max(width, 1), Math.Max(height, 1)); + if (cells == null) return shape; + + foreach (var cell in cells) + shape[new int2(cell.X, cell.Y)] = true; + + return shape; + } public bool TryTransferItem(EquippedCargoBay target, SimpleCommodity item, int quantity) { diff --git a/Assets/Scripts/UI/Menu/InventoryPanel.cs b/Assets/Scripts/UI/Menu/InventoryPanel.cs index f55cbe48f..48bf471ff 100644 --- a/Assets/Scripts/UI/Menu/InventoryPanel.cs +++ b/Assets/Scripts/UI/Menu/InventoryPanel.cs @@ -561,12 +561,12 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler if(Title) Title.text = cargo.Name; - // FakeOccupancy = new Shape(cargo.Data.InteriorShape.Width, cargo.Data.InteriorShape.Height); - // IgnoreOccupancy = new Shape(cargo.Data.InteriorShape.Width, cargo.Data.InteriorShape.Height); - Grid.constraintCount = cargo.Data.InteriorShape.Width; - foreach (var v in cargo.Data.InteriorShape.AllCoordinates) + // FakeOccupancy = new Shape(cargo.InteriorShape.Width, cargo.InteriorShape.Height); + // IgnoreOccupancy = new Shape(cargo.InteriorShape.Width, cargo.InteriorShape.Height); + Grid.constraintCount = cargo.InteriorShape.Width; + foreach (var v in cargo.InteriorShape.AllCoordinates) { - if (!cargo.Data.InteriorShape[v]) + if (!cargo.InteriorShape[v]) { var empty = new GameObject("Empty Node", typeof(RectTransform)); empty.transform.SetParent(Grid.transform); @@ -593,7 +593,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler if (item != null) { var itemPosition = cargo.Cargo[item]; - var originalOccupancy = cargo.Data.InteriorShape.Inset(GetItemShape(item), itemPosition, item.Rotation); + var originalOccupancy = cargo.InteriorShape.Inset(GetItemShape(item), itemPosition, item.Rotation); _dragCells = originalOccupancy.Coordinates .Select(v1 => Instantiate(CellInstances[v1], DragParent, true).transform).ToArray(); foreach(var dragCell in _dragCells) @@ -644,7 +644,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler { //foreach (var cell in _dragCells) cell.gameObject.SetActive(false); FakeItem = item; - FakeOccupancy = cargo.Data.InteriorShape.Inset(GetItemShape(item), placementPosition, item.Rotation); + FakeOccupancy = cargo.InteriorShape.Inset(GetItemShape(item), placementPosition, item.Rotation); RefreshCells(); GameManager.RegisterDragTarget(drag => { @@ -784,7 +784,7 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler bool ItemMatch(int2 offset) { var v2 = v + offset; - return !_displayedCargo.Data.InteriorShape[v2] || item == null || + return !_displayedCargo.InteriorShape[v2] || item == null || (FakeOccupancy?[v2]??false ? FakeItem : IgnoreOccupancy?[v2]??false ? null : _displayedCargo.Occupancy[v2.x, v2.y]) != item; } diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 78f6f61ea..ba9962d7f 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -176,9 +176,13 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. moves to typed payloads. Inventory panel equipment-grid geometry, hull/interior cell drawing, temperature overlay masking, thermal edge toggles, and entity cell tinting now - use typed hull shape/interior masks from the runtime catalog. Final equip, - cargo fit, and mutation acceptance still belong to the existing entity/cargo - simulation owners until those are rebuilt. + use typed hull shape/interior masks from the runtime catalog. `EquippedCargoBay` + now reads cargo interior shape, item fit shape, simple commodity max stack, + cargo bay mass, and cargo bay thermal mass from typed runtime catalog rows; + `InventoryPanel` lowers cargo-grid display from that typed `InteriorShape`. + Final equipment fit/equip acceptance, docking bay max-size, and behavior + construction still belong to legacy simulation projections until those owners + are rebuilt. The item properties panel also reads typed catalog title names, descriptions, manufacturer, base mass, max durability, thermal bounds, and thermal performance curve keys for basic item presentation without hydrating legacy @@ -682,11 +686,16 @@ First Aetheria surfaces to publish: - Done: move `EntityInstance` hull shape and hardpoint presentation/damage masks onto typed catalog rows; legacy `HullData` no longer supplies hull shape or hardpoint lists to scene entity instances. - - Done: move `InventoryPanel` entity-grid hull shape/interior rendering and - thermal overlay masking onto typed catalog rows; legacy `HullData` no - longer supplies equipment-grid display geometry. - - Done: delete the console `give` command instead of preserving a debug - operator path that hydrated typed item rows back into legacy item DTOs. + - Done: move `InventoryPanel` entity-grid hull shape/interior rendering and + thermal overlay masking onto typed catalog rows; legacy `HullData` no + longer supplies equipment-grid display geometry. + - Done: move `EquippedCargoBay` cargo geometry, item fit shape, simple stack + limits, cargo mass, cargo thermal mass, and `InventoryPanel` cargo-grid + lowering onto typed catalog rows; legacy `CargoBayData` remains only in + later simulation projections such as docking max-size and behavior + construction. + - Done: delete the console `give` command instead of preserving a debug + operator path that hydrated typed item rows back into legacy item DTOs. - Done: delete `ItemManager.GetCatalogEntries` after all live callers moved to typed catalog selection. - Done: delete `ILegacyItemCatalogReader.GetAll` and the type/global indexes