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,54 @@
|
||||
using System.Collections.Generic;
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Collections;
|
||||
using Unity.Entities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Authoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Bakes the designer-authored item definitions into a single ItemDatabase blob singleton (immutable,
|
||||
/// shared, Burst-fast), mirroring AbilityDatabaseAuthoring. Place ONE in the gameplay subscene; it streams
|
||||
/// identically into the client and server worlds (config, not replicated). DependsOn each definition so a
|
||||
/// value change re-bakes the blob. Runtime lookup is ID-keyed (ItemDatabaseBlob.TryGetItem), so the list
|
||||
/// order here does not matter and inserting an item never renumbers existing ids.
|
||||
/// </summary>
|
||||
public class ItemDatabaseAuthoring : MonoBehaviour
|
||||
{
|
||||
[Tooltip("All item definitions in the game (resources + tools/gear). Looked up at runtime by ItemId.")]
|
||||
public List<ItemDefinition> Items = new List<ItemDefinition>();
|
||||
|
||||
private class DatabaseBaker : Baker<ItemDatabaseAuthoring>
|
||||
{
|
||||
public override void Bake(ItemDatabaseAuthoring authoring)
|
||||
{
|
||||
var entity = GetEntity(TransformUsageFlags.None);
|
||||
|
||||
int count = authoring.Items != null ? authoring.Items.Count : 0;
|
||||
|
||||
var builder = new BlobBuilder(Allocator.Temp);
|
||||
ref var root = ref builder.ConstructRoot<ItemDatabaseBlob>();
|
||||
var arr = builder.Allocate(ref root.Items, count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var def = authoring.Items[i];
|
||||
if (def == null) { arr[i] = default; continue; }
|
||||
DependsOn(def);
|
||||
arr[i] = new ItemDefBlob
|
||||
{
|
||||
ItemId = (ushort)def.ItemId,
|
||||
Category = def.Category,
|
||||
Tier = def.Tier,
|
||||
StackMax = def.StackMax,
|
||||
Name = def.DisplayName,
|
||||
};
|
||||
}
|
||||
|
||||
var blob = builder.CreateBlobAssetReference<ItemDatabaseBlob>(Allocator.Persistent);
|
||||
builder.Dispose();
|
||||
AddBlobAsset(ref blob, out _);
|
||||
AddComponent(entity, new ItemDatabase { Value = blob });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ee44dc3bc9f3164592195d4068be8d1
|
||||
@@ -0,0 +1,31 @@
|
||||
using ProjectM.Simulation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Authoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Designer-facing definition of one item (resource, tool, weapon, gear, consumable). Numeric/byte fields
|
||||
/// are baked into the ItemDatabase blob (immutable, Burst-fast runtime config). Category and Tier are
|
||||
/// BYTES, not enums, to dodge BOTH the MCP enum-drop hazard (manage_* silently drop enum fields when set
|
||||
/// via tooling) AND the cross-assembly enum-in-Burst hazard. UI icon/description are deferred to a later
|
||||
/// managed lookup keyed by id, exactly like AbilityDefinition.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Project M/Item Definition", fileName = "Item_")]
|
||||
public class ItemDefinition : ScriptableObject
|
||||
{
|
||||
[Tooltip("Stable item id (ushort range). Keep 1=Aether, 2=Ore, 3=Biomass; reserve >3 for new items; 0 = none.")]
|
||||
public int ItemId = 4;
|
||||
|
||||
public string DisplayName = "Item";
|
||||
|
||||
[Tooltip("ItemCategory byte: 0=Resource, 1=Tool, 2=Weapon, 3=Gear, 4=Consumable.")]
|
||||
public byte Category = ItemCategory.Resource;
|
||||
|
||||
[Tooltip("Progression tier (0 = base). Higher-tier tools harvest higher-tier nodes / hit harder.")]
|
||||
public byte Tier = 0;
|
||||
|
||||
[Min(1)]
|
||||
[Tooltip("Max units that stack in one inventory slot (1 for non-stacking equipment).")]
|
||||
public int StackMax = 999;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84295e2f852afac4fa4b7384857281d9
|
||||
Reference in New Issue
Block a user