Index cargo by typed item keys
This commit is contained in:
parent
8337d5f5c7
commit
df59a9da62
9 changed files with 120 additions and 51 deletions
Binary file not shown.
|
|
@ -83,8 +83,10 @@ legacy catalog group/table annotations; their remaining metadata is projection
|
|||
and inspection metadata for the typed runtime bridge.
|
||||
Item instances now carry `AetheriaRuntimeItemReference`, a typed item-key
|
||||
facade. `ItemInstance.ItemKey` is the identity surface, while `ItemId` is a
|
||||
derived legacy-GUID compatibility projection for unfinished cargo and
|
||||
simulation paths.
|
||||
derived legacy-GUID compatibility projection for behavior config and broader
|
||||
simulation paths. Cargo inventory indexes, consumable activation lookup,
|
||||
action-bar consumable quantity/fill, transfer lookup, and trade owned counts
|
||||
now use item keys.
|
||||
The old generic `RuntimeCatalogLink<T>` abstraction, `ItemManager.GetData`
|
||||
hydration path, vague `ItemInstance.Data` identity field, and old
|
||||
`RuntimeItemReference.Projection` cache have been deleted; runtime item facts
|
||||
|
|
|
|||
|
|
@ -82,20 +82,20 @@ public class ActionBarConsumableBinding : ActionBarBinding
|
|||
|
||||
public override void Update()
|
||||
{
|
||||
Slot.QuantityRemaining.text = $"{Entity.CountItemsInCargo(TargetLegacyId)}";
|
||||
if (TargetLegacyId == Guid.Empty)
|
||||
Slot.QuantityRemaining.text = $"{Entity.CountItemsInCargo(TargetItemKey)}";
|
||||
if (string.IsNullOrWhiteSpace(TargetItemKey))
|
||||
{
|
||||
Slot.Fill.fillAmount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var instance = Entity.FindActiveConsumable(TargetLegacyId);
|
||||
var instance = Entity.FindActiveConsumable(TargetItemKey);
|
||||
if (instance == null) Slot.Fill.fillAmount = 0;
|
||||
else Slot.Fill.fillAmount = instance.RemainingDuration / instance.Duration;
|
||||
}
|
||||
|
||||
private Guid TargetLegacyId =>
|
||||
Guid.TryParse(Target.LegacyId, out var legacyId) ? legacyId : Guid.Empty;
|
||||
private string TargetItemKey =>
|
||||
Guid.TryParse(Target.LegacyId, out var legacyId) ? AetheriaRuntimeItemReference.FromLegacyId(legacyId) : "";
|
||||
|
||||
public string TargetItemDefinitionLegacyId => Target?.LegacyId ?? "";
|
||||
|
||||
|
|
@ -116,8 +116,11 @@ public class ActionBarGearBinding : ActionBarBinding
|
|||
{
|
||||
get
|
||||
{
|
||||
var itemId = Item?.EquippableItem?.ItemId ?? Guid.Empty;
|
||||
return itemId == Guid.Empty ? "" : itemId.ToString("D");
|
||||
var itemKey = Item?.EquippableItem?.ItemKey ?? "";
|
||||
const string legacyPrefix = "aetheria.item_definition:legacy:";
|
||||
return itemKey.StartsWith(legacyPrefix, StringComparison.OrdinalIgnoreCase)
|
||||
? itemKey.Substring(legacyPrefix.Length)
|
||||
: "";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior
|
|||
var cargo = Entity.FindItemInCargo(_data.AmmoType);
|
||||
if (cargo != null)
|
||||
{
|
||||
var item = cargo.ItemsOfType[_data.AmmoType][0];
|
||||
var item = cargo.GetFirstItem(_data.AmmoType);
|
||||
if (item is SimpleCommodity simpleCommodity)
|
||||
cargo.Remove(simpleCommodity, 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
|
|||
var cargo = Entity.FindItemInCargo(_data.AmmoType);
|
||||
if (cargo != null)
|
||||
{
|
||||
var item = cargo.ItemsOfType[_data.AmmoType][0];
|
||||
var item = cargo.GetFirstItem(_data.AmmoType);
|
||||
if (item is SimpleCommodity simpleCommodity)
|
||||
cargo.Remove(simpleCommodity, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class ItemUsage : Behavior
|
|||
var cargo = Entity.FindItemInCargo(_data.Item);
|
||||
if (cargo == null) return false;
|
||||
|
||||
var item = cargo.ItemsOfType[_data.Item][0];
|
||||
var item = cargo.GetFirstItem(_data.Item);
|
||||
if (item is SimpleCommodity simpleCommodity)
|
||||
cargo.Remove(simpleCommodity, 1);
|
||||
if (item is CraftedItemInstance craftedItemInstance)
|
||||
|
|
@ -47,4 +47,4 @@ public class ItemUsage : Behavior
|
|||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,31 +315,43 @@ public abstract class Entity
|
|||
_activeConsumables.Add(new ConsumableItemEffect(item, this));
|
||||
}
|
||||
|
||||
public ConsumableItemEffect FindActiveConsumable(string itemKey)
|
||||
{
|
||||
return _activeConsumables.FirstOrDefault(ac => ac.Item?.ItemKey == itemKey);
|
||||
}
|
||||
|
||||
public ConsumableItemEffect FindActiveConsumable(Guid itemId)
|
||||
{
|
||||
return _activeConsumables.FirstOrDefault(ac => ac.Item?.ItemId == itemId);
|
||||
return FindActiveConsumable(AetheriaRuntimeItemReference.FromLegacyId(itemId));
|
||||
}
|
||||
|
||||
public bool CanActivateConsumable(AetheriaRuntimeCatalogItem item)
|
||||
{
|
||||
var itemId = GetLegacyGuid(item);
|
||||
return item != null && itemId != Guid.Empty && (item.Stackable || FindActiveConsumable(itemId) == null);
|
||||
var itemKey = GetItemKey(item);
|
||||
return item != null && !string.IsNullOrWhiteSpace(itemKey) && (item.Stackable || FindActiveConsumable(itemKey) == null);
|
||||
}
|
||||
|
||||
public bool TryActivateConsumable(AetheriaRuntimeCatalogItem typedItem)
|
||||
{
|
||||
if (!CanActivateConsumable(typedItem)) return false;
|
||||
|
||||
var itemId = GetLegacyGuid(typedItem);
|
||||
var bay = FindItemInCargo(itemId);
|
||||
var itemKey = GetItemKey(typedItem);
|
||||
var bay = FindItemInCargo(itemKey);
|
||||
if (bay == null) return false;
|
||||
|
||||
var item = (ConsumableItem)bay.ItemsOfType[itemId].First();
|
||||
var item = (ConsumableItem)bay.GetFirstItem(itemKey);
|
||||
ActivateConsumable(item);
|
||||
bay.Remove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string GetItemKey(AetheriaRuntimeCatalogItem item)
|
||||
{
|
||||
return GetLegacyGuid(item) is var itemId && itemId != Guid.Empty
|
||||
? AetheriaRuntimeItemReference.FromLegacyId(itemId)
|
||||
: "";
|
||||
}
|
||||
|
||||
private static Guid GetLegacyGuid(AetheriaRuntimeCatalogItem item)
|
||||
{
|
||||
return item != null && Guid.TryParse(item.LegacyId, out var legacyId)
|
||||
|
|
@ -409,23 +421,33 @@ public abstract class Entity
|
|||
Temperature[position.x, position.y] += heat / ThermalMass[position.x, position.y];
|
||||
}
|
||||
|
||||
public int CountItemsInCargo(Guid itemDataID)
|
||||
public int CountItemsInCargo(string itemKey)
|
||||
{
|
||||
int sum = 0;
|
||||
foreach (var x in CargoBays)
|
||||
{
|
||||
if (x.ItemsOfType.ContainsKey(itemDataID))
|
||||
if (x.ItemsOfType.ContainsKey(itemKey))
|
||||
{
|
||||
foreach (var i in x.ItemsOfType[itemDataID]) sum += i is SimpleCommodity simpleCommodity ? simpleCommodity.Quantity : 1;
|
||||
foreach (var i in x.ItemsOfType[itemKey]) sum += i is SimpleCommodity simpleCommodity ? simpleCommodity.Quantity : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
public int CountItemsInCargo(Guid itemDataID)
|
||||
{
|
||||
return CountItemsInCargo(AetheriaRuntimeItemReference.FromLegacyId(itemDataID));
|
||||
}
|
||||
|
||||
public EquippedCargoBay FindItemInCargo(string itemKey)
|
||||
{
|
||||
return CargoBays.FirstOrDefault(c => c.ContainsItem(itemKey));
|
||||
}
|
||||
|
||||
public EquippedCargoBay FindItemInCargo(Guid itemDataID)
|
||||
{
|
||||
return CargoBays.FirstOrDefault(c => c.ItemsOfType.ContainsKey(itemDataID));
|
||||
return FindItemInCargo(AetheriaRuntimeItemReference.FromLegacyId(itemDataID));
|
||||
}
|
||||
|
||||
public Shape UnoccupiedSpace
|
||||
|
|
@ -450,14 +472,15 @@ public abstract class Entity
|
|||
// Returns the number of items successfully transferred
|
||||
public int TryTransferItems(Entity target, Guid itemDataID, int quantity)
|
||||
{
|
||||
var itemKey = AetheriaRuntimeItemReference.FromLegacyId(itemDataID);
|
||||
int quantityTransferred = 0;
|
||||
while (quantityTransferred < quantity)
|
||||
{
|
||||
EquippedCargoBay originInventory = CargoBays.FirstOrDefault(c => c.ItemsOfType.ContainsKey(itemDataID));
|
||||
EquippedCargoBay originInventory = CargoBays.FirstOrDefault(c => c.ContainsItem(itemKey));
|
||||
|
||||
if (originInventory == null) break;
|
||||
|
||||
var itemInstance = originInventory.ItemsOfType[itemDataID][0];
|
||||
var itemInstance = originInventory.GetFirstItem(itemKey);
|
||||
|
||||
if (itemInstance is SimpleCommodity simpleCommodity)
|
||||
{
|
||||
|
|
@ -1557,7 +1580,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
|
||||
public readonly ItemInstance[,] Occupancy;
|
||||
|
||||
public readonly Dictionary<Guid, List<ItemInstance>> ItemsOfType = new Dictionary<Guid, List<ItemInstance>>();
|
||||
public readonly Dictionary<string, List<ItemInstance>> ItemsOfType = new Dictionary<string, List<ItemInstance>>();
|
||||
|
||||
public Shape InteriorShape { get; }
|
||||
|
||||
|
|
@ -1576,6 +1599,21 @@ public class EquippedCargoBay : EquippedItem
|
|||
}
|
||||
}
|
||||
|
||||
public bool ContainsItem(string itemKey)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(itemKey) && ItemsOfType.ContainsKey(itemKey);
|
||||
}
|
||||
|
||||
public ItemInstance GetFirstItem(string itemKey)
|
||||
{
|
||||
return ContainsItem(itemKey) ? ItemsOfType[itemKey].FirstOrDefault() : null;
|
||||
}
|
||||
|
||||
public ItemInstance GetFirstItem(Guid itemId)
|
||||
{
|
||||
return GetFirstItem(AetheriaRuntimeItemReference.FromLegacyId(itemId));
|
||||
}
|
||||
|
||||
public EquippedCargoBay(ItemManager itemManager, EquippableItem item, int2 position, Entity entity, string name) : base(itemManager, item, position, entity)
|
||||
{
|
||||
var typedCargoBay = ItemManager.GetRuntimeItem(EquippableItem);
|
||||
|
|
@ -1627,7 +1665,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
// For simple commodities, search for existing item stacks to add to
|
||||
foreach (var cargoItem in Cargo.Keys)
|
||||
{
|
||||
if (item.ItemId != cargoItem.ItemId) continue;
|
||||
if (item.ItemKey != cargoItem.ItemKey) continue;
|
||||
|
||||
var cargoCommodity = (SimpleCommodity) cargoItem;
|
||||
if (cargoCommodity.Quantity >= maxStack) continue;
|
||||
|
|
@ -1719,11 +1757,9 @@ public class EquippedCargoBay : EquippedItem
|
|||
}
|
||||
Cargo[item] = cargoCoord;
|
||||
|
||||
if(!ItemsOfType.ContainsKey(item.ItemId))
|
||||
ItemsOfType[item.ItemId] = new List<ItemInstance>();
|
||||
ItemsOfType[item.ItemId].Add(item);
|
||||
AddTypedItemIndex(item);
|
||||
}
|
||||
else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.ItemId == item.ItemId)
|
||||
else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.ItemKey == item.ItemKey)
|
||||
{
|
||||
if (cargoCommodity.Quantity + item.Quantity <= maxStack)
|
||||
{
|
||||
|
|
@ -1763,9 +1799,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
}
|
||||
Cargo[item] = cargoCoord;
|
||||
|
||||
if(!ItemsOfType.ContainsKey(item.ItemId))
|
||||
ItemsOfType[item.ItemId] = new List<ItemInstance>();
|
||||
ItemsOfType[item.ItemId].Add(item);
|
||||
AddTypedItemIndex(item);
|
||||
|
||||
Mass += ItemManager.GetMass(item);
|
||||
ThermalMass += ItemManager.GetThermalMass(item);
|
||||
|
|
@ -1787,9 +1821,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
Occupancy[v.x, v.y] = null;
|
||||
|
||||
Cargo.Remove(item);
|
||||
ItemsOfType[item.ItemId].Remove(item);
|
||||
if (!ItemsOfType[item.ItemId].Any())
|
||||
ItemsOfType.Remove(item.ItemId);
|
||||
RemoveTypedItemIndex(item);
|
||||
|
||||
Mass -= ItemManager.GetMass(item);
|
||||
ThermalMass -= ItemManager.GetThermalMass(item);
|
||||
|
|
@ -1815,9 +1847,7 @@ public class EquippedCargoBay : EquippedItem
|
|||
Occupancy[v.x, v.y] = null;
|
||||
|
||||
Cargo.Remove(item);
|
||||
ItemsOfType[item.ItemId].Remove(item);
|
||||
if (!ItemsOfType[item.ItemId].Any())
|
||||
ItemsOfType.Remove(item.ItemId);
|
||||
RemoveTypedItemIndex(item);
|
||||
|
||||
Mass -= ItemManager.GetMass(item);
|
||||
ThermalMass -= ItemManager.GetThermalMass(item);
|
||||
|
|
@ -1837,6 +1867,29 @@ public class EquippedCargoBay : EquippedItem
|
|||
return ToShape(typedItem?.ShapeWidth ?? 1, typedItem?.ShapeHeight ?? 1, typedItem?.ShapeCells);
|
||||
}
|
||||
|
||||
private void AddTypedItemIndex(ItemInstance item)
|
||||
{
|
||||
var itemKey = item?.ItemKey ?? "";
|
||||
if (string.IsNullOrWhiteSpace(itemKey))
|
||||
return;
|
||||
|
||||
if (!ItemsOfType.ContainsKey(itemKey))
|
||||
ItemsOfType[itemKey] = new List<ItemInstance>();
|
||||
|
||||
ItemsOfType[itemKey].Add(item);
|
||||
}
|
||||
|
||||
private void RemoveTypedItemIndex(ItemInstance item)
|
||||
{
|
||||
var itemKey = item?.ItemKey ?? "";
|
||||
if (string.IsNullOrWhiteSpace(itemKey) || !ItemsOfType.ContainsKey(itemKey))
|
||||
return;
|
||||
|
||||
ItemsOfType[itemKey].Remove(item);
|
||||
if (!ItemsOfType[itemKey].Any())
|
||||
ItemsOfType.Remove(itemKey);
|
||||
}
|
||||
|
||||
private int GetMaxStack(SimpleCommodity item)
|
||||
{
|
||||
var typedItem = ItemManager.GetRuntimeItem(item);
|
||||
|
|
|
|||
|
|
@ -293,18 +293,18 @@ public class TradeMenu : MonoBehaviour
|
|||
x => () =>
|
||||
{
|
||||
if (x.IsHull)
|
||||
return GameManager.DockedEntity.Children.Count(s => s.Hull.ItemId == x.LegacyId && s is Ship {IsPlayerShip: true}).ToString();
|
||||
return GameManager.DockedEntity.Children.Count(s => s.Hull.ItemKey == x.ItemKey && s is Ship {IsPlayerShip: true}).ToString();
|
||||
if(x.Item is SimpleCommodity)
|
||||
return (_targetCargo.ItemsOfType.ContainsKey(x.LegacyId) ? _targetCargo.ItemsOfType[x.LegacyId].Cast<SimpleCommodity>().Sum(s=>s.Quantity) : 0).ToString();
|
||||
return (_targetCargo.ItemsOfType.ContainsKey(x.LegacyId) ? _targetCargo.ItemsOfType[x.LegacyId].Count : 0).ToString();
|
||||
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();
|
||||
},
|
||||
x =>
|
||||
{
|
||||
if (x.IsHull)
|
||||
return GameManager.DockedEntity.Children.Count(s => s.Hull.ItemId == x.LegacyId && s is Ship {IsPlayerShip: true});
|
||||
return GameManager.DockedEntity.Children.Count(s => s.Hull.ItemKey == x.ItemKey && s is Ship {IsPlayerShip: true});
|
||||
if(x.Item is SimpleCommodity)
|
||||
return _targetCargo.ItemsOfType.ContainsKey(x.LegacyId) ? _targetCargo.ItemsOfType[x.LegacyId].Cast<SimpleCommodity>().Sum(s=>s.Quantity) : 0;
|
||||
return _targetCargo.ItemsOfType.ContainsKey(x.LegacyId) ? _targetCargo.ItemsOfType[x.LegacyId].Count : 0;
|
||||
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;
|
||||
}));
|
||||
|
||||
Spreadsheet.ShowData(
|
||||
|
|
@ -471,6 +471,8 @@ public class TradeMenu : MonoBehaviour
|
|||
|
||||
public Guid LegacyId => Item?.ItemId ?? Guid.Empty;
|
||||
|
||||
public string ItemKey => Item?.ItemKey ?? "";
|
||||
|
||||
public string Name => !string.IsNullOrWhiteSpace(TypedItem?.Name) ? TypedItem.Name : "Unknown Item";
|
||||
|
||||
public float Mass => TypedItem != null ? (float)TypedItem.Mass : 0f;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
while hosting the CultMesh state node. `Aetheria.State.ApplyPending` remains a
|
||||
bounded local operator applicator for both pending lanes.
|
||||
- Shared item domain state is still partly built around `AetheriaRuntimeItemReference`,
|
||||
`ItemData`, `RuntimeBehaviorConfig`, derived GUID compatibility, and runtime catalog metadata. Dead
|
||||
`ItemData`, `RuntimeBehaviorConfig`, derived GUID compatibility in behavior
|
||||
config and broader simulation paths, and runtime catalog metadata. Dead
|
||||
user-record and galaxy-map-layer catalog roots have been deleted, and
|
||||
surviving runtime DTOs no longer carry legacy catalog group/table annotations. Newtonsoft,
|
||||
JsonKnownTypes, RethinkDB, LiteNetLib client transport, and the broken
|
||||
|
|
@ -620,7 +621,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
behavior metadata instead of rebuilding config DTOs for lookup.
|
||||
`ItemInstance.Reference` stores the typed item key, `ItemInstance.ItemKey`
|
||||
is the runtime identity surface, and `ItemInstance.ItemId` is a derived
|
||||
legacy-GUID compatibility projection;
|
||||
legacy-GUID compatibility projection. `EquippedCargoBay.ItemsOfType`,
|
||||
consumable activation, action-bar consumable fill/quantity display, item
|
||||
transfer lookup, and trade owned-count rows now use item keys rather than
|
||||
GUID-owned cargo indexes;
|
||||
there is no remaining `ItemInstance.Data` identity/backing field. The reader interface for this
|
||||
bridge is named `IRuntimeItemCatalogReader` and exposes only typed catalog
|
||||
row lookup. Behavior
|
||||
|
|
@ -1199,9 +1203,9 @@ First Aetheria surfaces to publish:
|
|||
`Aetheria.Shared.Unity`; the remaining MessagePack reference is contained
|
||||
in the typed state package's `.cc` reader.
|
||||
- In progress: convert domain references from GUID/base-class patterns to
|
||||
typed record refs. Item instances now carry typed item keys; remaining
|
||||
cargo/simulation dictionaries still derive legacy GUIDs until those
|
||||
structures move to typed keys.
|
||||
typed record refs. Item instances and cargo inventory indexes now carry
|
||||
typed item keys; remaining behavior config and broader simulation paths
|
||||
still derive legacy GUIDs until those structures move to typed keys.
|
||||
- Remove runtime dependency on `ItemData` DTOs as item instance owners.
|
||||
|
||||
5. Mesh host
|
||||
|
|
@ -1318,6 +1322,11 @@ First Aetheria surfaces to publish:
|
|||
`AetheriaRuntimeItemReference` and make the reference typed-key-first.
|
||||
`ItemInstance.ItemKey` is now the primary identity surface; `ItemId` is
|
||||
derived legacy compatibility for unfinished cargo and simulation paths.
|
||||
- Done: move `EquippedCargoBay.ItemsOfType`, consumable activation lookup,
|
||||
action-bar consumable quantity/fill, item transfer lookup, and trade owned
|
||||
counts from derived `Guid ItemId` keys to typed `ItemKey` strings. GUID
|
||||
behavior-config fields still translate at the cargo boundary until
|
||||
behavior config construction moves to typed item references.
|
||||
- Done: delete the dead `ItemManager.GetRuntimeItemProjection<T>` bridge
|
||||
after loadout generation stopped hydrating selected typed rows into
|
||||
`EquippableItemData` merely to instantiate equipment.
|
||||
|
|
|
|||
Loading…
Reference in a new issue