A networked container component for loot. It stores a host-authoritative NetList of InventoryItem structs, exposes helpers to add, remove, query and clear items, and projects Items into gameplay ItemEntry tuples.
using System.Linq;
using System.Collections.Generic;
using Sandbox;
namespace BrickJam;
/// <summary>
/// A networkable inventory entry. Replaces the legacy non-networkable <c>ItemEntry</c> dictionary
/// key with a flat, host-synced struct (prefab resource name + rarity + count).
/// </summary>
public struct InventoryItem
{
public string PrefabName { get; set; }
public LootRarity Rarity { get; set; }
public int Count { get; set; }
}
/// <summary>
/// Player inventory. Scene-System port of the legacy <c>ContainerComponent : EntityComponent</c>.
///
/// The legacy code kept split server/client dictionaries kept in sync via <c>[ClientRpc]</c>.
/// Here the state is a single host-authoritative <see cref="NetList{T}"/> (<see cref="SyncFlags.FromHost"/>),
/// which replicates to every client automatically.
///
/// Deferred: the <c>InventoryChanged</c> event + <c>Player.StoreSave</c> hooks belong to the
/// UI/persist systems and are wired when those land.
/// </summary>
[Title( "Container" )]
[Category( "Loot" )]
public sealed partial class ContainerComponent : Component
{
[Property] public int Limit { get; set; } = 20;
[Sync( SyncFlags.FromHost )] public NetList<InventoryItem> Items { get; set; } = new();
/// <summary>All entries with their counts, as gameplay-facing <see cref="ItemEntry"/> values.</summary>
public IEnumerable<(ItemEntry entry, int count)> Entries =>
Items.Select( i => (new ItemEntry { Prefab = LootPrefab.Get( i.PrefabName ), Rarity = i.Rarity }, i.Count) );
public int Count => Items.Count;
private int IndexOf( ItemEntry entry )
{
var name = entry.Prefab?.ResourceName;
for ( var i = 0; i < Items.Count; i++ )
if ( Items[i].PrefabName == name && Items[i].Rarity == entry.Rarity )
return i;
return -1;
}
public bool Add( ItemEntry entry, int amount = 1 )
{
if ( !Networking.IsHost )
return false;
var index = IndexOf( entry );
if ( index >= 0 )
{
var item = Items[index];
item.Count += amount;
Items[index] = item;
return true;
}
if ( Items.Count >= Limit )
return false;
Items.Add( new InventoryItem
{
PrefabName = entry.Prefab?.ResourceName,
Rarity = entry.Rarity,
Count = amount
} );
return true;
}
public bool Remove( ItemEntry entry, int amount = 1 )
{
if ( !Networking.IsHost )
return false;
var index = IndexOf( entry );
if ( index < 0 || Items[index].Count < amount )
return false;
var item = Items[index];
item.Count -= amount;
if ( item.Count <= 0 )
Items.RemoveAt( index );
else
Items[index] = item;
return true;
}
public int Has( ItemEntry entry )
{
var index = IndexOf( entry );
return index < 0 ? 0 : Items[index].Count;
}
public void Clear()
{
if ( Networking.IsHost )
Items.Clear();
}
}