Editor data model for architectural barriers. Defines enums for barrier style and ground behaviour, a bay class for panel overrides, and ArchBarrierSpec which holds all editable parameters (dimensions, panel layout, posts, rails, wear/seed) with computed properties and a shallow copy method.
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace Sunless.Architecture;
// Append only - a member inserted mid-list renumbers the rest and silently restyles every authored barrier.
public enum BarrierStyle
{
Picket,
PrecastSlab,
Palisade,
Guardrail,
PostAndRail,
Bollards,
// Holds fill rather than standing on it, so ArchFenceGen stands ArchWing on the spline instead of posts.
Retaining,
Catenary
}
// Precast bays stay level and staircase; a picket fence rakes.
public enum BarrierGround
{
Follow,
Step,
Level
}
// Overrides what the panel length would have given.
public sealed class ArchBarrierBay
{
public float Span { get; set; }
public int Courses { get; set; }
public bool Gate { get; set; }
}
// Shared by fences and road barriers.
public sealed class ArchBarrierSpec
{
public BarrierStyle Style { get; set; } = BarrierStyle.Picket;
public BarrierGround Ground { get; set; } = BarrierGround.Follow;
public float Height { get; set; } = 40f;
// Bays are whole panels, remainder a short closing bay - panels don't stretch.
public float PanelLength { get; set; } = 96f;
public bool EvenBays { get; set; }
public List<ArchBarrierBay> Bays { get; set; } = new();
public float PostSize { get; set; } = 5f;
// On a precast wall this is what the droppers bolt to.
public float PostOverhang { get; set; }
public int Courses { get; set; } = 4;
public float CourseHeight { get; set; }
public float PanelThickness { get; set; } = 2.4f;
public float PlinthHeight { get; set; }
public int Rails { get; set; } = 2;
public PicketTop Top { get; set; } = PicketTop.Pointed;
public int Droppers { get; set; }
public float DropperLean { get; set; } = 35f;
public float DropperLength { get; set; } = 16f;
public int Strands { get; set; } = 6;
public float GateAt { get; set; }
public float GateWidth { get; set; }
// Wear leans and slips, Broken is missing panels, CourseVary steps a bay's height.
public int Seed { get; set; }
public float Wear { get; set; }
public float Broken { get; set; }
public int CourseVary { get; set; }
public bool HasGate => GateWidth > 8f;
// The plinth is part of the height - the stack finishes on Height.
public float Course => CourseHeight > 0.5f
? CourseHeight
: MathF.Max( 2f, (Height - PlinthHeight) / Math.Max( 1, Courses ) );
public ArchBarrierSpec Copy()
{
var copy = (ArchBarrierSpec)MemberwiseClone();
copy.Bays = Bays.Select( bay => new ArchBarrierBay { Span = bay.Span, Courses = bay.Courses, Gate = bay.Gate } ).ToList();
return copy;
}
}