feat(measure): a player does not fit. The law was passing impossible routes.
Jahni walked composed strates for the first time: "'maze' is way too tight tunnel radius wise, i can't enter nor anything". The candidates he could not enter were the ones our metrics ranked BEST -- Maze had the highest walkable fraction (.285) and highest connected surface (.99) of all eight. ⭐ THE HEADLINE, AND IT IS BAD NEWS WORTH HAVING: old arrival->departure law passing on 7 of 8 candidates player-fit-restricted law CONNECTED ON 0 OF 8 **The primordial law has been passing on routes no player fits through.** Every "the world is traversable" claim in this project measured air, not passage. Player-fit fraction across the eight showcase candidates ranges .0000 (FloatingIslands -- literally zero) to .0117. The season composer now returns 0 survivors for 6 required slots, and the showcase gate rejects 8 of 8. That is the correct outcome. The gate is not tuned to a threshold; it requires a resolved player-fit volume and a connected player-fit route. Capsule confirmed by Jahni as the base ACharacter: 34 cm radius, 88 cm half-height = 1.36 voxels radius, 7.04 tall. Named constant with the derivation beside it. Two traps avoided, both of which would have produced confident nonsense: - THE COARSE GRID CANNOT RESOLVE A PLAYER. SampleStep 4 makes a cell 4 voxels, ~3x the player's radius, so fit is below the resolution of every metric built so far -- which is exactly why nothing flagged an impassable maze. Fit runs on step 1 and REFUSES (bPlayerFitResolved=false + reason) when the step is too coarse. - Manhattan distance >= Euclidean, so reusing the existing transform for clearance would OVERESTIMATE free space and report fits that do not exist. Clearance uses a separate Chebyshev transform; Manhattan stays only on the legacy feature-scale metric. ⚠️ MY ROUGHNESS HYPOTHESIS WAS WRONG, and Codex disproved it rather than confirming it. Forcing SurfaceRoughness=0 on the Maze moved PlayerFit .0105 -> .0138 and the restricted law stayed NotConnected. Minimum corridor clearance is 1.00 voxel (25 cm) with or without roughness -- the corridors are simply too tight for a 34 cm capsule, full stop. Roughness IS still a real pinch risk where reach exceeds corridor radius: Underwater 2.21x, FlatPlain 2.31x, CrystalChamber 1.81x, TunnelNetwork 1.44x on corridors, VerticalShafts 1.30x on connectors. The 5.625-voxel default bound stays dangerous. Islands measured, not changed (feel is Jahni's call): 0/2 touch either seal, median clear gap 47.8 above / 9.0 below -- but effective radius spans 27-258 voxels at H=128 with ThicknessRatio .546, so the worst case has zero guaranteed separation. Recommendation recorded: radius back to 18-42, StrateHeightInChunks 4 -> 6, ThicknessRatio <= .40. Build clean, 30 succeeded / 0 failed, verified in the namespace log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJiTcTSDNkKBtnNdiBtdaU
This commit is contained in:
1 parent
faa62d419e
commit
eb47efdec9
16 files changed
+1600
-91
No files matched your search
@@ -2285,6 +2285,14 @@ FVoxelStrateMeasuredMetrics VF_SummarizeStrateMetrics(
|
||||
Result.LargestWalkableSurfaceShare = Metrics.LargestWalkableSurfaceShare;
|
||||
Result.MedianFeatureScale = Metrics.MedianFeatureScale;
|
||||
Result.MedianVerticalClearance = Metrics.MedianVerticalClearance;
|
||||
Result.bPlayerFitResolved = Metrics.bPlayerFitResolved;
|
||||
Result.PlayerFitRefusalReason = Metrics.PlayerFitRefusalReason;
|
||||
Result.NumPlayerFitCells = Metrics.NumPlayerFitCells;
|
||||
Result.PlayerFitFraction = Metrics.PlayerFitFraction;
|
||||
Result.NumTraversableComponents = Metrics.NumTraversableComponents;
|
||||
Result.LargestTraversableComponentCells = Metrics.LargestTraversableComponentCells;
|
||||
Result.TraversableComponentShare = Metrics.TraversableComponentShare;
|
||||
Result.MinimumPlayerClearanceVoxels = Metrics.MinimumPlayerClearanceVoxels;
|
||||
Result.ResolvedMarginVoxels = Metrics.ResolvedMarginVoxels;
|
||||
Result.SampledMinZ = Metrics.SampledMinZ;
|
||||
Result.SampledMaxZ = Metrics.SampledMaxZ;
|
||||
@@ -2778,6 +2786,19 @@ namespace
|
||||
Metrics.LargestWalkableSurfaceShare);
|
||||
Object->SetNumberField(TEXT("median_feature_scale"), Metrics.MedianFeatureScale);
|
||||
Object->SetNumberField(TEXT("median_vertical_clearance"), Metrics.MedianVerticalClearance);
|
||||
Object->SetBoolField(TEXT("player_fit_resolved"), Metrics.bPlayerFitResolved);
|
||||
Object->SetStringField(TEXT("player_fit_refusal_reason"), Metrics.PlayerFitRefusalReason);
|
||||
Object->SetNumberField(TEXT("num_player_fit_cells"),
|
||||
static_cast<double>(Metrics.NumPlayerFitCells));
|
||||
Object->SetNumberField(TEXT("player_fit_fraction"), Metrics.PlayerFitFraction);
|
||||
Object->SetNumberField(TEXT("num_traversable_components"),
|
||||
Metrics.NumTraversableComponents);
|
||||
Object->SetNumberField(TEXT("largest_traversable_component_cells"),
|
||||
static_cast<double>(Metrics.LargestTraversableComponentCells));
|
||||
Object->SetNumberField(TEXT("traversable_component_share"),
|
||||
Metrics.TraversableComponentShare);
|
||||
Object->SetNumberField(TEXT("minimum_player_clearance_voxels"),
|
||||
Metrics.MinimumPlayerClearanceVoxels);
|
||||
Object->SetNumberField(TEXT("resolved_margin_voxels"), Metrics.ResolvedMarginVoxels);
|
||||
Object->SetNumberField(TEXT("sampled_min_z"), Metrics.SampledMinZ);
|
||||
Object->SetNumberField(TEXT("sampled_max_z"), Metrics.SampledMaxZ);
|
||||
@@ -2852,6 +2873,25 @@ namespace
|
||||
OutMetrics.MedianFeatureScale) && bValid;
|
||||
bValid = VF_ReadJsonInt32(Object, TEXT("median_vertical_clearance"),
|
||||
OutMetrics.MedianVerticalClearance) && bValid;
|
||||
if (Object->HasField(TEXT("player_fit_resolved")))
|
||||
{
|
||||
bValid = VF_ReadJsonBool(Object, TEXT("player_fit_resolved"),
|
||||
OutMetrics.bPlayerFitResolved) && bValid;
|
||||
bValid = VF_ReadJsonString(Object, TEXT("player_fit_refusal_reason"),
|
||||
OutMetrics.PlayerFitRefusalReason) && bValid;
|
||||
bValid = VF_ReadJsonInt64(Object, TEXT("num_player_fit_cells"),
|
||||
OutMetrics.NumPlayerFitCells) && bValid;
|
||||
bValid = VF_ReadJsonFloat(Object, TEXT("player_fit_fraction"),
|
||||
OutMetrics.PlayerFitFraction) && bValid;
|
||||
bValid = VF_ReadJsonInt32(Object, TEXT("num_traversable_components"),
|
||||
OutMetrics.NumTraversableComponents) && bValid;
|
||||
bValid = VF_ReadJsonInt64(Object, TEXT("largest_traversable_component_cells"),
|
||||
OutMetrics.LargestTraversableComponentCells) && bValid;
|
||||
bValid = VF_ReadJsonFloat(Object, TEXT("traversable_component_share"),
|
||||
OutMetrics.TraversableComponentShare) && bValid;
|
||||
bValid = VF_ReadJsonFloat(Object, TEXT("minimum_player_clearance_voxels"),
|
||||
OutMetrics.MinimumPlayerClearanceVoxels) && bValid;
|
||||
}
|
||||
bValid = VF_ReadJsonInt32(Object, TEXT("resolved_margin_voxels"),
|
||||
OutMetrics.ResolvedMarginVoxels) && bValid;
|
||||
bValid = VF_ReadJsonInt32(Object, TEXT("sampled_min_z"), OutMetrics.SampledMinZ) && bValid;
|
||||
@@ -2995,6 +3035,14 @@ namespace
|
||||
&& A.LargestWalkableSurfaceShare == B.LargestWalkableSurfaceShare
|
||||
&& A.MedianFeatureScale == B.MedianFeatureScale
|
||||
&& A.MedianVerticalClearance == B.MedianVerticalClearance
|
||||
&& A.bPlayerFitResolved == B.bPlayerFitResolved
|
||||
&& A.PlayerFitRefusalReason == B.PlayerFitRefusalReason
|
||||
&& A.NumPlayerFitCells == B.NumPlayerFitCells
|
||||
&& A.PlayerFitFraction == B.PlayerFitFraction
|
||||
&& A.NumTraversableComponents == B.NumTraversableComponents
|
||||
&& A.LargestTraversableComponentCells == B.LargestTraversableComponentCells
|
||||
&& A.TraversableComponentShare == B.TraversableComponentShare
|
||||
&& A.MinimumPlayerClearanceVoxels == B.MinimumPlayerClearanceVoxels
|
||||
&& A.ResolvedMarginVoxels == B.ResolvedMarginVoxels
|
||||
&& A.SampledMinZ == B.SampledMinZ
|
||||
&& A.SampledMaxZ == B.SampledMaxZ
|
||||
@@ -3075,6 +3123,10 @@ namespace
|
||||
&& FMath::IsFinite(Metrics.WalkableFloorAreaFraction)
|
||||
&& FMath::IsFinite(Metrics.LargestWalkableSurfaceShare)
|
||||
&& FMath::IsFinite(Metrics.MedianFeatureScale)
|
||||
&& (!Metrics.bPlayerFitResolved
|
||||
|| (FMath::IsFinite(Metrics.PlayerFitFraction)
|
||||
&& FMath::IsFinite(Metrics.TraversableComponentShare)
|
||||
&& FMath::IsFinite(Metrics.MinimumPlayerClearanceVoxels)))
|
||||
&& FMath::IsFinite(Metrics.LargestComponentPoint.X)
|
||||
&& FMath::IsFinite(Metrics.LargestComponentPoint.Y)
|
||||
&& FMath::IsFinite(Metrics.LargestComponentPoint.Z);
|
||||
|
||||
Reference in new issue
Block a user