From 00a036427df6ed08c7578567713e59fbd57adff5 Mon Sep 17 00:00:00 2001 From: Nibu Date: Fri, 13 Nov 2026 03:00:44 +0000 Subject: [PATCH] Lot moves to ItemInstance at key 11; stacks merge, split, restore and root by lot Co-Authored-By: Claude Sonnet 5.5 --- Assets/Scripts/ServerShared/Entity.cs | 6 +++--- Assets/Scripts/ServerShared/EntitySerializer.cs | 6 +++--- Assets/Scripts/ServerShared/ItemInstance.cs | 9 ++++++--- Assets/Scripts/ServerShared/ItemManager.cs | 5 +++-- Assets/Scripts/ServerShared/SavedGame.cs | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 43d9729d9..b520db17d 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -2465,7 +2465,7 @@ public class EquippedCargoBay : EquippedItem // For simple commodities, search for existing item stacks to add to foreach (var cargoItem in Cargo.Keys) { - if (!item.Data.Key.Equals(cargoItem.Data.Key)) continue; + if (!item.Data.Key.Equals(cargoItem.Data.Key) || item.Lot != cargoItem.Lot) continue; var cargoCommodity = (SimpleCommodity) cargoItem; if (cargoCommodity.Quantity >= itemData.MaxStack) continue; @@ -2563,7 +2563,7 @@ public class EquippedCargoBay : EquippedItem ItemsOfType[item.Data.Key] = new List(); ItemsOfType[item.Data.Key].Add(item); } - else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data.Key.Equals(item.Data.Key)) + else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data.Key.Equals(item.Data.Key) && cargoCommodity.Lot == item.Lot) { if (cargoCommodity.Quantity + item.Quantity <= itemData.MaxStack) { @@ -2643,7 +2643,7 @@ public class EquippedCargoBay : EquippedItem item.Quantity -= quantity; Mass -= itemData.Mass * quantity; ThermalMass -= itemData.Mass * itemData.SpecificHeat * quantity; - return new SimpleCommodity{Data = item.Data, Quantity = quantity, Rotation = item.Rotation}; + return new SimpleCommodity{Data = item.Data, Lot = item.Lot, Quantity = quantity, Rotation = item.Rotation}; } public void Remove(CraftedItemInstance item) diff --git a/Assets/Scripts/ServerShared/EntitySerializer.cs b/Assets/Scripts/ServerShared/EntitySerializer.cs index 9aefe5a19..73656b87e 100644 --- a/Assets/Scripts/ServerShared/EntitySerializer.cs +++ b/Assets/Scripts/ServerShared/EntitySerializer.cs @@ -60,8 +60,8 @@ public static class EntitySerializer && itemManager.GetData(commodity).MaxStack >= 1) { var maxStack = itemManager.GetData(commodity).MaxStack; - var first = new SimpleCommodity { Data = commodity.Data, Rotation = commodity.Rotation, Quantity = maxStack }; - var rest = new SimpleCommodity { Data = commodity.Data, Rotation = commodity.Rotation, Quantity = commodity.Quantity - maxStack }; + var first = new SimpleCommodity { Data = commodity.Data, Lot = commodity.Lot, Rotation = commodity.Rotation, Quantity = maxStack }; + var rest = new SimpleCommodity { Data = commodity.Data, Lot = commodity.Lot, Rotation = commodity.Rotation, Quantity = commodity.Quantity - maxStack }; if (!bay.TryStore(first, position)) rest.Quantity += first.Quantity; spill.Add((bay, rest)); return; @@ -82,7 +82,7 @@ public static class EntitySerializer var remaining = rest.Quantity; while (remaining > 0) { - var chunk = new SimpleCommodity { Data = rest.Data, Rotation = rest.Rotation, Quantity = Math.Min(remaining, maxStack) }; + var chunk = new SimpleCommodity { Data = rest.Data, Lot = rest.Lot, Rotation = rest.Rotation, Quantity = Math.Min(remaining, maxStack) }; var placed = home.TryStore(chunk) || bays.Where(b => b != home).Any(b => b.TryStore(chunk)); // A refused store may still have topped up a stack; what is left in the chunk found no room. remaining -= Math.Min(remaining, maxStack) - (placed ? 0 : chunk.Quantity); diff --git a/Assets/Scripts/ServerShared/ItemInstance.cs b/Assets/Scripts/ServerShared/ItemInstance.cs index 80a891666..a16553b9f 100644 --- a/Assets/Scripts/ServerShared/ItemInstance.cs +++ b/Assets/Scripts/ServerShared/ItemInstance.cs @@ -24,6 +24,11 @@ public abstract class ItemInstance { [JsonProperty("data"), Key(0)] public CultRecordRef Data; [JsonProperty("rotation"), Key(1)] public ItemRotation Rotation; + + // The lot this unit was minted or mined from: crafted units' design, provenance, workmanship and role fills all + // live there; a mined SimpleCommodity names its Extracted lot (zone, belt, ore). Lot 0 is no lot: bought, staged + // and loadout commodities, and every save from before the field reached SimpleCommodity. + [JsonProperty("lot"), Key(11)] public int Lot; } [Union(0, typeof(CompoundCommodity)), @@ -33,9 +38,7 @@ public abstract class ItemInstance public abstract class CraftedItemInstance : ItemInstance { // Keys 2 (Quality), 9 (Ingredients) and 10 (Product) belonged to fields moved to Lot; do not reuse them. - - // The lot this unit was minted from: its design, provenance, workmanship and role fills all live there. - [JsonProperty("lot"), Key(11)] public int Lot; + // Key 11 (Lot) lives on ItemInstance. } [MessagePackObject, JsonObject(MemberSerialization.OptIn)] diff --git a/Assets/Scripts/ServerShared/ItemManager.cs b/Assets/Scripts/ServerShared/ItemManager.cs index 090fe1545..774abbe83 100644 --- a/Assets/Scripts/ServerShared/ItemManager.cs +++ b/Assets/Scripts/ServerShared/ItemManager.cs @@ -72,8 +72,9 @@ public class ItemManager }; } - // The one resolution path from a crafted instance to the lot it was minted from. - public Lot GetLot(CraftedItemInstance item) => Lots[item.Lot]; + // The one resolution path from an instance to the lot it was minted or mined from. Lot 0 throws: a bought or + // staged commodity has no lot, and the caller asks Lot != 0 first. + public Lot GetLot(ItemInstance item) => Lots[item.Lot]; // Returns stat when not equipped: a null-entity context with no heat, no power and no modifiers. It says so // in its own name (UnequippedStatContext) rather than being a third quiet dialect of the arithmetic. diff --git a/Assets/Scripts/ServerShared/SavedGame.cs b/Assets/Scripts/ServerShared/SavedGame.cs index 5f42de446..21f3f3b71 100644 --- a/Assets/Scripts/ServerShared/SavedGame.cs +++ b/Assets/Scripts/ServerShared/SavedGame.cs @@ -225,7 +225,7 @@ public static class RunSave var roots = zones .SelectMany(zone => zone.Contents?.Entities ?? new List()) .SelectMany(EntitySerializer.Items) - .OfType() + .Where(item => item.Lot != 0) .Select(item => item.Lot); cache.Commit(batch => {