Inventory: per-player items backbone (DR-026 Phase 0)
Data-driven ItemDatabase catalog + per-player replicated InventorySlot ([GhostField] OwnerSendType.All, a StatModifier twin). Harvest reroutes to the firing player's personal inventory (optional ComponentLookup<GhostOwner> in ResourceHarvestSystem; remainder/un-owned -> ledger); the G-key InventoryDepositRequest RPC moves the bag into the shared ledger the build economy spends. Catalog asset (Aether/Ore/Biomass + Stone Pickaxe) wired into the Gameplay subscene; read-only HUD inventory panel. ushort ItemId subsumes ResourceId; byte Category/Tier baked for gear-tier progression. Session-only (no SaveData bump). Play-validated host+client: catalog baked into both worlds, the re-baked player ghost carries InventorySlot with a clean handshake, a server write replicates to the client owner, the deposit RPC round-trips, and the HUD renders catalog names. See DR-026. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
|
||||
namespace ProjectM.Simulation
|
||||
{
|
||||
/// <summary>
|
||||
/// One authored item definition, baked immutable into the <see cref="ItemDatabase"/> blob. This is the
|
||||
/// single source of truth for everything an item IS — resources, tools, weapons, gear, consumables — so
|
||||
/// adding game content is an authoring row + re-bake, with no code change. Id space is the SAME
|
||||
/// <c>ushort</c> space as <see cref="StorageEntry.ItemId"/> / <see cref="InventorySlot.ItemId"/>, and it
|
||||
/// SUBSUMES the low <see cref="ResourceId"/> byte ids (Aether=1/Ore=2/Biomass=3) — a resource is just a
|
||||
/// low-id item of <see cref="ItemCategory.Resource"/>. KEEP ids 1-3 stable for the existing resources and
|
||||
/// reserve new item ids > 3; 0 = none. Entity/prefab refs do NOT live here (blobs don't remap entity
|
||||
/// refs) — a future companion buffer carries those, exactly like AbilityPrefabElement.
|
||||
///
|
||||
/// The blob is config (baked identically into both worlds, NOT replicated, NOT in SaveData), so growing
|
||||
/// this struct later (a granted-ability id, a StatModifier-spec array, a slot id for Phase 1/2/3) is a
|
||||
/// pure re-bake with zero migration: no SaveData version bump, no ghost-hash change, no desync. <see cref="Tier"/>
|
||||
/// is baked NOW because the project's progression axis is gear tiers, so Phase 2/3 tier gating is a
|
||||
/// content-only edit.
|
||||
/// </summary>
|
||||
public struct ItemDefBlob
|
||||
{
|
||||
/// <summary>Stable item id (ushort; 1-3 reserved for the existing resources, keep stable for saves).</summary>
|
||||
public ushort ItemId;
|
||||
|
||||
/// <summary>Broad category (see <see cref="ItemCategory"/>), stored as a byte.</summary>
|
||||
public byte Category;
|
||||
|
||||
/// <summary>Progression tier (0 = base). Higher-tier tools harvest higher-tier nodes / hit harder (Phase 2/3).</summary>
|
||||
public byte Tier;
|
||||
|
||||
/// <summary>Max units that stack in a single inventory slot (1 for non-stacking equipment).</summary>
|
||||
public int StackMax;
|
||||
|
||||
/// <summary>Designer-facing display name (shown in the HUD inventory panel).</summary>
|
||||
public FixedString64Bytes Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immutable designer-authored item database, baked from ScriptableObjects to a blob asset and shared by
|
||||
/// every entity (Burst-fast, zero per-instance cost). Looked up by stable <see cref="ItemDefBlob.ItemId"/>
|
||||
/// — ID-KEYED, never by array index, so inserting a new item never renumbers existing ids.
|
||||
///
|
||||
/// NOTE: the lookup is intentionally NOT a 'readonly' method. A readonly struct method forces a defensive
|
||||
/// copy of a field when calling a non-readonly member on it; copying a BlobArray breaks its relative-offset
|
||||
/// pointer, so the array would read as empty. A plain (non-readonly) method accesses the BlobArray in place.
|
||||
/// Always reach this through 'ref blob.Value' (mirrors <see cref="AbilityDatabaseBlob"/>).
|
||||
/// </summary>
|
||||
public struct ItemDatabaseBlob
|
||||
{
|
||||
public BlobArray<ItemDefBlob> Items;
|
||||
|
||||
/// <summary>Linear lookup by item id (the array is tiny). Returns false if not present.</summary>
|
||||
public bool TryGetItem(ushort id, out ItemDefBlob def)
|
||||
{
|
||||
for (int i = 0; i < Items.Length; i++)
|
||||
{
|
||||
if (Items[i].ItemId == id)
|
||||
{
|
||||
def = Items[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
def = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user