using Unity.Entities; using Unity.NetCode; namespace ProjectM.Simulation { /// /// One (item, count) row in a player's PERSONAL inventory. The per-player DynamicBuffer of these is the /// server-authoritative source of what that player is carrying. A structural twin of /// : a [GhostField] buffer with so the owning /// (predicting) client receives its own inventory — without it the owner, being the owner, would not get /// the owner-typed buffer at all and the HUD would read empty. BOTH fields carry [GhostField]; the /// [GhostComponent] attribute alone does NOT auto-replicate fields (an un-annotated field ships as a /// silent zero), so the annotations mirror field-for-field. /// /// REPLICATION DISCIPLINE — the ONLY writers are server-only: /// (harvest yield) and the deposit-to-base RPC handler, both in the plain server SimulationSystemGroup. So /// there is no predicted-loop double-apply and the owner never mispredicts its inventory — it is a pure /// server-authored snapshot. NEVER mutate this from a client predicted system (that would reintroduce a /// double-apply / mispredict path). ItemId is the same opaque ushort id space as /// and the catalog. /// /// NOTE: adding this [GhostField] buffer CHANGES the player ghost serialization hash — the player prefab / /// subscene MUST be re-baked (consistently in both worlds) or the connect handshake desyncs. /// [GhostComponent(OwnerSendType = SendToOwnerType.All)] [InternalBufferCapacity(24)] public struct InventorySlot : IBufferElementData { /// Item carried in this slot (0 = empty/unused; aligns with InventoryMath's 0-id no-op). [GhostField] public ushort ItemId; /// Quantity in this slot (bounded by the item's StackMax when deposited via InventoryMath). [GhostField] public int Count; } }