wip(assembler): M1 round 5 -- native SurfaceWorld manifest delivered into the Unreal Core route
Manifest imported into UVoxelSettings (hash 8933693d9560ba9f), folded into the season content hash only when Core is on. BuildHost: W1/W8/W16 stable, 2553 surface tiles match standalone, 432 LOD transitions, collision on all 36 expected tiles. Matched timing 96.8 s native vs 197.3 s bridge (2.04x). Collision support tiles wait for Core region admission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
2d0cec90e4
commit
f67b519e75
11 files changed
+1002
-45
No files matched your search
@@ -2,6 +2,13 @@
|
||||
|
||||
#include "VoxelSeasonAsset.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "Misc/FileHelper.h"
|
||||
#endif
|
||||
|
||||
#include <VoxelForgeCore/VoxelForgeCore.h>
|
||||
#include <string>
|
||||
|
||||
int32 UVoxelSettings::GetEffectiveWorldSeed() const
|
||||
{
|
||||
if (!Season.IsNull())
|
||||
@@ -49,3 +56,123 @@ int32 UVoxelSettings::GetEffectiveSeasonNumber() const
|
||||
}
|
||||
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 stratum plans)"),
|
||||
*WorldAssemblyManifestHash, static_cast<int32>(Manifest->plan.strates.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
|
||||
}
|
||||
Reference in new issue
Block a user