Items/Pickups/BasePickup.cs
/// <summary>
/// A weapon, or weapons, or ammo, that can be picked up
/// </summary>
public abstract class BasePickup : Component, Component.ITriggerListener, Component.IPressable
{
	/// <summary>
	/// The pickup's collider, it is required
	/// </summary>
	[RequireComponent] public Collider Collider { get; set; }

	/// <summary>
	/// Should this pickup respawn over time, or just be destroyed on consume?
	/// </summary>
	[Property] public bool ShouldRespawn { get; set; } = true;

	/// <summary>
	/// How long should it take for this pickup to respawn?
	/// </summary>
	[Property] public float RespawnTimer { get; set; } = 5;

	/// <summary>
	/// The sound to play when picking up this item
	/// </summary>
	[Property] public SoundEvent PickupSound { get; set; }

	/// <summary>
	/// Are we allowed to pick up?
	/// </summary>
	[Sync] public bool IsPickupEnabled { get; set; } = true;

	protected override void OnEnabled()
	{
		base.OnEnabled();
		GameObject.Tags.Add( "pickup" );
	}

	/// <summary>
	/// Check if the player can pick up this object
	/// </summary>
	public virtual bool CanPickup( Player player, PlayerInventory inventory )
	{
		return true;
	}

	/// <summary>
	/// Give the player the effect of this pickup
	/// </summary>
	/// <returns>Should this object be consumed, eg on successful pickup</returns>
	protected virtual bool OnPickup( Player player, PlayerInventory inventory )
	{
		return true;
	}

	/// <summary>
	/// Called when a gameobject enters the trigger.
	/// </summary>
	void ITriggerListener.OnTriggerEnter( Collider other )
	{
		TryPickup( other.GameObject );
	}

	protected void TryPickup( GameObject other )
	{
		if ( !Networking.IsHost ) return;
		if ( GameObject.IsDestroyed ) return;
		if ( !IsPickupEnabled ) return;

		if ( !other.Components.TryGet( out Player player, FindMode.InParent ) )
			return;

		var inventory = player.Inventory;

		if ( !CanPickup( player, inventory ) )
			return;

		if ( !OnPickup( player, inventory ) )
			return;

		PlayPickupEffects( player );

		if ( ShouldRespawn )
		{
			Disable();
			Invoke( RespawnTimer, Enable );
		}
		else
		{
			DestroyGameObject();
		}
	}

	[Rpc.Broadcast]
	private void PlayPickupEffects( Player player )
	{
		if ( Application.IsDedicatedServer ) return;

		var snd = GameObject.PlaySound( PickupSound );
		if ( !snd.IsValid() )
			return;

		if ( player.IsValid() && player.IsLocalPlayer )
		{
			snd.SpacialBlend = 0;
		}
	}


	[Rpc.Broadcast]
	private void PlayRespawnEffects()
	{
		if ( Application.IsDedicatedServer ) return;

		Sound.Play( "items/item_respawn.sound", WorldPosition );
	}

	private void Enable()
	{
		IsPickupEnabled = true;
		Collider.Enabled = true;

		foreach ( var child in GameObject.Children )
		{
			child.Enabled = true;
		}

		Network.Refresh();
		PlayRespawnEffects();
	}

	private void Disable()
	{
		IsPickupEnabled = false;
		Collider.Enabled = false;

		foreach ( var child in GameObject.Children )
		{
			child.Enabled = false;
		}

		Network.Refresh();
	}


	bool IPressable.Press( IPressable.Event e )
	{
		TryPickup( e.Source.GameObject );
		return true;
	}

	bool IPressable.CanPress( Sandbox.Component.IPressable.Event e )
	{
		if ( !e.Source.Components.TryGet( out Player player ) )
			return false;

		if ( !player.Components.TryGet( out PlayerInventory inventory ) )
			return false;

		return CanPickup( player, inventory );
	}
}