fix(streaming): vertical reach follows the strate, and the level below the sheet ring is filled
The owner marked missing tiles around him in a 64-chunk surface strate with RenderDistanceChunks=768. Cause: the desired-set vertical clamp used the player's small window (bClampViewToStrate on, ViewDistanceUp/Down=5, margin 3), so at chunk Z=0 only [-5..3] was ever requested; the rest of his strate was never asked for. Second cause: with MaxClipLevel=3 and a two-level sheet span the outer ring is level 5, while the marching-cubes loop stopped at 3, leaving level 4 empty. The band now follows the player's whole strate plus margin ([-66..3] in the pinned case) and keeps the small window only when there are no strate bounds (inter-strate gap), so the hidden-rock column the clamp exists to avoid does not return. Bridge shells are emitted up to the level below the sheet ring, filling level 4. Pinned case desired tiles per level, before -> after: l0 343->343, l1 218->218, l2 129->178, l3 80->178, l4 0->178, l5 4801->9586; total 5,571 -> 10,681 (+91.7%). New focused fixture VoxelForgeVerticalStrateReachTest fails before and passes after. Stress repro passes (140.089 m, 4 holds, 0 full stops); strate crossing passes (0 holds, 0 floor overlap). ⚠️ Cost not established: the post-fix perf sample was incomplete and showed a 55.7 s p50 queue wait, which may be the fixture's extreme settings (768 render distance -> 9,586 sheet tiles) or a real backlog. Measure in the owner's world before merging. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
d7af2cab97
commit
30253f0e89
5 files changed
+344
-165
No files matched your search
@@ -0,0 +1,89 @@
|
|||||||
|
// Surface-strate streaming must keep the ground visible when the pawn is high in the same strate.
|
||||||
|
|
||||||
|
#if WITH_DEV_AUTOMATION_TESTS
|
||||||
|
|
||||||
|
#include "Misc/AutomationTest.h"
|
||||||
|
|
||||||
|
#include "VoxelClipmapDesiredTiles.h"
|
||||||
|
|
||||||
|
IMPLEMENT_SIMPLE_AUTOMATION_TEST(
|
||||||
|
FVoxelForgeVerticalStrateReachTest,
|
||||||
|
"VoxelForge.Streaming.VerticalStrateReach",
|
||||||
|
EAutomationTestFlags_ApplicationContextMask | EAutomationTestFlags::EngineFilter)
|
||||||
|
|
||||||
|
bool FVoxelForgeVerticalStrateReachTest::RunTest(const FString& Parameters)
|
||||||
|
{
|
||||||
|
constexpr int32 StrateBottomZ = -63;
|
||||||
|
constexpr int32 StrateTopZ = 0;
|
||||||
|
constexpr int32 PlayerChunkZ = 0; // high above this surface strate's ground
|
||||||
|
|
||||||
|
int32 MinChunkZ = MIN_int32;
|
||||||
|
int32 MaxChunkZ = MAX_int32;
|
||||||
|
VoxelClipmapDesiredTiles::ResolveVerticalBounds(
|
||||||
|
PlayerChunkZ, 5, 5, 3, true, true,
|
||||||
|
StrateTopZ, StrateBottomZ, MinChunkZ, MaxChunkZ);
|
||||||
|
TestEqual(TEXT("vertical reach follows the full surface strate plus margin"), MinChunkZ, -66);
|
||||||
|
TestEqual(TEXT("open-strate reach ends at the surface cap margin"), MaxChunkZ, 3);
|
||||||
|
|
||||||
|
VoxelClipmapDesiredTiles::FParameters Clipmap;
|
||||||
|
Clipmap.ClipRadius = 3;
|
||||||
|
Clipmap.MaxClipLevel = 3;
|
||||||
|
Clipmap.RenderDistanceChunks = 768;
|
||||||
|
Clipmap.bFarSheetRing = true;
|
||||||
|
Clipmap.FarSheetSpanLevels = 2;
|
||||||
|
|
||||||
|
TArray<FVoxelTileKey> Desired;
|
||||||
|
VoxelClipmapDesiredTiles::Build(
|
||||||
|
FIntVector(0, 0, PlayerChunkZ), MinChunkZ, MaxChunkZ, Clipmap, Desired);
|
||||||
|
|
||||||
|
TArray<int32> CountsByLevel;
|
||||||
|
CountsByLevel.Init(0, 6);
|
||||||
|
for (const FVoxelTileKey& Tile : Desired)
|
||||||
|
{
|
||||||
|
if (CountsByLevel.IsValidIndex(Tile.Level))
|
||||||
|
{
|
||||||
|
++CountsByLevel[Tile.Level];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int32 ExpectedCounts[] = {343, 218, 178, 178, 178, 9586};
|
||||||
|
for (int32 Level = 0; Level < static_cast<int32>(UE_ARRAY_COUNT(ExpectedCounts)); ++Level)
|
||||||
|
{
|
||||||
|
TestEqual(FString::Printf(TEXT("desired tile count at level %d"), Level),
|
||||||
|
CountsByLevel[Level], ExpectedCounts[Level]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto HasTile = [&Desired](int32 Level, const FIntVector& Coord)
|
||||||
|
{
|
||||||
|
return Desired.ContainsByPredicate([Level, &Coord](const FVoxelTileKey& Tile)
|
||||||
|
{
|
||||||
|
return Tile.Level == Level && Tile.Coord == Coord;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
TestTrue(TEXT("level 0 tile around the high pawn is present"),
|
||||||
|
HasTile(0, FIntVector(0, 0, 0)));
|
||||||
|
TestTrue(TEXT("level 4 bridge tile covering the ground below the pawn is present"),
|
||||||
|
HasTile(4, FIntVector(0, 0, -3)));
|
||||||
|
TestTrue(TEXT("adjacent level 4 ground tile is present"),
|
||||||
|
HasTile(4, FIntVector(1, 0, -3)));
|
||||||
|
TestTrue(TEXT("outer level 5 sheet reaches the 768-chunk horizon"),
|
||||||
|
HasTile(5, FIntVector(24, 0, 0)));
|
||||||
|
TestFalse(TEXT("clamping does not request a full hidden LOD0 column"),
|
||||||
|
HasTile(0, FIntVector(0, 0, -47)));
|
||||||
|
|
||||||
|
for (int32 Level = 0; Level <= 5; ++Level)
|
||||||
|
{
|
||||||
|
TestTrue(FString::Printf(TEXT("clip level %d is non-empty"), Level),
|
||||||
|
CountsByLevel[Level] > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddInfo(FString::Printf(
|
||||||
|
TEXT("center_z=%d strate=[%d..%d] view=[%d..%d] levels=[%d,%d,%d,%d,%d,%d] total=%d"),
|
||||||
|
PlayerChunkZ, StrateBottomZ, StrateTopZ, MinChunkZ, MaxChunkZ,
|
||||||
|
CountsByLevel[0], CountsByLevel[1], CountsByLevel[2], CountsByLevel[3],
|
||||||
|
CountsByLevel[4], CountsByLevel[5], Desired.Num()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WITH_DEV_AUTOMATION_TESTS
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VoxelTypes.h"
|
||||||
|
|
||||||
|
namespace VoxelClipmapDesiredTiles
|
||||||
|
{
|
||||||
|
struct FParameters
|
||||||
|
{
|
||||||
|
int32 ClipRadius = 3;
|
||||||
|
int32 MaxClipLevel = 4;
|
||||||
|
int32 RenderDistanceChunks = 0;
|
||||||
|
bool bFarSheetRing = true;
|
||||||
|
int32 FarSheetSpanLevels = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
FORCEINLINE int32 FloorDiv(int32 Value, int32 Divisor)
|
||||||
|
{
|
||||||
|
return Value >= 0 ? (Value / Divisor) : -(((-Value) + Divisor - 1) / Divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE FIntVector FloorDiv(const FIntVector& Value, int32 Divisor)
|
||||||
|
{
|
||||||
|
return FIntVector(FloorDiv(Value.X, Divisor), FloorDiv(Value.Y, Divisor),
|
||||||
|
FloorDiv(Value.Z, Divisor));
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE int32 OuterShellRadius(const FParameters& Parameters, int32 Radius, int32 MaxLevel)
|
||||||
|
{
|
||||||
|
if (Parameters.RenderDistanceChunks <= 0)
|
||||||
|
{
|
||||||
|
return Radius;
|
||||||
|
}
|
||||||
|
return FMath::Max(Radius,
|
||||||
|
(Parameters.RenderDistanceChunks + (1 << MaxLevel) - 1) >> MaxLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE void OuterShell(const FParameters& Parameters, int32 Radius, int32 MaxLevel,
|
||||||
|
int32& OutLevel, int32& OutRadius)
|
||||||
|
{
|
||||||
|
OutLevel = MaxLevel;
|
||||||
|
OutRadius = OuterShellRadius(Parameters, Radius, MaxLevel);
|
||||||
|
if (Parameters.bFarSheetRing && OutRadius > Radius)
|
||||||
|
{
|
||||||
|
OutLevel = MaxLevel + FMath::Clamp(Parameters.FarSheetSpanLevels, 1, 4);
|
||||||
|
OutRadius = FMath::Max(1,
|
||||||
|
(Parameters.RenderDistanceChunks + (1 << OutLevel) - 1) >> OutLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE void ResolveVerticalBounds(
|
||||||
|
int32 CenterChunkZ, int32 ViewDistanceUp, int32 ViewDistanceDown,
|
||||||
|
int32 StrateViewMarginChunks, bool bClampToStrate, bool bHasStrate,
|
||||||
|
int32 StrateTopChunkZ, int32 StrateBottomChunkZ,
|
||||||
|
int32& OutMinChunkZ, int32& OutMaxChunkZ)
|
||||||
|
{
|
||||||
|
OutMinChunkZ = MIN_int32;
|
||||||
|
OutMaxChunkZ = MAX_int32;
|
||||||
|
if (!bClampToStrate)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutMinChunkZ = CenterChunkZ - ViewDistanceDown;
|
||||||
|
OutMaxChunkZ = CenterChunkZ + ViewDistanceUp;
|
||||||
|
if (bHasStrate)
|
||||||
|
{
|
||||||
|
OutMinChunkZ = StrateBottomChunkZ - StrateViewMarginChunks;
|
||||||
|
OutMaxChunkZ = StrateTopChunkZ + StrateViewMarginChunks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE void Build(const FIntVector& Center, int32 MinChunkZ, int32 MaxChunkZ,
|
||||||
|
const FParameters& Parameters, TArray<FVoxelTileKey>& OutTiles)
|
||||||
|
{
|
||||||
|
OutTiles.Reset();
|
||||||
|
const int32 Radius = FMath::Max(1, Parameters.ClipRadius);
|
||||||
|
const int32 MaxLevel = FMath::Clamp(Parameters.MaxClipLevel, 0, 8);
|
||||||
|
const int32 OuterRadius = OuterShellRadius(Parameters, Radius, MaxLevel);
|
||||||
|
int32 SheetLevel = MaxLevel;
|
||||||
|
int32 SheetRadius = OuterRadius;
|
||||||
|
OuterShell(Parameters, Radius, MaxLevel, SheetLevel, SheetRadius);
|
||||||
|
const bool bSheetRing = SheetLevel > MaxLevel;
|
||||||
|
const int32 MaxMCRingLevel = bSheetRing ? SheetLevel - 1 : MaxLevel;
|
||||||
|
|
||||||
|
for (int32 Level = 0; Level <= MaxMCRingLevel; ++Level)
|
||||||
|
{
|
||||||
|
const int32 Pow = 1 << Level;
|
||||||
|
const FIntVector CenterLevel = FloorDiv(Center, Pow);
|
||||||
|
const FIntVector CenterFiner = Level > 0
|
||||||
|
? FloorDiv(Center, Pow >> 1) : FIntVector::ZeroValue;
|
||||||
|
const int32 LevelRadius = (Level == MaxLevel && !bSheetRing)
|
||||||
|
? OuterRadius : Radius;
|
||||||
|
|
||||||
|
int32 DeltaZMin = -LevelRadius;
|
||||||
|
int32 DeltaZMax = LevelRadius;
|
||||||
|
if (LevelRadius > Radius && MinChunkZ != MIN_int32)
|
||||||
|
{
|
||||||
|
DeltaZMin = FMath::Max(DeltaZMin, FloorDiv(MinChunkZ, Pow) - CenterLevel.Z);
|
||||||
|
DeltaZMax = FMath::Min(DeltaZMax, FloorDiv(MaxChunkZ, Pow) - CenterLevel.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 DeltaZ = DeltaZMin; DeltaZ <= DeltaZMax; ++DeltaZ)
|
||||||
|
for (int32 DeltaY = -LevelRadius; DeltaY <= LevelRadius; ++DeltaY)
|
||||||
|
for (int32 DeltaX = -LevelRadius; DeltaX <= LevelRadius; ++DeltaX)
|
||||||
|
{
|
||||||
|
const FIntVector Tile = CenterLevel + FIntVector(DeltaX, DeltaY, DeltaZ);
|
||||||
|
const int32 TileMinZ = Tile.Z << Level;
|
||||||
|
const int32 TileMaxZ = ((Tile.Z + 1) << Level) - 1;
|
||||||
|
if (TileMaxZ < MinChunkZ || TileMinZ > MaxChunkZ)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Level > 0)
|
||||||
|
{
|
||||||
|
const bool bCovered =
|
||||||
|
(2 * Tile.X >= CenterFiner.X - Radius)
|
||||||
|
&& (2 * Tile.X + 1 <= CenterFiner.X + Radius)
|
||||||
|
&& (2 * Tile.Y >= CenterFiner.Y - Radius)
|
||||||
|
&& (2 * Tile.Y + 1 <= CenterFiner.Y + Radius)
|
||||||
|
&& (2 * Tile.Z >= CenterFiner.Z - Radius)
|
||||||
|
&& (2 * Tile.Z + 1 <= CenterFiner.Z + Radius);
|
||||||
|
if (bCovered)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutTiles.Emplace(Tile, Level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bSheetRing)
|
||||||
|
{
|
||||||
|
const int32 SheetPow = 1 << SheetLevel;
|
||||||
|
const FIntVector CenterSheet = FloorDiv(Center, SheetPow);
|
||||||
|
const FIntVector CenterMC = FloorDiv(Center, 1 << MaxMCRingLevel);
|
||||||
|
const int32 LevelDelta = SheetLevel - MaxMCRingLevel;
|
||||||
|
|
||||||
|
int32 DeltaZMin = -SheetRadius;
|
||||||
|
int32 DeltaZMax = SheetRadius;
|
||||||
|
if (MinChunkZ != MIN_int32)
|
||||||
|
{
|
||||||
|
DeltaZMin = FMath::Max(DeltaZMin,
|
||||||
|
FloorDiv(MinChunkZ, SheetPow) - CenterSheet.Z);
|
||||||
|
DeltaZMax = FMath::Min(DeltaZMax,
|
||||||
|
FloorDiv(MaxChunkZ, SheetPow) - CenterSheet.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 DeltaZ = DeltaZMin; DeltaZ <= DeltaZMax; ++DeltaZ)
|
||||||
|
for (int32 DeltaY = -SheetRadius; DeltaY <= SheetRadius; ++DeltaY)
|
||||||
|
for (int32 DeltaX = -SheetRadius; DeltaX <= SheetRadius; ++DeltaX)
|
||||||
|
{
|
||||||
|
const FIntVector Tile = CenterSheet + FIntVector(DeltaX, DeltaY, DeltaZ);
|
||||||
|
const int32 TileMinZ = Tile.Z << SheetLevel;
|
||||||
|
const int32 TileMaxZ = ((Tile.Z + 1) << SheetLevel) - 1;
|
||||||
|
if (TileMaxZ < MinChunkZ || TileMinZ > MaxChunkZ)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool bCovered =
|
||||||
|
((Tile.X << LevelDelta) >= CenterMC.X - Radius)
|
||||||
|
&& ((((Tile.X + 1) << LevelDelta) - 1) <= CenterMC.X + Radius)
|
||||||
|
&& ((Tile.Y << LevelDelta) >= CenterMC.Y - Radius)
|
||||||
|
&& ((((Tile.Y + 1) << LevelDelta) - 1) <= CenterMC.Y + Radius)
|
||||||
|
&& ((Tile.Z << LevelDelta) >= CenterMC.Z - Radius)
|
||||||
|
&& ((((Tile.Z + 1) << LevelDelta) - 1) <= CenterMC.Z + Radius);
|
||||||
|
if (!bCovered)
|
||||||
|
{
|
||||||
|
OutTiles.Emplace(Tile, SheetLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "VoxelCaveMorphology.h"
|
#include "VoxelCaveMorphology.h"
|
||||||
#include "VoxelPassageGeometry.h"
|
#include "VoxelPassageGeometry.h"
|
||||||
#include "VoxelTilePostReach.h"
|
#include "VoxelTilePostReach.h"
|
||||||
|
#include "VoxelClipmapDesiredTiles.h"
|
||||||
// IWYU (FPSemantics = Precise ⇒ plus de PCH partagé) : GetPlayerPosition déréférence le pawn, donc
|
// IWYU (FPSemantics = Precise ⇒ plus de PCH partagé) : GetPlayerPosition déréférence le pawn, donc
|
||||||
// APawn doit être COMPLET — `Casts.h` n'en donne qu'une déclaration avant. APlayerController était
|
// APawn doit être COMPLET — `Casts.h` n'en donne qu'une déclaration avant. APlayerController était
|
||||||
// complet par transitivité seulement : on l'inclut explicitement, c'est exactement la fragilité
|
// complet par transitivité seulement : on l'inclut explicitement, c'est exactement la fragilité
|
||||||
@@ -53,6 +54,8 @@
|
|||||||
#include "Serialization/JsonWriter.h"
|
#include "Serialization/JsonWriter.h"
|
||||||
#include "ProfilingDebugging/CpuProfilerTrace.h" // Unreal Insights scopes (Perf 0)
|
#include "ProfilingDebugging/CpuProfilerTrace.h" // Unreal Insights scopes (Perf 0)
|
||||||
|
|
||||||
|
static int32 VF_MaxMarchingCubesLevel(const UVoxelSettings* Settings);
|
||||||
|
|
||||||
#if WITH_EDITOR
|
#if WITH_EDITOR
|
||||||
#include "VoxelStrateComposer.h"
|
#include "VoxelStrateComposer.h"
|
||||||
#include "VoxelStrateMeasure.h"
|
#include "VoxelStrateMeasure.h"
|
||||||
@@ -3580,7 +3583,7 @@ void AVoxelWorld::Tick(float DeltaTime)
|
|||||||
Min.X, Min.Y, Min.Z, Max.X, Max.Y, Max.Z,
|
Min.X, Min.Y, Min.Z, Max.X, Max.Y, Max.Z,
|
||||||
*FString::SanitizeFloat(TileExtentMetres),
|
*FString::SanitizeFloat(TileExtentMetres),
|
||||||
*FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ),
|
*FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ),
|
||||||
Settings && Level > Settings->MaxClipLevel ? 1 : 0));
|
Settings && Level > VF_MaxMarchingCubesLevel(Settings) ? 1 : 0));
|
||||||
}
|
}
|
||||||
VoxelForgeStartupTrace::Finish(TEXT("desired_set_satisfied_and_queue_drained"));
|
VoxelForgeStartupTrace::Finish(TEXT("desired_set_satisfied_and_queue_drained"));
|
||||||
}
|
}
|
||||||
@@ -5031,30 +5034,28 @@ static FORCEINLINE FIntVector VF_FloorDiv(const FIntVector& V, int32 D)
|
|||||||
return FIntVector(VF_FloorDiv(V.X, D), VF_FloorDiv(V.Y, D), VF_FloorDiv(V.Z, D));
|
return FIntVector(VF_FloorDiv(V.X, D), VF_FloorDiv(V.Y, D), VF_FloorDiv(V.Z, D));
|
||||||
}
|
}
|
||||||
|
|
||||||
// RENDER DISTANCE — rayon (en tuiles niveau-MaxLevel) de la coquille EXTERNE : ClipRadius, élargi
|
// F18 — the outer shell is either the MC render-distance level or the larger sheet ring. When
|
||||||
// si `RenderDistanceChunks` demande une portée horizontale au-delà du naturel R·2^MaxLevel. Partagé
|
// the sheet span skips levels, VF_MaxMarchingCubesLevel fills them with MC bridge shells.
|
||||||
// par BuildDesiredTiles (le desired set) et IsTileInClipRange (le même horizon pour le cull).
|
// Shared by desired selection and range culling so both use the same outer horizon.
|
||||||
static FORCEINLINE int32 VF_OuterShellRadius(const UVoxelSettings* Settings, int32 R, int32 MaxLevel)
|
|
||||||
{
|
|
||||||
const int32 Dist = Settings ? Settings->RenderDistanceChunks : 0;
|
|
||||||
if (Dist <= 0) return R;
|
|
||||||
return FMath::Max(R, (Dist + (1 << MaxLevel) - 1) >> MaxLevel); // ceil(Dist / 2^MaxLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// F18 — la coquille LA PLUS EXTERNE : niveau + rayon. Sans anneau feuille = (MaxLevel, rayon
|
|
||||||
// render-distance). Avec (`bFarSheetRing` et distance > portée naturelle) = l'anneau FEUILLE :
|
|
||||||
// niveau MaxLevel + FarSheetSpanLevels (une feuille couvre 2^span empreintes MC par axe), rayon
|
|
||||||
// re-dérivé à ce niveau. Partagé par BuildDesiredTiles et IsTileInClipRange (même horizon).
|
|
||||||
static FORCEINLINE void VF_OuterShell(const UVoxelSettings* Settings, int32 R, int32 MaxLevel,
|
static FORCEINLINE void VF_OuterShell(const UVoxelSettings* Settings, int32 R, int32 MaxLevel,
|
||||||
int32& OutLevel, int32& OutRadius)
|
int32& OutLevel, int32& OutRadius)
|
||||||
{
|
{
|
||||||
OutLevel = MaxLevel;
|
VoxelClipmapDesiredTiles::FParameters Parameters;
|
||||||
OutRadius = VF_OuterShellRadius(Settings, R, MaxLevel);
|
Parameters.RenderDistanceChunks = Settings ? Settings->RenderDistanceChunks : 0;
|
||||||
if (Settings && Settings->bFarSheetRing && OutRadius > R)
|
Parameters.bFarSheetRing = Settings && Settings->bFarSheetRing;
|
||||||
{
|
Parameters.FarSheetSpanLevels = Settings ? Settings->FarSheetSpanLevels : 2;
|
||||||
OutLevel = MaxLevel + FMath::Clamp(Settings->FarSheetSpanLevels, 1, 4);
|
VoxelClipmapDesiredTiles::OuterShell(Parameters, R, MaxLevel, OutLevel, OutRadius);
|
||||||
OutRadius = FMath::Max(1, (Settings->RenderDistanceChunks + (1 << OutLevel) - 1) >> OutLevel);
|
}
|
||||||
}
|
|
||||||
|
// When an expanded sheet ring skips LOD levels, keep an MC bridge at every intervening level.
|
||||||
|
static int32 VF_MaxMarchingCubesLevel(const UVoxelSettings* Settings)
|
||||||
|
{
|
||||||
|
const int32 Radius = Settings ? FMath::Max(1, Settings->ClipRadius) : 3;
|
||||||
|
const int32 MaxLevel = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
||||||
|
int32 OuterLevel = MaxLevel, OuterRadius = Radius;
|
||||||
|
VF_OuterShell(Settings, Radius, MaxLevel, OuterLevel, OuterRadius);
|
||||||
|
(void)OuterRadius;
|
||||||
|
return OuterLevel > MaxLevel ? OuterLevel - 1 : MaxLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& PlayerPosition,
|
void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& PlayerPosition,
|
||||||
@@ -5072,128 +5073,37 @@ void AVoxelWorld::BuildDesiredTiles(const FIntVector& Center, const FVector& Pla
|
|||||||
const int32 R = Settings ? FMath::Max(1, Settings->ClipRadius) : 3;
|
const int32 R = Settings ? FMath::Max(1, Settings->ClipRadius) : 3;
|
||||||
const int32 MaxLevel = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
const int32 MaxLevel = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
||||||
|
|
||||||
// RENDER DISTANCE (`RenderDistanceChunks`) : la coquille EXTERNE continue au-delà du rayon
|
// Render-distance tiles expand horizontally. The sheet ring retains its configured span;
|
||||||
// naturel jusqu'à couvrir la distance demandée — en tuiles MC niveau-MaxClipLevel, ou (F18,
|
// intermediate levels are emitted as marching-cubes bridge shells below it.
|
||||||
// `bFarSheetRing`) en tuiles FEUILLE plus grandes (niveau MaxLevel+span, deux heightfields
|
// IsTileInClipRange shares the outer-shell calculation so culling sees this same horizon.
|
||||||
// sol/cap au lieu de marching cubes — cf. GenerateSheetMesh). IsTileInClipRange partage
|
int32 StrateTopZ = 0, StrateBottomZ = 0;
|
||||||
// VF_OuterShell pour que le cull voie le même horizon.
|
bool bHasStrate = false;
|
||||||
const int32 ROuter = VF_OuterShellRadius(Settings, R, MaxLevel);
|
if (StrateManager)
|
||||||
int32 SheetLevel = MaxLevel, RSheet = ROuter;
|
{
|
||||||
VF_OuterShell(Settings, R, MaxLevel, SheetLevel, RSheet);
|
bHasStrate = StrateManager->GetStrateChunkZBounds(Center.Z, StrateTopZ, StrateBottomZ);
|
||||||
const bool bSheetRing = SheetLevel > MaxLevel;
|
}
|
||||||
|
|
||||||
// Strate-aware VERTICAL band (in level-0 chunk-Z). Without this the clipmap generates the
|
// Keep the clamp enabled, but cover the player's complete current strate plus its margin.
|
||||||
// occluded volume above/below (sealed strates are light-tight, §8.7) AND the full underground
|
// Only when no strate bounds exist (the inter-strate gap) does the small player window apply.
|
||||||
// depth — a huge column of invisible solid rock = the gen lag. So clamp the vertical reach to
|
|
||||||
// the player's strate ± margin (open-ceiling strates extend UP to the sky-cap). The clipmap
|
|
||||||
// stays full-reach HORIZONTALLY (the horizon) but limited vertically. ZLo/ZHi span ⇒ no clamp.
|
|
||||||
int32 ZLo = MIN_int32, ZHi = MAX_int32;
|
int32 ZLo = MIN_int32, ZHi = MAX_int32;
|
||||||
if (Settings && Settings->bClampViewToStrate && StrateManager)
|
VoxelClipmapDesiredTiles::ResolveVerticalBounds(
|
||||||
|
Center.Z,
|
||||||
|
Settings ? Settings->ViewDistanceUp : 5,
|
||||||
|
Settings ? Settings->ViewDistanceDown : 5,
|
||||||
|
Settings ? Settings->StrateViewMarginChunks : 3,
|
||||||
|
Settings && Settings->bClampViewToStrate,
|
||||||
|
bHasStrate, StrateTopZ, StrateBottomZ, ZLo, ZHi);
|
||||||
|
|
||||||
|
VoxelClipmapDesiredTiles::FParameters TileParameters;
|
||||||
|
TileParameters.ClipRadius = R;
|
||||||
|
TileParameters.MaxClipLevel = MaxLevel;
|
||||||
|
TileParameters.RenderDistanceChunks = Settings ? Settings->RenderDistanceChunks : 0;
|
||||||
|
TileParameters.bFarSheetRing = Settings && Settings->bFarSheetRing;
|
||||||
|
TileParameters.FarSheetSpanLevels = Settings ? Settings->FarSheetSpanLevels : 2;
|
||||||
|
VoxelClipmapDesiredTiles::Build(Center, ZLo, ZHi, TileParameters, DesiredSorted);
|
||||||
|
for (const FVoxelTileKey& Key : DesiredSorted)
|
||||||
{
|
{
|
||||||
const int32 Margin = Settings->StrateViewMarginChunks;
|
DesiredStamped.FindOrAdd(Key) = DesiredStamp;
|
||||||
ZLo = Center.Z - Settings->ViewDistanceDown;
|
|
||||||
ZHi = Center.Z + Settings->ViewDistanceUp;
|
|
||||||
int32 StrTopZ = 0, StrBotZ = 0;
|
|
||||||
if (StrateManager->GetStrateChunkZBounds(Center.Z, StrTopZ, StrBotZ))
|
|
||||||
{
|
|
||||||
const ECaveGeneratorType GenType = StrateManager->GetGeneratorTypeForChunk(Center);
|
|
||||||
const bool bOpen = (GenType == ECaveGeneratorType::SurfaceWorld
|
|
||||||
|| GenType == ECaveGeneratorType::FloatingIslands);
|
|
||||||
ZLo = FMath::Max(ZLo, StrBotZ - Margin);
|
|
||||||
ZHi = bOpen ? (StrTopZ + Margin) : FMath::Min(ZHi, StrTopZ + Margin);
|
|
||||||
}
|
|
||||||
// else: in the bedrock gap → keep the player window (see both sides while descending).
|
|
||||||
}
|
|
||||||
|
|
||||||
// Concentric shells: level 0 near the player, each coarser level a 2× larger shell beyond.
|
|
||||||
// A level-L tile is dropped if it's fully covered by the finer (L-1) level's box — that's
|
|
||||||
// the inner hole, so the shells tile space without big gaps.
|
|
||||||
for (int32 L = 0; L <= MaxLevel; ++L)
|
|
||||||
{
|
|
||||||
const int32 Pow = 1 << L; // level-L tile = 2^L chunks
|
|
||||||
const FIntVector CL = VF_FloorDiv(Center, Pow); // player's level-L tile coord
|
|
||||||
const FIntVector CF = (L > 0) ? VF_FloorDiv(Center, Pow >> 1) : FIntVector::ZeroValue;
|
|
||||||
|
|
||||||
// Rayon de CE niveau : R partout, sauf la coquille externe (render distance) — qui, si
|
|
||||||
// l'anneau FEUILLE est actif (F18), est émise à part plus bas (le niveau MaxLevel reste
|
|
||||||
// alors à R). Le test "covered by finer" garde R (le niveau plus fin n'est jamais étendu).
|
|
||||||
const int32 RL = (L == MaxLevel && !bSheetRing) ? ROuter : R;
|
|
||||||
|
|
||||||
// Anneau étendu : le balayage naïf serait (2·RL+1)³ — on restreint dz à la fenêtre de la
|
|
||||||
// clamp verticale AVANT la boucle (mêmes tuiles retenues : le `continue` Z ci-dessous
|
|
||||||
// rejetterait tout le reste). Sentinelles MIN/MAX (pas de clamp) ⇒ balayage plein.
|
|
||||||
int32 DzMin = -RL, DzMax = RL;
|
|
||||||
if (RL > R && ZLo != MIN_int32)
|
|
||||||
{
|
|
||||||
DzMin = FMath::Max(DzMin, VF_FloorDiv(ZLo, Pow) - CL.Z);
|
|
||||||
DzMax = FMath::Min(DzMax, VF_FloorDiv(ZHi, Pow) - CL.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32 dz = DzMin; dz <= DzMax; ++dz)
|
|
||||||
for (int32 dy = -RL; dy <= RL; ++dy)
|
|
||||||
for (int32 dx = -RL; dx <= RL; ++dx)
|
|
||||||
{
|
|
||||||
const FIntVector T = CL + FIntVector(dx, dy, dz);
|
|
||||||
|
|
||||||
// Strate-aware vertical clamp: drop tiles whose level-0 chunk-Z footprint doesn't
|
|
||||||
// overlap [ZLo, ZHi] (the occluded strate above/below / deep underground).
|
|
||||||
const int32 TZLo = T.Z << L;
|
|
||||||
const int32 TZHi = ((T.Z + 1) << L) - 1;
|
|
||||||
if (TZHi < ZLo || TZLo > ZHi) continue;
|
|
||||||
|
|
||||||
if (L > 0)
|
|
||||||
{
|
|
||||||
// Covered by the finer level iff the level-(L-1) tiles 2T..2T+1 (per axis)
|
|
||||||
// all lie inside the finer box [CF-R, CF+R].
|
|
||||||
const bool bCovered =
|
|
||||||
(2 * T.X >= CF.X - R) && (2 * T.X + 1 <= CF.X + R) &&
|
|
||||||
(2 * T.Y >= CF.Y - R) && (2 * T.Y + 1 <= CF.Y + R) &&
|
|
||||||
(2 * T.Z >= CF.Z - R) && (2 * T.Z + 1 <= CF.Z + R);
|
|
||||||
if (bCovered) continue;
|
|
||||||
}
|
|
||||||
const FVoxelTileKey Key(T, L);
|
|
||||||
DesiredSorted.Add(Key);
|
|
||||||
DesiredStamped.FindOrAdd(Key) = DesiredStamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// F18 — ANNEAU FEUILLE : la portée render-distance est couverte par des tuiles feuille
|
|
||||||
// (niveau SheetLevel > MaxLevel, LoadTile route niveau > MaxClipLevel vers GenerateSheetMesh).
|
|
||||||
// Trou intérieur = la boîte MC niveau-MaxLevel (rayon R), pas le niveau SheetLevel−1.
|
|
||||||
if (bSheetRing)
|
|
||||||
{
|
|
||||||
const int32 SPow = 1 << SheetLevel;
|
|
||||||
const FIntVector CS = VF_FloorDiv(Center, SPow);
|
|
||||||
const FIntVector CM = VF_FloorDiv(Center, 1 << MaxLevel);
|
|
||||||
const int32 K = SheetLevel - MaxLevel; // 1 feuille = 2^K tuiles MC par axe
|
|
||||||
|
|
||||||
int32 DzMin = -RSheet, DzMax = RSheet;
|
|
||||||
if (ZLo != MIN_int32)
|
|
||||||
{
|
|
||||||
DzMin = FMath::Max(DzMin, VF_FloorDiv(ZLo, SPow) - CS.Z);
|
|
||||||
DzMax = FMath::Min(DzMax, VF_FloorDiv(ZHi, SPow) - CS.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32 dz = DzMin; dz <= DzMax; ++dz)
|
|
||||||
for (int32 dy = -RSheet; dy <= RSheet; ++dy)
|
|
||||||
for (int32 dx = -RSheet; dx <= RSheet; ++dx)
|
|
||||||
{
|
|
||||||
const FIntVector T = CS + FIntVector(dx, dy, dz);
|
|
||||||
const int32 TZLo = T.Z << SheetLevel;
|
|
||||||
const int32 TZHi = ((T.Z + 1) << SheetLevel) - 1;
|
|
||||||
if (TZHi < ZLo || TZLo > ZHi) continue;
|
|
||||||
|
|
||||||
// Couverte par la boîte MC (empreinte entièrement dans [CM−R, CM+R] au niveau MaxLevel).
|
|
||||||
const bool bCovered =
|
|
||||||
((T.X << K) >= CM.X - R) && ((((T.X + 1) << K) - 1) <= CM.X + R) &&
|
|
||||||
((T.Y << K) >= CM.Y - R) && ((((T.Y + 1) << K) - 1) <= CM.Y + R) &&
|
|
||||||
((T.Z << K) >= CM.Z - R) && ((((T.Z + 1) << K) - 1) <= CM.Z + R);
|
|
||||||
if (bCovered) continue;
|
|
||||||
|
|
||||||
const FVoxelTileKey Key(T, SheetLevel);
|
|
||||||
DesiredSorted.Add(Key);
|
|
||||||
DesiredStamped.FindOrAdd(Key) = DesiredStamp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Streaming anchors (AI / remote players, §9.3): fold each one's small level-0 box into the SAME
|
// Streaming anchors (AI / remote players, §9.3): fold each one's small level-0 box into the SAME
|
||||||
@@ -5604,10 +5514,10 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
|
|||||||
"\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s],\"sheet\":%d"),
|
"\"tile_extent_m\":%s,\"coverage_extent_m\":[%s,%s,%s],\"sheet\":%d"),
|
||||||
Summary.Level, Summary.Count,
|
Summary.Level, Summary.Count,
|
||||||
Summary.Min.X, Summary.Min.Y, Summary.Min.Z,
|
Summary.Min.X, Summary.Min.Y, Summary.Min.Z,
|
||||||
Summary.Max.X, Summary.Max.Y, Summary.Max.Z,
|
Summary.Max.X, Summary.Max.Y, Summary.Max.Z,
|
||||||
*FString::SanitizeFloat(TileExtentMetres),
|
*FString::SanitizeFloat(TileExtentMetres),
|
||||||
*FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ),
|
*FString::SanitizeFloat(SpanX), *FString::SanitizeFloat(SpanY), *FString::SanitizeFloat(SpanZ),
|
||||||
Settings && Summary.Level > Settings->MaxClipLevel ? 1 : 0));
|
Settings && Summary.Level > VF_MaxMarchingCubesLevel(Settings) ? 1 : 0));
|
||||||
}
|
}
|
||||||
bStartupTraceDesiredRecorded = true;
|
bStartupTraceDesiredRecorded = true;
|
||||||
}
|
}
|
||||||
@@ -5628,7 +5538,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
|
|||||||
// dès que les feuilles sont actives, même si la coupe de contenu MC est désactivée.
|
// dès que les feuilles sont actives, même si la coupe de contenu MC est désactivée.
|
||||||
const bool bSheetsWantBand = Settings && Settings->bFarSheetRing
|
const bool bSheetsWantBand = Settings && Settings->bFarSheetRing
|
||||||
&& Settings->RenderDistanceChunks > 0;
|
&& Settings->RenderDistanceChunks > 0;
|
||||||
const int32 TopMC = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
const int32 TopMC = VF_MaxMarchingCubesLevel(Settings);
|
||||||
int32 NewLo = MIN_int32, NewHi = MAX_int32;
|
int32 NewLo = MIN_int32, NewHi = MAX_int32;
|
||||||
if ((CutMin <= 8 || bSheetsWantBand) && StrateManager)
|
if ((CutMin <= 8 || bSheetsWantBand) && StrateManager)
|
||||||
{
|
{
|
||||||
@@ -5649,7 +5559,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
|
|||||||
NewLo, NewHi, MeshBandChunkLo, MeshBandChunkHi, CutMin, CenterChunk.Z);
|
NewLo, NewHi, MeshBandChunkLo, MeshBandChunkHi, CutMin, CenterChunk.Z);
|
||||||
for (const FVoxelTileKey& T : LoadedTiles)
|
for (const FVoxelTileKey& T : LoadedTiles)
|
||||||
{
|
{
|
||||||
// Feuilles (niveau > MaxClipLevel) : toujours dépendantes de la bande.
|
// Sheets (above the last MC bridge level) always depend on the strate band.
|
||||||
if (T.Level < CutMin && T.Level <= TopMC) continue;
|
if (T.Level < CutMin && T.Level <= TopMC) continue;
|
||||||
const int32 CLo = T.Coord.Z << T.Level;
|
const int32 CLo = T.Coord.Z << T.Level;
|
||||||
const int32 CHi = ((T.Coord.Z + 1) << T.Level) - 1;
|
const int32 CHi = ((T.Coord.Z + 1) << T.Level) - 1;
|
||||||
@@ -5667,17 +5577,13 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// F18 — TROU XY de l'anneau feuille (voir VoxelWorld.h) : boîte MC niveau-MaxClipLevel
|
// The sheet XY hole follows the outermost MC bridge level and shrinks by one tile, leaving
|
||||||
// autour du joueur, rétrécie d'UNE tuile — le raccord feuille↔anneau MC garde une tuile
|
// an overlap at the mesh transition. Requeue sheets overlapping either the old or new hole
|
||||||
// MC pleine de recouvrement (même pas d'échantillonnage des deux côtés → discret), et en
|
// when the player crosses a bridge-level tile.
|
||||||
// avançant, les tuiles MC de la zone nouvellement découpée étaient déjà desired au
|
|
||||||
// crossing précédent (chargées avant que le trou ne les découvre). Changement (crossing
|
|
||||||
// de tuile MaxClipLevel, ~tous les 2^L chunks) ⇒ re-queue des feuilles chevauchant
|
|
||||||
// l'ancien OU le nouveau trou.
|
|
||||||
{
|
{
|
||||||
int32 NewMinX = MAX_int32, NewMinY = MAX_int32;
|
int32 NewMinX = MAX_int32, NewMinY = MAX_int32;
|
||||||
int32 NewMaxX = MIN_int32, NewMaxY = MIN_int32;
|
int32 NewMaxX = MIN_int32, NewMaxY = MIN_int32;
|
||||||
const int32 TopMCLvl = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
const int32 TopMCLvl = VF_MaxMarchingCubesLevel(Settings);
|
||||||
if (Settings && Settings->bFarSheetRing && Settings->RenderDistanceChunks > 0)
|
if (Settings && Settings->bFarSheetRing && Settings->RenderDistanceChunks > 0)
|
||||||
{
|
{
|
||||||
const int32 RClip = FMath::Max(1, Settings->ClipRadius);
|
const int32 RClip = FMath::Max(1, Settings->ClipRadius);
|
||||||
@@ -5926,11 +5832,10 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, bool bHighPriority)
|
|||||||
const int32 FullRes = Settings ? FMath::Max(1, Settings->FullResClipLevels) : 2;
|
const int32 FullRes = Settings ? FMath::Max(1, Settings->FullResClipLevels) : 2;
|
||||||
const int32 Extent = CHUNK_SIZE << Tile.Level;
|
const int32 Extent = CHUNK_SIZE << Tile.Level;
|
||||||
|
|
||||||
// F18 — tuile FEUILLE : BuildDesiredTiles n'émet des clés au-delà de MaxClipLevel que pour
|
// F18 — sheet-ring keys follow the last MC bridge level and mesh as two heightfields
|
||||||
// l'anneau feuille (render distance) — elles se maillent en deux heightfields (GenerateSheetMesh),
|
// (GenerateSheetMesh). Their sampling step matches that MC level; cells grow with sheet extent
|
||||||
// pas en marching cubes. Densité d'échantillonnage = celle de l'anneau MC niveau-MaxClipLevel
|
// up to 128 per axis, after which the step increases.
|
||||||
// (le nombre de cellules grandit avec la feuille, plafonné à 128/axe — au-delà le pas grossit).
|
const int32 TopMC = VF_MaxMarchingCubesLevel(Settings);
|
||||||
const int32 TopMC = Settings ? FMath::Clamp(Settings->MaxClipLevel, 0, 8) : 4;
|
|
||||||
const bool bSheetTile = Tile.Level > TopMC;
|
const bool bSheetTile = Tile.Level > TopMC;
|
||||||
|
|
||||||
int32 Cells = (Tile.Level < FullRes)
|
int32 Cells = (Tile.Level < FullRes)
|
||||||
|
|||||||
@@ -43,9 +43,17 @@ $BuildRecord = [ordered]@{ requested = [bool]$Build; status = 'not_requested' }
|
|||||||
$AssetEvidence = @()
|
$AssetEvidence = @()
|
||||||
$CommandletMetrics = [ordered]@{}
|
$CommandletMetrics = [ordered]@{}
|
||||||
$GameMetrics = [ordered]@{}
|
$GameMetrics = [ordered]@{}
|
||||||
$SurfaceFallMetrics = [ordered]@{ requested = $Scenario -in @('tests', 'surface-fall'); status = 'not_run' }
|
$SurfaceFallMetrics = [ordered]@{
|
||||||
|
requested = $Scenario -eq 'surface-fall' -or
|
||||||
|
($Scenario -eq 'tests' -and [string]::IsNullOrWhiteSpace($TestFilter))
|
||||||
|
status = 'not_run'
|
||||||
|
}
|
||||||
$StrateCrossingMetrics = [ordered]@{ requested = $Scenario -eq 'crossing'; status = 'not_run' }
|
$StrateCrossingMetrics = [ordered]@{ requested = $Scenario -eq 'crossing'; status = 'not_run' }
|
||||||
$CollisionGateStressMetrics = [ordered]@{ requested = $Scenario -in @('tests', 'gate-stress'); status = 'not_run' }
|
$CollisionGateStressMetrics = [ordered]@{
|
||||||
|
requested = $Scenario -eq 'gate-stress' -or
|
||||||
|
($Scenario -eq 'tests' -and [string]::IsNullOrWhiteSpace($TestFilter))
|
||||||
|
status = 'not_run'
|
||||||
|
}
|
||||||
$TestMetrics = @()
|
$TestMetrics = @()
|
||||||
$ParityEvidence = [ordered]@{ requested = $Scenario -eq 'parity'; status = 'not_run' }
|
$ParityEvidence = [ordered]@{ requested = $Scenario -eq 'parity'; status = 'not_run' }
|
||||||
$DllEvidence = [ordered]@{
|
$DllEvidence = [ordered]@{
|
||||||
@@ -1038,9 +1046,9 @@ try {
|
|||||||
Add-Failure "automation tests failed: $failedNames"
|
Add-Failure "automation tests failed: $failedNames"
|
||||||
}
|
}
|
||||||
|
|
||||||
# The runtime collision-gate repro is part of the tests scenario as an integration
|
if ([string]::IsNullOrWhiteSpace($TestFilter)) {
|
||||||
# test alongside the 44 pure automation tests. It uses the same isolated host/assets
|
# The unfiltered suite includes its collision integration repros. A filtered run is
|
||||||
# and gets its own launch ledger entry and log.
|
# bounded to its named automation tests and does not launch unrelated scenarios.
|
||||||
$surfaceBaseCvars = [ordered]@{
|
$surfaceBaseCvars = [ordered]@{
|
||||||
'voxel.TestSurfaceFall' = 1
|
'voxel.TestSurfaceFall' = 1
|
||||||
'voxel.TestSurfaceFallSpawnHeightVoxels' = 20
|
'voxel.TestSurfaceFallSpawnHeightVoxels' = 20
|
||||||
@@ -1071,6 +1079,7 @@ try {
|
|||||||
$stressReason = [string](Get-JsonValue $CollisionGateStressMetrics 'reason' '')
|
$stressReason = [string](Get-JsonValue $CollisionGateStressMetrics 'reason' '')
|
||||||
Add-Failure "collision-gate stress repro did not pass: $($CollisionGateStressMetrics.status) $stressReason"
|
Add-Failure "collision-gate stress repro did not pass: $($CollisionGateStressMetrics.status) $stressReason"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'parity' {
|
'parity' {
|
||||||
$parityArgs = New-CommonArguments 'commandlet' (Join-Path $RunRoot 'Logs\parity-commandlet.log') (Merge-Cvars $baseCvars)
|
$parityArgs = New-CommonArguments 'commandlet' (Join-Path $RunRoot 'Logs\parity-commandlet.log') (Merge-Cvars $baseCvars)
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user