Files
VoxelForge/Source/VoxelForge/Public/VoxelSeasonManifest.h
T
Fr0zkaandClaude Opus 5.5 bc0f9ee791 wip(step3): 12.5 cm voxels, fall-through fixed, brick evaluator in game, organic tunnels -- speed gate FAILS
Stopped by the owner's decision (in-game lit captures were eating the round); he judges the look in
game instead.
1. Fall-through with the research field: fixed. Deep drop, gate on: 2 holds (0.50 s), min foot
   clearance +43 cm; gate off: penetrates (-278 cm). Stress fixture offsets converted to metres.
2. VOXEL_SIZE 25 -> 12.5 cm. Physical sizes kept in metres (player, steps, gate, insets, research
   field sizes, dig radii, test thresholds); class defaults that count chunks/voxels doubled
   (ClipRadius 6, RenderDistanceChunks 1536, ViewDistance*, StrateViewMargin 6,
   PawnCollisionRadius 2, SkirtCells 4, EdgeSealThickness 128, decoration spacings, density volume
   res 256). Asset values override these defaults: the owner must double his own.
   Ring scale, six workers, idle, step-2f field before the look changes: 64 m cube (519^3) 4.55 s;
   32 m cube (259^3) 0.95 s.
3. In game: tiles go through the brick evaluator (proved by a log marker); profile switch rebuilds
   the loaded world (~5,800 tiles); full-detail fill 12.4 s after spawn in the visible-window test.
4. Look: round winding tunnels, per-column ellipsoid/lattice caches. All step-2f geometry gates pass
   at 12.5 cm (0 crumbs, 1 solid component per profile, solid share 69-87%). 259^3 ring, six workers:
   1.08-2.02 s (worst HyperComplex) -- the 600 ms gate FAILS. Lit captures failed (hidden/off-screen
   window, then blank frames); not pursued.

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

300 lines
12 KiB
C++

