Editor utility for balcony/fixture barriers. It builds a barrier specification from a path and kit values, resolves barrier geometry into a shape, and exposes Build and Ghost helpers to generate mesh or ghost preview.
using System;
using System.Collections.Generic;
using Sandbox;
namespace Sunless.Architecture;
// Edge protection on anything hung off an elevation - a balcony's balustrade, a fire escape's landing
// rail, the rake beside a flight. The barrier engine already owns posts, bays, rails and balusters, so
// nothing here grows a second one: a fixture says where its edge is and how high to stand on it, exactly
// as ArchRoofGuard hands a parapet over.
public static class ArchFixtureGuard
{
// Bays are authored EDGE BY EDGE, so every station lands either on a corner or inside one straight
// stretch. Divided by arc length alone a bay spans a corner and its rail cuts the corner off.
public static ArchBarrierSpec Spec( ArchKit kit, float height, IReadOnlyList<Vector3> path, BarrierGround ground )
{
var spec = new ArchBarrierSpec
{
Style = BarrierStyle.Picket,
Top = PicketTop.Flat,
Ground = ground,
Height = MathF.Max( 12f, height ),
PanelLength = MathF.Max( 24f, kit.RoofGuardBay ),
PostSize = MathF.Max( 1f, kit.NewelSize ),
Rails = 2
};
for ( var edge = 0; edge + 1 < (path?.Count ?? 0); edge++ )
{
var division = ArchDivide.AtMost( (path[edge + 1] - path[edge]).Length, spec.PanelLength );
for ( var bay = 0; bay < division.Count; bay++ )
{
spec.Bays.Add( new ArchBarrierBay { Span = division.Step } );
}
}
return spec;
}
// One resolve for the generator and the ghost: the posts drawn are the posts built.
public static ArchBarrierShape Resolve( IReadOnlyList<Vector3> path, ArchBarrierSpec spec )
{
if ( path is not { Count: >= 2 } )
{
return new ArchBarrierShape();
}
return ArchBarrierShape.Resolve( ArchCurve.Polyline( path ), spec );
}
public static void Build( ArchMesh canvas, IReadOnlyList<Vector3> path, ArchKit kit, float height, BarrierGround ground, ArchBarrierBrushes brushes )
{
var spec = Spec( kit, height, path, ground );
ArchBarrierGen.Build( canvas, Resolve( path, spec ), spec, kit, brushes );
}
public static void Ghost( IReadOnlyList<Vector3> path, ArchKit kit, float height, BarrierGround ground )
{
var spec = Spec( kit, height, path, ground );
ArchGhost.Barrier( Resolve( path, spec ), spec );
}
}