Carriable/WateringCan.cs
using System.Threading.Tasks;
using Clover.Items;
using Clover.Player;

namespace Clover.Carriable;

[Category( "Clover/Carriable" )]
public sealed class WateringCan : BaseCarriable
{
	[Property] public ParticleConeEmitter WaterParticles { get; set; }

	[Property] public SoundEvent WateringSound { get; set; }

	private SoundHandle _wateringSoundHandle;

	protected override void OnAwake()
	{
		base.OnAwake();
		if ( WaterParticles != null )
		{
			WaterParticles.Enabled = false;
		}
	}

	public override bool ShouldDisableMovement()
	{
		return WaterParticles?.Enabled ?? false;
	}


	public override void OnUseDown()
	{
		if ( !CanUse() )
		{
			return;
		}

		base.OnUseDown();

		NextUse = UseTime;

		if ( !Networking.IsHost )
		{
			Log.Error( "Only the host can use world altering items for now." );
			return;
		}

		var pos = Player.GetAimingGridPosition();

		var worldItems = Player.World.GetItems( pos ).ToList();

		if ( worldItems.Count == 0 )
		{
			_ = PourWaterAsync();
			return;
		}

		var floorItem = worldItems.FirstOrDefault( x => x.GetComponent<IWaterable>() != null );

		if ( floorItem != null )
		{
			WaterItem( floorItem );
			return;
		}

		_ = PourWaterAsync();
	}

	private async void WaterItem( WorldItem floorItem )
	{
		Log.Info( "Watering item." );
		// (floorItem.Node as IWaterable)?.OnWater( this );

		if ( !floorItem.Components.TryGet<IWaterable>( out var waterable ) )
		{
			Log.Warning( "Item is not waterable." );
			return;
		}

		waterable.OnWater( this );

		Durability--;

		await PourWaterAsync();
		Log.Info( "Item watered." );
	}

	[Rpc.Broadcast]
	public void StartEmitting()
	{
		if ( WaterParticles.IsValid() )
		{
			WaterParticles.Enabled = true;
		}
	}

	[Rpc.Broadcast]
	public void StopEmitting()
	{
		if ( WaterParticles.IsValid() )
		{
			WaterParticles.Enabled = false;
		}
	}

	private async Task PourWaterAsync()
	{
		Log.Info( "Wasting water." );

		// GetNode<AnimationPlayer>( "AnimationPlayer" ).Play( "watering" );
		// GetNode<AudioStreamPlayer3D>( "Watering" ).Play();
		StartEmitting();

		Model.LocalRotation = Rotation.FromPitch( -20 );

		_wateringSoundHandle = Sound.Play( WateringSound, WorldPosition );
		// await ToSignal( GetTree().CreateTimer( UseTime ), Timer.SignalName.Timeout );
		await Task.DelayRealtimeSeconds( UseTime );

		// GetNode<AudioStreamPlayer3D>( "Watering" ).Stop();
		_wateringSoundHandle?.Stop();

		StopEmitting();

		Model.LocalRotation = Rotation.Identity;

		Log.Info( "Water wasted." );
	}
}