// Offline Tier 4c composition plus the runtime-readable, diffable Tier A manifest.
#pragma once
#include "CoreMinimal.h"
#include "VoxelStrateComposer.h"
#include "VoxelStrateMeasure.h"
class UVoxelSettings;
/** Why the provisional season selector put one surviving candidate in a slot. */
enum class EVoxelSeasonSelectionReason : uint8
{
Grounded,
Outlier,
Fixed,
};
/**
* Explicit, reviewable selection knobs for one season.
*
* None of these values is a settled definition of quality. They are the first policy Jahni can
* change after walking the review page. Hard validation remains separate from this policy.
*/
struct VOXELFORGE_API FVoxelSeasonSelectionPolicy
{
// Placeholder mix only: ordinary strates give an outlier contrast. Revisit after the first
// season review; this is not a learned or final quality score.
float GroundedFraction = 0.75f;
float OutlierFraction = 0.25f;
// Below this measured distance two neighbours look too similar. The selector subtracts a
// penalty proportional to the gap; provisional because the useful contrast is visual.
double AdjacentSimilarityDistanceThreshold = 0.20;
double AdjacentSimilarityPenaltyWeight = 1.0;
// Rewards an unseen archetype/recipe in the already chosen prefix. These are variety
// tie-breakers, not claims that one archetype or recipe is better. Provisional review knobs.
double NewArchetypeBonus = 0.10;
double NewRecipeBonus = 0.05;
// GDD §6 says roughly every five levels, and a boss is intermediary rather than terminal.
// This interval is therefore an explicit provisional layout knob, not a quality score.
int32 BossSlotInterval = 5;
// Tier 2 hard gate: a surviving air component must retain at least this share. Provisional
// only in its threshold; the existence of the gate is non-negotiable for a shippable season.
float MinimumLargestComponentShare = 0.50f;
// Normalizers for the two unbounded measured dimensions in the adjacency distance. Fractions
// already live in [0,1]. These physical scales are provisional and visible in the manifest.
float FeatureScaleNormalizationVoxels = 256.0f;
float ClearanceNormalizationVoxels = 64.0f;
};
/** A caller-supplied fixed slot for tests/tools that already have a complete manifest record. */
struct VOXELFORGE_API FVoxelSeasonFixedStrate
{
int32 Seed = 0;
int32 HeightInChunks = 8;
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
FVoxelStrateArchetypeParams Params;
FVoxelOpStackRecipe Recipe;
FVoxelStrateRegionManifest Regions;
bool bUsesRecipe = true;
bool bUsesRegions = false;
FString SourceDefinitionPath;
};
/** Settings for the offline build-box pass. No member is consulted by normal runtime generation. */
struct VOXELFORGE_API FVoxelSeasonCompositionSettings
{
// Optional live-world settings. TotalStrates, spine/gap values, and FixedStrates are read
// from it when present. The pointer is borrowed for the duration of VF_ComposeSeason only.
const UVoxelSettings* WorldSettings = nullptr;
// Optional preloaded corpus. With nullptr the composer loads the project asset corpus on the
// build box, exactly like the existing offline composer tests.
const FVoxelStrateCorpus* Corpus = nullptr;
// 24 gives a useful minute-scale automation pass at the default coarse measurement window.
// Production can raise this to the overnight budget without changing the policy.
int32 CandidateCount = 24;
int32 SelectedStrateCount = 10;
// Generated candidates use one stable height. Fixed authored slots may provide their own
// height. World layout bounds are written into every selected parameter family below.
int32 StrateHeightInChunks = 8;
int32 InterStrateGapChunks = 0;
float OriginSpineRadius = 28.0f;
float WorldRadiusVoxels = 0.0f;
// Coarse measurement is deliberately bounded. Tests may reduce the window; production may
// spend the overnight budget on a finer pass after the selector has been judged.
FVoxelStrateMeasureSettings MeasureSettings;
// Player-fit is a separate, explicitly fine pass. SampleStep values other than one are
// refused by the metric, never interpreted as an approximate capsule answer.
FVoxelStrateMeasureSettings PlayerFitMeasureSettings;
FVoxelSeasonSelectionPolicy SelectionPolicy;
// Explicit composed fixed slots take precedence. When empty, the composer adapts the
// existing UVoxelSettings::FixedStrates map, preserving its absolute slot indices.
TMap<int32, FVoxelSeasonFixedStrate> FixedStrates;
// Empty means ProjectSavedDir()/VoxelForge/Seasons. Files are never written to the runtime
// content directory by this API.
FString OutputDirectory;
bool bWriteArtifacts = true;
bool bWriteReviewPage = true;
bool bIncludeCandidateAudit = true;
// Informational only; when WorldSettings is present CurrentSeason supplies the default.
int32 SeasonNumber = 0;
FVoxelSeasonCompositionSettings()
{
// The existing Tier 4b test uses step 4. Season composition defaults to step 8 so the
// default automation artifact is measured in minutes, while MaxCells remains bounded.
MeasureSettings.SampleStep = 8;
MeasureSettings.RadiusInVoxels = 512;
MeasureSettings.MaxCells = 8000000;
MeasureSettings.MaxRouteRetries = 16;
MeasureSettings.HeadroomCells = 2;
MeasureSettings.InteriorMarginVoxels = -1;
PlayerFitMeasureSettings.SampleStep = 1;
PlayerFitMeasureSettings.RadiusInVoxels = 128;
// A fitted mouth-to-mouth XY window across an 8-chunk (256-voxel) strate can approach
// four million cells. Keep the cap finite and below the old multi-gigabyte retry cost.
PlayerFitMeasureSettings.MaxCells = 4000000;
PlayerFitMeasureSettings.MaxRouteRetries = 16;
PlayerFitMeasureSettings.HeadroomCells = 2;
PlayerFitMeasureSettings.InteriorMarginVoxels = -1;
}
};
/** Compact audit row; the full vectors live only for selected strates. */
struct VOXELFORGE_API FVoxelSeasonCandidateAudit
{
int32 CandidateIndex = INDEX_NONE;
int32 Seed = 0;
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
uint32 RecipeHash = 0;
double DistanceFromCorpusCentroid = 0.0;
bool bPassedHardGates = false;
bool bSelected = false;
FString RejectionReason;
};
/** Count of one explicit hard-gate or final-placement rejection reason. */
struct VOXELFORGE_API FVoxelSeasonRejectionCount
{
FString Reason;
int32 Count = 0;
};
/** One ordered Tier A spine entry. */
struct VOXELFORGE_API FVoxelSeasonStrate
{
// DepthIndex is the absolute world-layout slot. CandidateIndex is the offline attempt id.
int32 DepthIndex = INDEX_NONE;
int32 CandidateIndex = INDEX_NONE;
int32 Seed = 0;
int32 HeightInChunks = 0;
int32 TopWorldZ = 0;
int32 BottomWorldZ = 0;
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
FVoxelOpStackRecipe Recipe;
FVoxelStrateArchetypeParams Params;
// When true this is the complete lateral parent description. Params/Archetype remain the
// compatibility identity of region zero; runtime rebuilds use Regions and never blend params.
FVoxelStrateRegionManifest Regions;
FVoxelStrateMeasuredMetrics Metrics;
double DistanceFromCorpusCentroid = 0.0;
FString SelectionReason;
FString SourceDefinitionPath;
bool bGrounded = false;
bool bOutlier = false;
bool bBossSlot = false;
bool bFixed = false;
bool bUsesRecipe = true;
bool bUsesRegions = false;
bool bPassedNonVacuous = false;
bool bPassedLargestComponent = false;
bool bPassedPrimordialLaw = false;
EVoxelConnectivityResult PrimordialLawResult = EVoxelConnectivityResult::OutOfWindow;
};
/**
* The stored Tier A season artifact.
*
* Tier B is intentionally absent: its hash-lattice field remains an arithmetic/enumeration API,
* not a second stored table. Strates is ordered from the surface down and is the only finite spine
* persisted by this task.
*/
struct VOXELFORGE_API FVoxelSeasonManifest
{
static constexpr int32 CurrentSchemaVersion = 2;
bool bValid = false;
int32 SchemaVersion = CurrentSchemaVersion;
FString Error;
int32 Season = 0;
int32 Seed = 0;
uint32 InputCorpusHash = 0;
// SHA-1 of the canonical manifest JSON with this field omitted. This detects stale cooked
// season assets without requiring the editor-only input corpus on a player's machine.
FString ContentHash;
int32 CandidateCount = 0;
int32 SurvivorCount = 0;
int32 SelectedCount = 0;
int32 RejectedCount = 0;
int32 GroundedSelectedCount = 0;
int32 OutlierSelectedCount = 0;
int32 FixedSelectedCount = 0;
int32 TotalStrates = 0;
int32 InterStrateGapChunks = 0;
float OriginSpineRadius = 0.0f;
float WorldRadiusVoxels = 0.0f;
FVoxelSeasonSelectionPolicy SelectionPolicy;
FString PolicyNote;
TArray<FVoxelSeasonStrate> Strates;
TArray<FVoxelSeasonCandidateAudit> CandidateAudit;
TArray<FVoxelSeasonRejectionCount> RejectionCounts;
// Derived artifact locations; intentionally not serialized into the portable JSON.
FString ManifestPath;
FString ReviewPagePath;
FString SerializedJson;
bool IsUsable() const
{
if (!bValid || !Error.IsEmpty() || ContentHash.Len() != 40 || WorldRadiusVoxels != 0.0f
|| Strates.Num() != SelectedCount || SelectedCount <= 0)
{
return false;
}
for (const FVoxelSeasonStrate& Strate : Strates)
{
// Region composition is intentionally not a shippable season format yet. Keeping
// this rejection in the portable manifest contract prevents an editor experiment
// from becoming packaged terrain merely because its density evaluator exists.
if (Strate.bUsesRegions)
{
return false;
}
}
return true;
}
};
/** Compose, validate, select, serialize, and (by default) write one season. Editor/build-box only. */
#if WITH_EDITOR
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
int32 SeasonSeed, const FVoxelSeasonCompositionSettings& Settings);
/** Convenience overload that adapts the existing runtime settings asset. */
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
int32 SeasonSeed, const UVoxelSettings* WorldSettings);
#endif
/** Serialize/read the complete Tier A manifest as stable pretty JSON. */
VOXELFORGE_API FString VF_SerializeVoxelSeasonManifest(
const FVoxelSeasonManifest& Manifest);
/** Parse an in-memory/cooked JSON manifest and verify its embedded content hash. */
VOXELFORGE_API bool VF_DeserializeVoxelSeasonManifest(
const FString& ManifestJson, FVoxelSeasonManifest& OutManifest, FString& OutReport);
/** Stable SHA-1 over the canonical manifest payload (the content_hash field itself is omitted). */
VOXELFORGE_API FString VF_ComputeVoxelSeasonManifestContentHash(
const FVoxelSeasonManifest& Manifest);
VOXELFORGE_API bool VF_SaveVoxelSeasonManifest(
const FString& ManifestPath, const FVoxelSeasonManifest& Manifest, FString& OutReport);
VOXELFORGE_API bool VF_LoadVoxelSeasonManifest(
const FString& ManifestPath, FVoxelSeasonManifest& OutManifest, FString& OutReport);
/** Rebuild exactly the stack represented by one manifest entry. */
VOXELFORGE_API bool VF_BuildSeasonStrateStack(
const FVoxelSeasonStrate& Strate,
float SpineRadius,
const UVoxelStrateManager* StrateManager,
FVoxelOpStack& OutStack,
FVoxelOpContext& OutContext,
FString* OutError = nullptr);
/** Verbose alias for tests/tools that want the round-trip operation named explicitly. */
VOXELFORGE_API bool VF_RebuildVoxelSeasonStrate(
const FVoxelSeasonStrate& Strate,
float SpineRadius,
const UVoxelStrateManager* StrateManager,
FVoxelOpStack& OutStack,
FVoxelOpContext& OutContext,
FString* OutError = nullptr);