The composer could invent, measure and show strates. What did not exist was an ARTEFACT a season could ship. Now it does. VF_ComposeSeason: generate N candidates -> measure -> reject failures -> select a descent sequence -> emit a JSON manifest + a review page. ⭐ THE PROPERTY THAT MATTERS: round-trip bit-identity. The manifest was loaded, every selected stack rebuilt, and 393,216 density samples compared BIT-IDENTICALLY. Re-composing the same seed yields byte-identical JSON. A manifest that cannot reproduce its own world is worthless, and that is the one thing that could not be assumed. Floats serialise as readable values PLUS exact IEEE bits, so a season survives a text round trip. Test season: 24 generated, 19 survived the hard gates, 6 selected. 18 not selected -- 4 vacuous, 1 primordial-law failure, 13 policy non-selections. 4 grounded, 2 outliers. EVERY selected slot passes the primordial law, asserted per slot rather than sampled. Selection policy is explicit, named and PROVISIONAL, because Jahni has not defined "good" yet and said so: "it'll be easier once i'm able to see the strates candidates." So no quality score was invented and presented as settled. The knobs are 75/25 grounded-to-outlier (outlier axis = distance from corpus centroid), adjacent-similarity threshold .20 with penalty 1.0, new-archetype bonus .10, new-recipe bonus .05, boss cadence every 5th non-terminal slot. All of them are his to turn. The veto is a review page in DESCENT ORDER -- the season read top to bottom the way it is played, not the survivor/outlier ordering the candidate sheet uses. Reuses VoxelStratePreview rather than a second renderer. Saved/VoxelForge/SeasonTest/season_0000_seed_9320/season_manifest.json .../review/index.html ⚠️ FIVE GAPS CODEX RAISED, recorded not buried: 1. §4's Tier A is strates PLUS passages; only the strate spine is persisted. Manager-generated passage geometry and content placement are not. 2. Authored fixed strates keep scalar vectors + asset paths, not every asset-level passage/biome/disturbance/content field. 3. Boss slots are MARKERS, not arena or content guarantees. 4. WorldRadiusVoxels == 0 is enforced as specced but contradicts a production bounded world -- Jahni's call, still unset by design. 5. Bit identity is proven for the same build and platform. A frozen season spanning engine versions needs an explicit schema contract. Real risk, since seasons freeze generation for months. Build clean, 28 succeeded / 0 failed, verified by me. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJiTcTSDNkKBtnNdiBtdaU
655 lines
25 KiB
C++
655 lines
25 KiB
C++
// Offline strate corpus and parameter composer.
|
|
//
|
|
// This is deliberately not part of the runtime generation path. The composer is a build-box
|
|
// tool/test API: it loads authored vectors, measures their spread, and makes deterministic
|
|
// candidates by blending those vectors before applying spread-relative (or season-zero bootstrap)
|
|
// jitter.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "VoxelStrateTypes.h"
|
|
#include "VoxelDensityOpStack.h"
|
|
#include "VoxelStrateMeasure.h"
|
|
|
|
#include "VoxelStrateComposer.generated.h"
|
|
|
|
class UVoxelSettings;
|
|
class UVoxelStrateDefinition;
|
|
class UVoxelStrateManager;
|
|
|
|
#if WITH_EDITOR
|
|
// The complete definitions live in VoxelSeasonManifest.h. Keeping this forward declaration here
|
|
// makes the Tier 4c entry point discoverable from the composer header without creating a circular
|
|
// include (the manifest header includes this one for the existing vector/recipe types).
|
|
struct FVoxelSeasonManifest;
|
|
struct FVoxelSeasonCompositionSettings;
|
|
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
|
|
int32 SeasonSeed, const FVoxelSeasonCompositionSettings& Settings);
|
|
#endif
|
|
|
|
/** The one-bit identity choice at the root of a rolled structure. */
|
|
UENUM(BlueprintType)
|
|
enum class EVoxelStrateRootPolarity : uint8
|
|
{
|
|
RockCarve = 0,
|
|
VoidFill = 1,
|
|
};
|
|
|
|
/** Native parameter family an op reads when a recipe is materialised. */
|
|
UENUM(BlueprintType)
|
|
enum class EVoxelStrateParamBlock : uint8
|
|
{
|
|
None = 0,
|
|
TunnelNetwork = 1,
|
|
Slab = 2,
|
|
Maze = 3,
|
|
Surface = 4,
|
|
VerticalShaft = 5,
|
|
FloatingIsland = 6,
|
|
};
|
|
|
|
/** Stable manifest id for every op the offline structure roller may place. */
|
|
UENUM(BlueprintType)
|
|
enum class EVoxelStrateOpClass : uint8
|
|
{
|
|
ConstantRockSource = 0,
|
|
ConstantVoidSource = 1,
|
|
RoomGraphSource = 2,
|
|
LatticeCorridorSource = 3,
|
|
ShaftFieldSource = 4,
|
|
IslandBlobSource = 5,
|
|
NoiseRibbonSource = 6,
|
|
SdfRoughnessMod = 7,
|
|
SdfCarve = 8,
|
|
SdfFill = 9,
|
|
GridColumnMod = 10,
|
|
CaveRoughnessMod = 11,
|
|
CaveTerraceMod = 12,
|
|
LayerLineMod = 13,
|
|
RibbingMod = 14,
|
|
CaveOverhangMod = 15,
|
|
CaveCliffMod = 16,
|
|
ScallopMod = 17,
|
|
CaveArchMod = 18,
|
|
RoomColumnMod = 19,
|
|
DomeMod = 20,
|
|
PinchMod = 21,
|
|
FloorBiasMod = 22,
|
|
WormFieldSource = 23,
|
|
ShaftLedgeMod = 24,
|
|
DensityNoiseCarveMod = 25,
|
|
DensityNoiseFillMod = 26,
|
|
};
|
|
|
|
/** One creative op in the serialisable structure manifest. */
|
|
USTRUCT(BlueprintType)
|
|
struct VOXELFORGE_API FVoxelOpRecipeEntry
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
EVoxelStrateOpClass OpClass = EVoxelStrateOpClass::ConstantRockSource;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
EVoxelStrateParamBlock ParamBlock = EVoxelStrateParamBlock::None;
|
|
};
|
|
|
|
/**
|
|
* Serialisable creative structure. Structural posts are intentionally absent: the recipe builder
|
|
* appends spine, vertical seal, passage carve, and XY edge seal in that fixed order every time.
|
|
*/
|
|
USTRUCT(BlueprintType)
|
|
struct VOXELFORGE_API FVoxelOpStackRecipe
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
EVoxelStrateRootPolarity RootPolarity = EVoxelStrateRootPolarity::RockCarve;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
FVoxelOpRecipeEntry Root;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
FVoxelOpRecipeEntry ShapeSource;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
FVoxelOpRecipeEntry Conversion;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
TArray<FVoxelOpRecipeEntry> Modifiers;
|
|
|
|
// Which native block supplies the mandatory structural post parameters.
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Recipe")
|
|
EVoxelStrateParamBlock StructuralParamBlock = EVoxelStrateParamBlock::None;
|
|
};
|
|
|
|
/** The kind of value represented by one entry of VF_STRATE_PARAM_FIELDS. */
|
|
enum class EVoxelStrateFieldKind : uint8
|
|
{
|
|
Continuous,
|
|
Integer,
|
|
Boolean,
|
|
Enum,
|
|
};
|
|
|
|
/** A field deliberately kept out of the parameter roll after the measured liveness audit. */
|
|
struct VOXELFORGE_API FVoxelStrateFieldExclusion
|
|
{
|
|
FString FieldName;
|
|
FString Reason;
|
|
};
|
|
|
|
/** Measured statistics for one field in one archetype's corpus group. */
|
|
struct VOXELFORGE_API FVoxelStrateFieldSpread
|
|
{
|
|
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
|
|
FString ParamStructName;
|
|
FString FieldName;
|
|
EVoxelStrateFieldKind Kind = EVoxelStrateFieldKind::Continuous;
|
|
bool bExcluded = false;
|
|
bool bReflected = false;
|
|
|
|
// Actual authored corpus samples and synthetic per-operation default samples are kept
|
|
// separate in the report. SampleCount is their effective total used for the statistics.
|
|
int32 AuthoredSampleCount = 0;
|
|
int32 PromotedSampleCount = 0;
|
|
int32 DefaultSeedCount = 0;
|
|
int32 SampleCount = 0;
|
|
double Min = 0.0;
|
|
double Max = 0.0;
|
|
double Mean = 0.0;
|
|
double StdDev = 0.0;
|
|
|
|
// These are copied from UPROPERTY ClampMin/ClampMax when reflection metadata is available in
|
|
// the current build. They are safety limits, never the source of a roll range.
|
|
bool bHasClampMin = false;
|
|
bool bHasClampMax = false;
|
|
double ClampMin = 0.0;
|
|
double ClampMax = 0.0;
|
|
};
|
|
|
|
/** Where a member of the offline corpus came from. */
|
|
enum class EVoxelStrateCorpusProvenance : uint8
|
|
{
|
|
Project,
|
|
Default,
|
|
Promoted,
|
|
};
|
|
|
|
/** The finite, diffable metric summary stored with a promoted strate. */
|
|
struct VOXELFORGE_API FVoxelStrateMeasuredMetrics
|
|
{
|
|
bool bValid = false;
|
|
|
|
int64 NumSampled = 0;
|
|
int64 NumAir = 0;
|
|
int64 NumSolid = 0;
|
|
float AirFraction = 0.0f;
|
|
int32 NumAirComponents = 0;
|
|
float LargestComponentShare = 0.0f;
|
|
FVector LargestComponentPoint = FVector::ZeroVector;
|
|
int64 LargestComponentCells = 0;
|
|
int32 NumComponentsAtLeast1Pct = 0;
|
|
float WalkableFraction = 0.0f;
|
|
float MedianFeatureScale = 0.0f;
|
|
int32 MedianVerticalClearance = 0;
|
|
|
|
int32 ResolvedMarginVoxels = 0;
|
|
int32 SampledMinZ = 0;
|
|
int32 SampledMaxZ = 0;
|
|
int32 SampledNumX = 0;
|
|
int32 SampledNumY = 0;
|
|
int32 SampledNumZ = 0;
|
|
float SampledMinX = 0.0f;
|
|
float SampledMaxX = 0.0f;
|
|
float SampledMinY = 0.0f;
|
|
float SampledMaxY = 0.0f;
|
|
|
|
// This is the component-size audit trail, not a retained density grid. It is bounded by the
|
|
// number of discovered air components and is useful when reviewing a promoted record.
|
|
TArray<int64> AirComponentCells;
|
|
|
|
bool IsUsable() const;
|
|
};
|
|
|
|
/** Copy the measured facts that are safe and useful to persist; no sampler or grid is retained. */
|
|
VOXELFORGE_API FVoxelStrateMeasuredMetrics VF_SummarizeStrateMetrics(
|
|
const FVoxelStrateMetrics& Metrics);
|
|
|
|
/** Native parameter storage for every currently supported strate archetype. */
|
|
struct VOXELFORGE_API FVoxelStrateArchetypeParams
|
|
{
|
|
FStrateGenerationParams TunnelNetworkParams;
|
|
FSlabGenerationParams SlabParams;
|
|
FMazeGenerationParams MazeParams;
|
|
FSurfaceGenerationParams SurfaceParams;
|
|
FVerticalShaftParams VerticalShaftParams;
|
|
FFloatingIslandParams FloatingIslandParams;
|
|
};
|
|
|
|
/** One known-good authored vector and the archetype that gives it meaning. */
|
|
struct VOXELFORGE_API FVoxelStrateCorpusEntry
|
|
{
|
|
FString SourcePath;
|
|
FString SourceName;
|
|
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
|
|
|
|
// Native storage is selected by Archetype. Keeping every family here makes the corpus
|
|
// type-safe without changing any runtime generation parameter struct.
|
|
FVoxelStrateArchetypeParams ArchetypeParams;
|
|
|
|
// Compatibility view for callers of the original Tier 4a API. It is meaningful for
|
|
// TunnelNetwork/Underwater entries and is the same value as ArchetypeParams.TunnelNetworkParams.
|
|
FStrateGenerationParams Params;
|
|
|
|
// The current asset format has no corpus weight field. Loaded hand-authored entries therefore
|
|
// use 1.0. The field remains explicit so a future offline corpus can assign weights without
|
|
// changing the roll algorithm.
|
|
float Weight = 1.0f;
|
|
|
|
EVoxelStrateCorpusProvenance Provenance = EVoxelStrateCorpusProvenance::Project;
|
|
|
|
// Promoted entries retain their recipe and re-measured facts so the next policy decision can
|
|
// compare measured geometry, not only parameter-space distance. Project/default entries leave
|
|
// these fields unset unless an offline simulation explicitly measures them.
|
|
bool bHasRecipe = false;
|
|
FVoxelOpStackRecipe Recipe;
|
|
bool bHasMeasuredMetrics = false;
|
|
FVoxelStrateMeasuredMetrics MeasuredMetrics;
|
|
|
|
FString PromotionRecordId;
|
|
int32 PromotionSeason = INDEX_NONE;
|
|
int32 PromotionSeed = 0;
|
|
int32 PromotionCandidateIndex = INDEX_NONE;
|
|
uint32 PromotionInputCorpusHash = 0;
|
|
};
|
|
|
|
/** A candidate record that is eligible to be considered for corpus promotion. */
|
|
struct VOXELFORGE_API FVoxelStratePromotableRecord
|
|
{
|
|
FString RecordId;
|
|
int32 Season = 0;
|
|
int32 Seed = 0;
|
|
int32 CandidateIndex = INDEX_NONE;
|
|
uint32 InputCorpusHash = 0;
|
|
|
|
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
|
|
FVoxelStrateArchetypeParams Params;
|
|
FVoxelOpStackRecipe Recipe;
|
|
FVoxelStrateMeasuredMetrics MeasuredMetrics;
|
|
|
|
// These are recorded evidence for review. The loader deliberately ignores the stored metric
|
|
// and gate values and asks its verifier to rebuild/re-measure the recipe instead.
|
|
bool bPassedNonVacuous = false;
|
|
bool bPassedLargestComponent = false;
|
|
bool bPassedPrimordialLaw = false;
|
|
};
|
|
|
|
/** Fresh validation output used by the safe promoted-record loader. */
|
|
struct VOXELFORGE_API FVoxelStratePromotionVerification
|
|
{
|
|
bool bPassedNonVacuous = false;
|
|
bool bPassedLargestComponent = false;
|
|
bool bPassedPrimordialLaw = false;
|
|
FVoxelStrateMeasuredMetrics MeasuredMetrics;
|
|
FString FailureReason;
|
|
|
|
bool PassedAllGates() const
|
|
{
|
|
return bPassedNonVacuous && bPassedLargestComponent && bPassedPrimordialLaw
|
|
&& MeasuredMetrics.IsUsable();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* World-specific re-measurement seam for promoted records.
|
|
*
|
|
* A corpus store cannot know the active fixture, mouths, or validation window. Its caller must
|
|
* provide this verifier; a null verifier means promoted records are skipped rather than trusted.
|
|
*/
|
|
class VOXELFORGE_API IVoxelStratePromotionVerifier
|
|
{
|
|
public:
|
|
virtual ~IVoxelStratePromotionVerifier() = default;
|
|
virtual bool Verify(const FVoxelStratePromotableRecord& Record,
|
|
FVoxelStratePromotionVerification& OutVerification) const = 0;
|
|
|
|
// Optional companion audit for project/default members. A policy pass can then compare a
|
|
// candidate against the measured corpus rather than falling back to parameter identity. A
|
|
// world-specific verifier may return false when that fixture cannot measure the member.
|
|
virtual bool MeasureCorpusEntry(const FVoxelStrateCorpusEntry& Entry,
|
|
FVoxelStrateMeasuredMetrics& OutMetrics) const
|
|
{
|
|
(void)Entry;
|
|
(void)OutMetrics;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/** Explicit, provisional Tier 5 policy. The owner can change these after seeing the preview. */
|
|
struct VOXELFORGE_API FVoxelStratePromotionPolicy
|
|
{
|
|
// Five normalized measured dimensions are compared with Euclidean distance. 0.20 is large
|
|
// enough to reject close copies while still admitting genuinely different geometry; it is a
|
|
// provisional review threshold, not a claim that this is the owner's final definition of good.
|
|
double MinimumNormalizedMeasuredMetricDistance = 0.20;
|
|
int32 MaxPromotionsPerSeason = 6;
|
|
|
|
// Physical normalization for the two unbounded-in-principle metric dimensions. Air fraction,
|
|
// largest share, and walkable fraction already live in [0,1].
|
|
float FeatureScaleNormalizationVoxels = 256.0f;
|
|
float ClearanceNormalizationVoxels = 64.0f;
|
|
};
|
|
|
|
/** Counters and accepted records from one deterministic policy pass. */
|
|
struct VOXELFORGE_API FVoxelStratePromotionBatchResult
|
|
{
|
|
bool bPolicyValid = false;
|
|
TArray<FVoxelStratePromotableRecord> Promoted;
|
|
int32 NumCandidates = 0;
|
|
int32 NumValidationRejected = 0;
|
|
int32 NumCorpusHashRejected = 0;
|
|
int32 NumNearDuplicateRejected = 0;
|
|
int32 NumCapRejected = 0;
|
|
double MinimumAcceptedDistance = 0.0;
|
|
};
|
|
|
|
/** One line of the diffable season manifest written beside the cumulative record store. */
|
|
struct VOXELFORGE_API FVoxelStrateSeasonManifest
|
|
{
|
|
int32 Season = 0;
|
|
int32 Seed = 0;
|
|
uint32 InputCorpusHash = 0;
|
|
int32 CandidateCount = 0;
|
|
int32 SurvivorCount = 0;
|
|
int32 PromotedCount = 0;
|
|
int32 CorpusSize = 0;
|
|
int32 ProjectCount = 0;
|
|
int32 DefaultCount = 0;
|
|
int32 PromotedCorpusCount = 0;
|
|
float SurvivalRate = 0.0f;
|
|
double MeasuredSpread = 0.0;
|
|
};
|
|
|
|
/** Result of one deterministic roll, including provenance for the offline report. */
|
|
struct VOXELFORGE_API FVoxelStrateRollInfo
|
|
{
|
|
bool bValid = false;
|
|
FString FailureReason;
|
|
|
|
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
|
|
FVoxelStrateArchetypeParams ArchetypeParams;
|
|
|
|
// Compatibility view for the original tunnel-only API. For a non-tunnel roll, the native
|
|
// result is in ArchetypeParams and this member is not the active candidate vector.
|
|
FStrateGenerationParams Params;
|
|
|
|
TArray<int32> ParentEntryIndices;
|
|
TArray<float> ParentWeights;
|
|
int32 DominantParentPosition = INDEX_NONE;
|
|
|
|
// Provenance for the starved-corpus fallback. Names are keyed as "archetype:field" so a
|
|
// report can distinguish field descriptors from the number of times they were applied.
|
|
int32 BootstrapJitterFieldCount = 0;
|
|
TArray<FString> BootstrapJitterFieldNames;
|
|
};
|
|
|
|
#if WITH_EDITOR
|
|
/**
|
|
* One candidate materialised by the same deterministic calls used by the offline composer tests.
|
|
* This is an editor-only hand-off object: it is never a reflected asset and never part of the
|
|
* shipping generation contract.
|
|
*/
|
|
struct VOXELFORGE_API FVoxelStrateComposerCandidate
|
|
{
|
|
bool bValid = false;
|
|
FString FailureReason;
|
|
|
|
int32 Seed = 0;
|
|
int32 Index = 0;
|
|
bool bStructureRoll = false;
|
|
|
|
ECaveGeneratorType Archetype = ECaveGeneratorType::TunnelNetwork;
|
|
FVoxelStrateArchetypeParams ArchetypeParams;
|
|
FVoxelOpStackRecipe Recipe;
|
|
|
|
// Kept so automation/editor callers can audit the exact six independent structure blocks
|
|
// without re-rolling them through a second implementation.
|
|
FVoxelStrateRollInfo ParameterRoll;
|
|
TArray<FVoxelStrateRollInfo> StructureBlockRolls;
|
|
};
|
|
#endif
|
|
|
|
/**
|
|
* Known-good strate vectors plus their measured field spread.
|
|
*
|
|
* `LoadFromAssetRegistry` enumerates every project UVoxelStrateDefinition through the Asset
|
|
* Registry, explicitly excluding Saved/Autosaves and Saved/Cooked copies. It also adds one
|
|
* known-good default vector for every archetype/family in VoxelStrateTypes.h, then optionally
|
|
* loads the cumulative promoted-record JSON store. Promoted records enter only after the caller's
|
|
* world-specific verifier rebuilds and remeasures them; with no verifier they are skipped safely.
|
|
* Parents are selected only inside the exact archetype group; no cross-archetype blend is attempted.
|
|
*/
|
|
class VOXELFORGE_API FVoxelStrateCorpus
|
|
{
|
|
public:
|
|
void Reset();
|
|
|
|
bool LoadFromAssetRegistry(
|
|
FString& OutReport,
|
|
const FString& PromotedStorePath = FString(),
|
|
const IVoxelStratePromotionVerifier* PromotionVerifier = nullptr);
|
|
|
|
/**
|
|
* Compatibility alias retained for callers compiled against the first Tier 4a pass. The
|
|
* settings argument is audited only for diagnostics; it is not a corpus input.
|
|
*/
|
|
bool LoadFromSettings(const UVoxelSettings* Settings, FString& OutReport);
|
|
bool LoadFromDefinitions(const TArray<UVoxelStrateDefinition*>& Definitions, FString& OutReport);
|
|
|
|
/** Add an already-resolved vector, primarily for offline tools and focused tests. */
|
|
bool AddEntry(const FString& SourcePath, const FString& SourceName,
|
|
ECaveGeneratorType Archetype, const FStrateGenerationParams& Params,
|
|
float Weight = 1.0f);
|
|
bool AddEntry(const FString& SourcePath, const FString& SourceName,
|
|
ECaveGeneratorType Archetype, const FVoxelStrateArchetypeParams& Params,
|
|
float Weight = 1.0f);
|
|
|
|
/** Load cumulative promoted records, re-verifying every record before it enters Entries. */
|
|
bool LoadPromotedRecords(const FString& StorePath,
|
|
const IVoxelStratePromotionVerifier* PromotionVerifier,
|
|
FString& OutReport);
|
|
|
|
/** Attach an offline measurement to an existing member without changing corpus identity. */
|
|
bool SetMeasuredMetrics(const FString& SourcePath,
|
|
const FVoxelStrateMeasuredMetrics& Metrics);
|
|
|
|
bool IsValid() const { return bSchemaValid && Entries.Num() > 0; }
|
|
bool IsSchemaValid() const { return bSchemaValid; }
|
|
const FString& GetSchemaError() const { return SchemaError; }
|
|
|
|
int32 Num() const { return Entries.Num(); }
|
|
const TArray<FVoxelStrateCorpusEntry>& GetEntries() const { return Entries; }
|
|
const TArray<FVoxelStrateFieldSpread>& GetFieldSpreads() const { return FieldSpreads; }
|
|
const TArray<FString>& GetSkippedDefinitions() const { return SkippedDefinitions; }
|
|
|
|
int32 NumForArchetype(ECaveGeneratorType Archetype) const;
|
|
int32 NumForProvenance(EVoxelStrateCorpusProvenance Provenance) const;
|
|
|
|
const FVoxelStrateFieldSpread* FindSpread(
|
|
ECaveGeneratorType Archetype, const FString& FieldName) const;
|
|
const FVoxelStrateFieldSpread* FindSpread(const FString& FieldName) const;
|
|
|
|
/** Stable hash of source paths, archetypes, weights, and every listed scalar corpus field. */
|
|
uint32 GetContentsHash() const;
|
|
|
|
/** Explicit exclusion list retained after the fixed-lattice terrain-detail liveness audit. */
|
|
static const TArray<FVoxelStrateFieldExclusion>& GetNonTunableFields();
|
|
|
|
/** True in an editor build where UPROPERTY metadata was available while spreads were built. */
|
|
bool AreClampMetadataAvailableAtBuild() const { return bClampMetadataAvailableAtBuild; }
|
|
|
|
/** False by policy: metadata is not promised to survive into a cooked runtime. */
|
|
bool AreClampMetadataAvailableAtRuntime() const { return false; }
|
|
|
|
private:
|
|
bool AddEntryInternal(const FString& SourcePath, const FString& SourceName,
|
|
ECaveGeneratorType Archetype,
|
|
const FVoxelStrateArchetypeParams& Params,
|
|
float Weight, EVoxelStrateCorpusProvenance Provenance,
|
|
const FVoxelOpStackRecipe* Recipe,
|
|
const FVoxelStrateMeasuredMetrics* Metrics,
|
|
const FString& PromotionRecordId,
|
|
int32 PromotionSeason,
|
|
int32 PromotionSeed,
|
|
int32 PromotionCandidateIndex,
|
|
uint32 PromotionInputCorpusHash,
|
|
bool bRebuild);
|
|
void RebuildSpreads();
|
|
|
|
TArray<FVoxelStrateCorpusEntry> Entries;
|
|
TArray<FVoxelStrateFieldSpread> FieldSpreads;
|
|
TArray<FString> SkippedDefinitions;
|
|
FString SchemaError;
|
|
bool bSchemaValid = true;
|
|
bool bClampMetadataAvailableAtBuild = false;
|
|
};
|
|
|
|
/** Human-readable name used by the offline report. */
|
|
VOXELFORGE_API const TCHAR* VF_GetStrateArchetypeName(ECaveGeneratorType Archetype);
|
|
VOXELFORGE_API const TCHAR* VF_GetStrateCorpusProvenanceName(
|
|
EVoxelStrateCorpusProvenance Provenance);
|
|
|
|
/** Full provenance result. Pure with respect to the corpus: no global or retained RNG state. */
|
|
VOXELFORGE_API FVoxelStrateRollInfo VF_RollStrateParamsDetailed(
|
|
const FVoxelStrateCorpus& Corpus, int32 Seed, int32 Index);
|
|
|
|
/** Roll one exact native family, used to feed the independent blocks of a novel recipe. */
|
|
VOXELFORGE_API FVoxelStrateRollInfo VF_RollStrateParamsDetailedForArchetype(
|
|
const FVoxelStrateCorpus& Corpus, ECaveGeneratorType Archetype, int32 Seed, int32 Index);
|
|
|
|
/** Pure structure roll: no retained RNG state and no corpus/runtime dependency. */
|
|
VOXELFORGE_API FVoxelOpStackRecipe VF_RollStrateStructure(int32 Seed, int32 Index);
|
|
|
|
/**
|
|
* Provenance for a parameter block that does not read the authored corpus.
|
|
*
|
|
* NaiveUniform is the §3.3 control: every scalar is rolled independently inside the same
|
|
* finite code-declared envelope used by the constraint arm. ConstraintSampled draws the
|
|
* independent geometry quantities and derives the coupled quantities from generator equations.
|
|
* Neither mode reads a strate asset or a corpus entry.
|
|
*/
|
|
enum class EVoxelStrateCorpusFreeSamplingMode : uint8
|
|
{
|
|
NaiveUniform,
|
|
ConstraintSampled,
|
|
};
|
|
|
|
/** Roll one native parameter family without consulting FVoxelStrateCorpus. */
|
|
VOXELFORGE_API FVoxelStrateRollInfo VF_RollStrateParamsCorpusFree(
|
|
ECaveGeneratorType Archetype,
|
|
int32 Seed,
|
|
int32 Index,
|
|
EVoxelStrateCorpusFreeSamplingMode Mode,
|
|
float StrateHeightInVoxels);
|
|
|
|
/** Validate the hard geometry relations used by ConstraintSampled and the corpus audit. */
|
|
VOXELFORGE_API bool VF_ValidateStrateCorpusFreeConstraints(
|
|
ECaveGeneratorType Archetype,
|
|
const FVoxelStrateArchetypeParams& Params,
|
|
float StrateHeightInVoxels,
|
|
FString& OutViolation);
|
|
|
|
/** Normalized Euclidean distance in the five policy metric dimensions. */
|
|
VOXELFORGE_API double VF_NormalizedMeasuredMetricDistance(
|
|
const FVoxelStrateMeasuredMetrics& A,
|
|
const FVoxelStrateMeasuredMetrics& B,
|
|
const FVoxelStratePromotionPolicy& Policy);
|
|
|
|
/** Select deterministic, validated, varied records for one season. */
|
|
VOXELFORGE_API FVoxelStratePromotionBatchResult VF_SelectStratePromotions(
|
|
const FVoxelStrateCorpus& Corpus,
|
|
const TArray<FVoxelStratePromotableRecord>& Candidates,
|
|
const FVoxelStratePromotionPolicy& Policy);
|
|
|
|
/** Write/readable cumulative JSON store; records are sorted by RecordId before writing. */
|
|
VOXELFORGE_API bool VF_SaveStratePromotedRecords(
|
|
const FString& StorePath,
|
|
const TArray<FVoxelStratePromotableRecord>& Records,
|
|
FString& OutReport);
|
|
|
|
/** Write the matching season summary beside the promoted-record store. */
|
|
VOXELFORGE_API bool VF_SaveStrateSeasonManifest(
|
|
const FString& ManifestPath,
|
|
const FVoxelStrateSeasonManifest& Manifest,
|
|
FString& OutReport);
|
|
|
|
#if WITH_EDITOR
|
|
/**
|
|
* Roll one candidate for the editor walk-through path. Parameter rolls call
|
|
* VF_RollStrateParamsDetailed; structure rolls call VF_RollStrateStructure and the exact six
|
|
* VF_RollStrateParamsDetailedForArchetype block rolls used by the structure test.
|
|
*/
|
|
VOXELFORGE_API FVoxelStrateComposerCandidate VF_RollStrateCandidate(
|
|
const FVoxelStrateCorpus& Corpus, int32 Seed, int32 Index, bool bRollStructure);
|
|
|
|
/**
|
|
* Build a parameter-roll candidate through the same archetype-to-stack mapping used by production
|
|
* GetDensityAt/ClassifyTile. This is editor-only so the offline composer remains absent from a
|
|
* shipping build; the result is used only for the post-apply density sanity check.
|
|
*/
|
|
VOXELFORGE_API bool VF_BuildNativeStrateStackForCandidate(
|
|
ECaveGeneratorType Archetype,
|
|
const FVoxelStrateArchetypeParams& Params,
|
|
int32 Seed,
|
|
float SpineRadius,
|
|
float WorldRadiusVoxels,
|
|
float EdgeSealThickness,
|
|
const UVoxelStrateManager* StrateManager,
|
|
FVoxelOpStack& OutStack,
|
|
FVoxelOpContext& OutContext);
|
|
|
|
/** Build the persisted record from the exact editor candidate and its just-measured gate facts. */
|
|
VOXELFORGE_API FVoxelStratePromotableRecord VF_MakeStratePromotableRecord(
|
|
const FVoxelStrateComposerCandidate& Candidate,
|
|
const FVoxelStrateMetrics& Metrics,
|
|
int32 Season,
|
|
uint32 InputCorpusHash,
|
|
bool bPassedNonVacuous,
|
|
bool bPassedLargestComponent,
|
|
bool bPassedPrimordialLaw);
|
|
#endif
|
|
|
|
/** Stable compact representation and equality/hash helpers for manifests and reports. */
|
|
VOXELFORGE_API FString VF_FormatStrateStructureRecipe(const FVoxelOpStackRecipe& Recipe);
|
|
VOXELFORGE_API uint32 VF_HashStrateStructureRecipe(const FVoxelOpStackRecipe& Recipe);
|
|
VOXELFORGE_API bool VF_AreStrateStructureRecipesIdentical(
|
|
const FVoxelOpStackRecipe& A, const FVoxelOpStackRecipe& B);
|
|
|
|
/** The compact API requested by the composer design. */
|
|
VOXELFORGE_API FStrateGenerationParams VF_RollStrateParams(
|
|
const FVoxelStrateCorpus& Corpus, int32 Seed, int32 Index);
|
|
|
|
/** Bitwise comparison over exactly the fields in FStrateGenerationParams::Lerp. */
|
|
VOXELFORGE_API bool VF_AreStrateParamsBitIdentical(
|
|
const FStrateGenerationParams& A, const FStrateGenerationParams& B);
|
|
|
|
/** Bitwise comparison of the native vector for one archetype family. */
|
|
VOXELFORGE_API bool VF_AreStrateArchetypeParamsBitIdentical(
|
|
const FVoxelStrateArchetypeParams& A,
|
|
const FVoxelStrateArchetypeParams& B,
|
|
ECaveGeneratorType Archetype);
|
|
|
|
/**
|
|
* Normalised distance from the measured centroid of one exact-archetype corpus group.
|
|
*
|
|
* This is an offline ordering aid for the preview only. Continuous/integer fields are measured
|
|
* in their corpus units; zero-spread fields use a conservative scale floor so the value remains
|
|
* finite without turning clamps into roll ranges. It never participates in generation.
|
|
*/
|
|
VOXELFORGE_API double VF_DistanceFromStrateCorpusCentroid(
|
|
const FVoxelStrateCorpus& Corpus,
|
|
const FVoxelStrateArchetypeParams& Params,
|
|
ECaveGeneratorType Archetype);
|