Editor/Services/ArchPickers.cs

Editor-side picker registry for architecture elements. Defines IArchPicker and ArchPicking which collects hit results during a pick operation, and ArchPickers which builds a table of available IArchPicker implementations and provides lookup/exception helpers.

Reflection
namespace Sunless.Architecture;

public interface IArchPicker
{
	ArchKind Kind { get; }

	void Under( ArchPicking picking );
}

public sealed class ArchPicking
{
	readonly List<ArchHit> hits;

	public ArchLayerNode Node { get; }
	public ArchKit Kit { get; }
	public int Level { get; }
	public Vector2 Point { get; }

	public ArchPicking( ArchLayerNode node, ArchKit kit, int level, Vector2 point, List<ArchHit> hits )
	{
		Node = node;
		Kit = kit;
		Level = level;
		Point = point;
		this.hits = hits;
	}

	public void Hit( ArchHitChannel channel, float distance, bool direct )
	{
		hits.Add( ArchPick.Hit( Node, channel, distance, direct ) );
	}

	public void HitChild( object payload, ArchHitChannel channel, float distance, bool direct )
	{
		hits.Add( ArchPick.Hit( ArchPick.Child( Node, payload ), channel, distance, direct ) );
	}
}

public sealed class ArchPickers : ArchTable<ArchPickers, ArchKind, IArchPicker>
{
	protected override IEnumerable<IArchPicker> Standing()
	{
		yield return new ArchStairPicker();
		yield return new ArchCarvedStairPicker();
		yield return new ArchPorchPicker();
		yield return new ArchRoadPicker();
	}

	protected override ArchKind KeyOf( IArchPicker picker ) => picker.Kind;

	protected override bool Accepts( IArchPicker picker ) => picker.Kind.Known;

	protected override string Collision( IArchPicker standing, IArchPicker picker )
	{
		return $"{picker.Kind.Ident} is picked by both {standing.GetType().Name} and {picker.GetType().Name}";
	}

	public IArchPicker For( ArchKind kind ) => Held( kind );

	public ArchPickers Except( ArchKind kind ) => Without( kind );
}