EquipmentSlots.cs
using Sandbox;
using System;
using System.Collections.Generic;
using System.Text;

/// <summary>
/// Manages named equipment slots (head, chest, weapon, etc.)
/// Each EquipSlot enum value that isn't None gets one slot.
/// </summary>
public class EquipmentSlots
{
    private readonly Dictionary<EquipSlot, InventorySlot> _slots = new();

    public EquipmentSlots()
    {
        // Create one slot for every equip slot type except None
        foreach ( EquipSlot slotType in Enum.GetValues( typeof( EquipSlot ) ) )
        {
            if ( slotType == EquipSlot.None ) continue;
            _slots[slotType] = new InventorySlot();
        }
    }

    /// <summary>Returns the InventorySlot for the given equipment slot type, or null if not found.</summary>
    public InventorySlot GetSlot( EquipSlot slotType )
        => _slots.TryGetValue( slotType, out var slot ) ? slot : null;

    /// <summary>Returns true if the given equipment slot is empty or doesn't exist.</summary>
    public bool IsSlotEmpty( EquipSlot slotType )
        => GetSlot( slotType )?.IsEmpty ?? true;

    /// <summary>
    /// Equip an item into its designated slot.
    /// Returns the item that was previously in that slot (if any), or null.
    /// </summary>
    public InventoryItem Equip( InventoryItem item )
    {
        if ( item == null || item.EquipSlot == EquipSlot.None ) return null;

        var slot = GetSlot( item.EquipSlot );
        if ( slot == null ) return null;

        // Grab whatever was there before
        var previous = slot.IsEmpty ? null : slot.Item;
        slot.Clear();
        slot.Set( item, 1 );
        return previous;
    }

    /// <summary>
    /// Unequip whatever is in the given slot. Returns the item, or null if empty.
    /// </summary>
    public InventoryItem Unequip( EquipSlot slotType )
    {
        var slot = GetSlot( slotType );
        if ( slot == null || slot.IsEmpty ) return null;

        var item = slot.Item;
        slot.Clear();
        return item;
    }

    /// <summary>Iterates over all equipment slot key-value pairs.</summary>
    public IEnumerable<KeyValuePair<EquipSlot, InventorySlot>> AllSlots()
        => _slots;

    // ─── Network Serialization ───────────────────────────────────

    /// <summary>
    /// Format: "Head=item/path:1|Chest=item/path:1|..."
    /// </summary>
    public string Serialize()
    {
        var sb = new StringBuilder();
        bool first = true;
        foreach ( var kvp in _slots )
        {
            if ( !first ) sb.Append( '|' );
            first = false;
            sb.Append( kvp.Key.ToString() );
            sb.Append( '=' );
            sb.Append( kvp.Value.Serialize() );
        }
        return sb.ToString();
    }

    public void Deserialize( string data )
    {
        // Clear all first
        foreach ( var slot in _slots.Values )
            slot.Clear();

        if ( string.IsNullOrEmpty( data ) ) return;

        foreach ( var entry in data.Split( '|' ) )
        {
            var parts = entry.Split( '=' );
            if ( parts.Length != 2 ) continue;

            if ( Enum.TryParse<EquipSlot>( parts[0], out var slotType )
                 && _slots.TryGetValue( slotType, out var slot ) )
            {
                slot.Deserialize( parts[1] );
            }
        }
    }
}