Editor/Carve/ArchCutManifest.cs

Editor manifest class for the 'Cut' architecture kind. It defines metadata and behavior for ArchCutPart instances, including hosting types, labels, glyph, subtool, layer stage determination, filing/unfiling into buildings, loop extraction, and height lookup.

Reflection
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

namespace Sunless.Architecture;

public sealed class ArchCutManifest : ArchKindManifest<ArchCutPart>
{
	public override ArchKind Kind => ArchKind.Cut;

	public override string Slot => "Cuts";

	// A cut is world-space and a road carries its own, so every unit files them - which is why ArchPlan.AllCuts
	// walks Units rather than Buildings.
	public override IEnumerable<Type> Hosts => new[] { typeof( ArchUnit ) };

	public override string Label => "Cut";

	public override string Glyph => "content_cut";

	public override string Subtool => ArchSubtools.Bool;

	public override int DirectRank => 14;

	// A bite that wears damage finishes the surface it took; one that opens a shaft voids it, and only the part
	// knows which, so a bare kind falls to Void.
	public override ArchLayerStage Stage( object payload )
	{
		return payload is ArchCutPart { IsDamage: true } ? ArchLayerStage.Finish : ArchLayerStage.Void;
	}

	public override bool File( object host, object payload )
	{
		if ( payload is not ArchCutPart cut )
		{
			return false;
		}

		// Nesting a cut under a porch says what the bite belongs to, the way a walkway's deck record does, and
		// moves nothing the generator reads.
		if ( host is ArchPorchPart )
		{
			return true;
		}

		if ( host is not ArchBuilding building )
		{
			return false;
		}

		building.Cuts.Add( cut );

		return true;
	}

	public override bool Unfile( ArchPlan plan, object payload )
	{
		return payload is ArchCutPart cut && plan.Buildings.Any( building => building.Cuts.Remove( cut ) );
	}

	public override IReadOnlyList<List<Vector2>> Loops( object payload )
	{
		return payload is ArchCutPart cut ? cut.Outlines().ToList() : base.Loops( payload );
	}

	public override float Height( object payload, float fallback )
	{
		return payload is ArchCutPart cut && cut.Segments.Count > 0 ? cut.Segments[0].TopHeight : fallback;
	}
}