Code/ItemPickup.cs
using Sandbox;
using System;

public enum PickupMode
{
    /// <summary>Automatically picks up when a player walks within PickupRadius.</summary>
    Proximity,
    /// <summary>Picked up via PlayerPickupHandler raycast (E key).</summary>
    Raycast,
    /// <summary>Only picked up when Pickup() is called directly from code.</summary>
    Manual
}

public class ItemPickup : Component
{
    /// <summary>How this item can be picked up.</summary>
    [Property] public PickupMode Mode { get; set; } = PickupMode.Proximity;

    /// <summary>The item to give to the player on pickup.</summary>
    [Property] public InventoryItem Item { get; set; }

    /// <summary>How many of the item to give.</summary>
    [Property, Range( 1, 999 )] public int Quantity { get; set; } = 1;

    /// <summary>If true, the GameObject is destroyed after a successful pickup.</summary>
    [Property] public bool DestroyOnPickup { get; set; } = true;

    /// <summary>Proximity pickup radius in world units.</summary>
    [Property] public float PickupRadius { get; set; } = 100f;

    /// <summary>Fired when the item is successfully picked up.</summary>
    public event Action<InventoryComponent> OnPickupSuccess;

    /// <summary>Fired when a pickup attempt fails (e.g. inventory full).</summary>
    public event Action<InventoryComponent> OnPickupFailed;

    private TimeSince _lastProximityCheck;

    protected override void OnUpdate()
    {
        if ( Mode != PickupMode.Proximity ) return;
        if ( Item == null ) return;
        if ( _lastProximityCheck < 0.25f ) return;
        _lastProximityCheck = 0;

        var allInventory = Scene.GetAllComponents<InventoryComponent>();
        foreach ( var inv in allInventory )
        {
            float dist = inv.Transform.Position.Distance( Transform.Position );
            if ( dist <= PickupRadius )
            {
                if ( Pickup( inv ) )
                    break;
            }
        }
    }

    /// <summary>
    /// Attempt to give this item to the given inventory.
    /// Returns true on success. Fires OnPickupSuccess or OnPickupFailed accordingly.
    /// </summary>
    public bool Pickup( InventoryComponent inventory )
    {
        if ( Item == null || inventory == null )
            return false;

        if ( !CanPickup( inventory ) )
            return false;

        int leftover = inventory.GiveItem( Item, Quantity );
        if ( leftover > 0 )
        {
            OnPickupFailed?.Invoke( inventory );
            return false;
        }

        OnPickupSuccess?.Invoke( inventory );

        if ( DestroyOnPickup )
            GameObject.Destroy();

        return true;
    }

    /// <summary>Override to add custom pickup conditions. Returns true by default.</summary>
    protected virtual bool CanPickup( InventoryComponent inventory ) => true;
}