Park/SelectionSystem.cs
using HC3.Terraforming;
using HC3.UI;

namespace HC3;

/// <summary>
/// Handles selecting objects in the world and showing selection effects.
/// </summary>
public sealed class SelectionSystem : Component
{
	/// <summary>
	/// Singleton
	/// </summary>
	public static SelectionSystem Instance { get; private set; }

	// Currently selected object
	GameObject Selected;

	// Currently hovered object -- this can differ from the selected object
	GameObject Hovered;

	protected override void OnAwake()
	{
		Instance = this;
	}

	protected override void OnUpdate()
	{
		if ( Input.Released( "Attack1" ) )
		{
			// Get screen ray
			var screenToWorld = Scene.Camera.ScreenPixelToRay( Mouse.Position );

			// Trace to the ground
			var trace = Scene.Trace.Ray( screenToWorld, 1024000f )
					.UsePhysicsWorld()
					.HitTriggers()
					.WithTag( "selectable" )
					.RunAll();

			// Find selectable
			var obj = trace
				.OrderByDescending( x => x.GameObject.GetComponent<Guest>() is not null )
				.ThenBy( x => x.Distance )
				.FirstOrDefault();

			Hovered = obj.GameObject;

			Select( Hovered );
		}
	}

	/// <summary>
	/// Called when we select something
	/// </summary>
	/// <param name="inspectable"></param>
	public void OnSelected( IInspectable inspectable )
	{
		ShowEffect( Selected, false );

		Selected = inspectable?.GameObject;
		IInspectable.Current = inspectable;

		// Do we have any effects?
		ShowEffect( Selected, true );
	}

	/// <summary>
	/// Show a selection effect if the GameObject we're selecting has a <see cref="SelectionEffect"/> component
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="show"></param>
	private void ShowEffect( GameObject obj, bool show )
	{
		if ( !obj.IsValid() )
			return;

		var effectComponent = obj.GetComponentInChildren<SelectionEffect>( true );
		if ( !effectComponent.IsValid() ) return;

		effectComponent.GameObject.Enabled = show;
	}

	/// <summary>
	/// We are selecting an object
	/// </summary>
	/// <param name="obj"></param>
	public void Select( GameObject obj )
	{
		if ( !obj.IsValid() )
		{
			return;
		}

		// TODO: Split this out, this is shit

		if ( BuildingPlacer.Instance.IsPlacing || BuildingPlacer.Instance.IsDestroying )
			return;

		if ( Terraformer.Instance?.IsTerraforming ?? false )
			return;

		/// Do we have an inspectable?
		if ( obj.GetComponentInParent<IInspectable>() is { IsValid: true } inspectable )
		{
			if ( inspectable.Select() is { } inspector )
			{
				// TODO: Configurable sound?
				Sound.Play( "click5" );
				WindowManager.Instance.Open( inspector );
			}
		}
	}
}