Files
VoxelForge/Source/VoxelForge/Private/VoxelSettings.cpp
T
Fr0zkaandClaude Opus 5 faa62d419e feat(runtime): the composed world can BE the game world
Jahni: "can you not implement those settings? as in, have them be live in
game?" This is that. The composer stops being a lab tool.

THE ARCHITECTURAL LINE, which is the whole design (COMPOSER-NOTES §3.1):
COMPOSITION stays editor-only, EVALUATION becomes runtime. Rolling,
measuring, preview, selection, promotion, the corpus -- none of it reaches
a player's machine. What crosses into the runtime is exactly two things:
reading a season manifest, and materialising a recipe into an op stack.

  UVoxelSeasonAsset      a cookable UPrimaryDataAsset holding the manifest,
                         so a season ships in a packaged game. The JSON
                         stays the reviewable, git-diffable artefact.
  UVoxelSettings::Season  optional. Unset => behaviour is exactly as today.
  GetEffective*()         season seed / spine radius / world radius / season
                         number override the authored values when assigned.
                         The test deliberately sets DIFFERENT authored
                         values, so "the season is authoritative" is proved
                         rather than coincidental.

⭐ MULTIPLAYER DETERMINISM, PROVED: two independent runtime managers built
the same season and compared 393,216 density samples BIT-IDENTICALLY. This
is the property the whole multiplayer model rests on -- replicate seed +
layout + diff, never geometry.

⭐ AND A STALE SEASON IS DETECTABLE, NOT SILENT. Initialize() now returns
bool and an assigned-but-invalid season NEVER falls back to the authored
pool. Falling back would hand a client a world that looks fine and is not
the season -- silent divergence, the worst failure mode in a shared world.
GetCurrentSeasonContentHash() is exposed BlueprintPure to compare at join.

HasComposerRecipeOverride() is gone. It force-classified every custom recipe
as Mixed, which was correct while box verdicts were only proved for
hand-written stacks -- but 8e346a3 made EffectOverBox correct in ISOLATION,
proved on a stack no builder produces. Keeping the force would have cost
tile skipping on every composed world forever.

VF_RollStrateRegionCount moved behind WITH_EDITOR while the partition-seed
helpers stayed runtime: rolling out, evaluation in. Lateral regions remain
gated off.

⚠️ Sol hit its usage limit mid-task, so the edits arrived unvalidated. I
built and ran them myself rather than assume -- and they did not compile:
VoxelForgeComposerSeasonTest.cpp was missing UObject/Package.h, which every
other test picks up transitively through the shared fixture it does not use.
One include; every NewObject/GetTransientPackage in the file was failing.

Editor build clean. SHIPPING BUILD SUCCEEDS -- the invariant that proves no
composer roller is linked into a packaged game. 30 succeeded / 0 failed.

⚠️ UNVERIFIED: whether it looks right on screen. Nothing headless can tell
us that; it needs Jahni to assign a season asset and press play.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJiTcTSDNkKBtnNdiBtdaU
2026-09-05 08:37:01 +02:00

52 lines
1.1 KiB
C++

#include "VoxelSettings.h"
#include "VoxelSeasonAsset.h"
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;
}