Property sheet for the DistrictEditor tool, split into a partial class. Declares the building mix, street, canal, bridge and overpass enums and all the generation options exposed in the editor inspector, plus an UnusedOptions override that hides groups of properties which do not apply to the current mix or feature toggles.
namespace AdvancedMappingTools;
public enum WorldBuildingMix
{
DistrictStyle,
MixedCity,
Houses,
HighRises,
Custom,
NewYork
}
public enum WorldStreetPattern
{
Grid,
Organic,
LongBlocks
}
public enum WorldBridgeStyle
{
Girder,
Arch,
Truss
}
public sealed partial class DistrictEditor
{
internal Material ContentSurface => Surface ?? Tool?.ActiveMaterial ?? Material.Load( GenContext.DefaultMaterial );
[Property, Group( "Buildings" ), Title( "Place Buildings" ), WideMode]
public bool PlaceBuildings { get; set; } = true;
[Property, Group( "Buildings" ), Title( "Building Mix" ), WideMode]
public WorldBuildingMix BuildingMix { get; set; } = WorldBuildingMix.MixedCity;
[Property, Group( "Buildings" ), Range( 0, 1 ), WideMode]
public float BuildingDensity { get; set; } = .8f;
[Property, Group( "Buildings" ), Title( "Building Limit" ), Range( 1, 256, slider: false ), WideMode, Description( "Maximum buildings per generation. Detailed buildings contain many editable parts." )]
public int BuildingLimit { get; set; } = 32;
[Property, Group( "Buildings" ), Title( "Building Part Budget" ), Range( 1000, 100000, slider: false ), WideMode, Description( "Stops placement before this many detailed building parts. Raise carefully for large cities." )]
public int BuildingPartBudget { get; set; } = 16000;
[Property, Group( "Buildings" ), Range( 0, 128, slider: false ), WideMode]
public float Setback { get; set; } = 24;
[Property, Group( "Buildings" ), Title( "Plot Coverage" ), Range( .2f, .99f ), WideMode]
public float PlotCoverage { get; set; } = .75f;
[Property, Group( "Building Heights" ), Title( "House Floors Min" ), Range( 1, 16, slider: false ), WideMode]
public int HouseFloorsMin { get; set; } = 1;
[Property, Group( "Building Heights" ), Title( "House Floors Max" ), Range( 1, 16, slider: false ), WideMode]
public int HouseFloorsMax { get; set; } = 3;
[Property, Group( "Building Heights" ), Title( "Apartment Floors Min" ), Range( 1, 32, slider: false ), WideMode]
public int ApartmentFloorsMin { get; set; } = 3;
[Property, Group( "Building Heights" ), Title( "Apartment Floors Max" ), Range( 1, 32, slider: false ), WideMode]
public int ApartmentFloorsMax { get; set; } = 7;
[Property, Group( "Building Heights" ), Title( "High-Rise Floors Min" ), Range( 2, 64, slider: false ), WideMode]
public int TowerFloorsMin { get; set; } = 10;
[Property, Group( "Building Heights" ), Title( "High-Rise Floors Max" ), Range( 2, 64, slider: false ), WideMode]
public int TowerFloorsMax { get; set; } = 20;
[Property, Group( "Building Heights" ), Title( "Storey Height" ), Range( 80, 256, slider: false ), WideMode]
public float BuildingStoreyHeight { get; set; } = 128;
[Property, Group( "Building Details" ), Title( "House Roof" ), WideMode]
public HouseRoof HouseRoofStyle { get; set; } = HouseRoof.Gable;
[Property, Group( "Building Details" ), Title( "Balconies" ), WideMode]
public bool BuildingBalconies { get; set; } = false;
[Property, Group( "Building Details" ), Title( "House Interiors" ), WideMode]
public bool BuildingInteriors { get; set; } = false;
[Property, Group( "Building Details" ), Title( "Facade Variation" ), Range( 0, 1 ), WideMode]
public float BuildingVariation { get; set; } = .15f;
[Property, Group( "New York" ), Title( "Tower Share" ), Range( 0, 1 ), WideMode]
public float NewYorkTowerShare { get; set; } = .38f;
[Property, Group( "New York" ), Title( "Brownstone Share" ), Range( 0, 1 ), WideMode]
public float NewYorkBrownstoneShare { get; set; } = .18f;
[Property, Group( "New York" ), Title( "Fire Escapes" ), WideMode]
public bool NewYorkFireEscapes { get; set; } = true;
[Property, Group( "New York" ), Title( "Roof Water Tanks" ), WideMode]
public bool NewYorkWaterTanks { get; set; } = true;
[Property, Group( "New York" ), Title( "Tower Setbacks" ), WideMode]
public bool NewYorkSetbacks { get; set; } = true;
[Property, Group( "New York" ), Title( "Detailed Window Frames" ), WideMode, Description( "Adds more geometry for close-up façades. Dense districts stay cheaper with it off." )]
public bool NewYorkWindowFrames { get; set; } = false;
[Property, Group( "Custom Mix" ), Title( "House Weight" ), Range( 0, 100, slider: false ), WideMode]
public float HouseWeight { get; set; } = 40;
[Property, Group( "Custom Mix" ), Title( "Apartment Weight" ), Range( 0, 100, slider: false ), WideMode]
public float ApartmentWeight { get; set; } = 25;
[Property, Group( "Custom Mix" ), Title( "High-Rise Weight" ), Range( 0, 100, slider: false ), WideMode]
public float TowerWeight { get; set; } = 15;
[Property, Group( "Custom Mix" ), Title( "Warehouse Weight" ), Range( 0, 100, slider: false ), WideMode]
public float WarehouseWeight { get; set; } = 5;
[Property, Group( "Street Variety" ), Title( "Street Layout" ), WideMode, Description( "Organic adds at least 0.12 crossing irregularity. Long Blocks doubles the block aspect ratio." )]
public WorldStreetPattern StreetPattern { get; set; }
[Property, Group( "Street Variety" ), Title( "Block Aspect Ratio" ), Range( .5f, 3 ), WideMode]
public float BlockAspect { get; set; } = 1;
[Property, Group( "Street Variety" ), Title( "Vary Streets" ), WideMode]
public bool VaryStreets { get; set; } = true;
[Property, Group( "Street Variety" ), Title( "Side Street Type" ), WideMode]
public RoadType SideStreetType { get; set; } = RoadType.Service;
[Property, Group( "Street Variety" ), Title( "Side Street Width" ), Range( .4f, 1 ), WideMode, Description( "Fraction of Street Width. Main roads keep the full reserved width." )]
public float SideStreetWidth { get; set; } = .7f;
[Property, Group( "Street Variety" ), Title( "Main Street Share" ), Range( 0, 1 ), WideMode]
public float MainStreetShare { get; set; } = .35f;
[Property, Group( "Street Variety" ), Title( "Curve Streets" ), Range( 0, .08f ), WideMode, Description( "Bends each street within its reserved corridor; junction positions remain unchanged." )]
public float StreetBend { get; set; } = .025f;
[Property, Group( "Canal" ), Title( "Add Canal" ), WideMode]
public bool AddCanal { get; set; } = false;
[Property, Group( "Canal" ), Title( "Canal Width" ), Range( 64, 2048, slider: false ), WideMode]
public float CanalWidth { get; set; } = 320;
[Property, Group( "Canal" ), Title( "Canal Depth" ), Range( 16, 512, slider: false ), WideMode]
public float CanalDepth { get; set; } = 96;
[Property, Group( "Canal" ), Title( "Canal Angle" ), Range( -180, 180, slider: false ), WideMode]
public float CanalAngle { get; set; } = 90;
[Property, Group( "Canal" ), Title( "Canal Offset" ), Range( -16384, 16384, slider: false ), WideMode]
public float CanalOffset { get; set; } = 0;
[Property, Group( "Bridges" ), Title( "Bridge Style" ), WideMode]
public WorldBridgeStyle BridgeStyle { get; set; } = WorldBridgeStyle.Girder;
[Property, Group( "Bridges" ), Title( "Canal Bridge Rise" ), Range( 0, 128, slider: false ), WideMode]
public float CanalBridgeRise { get; set; } = 8;
[Property, Group( "Bridges" ), Title( "Railing Height" ), Range( 0, 128, slider: false ), WideMode]
public float BridgeRailingHeight { get; set; } = 36;
[Property, Group( "Bridges" ), Title( "Walkway Width" ), Range( 0, 128, slider: false ), WideMode]
public float BridgeWalkwayWidth { get; set; } = 32;
[Property, Group( "Bridges" ), Title( "Railing Post Spacing" ), Range( 48, 256, slider: false ), WideMode]
public float BridgePostSpacing { get; set; } = 96;
[Property, Group( "Bridges" ), Title( "Support Spacing" ), Range( 128, 4096, slider: false ), WideMode]
public float BridgeSupportSpacing { get; set; } = 768;
[Property, Group( "Bridges" ), Title( "Deck Thickness" ), Range( 8, 128, slider: false ), WideMode]
public float BridgeThickness { get; set; } = 24;
[Property, Group( "Materials" ), Title( "Bridge Road Surface" ), WideMode]
public Material BridgeRoadMaterial { get; set; }
[Property, Group( "Overpass" ), Title( "Add Overpass" ), WideMode]
public bool AddOverpass { get; set; } = false;
[Property, Group( "Overpass" ), Title( "Overpass Height" ), Range( 192, 2048, slider: false ), WideMode]
public float OverpassHeight { get; set; } = 384;
[Property, Group( "Overpass" ), Title( "Ramp Length" ), Range( 256, 8192, slider: false ), WideMode]
public float OverpassRamp { get; set; } = 2048;
[Property, Group( "Overpass" ), Title( "Overpass Offset" ), Range( -16384, 16384, slider: false ), WideMode]
public float OverpassOffset { get; set; } = 0;
[Property, Group( "Materials" ), Title( "Building Walls" ), WideMode]
public Material BuildingWallMaterial { get; set; }
[Property, Group( "Materials" ), Title( "Building Roofs" ), WideMode]
public Material BuildingRoofMaterial { get; set; }
[Property, Group( "Materials" ), Title( "Building Glass" ), WideMode]
public Material BuildingGlassMaterial { get; set; }
[Property, Group( "Materials" ), Title( "Bridge Structure" ), WideMode]
public Material BridgeMaterial { get; set; }
[Property, Group( "Materials" ), Title( "Canal Water" ), WideMode]
public Material WaterMaterial { get; set; }
string _lastContentStatus;
[Property, ReadOnly, Group( "District" ), WideMode]
public string ContentPreview => _lastContentStatus ?? "Building volumes preview the height mix. Creation places editable building/bridge parts. The canal cuts generated blocks, not existing terrain.";
public override IReadOnlySet<string> UnusedOptions => ContentHidden();
IReadOnlySet<string> ContentHidden()
{
var hidden = new HashSet<string>();
if ( !PlaceBuildings )
foreach ( var p in Sandbox.Internal.GlobalToolsNamespace.EditorTypeLibrary.GetType( GetType() ).Properties.Where( p => p.Group is "Buildings" or "Building Heights" or "Building Details" or "Custom Mix" or "New York" ) )
if ( p.Name != nameof( PlaceBuildings ) )
hidden.Add( p.Name );
if ( !AddCanal && !AddOverpass )
hidden.UnionWith( new[] { nameof( BridgeStyle ), nameof( BridgeRailingHeight ), nameof( BridgeMaterial ), nameof( BridgeWalkwayWidth ), nameof( BridgePostSpacing ), nameof( BridgeSupportSpacing ), nameof( BridgeThickness ), nameof( BridgeRoadMaterial ) } );
if ( BuildingMix == WorldBuildingMix.HighRises )
hidden.UnionWith( new[] { nameof( HouseFloorsMin ), nameof( HouseFloorsMax ), nameof( ApartmentFloorsMin ), nameof( ApartmentFloorsMax ), nameof( HouseRoofStyle ), nameof( BuildingInteriors ) } );
if ( BuildingMix == WorldBuildingMix.Houses )
hidden.UnionWith( new[] { nameof( TowerFloorsMin ), nameof( TowerFloorsMax ), nameof( ApartmentFloorsMin ), nameof( ApartmentFloorsMax ), nameof( BuildingBalconies ) } );
if ( BuildingMix == WorldBuildingMix.DistrictStyle )
hidden.UnionWith( new[] { nameof( TowerFloorsMin ), nameof( TowerFloorsMax ) } );
if ( BuildingMix != WorldBuildingMix.NewYork )
foreach ( var p in Sandbox.Internal.GlobalToolsNamespace.EditorTypeLibrary.GetType( GetType() ).Properties.Where( p => p.Group == "New York" ) )
hidden.Add( p.Name );
if ( BuildingMix == WorldBuildingMix.NewYork )
hidden.UnionWith( new[] { nameof( BuildingInteriors ), nameof( BuildingBalconies ), nameof( HouseRoofStyle ), nameof( MainStreetShare ) } );
if ( BuildingMix != WorldBuildingMix.Custom )
foreach ( var name in new[]
{
nameof( HouseWeight ),
nameof( ApartmentWeight ),
nameof( TowerWeight ),
nameof( WarehouseWeight )
}
)
hidden.Add( name );
if ( !AddCanal )
foreach ( var name in new[]
{
nameof( CanalWidth ),
nameof( CanalDepth ),
nameof( CanalAngle ),
nameof( CanalOffset ),
nameof( CanalBridgeRise ),
nameof( WaterMaterial )
}
)
hidden.Add( name );
if ( !AddOverpass )
foreach ( var name in new[]
{
nameof( OverpassHeight ),
nameof( OverpassRamp ),
nameof( OverpassOffset )
}
)
hidden.Add( name );
if ( !VaryStreets )
foreach ( var name in new[]
{
nameof( SideStreetType ),
nameof( SideStreetWidth ),
nameof( MainStreetShare )
}
)
hidden.Add( name );
return hidden;
}
}