Editor-side integration layer for surface and ground fitting in Advanced Mapping Tools. Defines ISurfaceAwareSettings, a SurfaceIntegration helper that builds a SurfaceBuildContext when surface or mount fitting is enabled, a GroundAwareStampEditor base that exposes ground probe properties and records debug info during mesh builds, plus partial additions to BalconyStudioSettings and BalconyStudioEditor for column ground fitting.
namespace AdvancedMappingTools;
public interface ISurfaceAwareSettings
{
bool SurfaceEnabled { get; }
SurfaceProbeOptions ProbeOptions();
}
public static class SurfaceIntegration
{
public static SurfaceBuildContext Context( GeneratorSettings settings, Scene scene, Transform world, GameObject ignore = null ) => (settings is ISurfaceAwareSettings aware && aware.SurfaceEnabled || settings is IAnchorAwareSettings mounts && mounts.MountsEnabled) ? new( SurfaceSolver.Begin( scene, ignore.IsValid() ? [ignore] : null ), world ) : null;
}
public abstract class GroundAwareStampEditor( PrimitiveTool tool ) : StampEditor( tool )
{
[Property, Group( "Surface & Ground" ), WideMode]
public bool FitToGround { get; set; }
[Property, Group( "Surface & Ground" ), Range( .01f, 100000, slider: false ), WideMode]
public float GroundRange { get; set; } = 2048;
[Property, Group( "Surface & Ground" ), Range( 0, 4096, slider: false ), WideMode]
public float GroundMinimum { get; set; } = .01f;
[Property, Group( "Surface & Ground" ), Range( -4096, 4096, slider: false ), WideMode]
public float GroundOffset { get; set; }
[Property, Group( "Surface & Ground" ), WideMode]
public SurfaceSelection GroundSelection { get; set; } = SurfaceSelection.Nearest;
[Property, Group( "Surface & Ground" ), WideMode]
public SurfaceKind GroundKind { get; set; }
[Property, Group( "Surface & Ground" ), WideMode]
public string GroundIncludeTags { get; set; } = "";
[Property, Group( "Surface & Ground" ), WideMode]
public string GroundExcludeTags { get; set; } = "";
[Property, Group( "Surface & Ground" ), WideMode]
public bool ManualGroundLength { get; set; }
[Property, Group( "Surface & Ground" ), Range( 1, 100000, slider: false ), WideMode]
public float GroundLength { get; set; } = 160;
[Property, Group( "Surface & Ground" ), WideMode]
public bool ShowGroundDebug { get; set; }
[System.Text.Json.Serialization.JsonIgnore, Property, ReadOnly, Group( "Surface & Ground" ), WideMode]
public string GroundStatus => FitToGround ? SurfaceDebug.Summary( Title ) : "Ground fitting off; original dimensions.";
public override bool ChangesOtherSettings( string property ) => property is nameof( FitToGround ) or nameof( ManualGroundLength );
public override IReadOnlySet<string> UnusedOptions
{
get
{
var h = new HashSet<string>( base.UnusedOptions );
if ( !FitToGround )
h.UnionWith( [nameof( GroundRange ), nameof( GroundMinimum ), nameof( GroundOffset ), nameof( GroundSelection ), nameof( GroundKind ), nameof( GroundIncludeTags ), nameof( GroundExcludeTags ), nameof( ManualGroundLength ), nameof( GroundLength ), nameof( ShowGroundDebug )] );
if ( !ManualGroundLength )
h.Add( nameof( GroundLength ) );
return h;
}
}
protected SurfaceProbeOptions Options() => new()
{
Enabled = FitToGround,
MaximumDistance = GroundRange,
MinimumDistance = GroundMinimum,
Offset = GroundOffset,
Selection = GroundSelection,
Kind = GroundKind,
IncludeTags = GroundIncludeTags,
ExcludeTags = GroundExcludeTags,
Manual = ManualGroundLength,
ManualDistance = GroundLength
};
protected SurfaceReadSession GroundRead { get; private set; }
protected override void BuildMesh( MeshKit kit )
{
GroundRead = FitToGround ? SurfaceSolver.Begin( SceneEditorSession.Active?.Scene ?? Game.ActiveScene ) : null;
try
{
base.BuildMesh( kit );
}
finally
{
if ( GroundRead != null )
SurfaceDebug.Record( Title, GroundRead );
GroundRead = null;
}
}
public override void OnUpdate( SceneTrace trace )
{
base.OnUpdate( trace );
if ( FitToGround && ShowGroundDebug )
SurfaceDebug.Draw( Title );
}
}
public sealed partial class BalconyStudioSettings
{
[Property, Group( "Surface & Ground" ), WideMode]
public bool FitColumnsToGround { get; set; }
[Property, Group( "Surface & Ground" ), Range( .01f, 100000, slider: false ), WideMode]
public float GroundRange { get; set; } = 2048;
[Property, Group( "Surface & Ground" ), Range( 0, 4096, slider: false ), WideMode]
public float GroundMinimum { get; set; } = .01f;
[Property, Group( "Surface & Ground" ), Range( -4096, 4096, slider: false ), WideMode]
public float GroundOffset { get; set; }
[Property, Group( "Surface & Ground" ), WideMode]
public SurfaceSelection GroundSelection { get; set; }
[Property, Group( "Surface & Ground" ), WideMode]
public SurfaceKind GroundKind { get; set; }
[Property, Group( "Surface & Ground" ), WideMode]
public string GroundIncludeTags { get; set; } = "";
[Property, Group( "Surface & Ground" ), WideMode]
public string GroundExcludeTags { get; set; } = "";
[Property, Group( "Surface & Ground" ), WideMode]
public bool ManualGroundLength { get; set; }
[Property, Group( "Surface & Ground" ), Range( 1, 100000, slider: false ), WideMode]
public float GroundLength { get; set; } = 128;
[Property, Group( "Surface & Ground" ), WideMode]
public bool ShowGroundDebug { get; set; }
[System.Text.Json.Serialization.JsonIgnore, Property, ReadOnly, Group( "Surface & Ground" ), WideMode]
public string GroundStatus => SurfaceEnabled ? SurfaceDebug.Summary( "Balcony Studio" ) : "Ground fitting off; original support dimensions.";
[System.Text.Json.Serialization.JsonIgnore]
public bool SurfaceEnabled => FitColumnsToGround && SupportColumns;
public SurfaceProbeOptions ProbeOptions() => new()
{
Enabled = SurfaceEnabled,
MaximumDistance = GroundRange,
MinimumDistance = GroundMinimum,
Offset = GroundOffset,
Selection = GroundSelection,
Kind = GroundKind,
IncludeTags = GroundIncludeTags,
ExcludeTags = GroundExcludeTags,
Manual = ManualGroundLength,
ManualDistance = GroundLength
};
void HideGroundSettings( HashSet<string> h )
{
if ( !SupportColumns )
h.Add( nameof( FitColumnsToGround ) );
if ( !SurfaceEnabled )
h.UnionWith( [nameof( GroundRange ), nameof( GroundMinimum ), nameof( GroundOffset ), nameof( GroundSelection ), nameof( GroundKind ), nameof( GroundIncludeTags ), nameof( GroundExcludeTags ), nameof( ManualGroundLength ), nameof( GroundLength ), nameof( ShowGroundDebug )] );
if ( !ManualGroundLength )
h.Add( nameof( GroundLength ) );
}
}
public sealed partial class BalconyStudioEditor
{
public override void OnUpdate( SceneTrace trace )
{
base.OnUpdate( trace );
if ( Settings.SurfaceEnabled && Settings.ShowGroundDebug )
SurfaceDebug.Draw( "Balcony Studio" );
if ( Settings.MountsEnabled && Settings.ShowMountDebug )
SurfaceDebug.Draw( Settings.MountOwner );
}
}