#pragma once #include "CoreMinimal.h" #include "Json.h" #include "VoxelBiomeDefinition.h" #include "VoxelGenerator.h" #include "VoxelSettings.h" #include "VoxelStrateDefinition.h" #include "VoxelStrateManager.h" #include "VoxelTerrainOpDefinition.h" #include #include #include #include #include #include struct FStandaloneParitySample { FVector PositionVoxels; float PluginDensity = 0.0f; std::string Kind; int32 StrateIndex = INDEX_NONE; }; struct FStandalonePassageVoidCrossing { std::size_t passageIndex=0; std::size_t firstSegment=0; std::size_t lastSegment=0; std::uint64_t unsupportedSamples=0; double unsupportedLengthMetres=0.0; std::array startPoint{}; std::array endPoint{}; bool needsColumn=false; bool connectedAtStart=false; bool connectedAtEnd=false; std::int64_t centerXSubvoxels=0; std::int64_t centerYSubvoxels=0; std::int64_t topZSubvoxels=0; std::int64_t bottomZSubvoxels=0; std::int64_t minimumRadiusSubvoxels=0; std::int64_t nominalRadiusSubvoxels=0; std::int64_t maximumRadiusSubvoxels=0; double naturalSurfaceReliefMetres=0.0; double maximumRouteOffsetMetres=0.0; double maximumBoreRadiusMetres=0.0; bool needsRootTaper=false; }; struct FStandalonePassageVoidCrossingCache { std::mutex mutex; std::unordered_map> byLayout; }; struct FStandaloneOwnerWorld { std::unique_ptr Settings; std::unique_ptr Manager; std::unique_ptr Generator; std::vector> DefinitionStorage; std::vector> BiomeStorage; std::vector> OperationStorage; std::vector DensitySamples; FVector ViewerStartVoxels = FVector::ZeroVector; bool ViewerStartFound = false; int32 Seed = 0; int32 ClipRadius = 6; int32 MaxClipLevel = 8; int32 FullResClipLevels = 2; int32 CoarseTileCells = 16; int32 RenderDistanceChunks = 1536; int32 StrateContentCutMinLevel = 9; bool bGenerateSkirts = true; int32 SkirtCells = 2; int32 LODOctaveDrop = 0; std::uint32_t OwnerVoxelSizeMicrons = 125000; std::uint32_t CoreVoxelSizeMicrons = 250000; std::uint32_t StrateLayoutChunkSizeMicrometres = 8000000; std::int64_t StrateLayoutChunkWidthSubvoxels = 8192; bool bHasUnrealResolvedCorePlan = false; std::shared_ptr PassageVoidCrossingCache = std::make_shared(); }; namespace StandaloneOwnerLoader { template inline void ReadField(const VFJson::Value& Object, const char* Name, T& Out) { const VFJson::Value& Value = Object.Get(Name); if constexpr (std::is_same_v) { if (std::holds_alternative(Value.Data)) Out = Value.Boolean(Out); else if (Value.IsNumber()) Out = Value.Number() != 0.0; } else if constexpr (std::is_enum_v) { if (Value.IsNumber()) Out = static_cast(Value.Integer()); } else if constexpr (std::is_arithmetic_v) { if (Value.IsNumber()) Out = static_cast(Value.Number()); } } inline void ReadText(const VFJson::Value& Object, const char* Name, FText& Out) { const VFJson::Value& Value = Object.Get(Name); if (Value.IsString()) Out = FText::FromString(FString(Value.String())); } inline void ReadLinearColor(const VFJson::Value& Object, FLinearColor& Out) { ReadField(Object, "R", Out.R); ReadField(Object, "G", Out.G); ReadField(Object, "B", Out.B); ReadField(Object, "A", Out.A); } inline void ReadVector(const VFJson::Value& Object, FVector& Out) { ReadField(Object, "x", Out.X); ReadField(Object, "y", Out.Y); ReadField(Object, "z", Out.Z); } inline void ReadGenerationParams(const VFJson::Value& J, FStrateGenerationParams& P) { #define VF_LOAD_STRATE_FIELD(Name) ReadField(J, #Name, P.Name); VF_STRATE_PARAM_FIELDS(VF_LOAD_STRATE_FIELD, VF_LOAD_STRATE_FIELD) #undef VF_LOAD_STRATE_FIELD ReadField(J, "bTunnelFloorEnabled", P.bTunnelFloorEnabled); } inline void ReadDisturbances(const VFJson::Value& J, FStrateDisturbanceParams& P) { ReadField(J,"ChasmDensity",P.ChasmDensity); ReadField(J,"ChasmSpacing",P.ChasmSpacing); ReadField(J,"ChasmRadius",P.ChasmRadius); ReadField(J,"BridgeDensity",P.BridgeDensity); ReadField(J,"BridgeSpacing",P.BridgeSpacing); ReadField(J,"BridgeRadius",P.BridgeRadius); ReadField(J,"RidgeDensity",P.RidgeDensity); ReadField(J,"RidgeSpacing",P.RidgeSpacing); ReadField(J,"RidgeHeight",P.RidgeHeight); ReadField(J,"RidgeThickness",P.RidgeThickness); ReadField(J,"BaseDensity",P.BaseDensity); ReadField(J,"BoundarySealThickness",P.BoundarySealThickness); } inline void ReadPassageConfig(const VFJson::Value& J, FStratePassageConfig& P) { ReadField(J,"Connections",P.Connections); ReadField(J,"Style",P.Style); ReadField(J,"MouthRadius",P.MouthRadius); ReadField(J,"MidRadius",P.MidRadius); ReadField(J,"ReachMin",P.ReachMin); ReadField(J,"ReachMax",P.ReachMax); ReadField(J,"DistanceMin",P.DistanceMin); ReadField(J,"DistanceMax",P.DistanceMax); ReadField(J,"Wander",P.Wander); ReadField(J,"Segments",P.Segments); ReadField(J,"VerticalWobble",P.VerticalWobble); ReadField(J,"SpiralRadius",P.SpiralRadius); ReadField(J,"SpiralTurns",P.SpiralTurns); ReadField(J,"CascadeSteps",P.CascadeSteps); ReadField(J,"CascadeLedge",P.CascadeLedge); } inline void ReadSurfaceParams(const VFJson::Value& J, FSurfaceGenerationParams& P) { #define VF_SURFACE_FIELD(Name) ReadField(J, #Name, P.Name); VF_SURFACE_FIELD(BaseGroundRelative) VF_SURFACE_FIELD(ElevationRange) VF_SURFACE_FIELD(ContinentFrequency) VF_SURFACE_FIELD(MountainStrength) VF_SURFACE_FIELD(MountainFrequency) VF_SURFACE_FIELD(DetailFrequency) VF_SURFACE_FIELD(SurfaceRoughness) VF_SURFACE_FIELD(HeightWarpStrength) VF_SURFACE_FIELD(HeightWarpFrequency) VF_SURFACE_FIELD(ReliefFrequency) VF_SURFACE_FIELD(ReliefStrength) VF_SURFACE_FIELD(ReliefContrast) VF_SURFACE_FIELD(TerraceStrength) VF_SURFACE_FIELD(TerraceHeight) VF_SURFACE_FIELD(TerraceHardness) VF_SURFACE_FIELD(LayerLineDepth) VF_SURFACE_FIELD(LayerLineSpacing) VF_SURFACE_FIELD(CliffStrength) VF_SURFACE_FIELD(CliffSlopeThreshold) VF_SURFACE_FIELD(CliffSharpness) VF_SURFACE_FIELD(CliffSampleDist) VF_SURFACE_FIELD(OverhangStrength) VF_SURFACE_FIELD(OverhangReach) VF_SURFACE_FIELD(OverhangHeight) VF_SURFACE_FIELD(OverhangFrequency) VF_SURFACE_FIELD(OverhangZScale) VF_SURFACE_FIELD(OverhangSlopeThreshold) VF_SURFACE_FIELD(WaterLevelRelative) VF_SURFACE_FIELD(BeachWidth) VF_SURFACE_FIELD(CeilingRelative) VF_SURFACE_FIELD(CeilingRoughness) VF_SURFACE_FIELD(CeilingRoughnessFrequency) VF_SURFACE_FIELD(CeilingUndulation) VF_SURFACE_FIELD(CeilingUndulationFrequency) VF_SURFACE_FIELD(CeilingRidgeStrength) VF_SURFACE_FIELD(CeilingRidgeFrequency) VF_SURFACE_FIELD(CeilingWarpStrength) VF_SURFACE_FIELD(CeilingWarpFrequency) VF_SURFACE_FIELD(BoundarySealThickness) VF_SURFACE_FIELD(BaseDensity) #undef VF_SURFACE_FIELD } inline void ReadSlabParams(const VFJson::Value& J, FSlabGenerationParams& P) { #define VF_SLAB_FIELD(Name) ReadField(J, #Name, P.Name); VF_SLAB_FIELD(FloorRelativeHeight) VF_SLAB_FIELD(CeilingRelativeHeight) VF_SLAB_FIELD(FloorRoughness) VF_SLAB_FIELD(FloorRoughnessFrequency) VF_SLAB_FIELD(CeilingRoughness) VF_SLAB_FIELD(CeilingRoughnessFrequency) VF_SLAB_FIELD(ColumnDensity) VF_SLAB_FIELD(ColumnMinRadius) VF_SLAB_FIELD(ColumnMaxRadius) VF_SLAB_FIELD(ColumnSpacing) VF_SLAB_FIELD(BoundarySealThickness) VF_SLAB_FIELD(BaseDensity) #undef VF_SLAB_FIELD } inline void ReadMazeParams(const VFJson::Value& J, FMazeGenerationParams& P) { #define VF_MAZE_FIELD(Name) ReadField(J, #Name, P.Name); VF_MAZE_FIELD(CellSize) VF_MAZE_FIELD(CorridorRadius) VF_MAZE_FIELD(BranchProbability) VF_MAZE_FIELD(Verticality) VF_MAZE_FIELD(SurfaceRoughness) VF_MAZE_FIELD(BoundarySealThickness) VF_MAZE_FIELD(BaseDensity) #undef VF_MAZE_FIELD } inline void ReadVerticalShaftParams(const VFJson::Value& J, FVerticalShaftParams& P) { #define VF_SHAFT_FIELD(Name) ReadField(J, #Name, P.Name); VF_SHAFT_FIELD(ShaftSpacing) VF_SHAFT_FIELD(ShaftDensity) VF_SHAFT_FIELD(ShaftMinRadius) VF_SHAFT_FIELD(ShaftMaxRadius) VF_SHAFT_FIELD(CrossConnectChance) VF_SHAFT_FIELD(ConnectorRadius) VF_SHAFT_FIELD(LedgeSpacing) VF_SHAFT_FIELD(LedgeDepth) VF_SHAFT_FIELD(SurfaceRoughness) VF_SHAFT_FIELD(BoundarySealThickness) VF_SHAFT_FIELD(BaseDensity) #undef VF_SHAFT_FIELD } inline void ReadFloatingIslandParams(const VFJson::Value& J, FFloatingIslandParams& P) { #define VF_ISLAND_FIELD(Name) ReadField(J, #Name, P.Name); VF_ISLAND_FIELD(IslandSpacing) VF_ISLAND_FIELD(IslandDensity) VF_ISLAND_FIELD(IslandMinRadius) VF_ISLAND_FIELD(IslandMaxRadius) VF_ISLAND_FIELD(ThicknessRatio) VF_ISLAND_FIELD(VerticalJitter) VF_ISLAND_FIELD(TopFlatten) VF_ISLAND_FIELD(SurfaceRoughness) VF_ISLAND_FIELD(SDFBlendRadius) VF_ISLAND_FIELD(BoundarySealThickness) VF_ISLAND_FIELD(BaseDensity) #undef VF_ISLAND_FIELD } inline void ReadBiomeMap(const VFJson::Value& J, FBiomeMapParams& P) { ReadField(J,"CellSize",P.CellSize); ReadField(J,"WarpStrength",P.WarpStrength); ReadField(J,"WarpFrequency",P.WarpFrequency); ReadField(J,"BorderBlend",P.BorderBlend); ReadField(J,"ReliefFrequency",P.ReliefFrequency); ReadField(J,"ReliefContrast",P.ReliefContrast); ReadField(J,"MoistureFrequency",P.MoistureFrequency); } inline void ReadOperation(const VFJson::Value& J, UVoxelTerrainOpDefinition& O) { ReadField(J,"Type",O.Type); #define VF_OPERATION_FIELD(Name) ReadField(J, #Name, O.Name); VF_OPERATION_FIELD(TerraceStepHeight) VF_OPERATION_FIELD(TerraceHardness) VF_OPERATION_FIELD(TerraceNoiseDisplacement) VF_OPERATION_FIELD(LayerLineSpacing) VF_OPERATION_FIELD(LayerLineDepth) VF_OPERATION_FIELD(RibbingSpacing) VF_OPERATION_FIELD(RibbingDepth) VF_OPERATION_FIELD(CliffStrength) VF_OPERATION_FIELD(ScallopStrength) VF_OPERATION_FIELD(ScallopFrequency) VF_OPERATION_FIELD(OverhangStrength) VF_OPERATION_FIELD(OverhangDepth) VF_OPERATION_FIELD(OverhangFrequency) VF_OPERATION_FIELD(ArchDensity) VF_OPERATION_FIELD(ArchMinRadius) VF_OPERATION_FIELD(ArchMaxRadius) VF_OPERATION_FIELD(ColumnDensity) VF_OPERATION_FIELD(ColumnMinRadius) VF_OPERATION_FIELD(ColumnMaxRadius) VF_OPERATION_FIELD(PitDensity) VF_OPERATION_FIELD(PitMinRadius) VF_OPERATION_FIELD(PitMaxRadius) VF_OPERATION_FIELD(PitDepth) VF_OPERATION_FIELD(ChimneyDensity) VF_OPERATION_FIELD(ChimneyMinRadius) VF_OPERATION_FIELD(ChimneyMaxRadius) VF_OPERATION_FIELD(ChimneyHeight) VF_OPERATION_FIELD(DomeDensity) VF_OPERATION_FIELD(DomeMinRadius) VF_OPERATION_FIELD(DomeMaxRadius) VF_OPERATION_FIELD(DomeHeightRatio) VF_OPERATION_FIELD(PinchDensity) VF_OPERATION_FIELD(PinchStrength) VF_OPERATION_FIELD(PinchLength) #undef VF_OPERATION_FIELD } inline void ReadBiome(const VFJson::Value& J, UVoxelBiomeDefinition& B) { ReadText(J,"BiomeName",B.BiomeName); ReadText(J,"BiomeDescription",B.BiomeDescription); ReadLinearColor(J.Get("DebugColor"),B.DebugColor); ReadField(J,"ReliefMin",B.ReliefMin); ReadField(J,"ReliefMax",B.ReliefMax); ReadField(J,"MoistureMin",B.MoistureMin); ReadField(J,"MoistureMax",B.MoistureMax); ReadField(J,"bOverrideTerrain",B.bOverrideTerrain); ReadField(J,"GeneratorType",B.GeneratorType); ReadSurfaceParams(J.Get("SurfaceParams"),B.SurfaceParams); ReadField(J,"bOverrideAtmosphere",B.bOverrideAtmosphere); ReadLinearColor(J.Get("FogColor"),B.FogColor); ReadField(J,"FogDensity",B.FogDensity); ReadLinearColor(J.Get("AmbientLightColor"),B.AmbientLightColor); ReadField(J,"AmbientLightIntensity",B.AmbientLightIntensity); ReadField(J,"MaterialPaletteIndex",B.MaterialPaletteIndex); } inline UVoxelStrateDefinition* ReadDefinition( FStandaloneOwnerWorld& World, const VFJson::Value& Slot, int32 SlotIndex) { const VFJson::Value& J = Slot.Get("asset"); auto Definition = std::make_unique(); ReadText(J,"StrateName",Definition->StrateName); ReadText(J,"StrateDescription",Definition->StrateDescription); ReadField(J,"StrateHeightInChunks",Definition->StrateHeightInChunks); ReadField(J,"TransitionType",Definition->TransitionType); ReadField(J,"TransitionBlendChunks",Definition->TransitionBlendChunks); ReadField(J,"GeneratorType",Definition->GeneratorType); ReadField(J,"bEnableWorms",Definition->bEnableWorms); ReadGenerationParams(Slot.Get("generation_params"),Definition->GenerationParams); ReadSlabParams(J.Get("SlabParams"),Definition->SlabParams); ReadMazeParams(J.Get("MazeParams"),Definition->MazeParams); ReadVerticalShaftParams(J.Get("VerticalShaftParams"),Definition->VerticalShaftParams); ReadFloatingIslandParams(J.Get("FloatingIslandParams"),Definition->FloatingIslandParams); ReadDisturbances(Slot.Get("disturbances"),Definition->Disturbances); ReadPassageConfig(Slot.Get("passage_config"),Definition->PassageConfig); ReadSurfaceParams(J.Get("SurfaceParams"),Definition->SurfaceParams); ReadBiomeMap(J.Get("BiomeMapParams"),Definition->BiomeMapParams); ReadField(J,"bHasWater",Definition->bHasWater); const auto& Biomes = J.Get("Biomes").AsArray(); Definition->Biomes.Reserve(static_cast(Biomes.size())); for (const VFJson::Value& BiomeJson : Biomes) { auto Biome = std::make_unique(); ReadBiome(BiomeJson,*Biome); Definition->Biomes.Add(Biome.get()); World.BiomeStorage.push_back(std::move(Biome)); } const auto& OperationEntries = Slot.Get("terrain_operation_assets").AsArray(); Definition->TerrainOperations.Reserve(static_cast(OperationEntries.size())); for (int32 I = 0; I < static_cast(OperationEntries.size()); ++I) { const VFJson::Value& EntryJson = OperationEntries[static_cast(I)]; const VFJson::Value& AssetJson = EntryJson.Get("asset"); const VFJson::Value& PathJson = EntryJson.Get("asset_path"); const FString Path = PathJson.IsString() ? FString(PathJson.String()) : FString{}; FStrateTerrainOpEntry Entry; ReadField(EntryJson,"weight",Entry.Weight); ReadField(EntryJson,"probability",Entry.Probability); if (AssetJson.IsObject()) { auto Operation = std::make_unique(); ReadOperation(AssetJson,*Operation); UVoxelTerrainOpDefinition* Raw = Operation.get(); World.OperationStorage.push_back(std::move(Operation)); Entry.Operation.Set(Raw,Path); RegisterStandaloneAsset(Path,Raw); } else if (!Path.IsEmpty()) Entry.Operation = TSoftObjectPtr(Path); Definition->TerrainOperations.Add(std::move(Entry)); } const FString SyntheticPath = FString::Printf("/Standalone/Strate_%d",SlotIndex); Definition->PostLoad(); UVoxelStrateDefinition* Raw = Definition.get(); World.DefinitionStorage.push_back(std::move(Definition)); RegisterStandaloneAsset(SyntheticPath,Raw); return Raw; } inline bool Resolve(const VFJson::Value& Root, FStandaloneOwnerWorld& Out, std::string& Error) { const VFJson::Value& CoreVoxelSize = Root.Get("core_voxel_size_cm"); const VFJson::Value& CoreVoxelSizeMicrons = Root.Get("core_voxel_size_microns"); const VFJson::Value& OwnerVoxelSize = Root.Get("owner_voxel_size_cm"); const VFJson::Value& OwnerVoxelSizeMicrons = Root.Get("owner_voxel_size_microns"); const VFJson::Value& OwnerToCoreScale = Root.Get("owner_to_core_length_scale"); const double CoreCm = CoreVoxelSize.Number(Root.Get("voxel_size_cm").Number(VOXEL_SIZE)); const double OwnerCm = OwnerVoxelSize.Number(VOXEL_SIZE * 0.5); const double CoreMicrons = CoreVoxelSizeMicrons.Number(CoreCm * 10000.0); const double OwnerMicrons = OwnerVoxelSizeMicrons.Number(OwnerCm * 10000.0); if (!std::isfinite(CoreCm) || !std::isfinite(OwnerCm) || CoreCm < VOXEL_SIZE * 0.5 || CoreCm > VOXEL_SIZE || OwnerCm <= 0.0 || std::abs(CoreMicrons - CoreCm * 10000.0) > 0.01 || std::abs(OwnerMicrons - OwnerCm * 10000.0) > 0.01 || !Root.Get("voxel_size_cm").IsNumber() || std::abs(Root.Get("voxel_size_cm").Number() - CoreCm) > 0.0001) { Error = "exported Core voxel size is invalid or inconsistent: core_cm=" + std::to_string(CoreCm) + " owner_cm=" + std::to_string(OwnerCm) + " root_voxel_cm=" + std::to_string(Root.Get("voxel_size_cm").Number()) + " core_microns=" + std::to_string(CoreMicrons) + " owner_microns=" + std::to_string(OwnerMicrons); return false; } const double ExpectedRatio = OwnerCm / CoreCm; const bool bHasImportScale = OwnerVoxelSize.IsNumber() || CoreVoxelSize.IsNumber() || OwnerToCoreScale.IsNumber(); if (bHasImportScale && (!OwnerVoxelSize.IsNumber() || !CoreVoxelSize.IsNumber() || !OwnerToCoreScale.IsNumber() || std::abs(OwnerToCoreScale.Number() - ExpectedRatio) > 1.0e-9)) { Error = "owner-to-Core import scale does not match the resolved voxel sizes"; return false; } Out.OwnerVoxelSizeMicrons = static_cast(std::llround(OwnerMicrons)); Out.CoreVoxelSizeMicrons = static_cast(std::llround(CoreMicrons)); Out.Seed = static_cast(Root.Get("seed").Integer()); Out.ClipRadius = static_cast(Root.Get("clip_radius").Integer(6)); Out.MaxClipLevel = static_cast(Root.Get("max_clip_level").Integer(8)); Out.FullResClipLevels = static_cast(Root.Get("full_res_clip_levels").Integer(2)); Out.CoarseTileCells = static_cast(Root.Get("coarse_tile_cells").Integer(16)); Out.RenderDistanceChunks = static_cast(Root.Get("render_distance_chunks").Integer(1536)); Out.StrateContentCutMinLevel = static_cast(Root.Get("strate_content_cut_min_level").Integer(9)); Out.bGenerateSkirts = Root.Get("generate_skirts").Boolean(true); Out.SkirtCells = static_cast(Root.Get("skirt_cells").Integer(2)); Out.LODOctaveDrop = static_cast(Root.Get("lod_octave_drop").Integer(0)); ReadVector(Root.Get("viewer_start"),Out.ViewerStartVoxels); Out.ViewerStartFound = Root.Get("viewer_start").Get("found_open_space").Boolean(); for (const VFJson::Value& SampleJson : Root.Get("density_samples").AsArray()) { FStandaloneParitySample Sample; ReadField(SampleJson,"x",Sample.PositionVoxels.X); ReadField(SampleJson,"y",Sample.PositionVoxels.Y); ReadField(SampleJson,"z",Sample.PositionVoxels.Z); ReadField(SampleJson,"density",Sample.PluginDensity); ReadField(SampleJson,"strate_index",Sample.StrateIndex); Sample.Kind = SampleJson.Get("kind").String(); Out.DensitySamples.push_back(std::move(Sample)); } Out.Settings = std::make_unique(); const VFJson::Value& SettingsJson = Root.Get("settings_asset"); Out.Settings->Seed = Out.Seed; ReadField(Root,"origin_spine_radius",Out.Settings->OriginSpineRadius); ReadField(Root,"world_radius_voxels",Out.Settings->WorldRadiusVoxels); ReadField(Root,"edge_seal_thickness",Out.Settings->EdgeSealThickness); ReadField(Root,"open_surface_entry",Out.Settings->bOpenSurfaceEntry); ReadField(Root,"inter_strate_gap_chunks",Out.Settings->InterStrateGapChunks); ReadField(SettingsJson,"total_strates",Out.Settings->TotalStrates); ReadField(Root,"clip_radius",Out.Settings->ClipRadius); ReadField(Root,"max_clip_level",Out.Settings->MaxClipLevel); ReadField(Root,"full_res_clip_levels",Out.Settings->FullResClipLevels); ReadField(Root,"coarse_tile_cells",Out.Settings->CoarseTileCells); ReadField(Root,"render_distance_chunks",Out.Settings->RenderDistanceChunks); ReadField(Root,"generate_skirts",Out.Settings->bGenerateSkirts); ReadField(Root,"skirt_cells",Out.Settings->SkirtCells); ReadField(Root,"lod_octave_drop",Out.Settings->LODOctaveDrop); ReadField(Root,"strate_content_cut_min_level",Out.Settings->StrateContentCutMinLevel); ReadField(SettingsJson,"TotalStrates",Out.Settings->TotalStrates); ReadField(SettingsJson,"InterStrateGapChunks",Out.Settings->InterStrateGapChunks); ReadField(SettingsJson,"StrateLayoutChunkSizeMeters",Out.Settings->StrateLayoutChunkSizeMeters); const VFJson::Value& LayoutChunkMicrometres=Root.Get("strate_layout_chunk_size_um"); const double LayoutChunkSizeMicrometres=LayoutChunkMicrometres.IsNumber() ?LayoutChunkMicrometres.Number() :static_cast(Out.Settings->StrateLayoutChunkSizeMeters)*1000000.0; if(!std::isfinite(LayoutChunkSizeMicrometres)||LayoutChunkSizeMicrometres<250000.0 ||LayoutChunkSizeMicrometres>64000000.0 ||std::abs(LayoutChunkSizeMicrometres-std::round(LayoutChunkSizeMicrometres))>0.001) {Error="strate layout chunk size must be an integral micrometre value between 0.25 m and 64 m";return false;} Out.StrateLayoutChunkSizeMicrometres=static_cast(std::llround(LayoutChunkSizeMicrometres)); Out.Settings->StrateLayoutChunkSizeMeters=static_cast(LayoutChunkSizeMicrometres/1000000.0); Out.StrateLayoutChunkWidthSubvoxels=static_cast(std::llround( LayoutChunkSizeMicrometres*256.0/CoreMicrons)); if(Out.StrateLayoutChunkWidthSubvoxels<=0) {Error="strate layout chunk size resolves to no Core subvoxels";return false;} Out.Settings->StratePool.Reset(); Out.Settings->FixedStrates.Empty(); const auto& Strates = Root.Get("strates").AsArray(); Out.Settings->TotalStrates = static_cast(Strates.size()); for (int32 I = 0; I < static_cast(Strates.size()); ++I) { UVoxelStrateDefinition* Definition = ReadDefinition(Out,Strates[static_cast(I)],I); const FString SyntheticPath = FString::Printf("/Standalone/Strate_%d",I); TSoftObjectPtr SoftDefinition; SoftDefinition.Set(Definition,SyntheticPath); Out.Settings->FixedStrates.Add(I,std::move(SoftDefinition)); } if (Strates.empty()) { Error = "owner JSON contains no resolved strates"; return false; } Out.Manager = std::make_unique(); if (!Out.Manager->Initialize(Out.Settings.get(),Out.Seed)) { Error = "copied strate manager rejected the owner settings snapshot"; return false; } Out.Manager->SetHardTransitionFallbackForAssembly(true); Out.Generator = std::make_unique(); Out.Generator->InitializeSettings(Out.Settings.get()); Out.Generator->SetStrateManager(Out.Manager.get()); return true; } inline bool LoadJson(std::string_view Json,FStandaloneOwnerWorld& Out,std::string& Error) { VFJson::Value Root; if(!VFJson::Parser(std::string(Json)).Parse(Root,Error))return false; return Resolve(Root,Out,Error); } inline bool Load(const std::string& Path,FStandaloneOwnerWorld& Out,std::string& Error) { VFJson::Value Root; if(!VFJson::Load(Path,Root,Error))return false; return Resolve(Root,Out,Error); } }