Files
VoxelForge/Source/VoxelForge/Private/VoxelSettings.cpp
T
Fr0zkaandClaude Opus 5.5 48fa028086 wip(assembler): M3 round 3 -- separated islands + Unreal island route (owner build 18:46)
Islands read as separate (91.89% open sky at mid-height), underside cavity closed,
rim teeth were capture shading. Island manifest import + BuildHost proof passed on the
pre-cache tree; M1 SurfaceWorld and M2 V1/V2 gates passed.

Known open: final XY-column cache compiled in the owner build but is unverified;
island LOD0 p95 ~155 ms misses the 133 ms sprint deadline (legacy ~43 ms); the island
manifest only fits the BuildHost fixture layout (owner's world: Core init fails,
empty world) -> round 4 builds plans inside Unreal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
2026-10-10 20:53:03 +02:00

181 lines
5.6 KiB
C++

#include "VoxelSettings.h"
#include "VoxelSeasonAsset.h"
#if WITH_EDITOR
#include "Misc/FileHelper.h"
#endif
#include <VoxelForgeCore/VoxelForgeCore.h>
#include <string>
int32 UVoxelSettings::GetEffectiveWorldSeed() const
{
if (!Season.IsNull())
{
if (const UVoxelSeasonAsset* Asset = Season.LoadSynchronous())
{
return Asset->GetSeasonSeed();
}
}
return Seed;
}
float UVoxelSettings::GetEffectiveOriginSpineRadius() const
{
if (!Season.IsNull())
{
if (const UVoxelSeasonAsset* Asset = Season.LoadSynchronous())
{
return Asset->GetOriginSpineRadius();
}
}
return OriginSpineRadius;
}
float UVoxelSettings::GetEffectiveWorldRadiusVoxels() const
{
if (!Season.IsNull())
{
if (const UVoxelSeasonAsset* Asset = Season.LoadSynchronous())
{
return Asset->GetWorldRadiusVoxels();
}
}
return WorldRadiusVoxels;
}
int32 UVoxelSettings::GetEffectiveSeasonNumber() const
{
if (!Season.IsNull())
{
if (const UVoxelSeasonAsset* Asset = Season.LoadSynchronous())
{
return Asset->GetSeasonNumber();
}
}
return CurrentSeason;
}
bool UVoxelSettings::SetWorldAssemblyManifestJson(const FString& InJson, FString& OutReport)
{
OutReport.Reset();
if (InJson.IsEmpty())
{
OutReport = TEXT("world assembly manifest JSON is empty");
return false;
}
FTCHARToUTF8 Utf8Json(*InJson);
std::string CoreError;
const std::optional<VoxelForgeCore::WorldAssemblyManifest> Manifest =
VoxelForgeCore::WorldAssemblyManifest::FromJson(
std::string_view(Utf8Json.Get(), static_cast<std::size_t>(Utf8Json.Length())), CoreError);
if (!Manifest)
{
OutReport = FString::Printf(TEXT("world assembly manifest is invalid: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
if (Manifest->recipe.seed != static_cast<uint32>(GetEffectiveWorldSeed()))
{
OutReport = FString::Printf(
TEXT("world assembly seed %u does not match the effective settings seed %d"),
Manifest->recipe.seed, GetEffectiveWorldSeed());
return false;
}
const std::string CanonicalJson = Manifest->ToJson();
if (CanonicalJson.empty())
{
OutReport = TEXT("world assembly manifest could not be canonicalized");
return false;
}
Modify();
WorldAssemblyManifestJson = UTF8_TO_TCHAR(CanonicalJson.c_str());
WorldAssemblyManifestHash = FString::Printf(TEXT("%016llx"),
static_cast<unsigned long long>(Manifest->contentHash));
MarkPackageDirty();
OutReport = FString::Printf(
TEXT("imported native world assembly %s (%d SurfaceWorld plans, %d floating-island plans)"),
*WorldAssemblyManifestHash, static_cast<int32>(Manifest->plan.strates.size()),
static_cast<int32>(Manifest->floatingIslands.size()));
return true;
}
bool UVoxelSettings::GetWorldAssemblyManifestJson(
FString& OutCanonicalJson, FString& OutContentHash, FString& OutError) const
{
OutCanonicalJson.Reset();
OutContentHash.Reset();
OutError.Reset();
if (WorldAssemblyManifestJson.IsEmpty())
{
if (!WorldAssemblyManifestHash.IsEmpty())
{
OutError = TEXT("world assembly hash is set but its manifest JSON is empty");
return false;
}
return true;
}
FTCHARToUTF8 Utf8Json(*WorldAssemblyManifestJson);
std::string CoreError;
const std::optional<VoxelForgeCore::WorldAssemblyManifest> Manifest =
VoxelForgeCore::WorldAssemblyManifest::FromJson(
std::string_view(Utf8Json.Get(), static_cast<std::size_t>(Utf8Json.Length())), CoreError);
if (!Manifest)
{
OutError = FString::Printf(TEXT("cooked world assembly manifest is invalid: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
if (Manifest->recipe.seed != static_cast<uint32>(GetEffectiveWorldSeed()))
{
OutError = TEXT("cooked world assembly seed no longer matches the effective settings seed");
return false;
}
const FString ComputedHash = FString::Printf(TEXT("%016llx"),
static_cast<unsigned long long>(Manifest->contentHash));
if (!ComputedHash.Equals(WorldAssemblyManifestHash, ESearchCase::IgnoreCase))
{
OutError = FString::Printf(
TEXT("cooked world assembly hash mismatch (stored %s, computed %s)"),
*WorldAssemblyManifestHash, *ComputedHash);
return false;
}
const std::string CanonicalJson = Manifest->ToJson();
if (CanonicalJson.empty())
{
OutError = TEXT("cooked world assembly manifest could not be canonicalized");
return false;
}
OutCanonicalJson = UTF8_TO_TCHAR(CanonicalJson.c_str());
OutContentHash = ComputedHash;
return true;
}
void UVoxelSettings::ImportWorldAssemblyManifestJson()
{
#if WITH_EDITOR
FString JsonText;
FString Report;
if (SourceWorldAssemblyManifestJson.FilePath.IsEmpty()
|| !FFileHelper::LoadFileToString(JsonText, *SourceWorldAssemblyManifestJson.FilePath))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelSettings] Could not read world assembly manifest '%s'."),
*SourceWorldAssemblyManifestJson.FilePath);
return;
}
if (!SetWorldAssemblyManifestJson(JsonText, Report))
{
UE_LOG(LogTemp, Error, TEXT("[VoxelSettings] World assembly import failed: %s"), *Report);
return;
}
UE_LOG(LogTemp, Log, TEXT("[VoxelSettings] %s"), *Report);
#else
UE_LOG(LogTemp, Error, TEXT("[VoxelSettings] World assembly JSON import is editor-only."));
#endif
}