refactor(dead-code): remove functions, members and types with no caller
Each symbol below had zero references in Source/ (tests included), Tools/, Config/ and the build files after comment/string stripping. Functions: EvaluateTunnelCoreSDF, EvaluateSDF (uncached wrapper), IsTunnelSupportFloorWorldPoint, BuildTunnelSupportFloorColumn, IsTunnelSupportFloorColumnZ, GetTunnelSupportFloorColumnBand, VF_TunnelFloorAtSegment, VF_ProjectSweptTunnelFloor, FVoxelWormField EvaluateExact, ApplyPassageLandingAirMC, ApplyPassageTunnelAirMC, GetGenerationParamsFingerprint, FVoxelStrateCorpus::LoadFromSettings, GetSkippedDefinitions, VF_RollStrateParams, VF_ArePlayerFitConnectedWithSampler, VF_GetVoxelSeasonSelectionReasonName, UVoxelSeasonAsset::GetManifestContentHash, FVoxelStackSampler::IsRunning, CompareSkippedPostValue, MakeSurfaceColumnSource, WriteObjTile, ExploreEffectName, ExploreTileClassName, and the VoxelTypes.h chunk-local helpers (WorldToLocalCoord, ChunkToWorldPos, LocalToIndex, IndexToLocal, IsValidLocalCoord, GetFaceDirection, GetFaceNormal, CHUNK_SIZE_SQUARED, CHUNK_VOLUME). Members/types: write-only floor flags (FVoxelOpSample:: bProtectedStructuralFloor, StructuralFloorMinimumDensity, bTunnelCoreSupportFloor; bSupportFloor on the tunnel evaluations; FTunnelFloorSegmentProfile::NumSteps), UVoxelStrateManager::BlendChunks, unused FSummary counters in the stack sampler, two unused FVoxelSeasonCompositionSettings aliases, and a few unused locals/constants. No UPROPERTY, UFUNCTION, reflected type or enum was touched. Behaviour is unchanged: removed code was unreachable or only written, never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URDGLsu7c4nunqNFPJEFPU
This commit is contained in:
26 files changed
+9
-1113
No files matched your search
@@ -81,7 +81,6 @@ namespace
|
||||
struct FVFTunnelShapeEvaluation
|
||||
{
|
||||
float SDF = FLT_MAX;
|
||||
bool bSupportFloor = false;
|
||||
bool bHasSweptFloor = false;
|
||||
float SweptFloorZ = -FLT_MAX;
|
||||
float SweptFloorRadius = 0.0f;
|
||||
@@ -548,7 +547,6 @@ namespace
|
||||
Profile.NaturalStartFloorZ = FloorA;
|
||||
Profile.NaturalEndFloorZ = FloorB;
|
||||
Profile.bLedgeTransition = false;
|
||||
Profile.NumSteps = 0;
|
||||
|
||||
if (bHasLedgeLevels)
|
||||
{
|
||||
@@ -934,27 +932,6 @@ namespace
|
||||
return FloorZ;
|
||||
}
|
||||
|
||||
FORCEINLINE float VF_TunnelFloorAtSegment(
|
||||
const FVector& A, float RadiusA,
|
||||
const FVector& B, float RadiusB,
|
||||
float T, int32 SegmentIndex, int32 NumSegments,
|
||||
const FVector& Position,
|
||||
const FCachedTunnel& Tunnel,
|
||||
const void* CacheIdentity, int32 TunnelIndex,
|
||||
bool bEvaluateRelief,
|
||||
const FVFFloorReliefColumnKey& Column,
|
||||
const FTunnelFloorSegmentProfile* FloorProfile,
|
||||
const FVFRoomFloorOwnership* RoomFloorOwnership)
|
||||
{
|
||||
const FVFTunnelFloorTerms Terms = VF_TunnelFloorTerms(
|
||||
A, RadiusA, B, RadiusB,
|
||||
T, SegmentIndex, NumSegments, Tunnel, FloorProfile,
|
||||
RoomFloorOwnership);
|
||||
return VF_TunnelFloorFromTerms(
|
||||
Position, Tunnel, Terms,
|
||||
CacheIdentity, TunnelIndex, bEvaluateRelief, Column);
|
||||
}
|
||||
|
||||
FORCEINLINE bool VF_ProjectTunnelSegmentXY(
|
||||
const FVector& Position, const FVector& A, const FVector& B,
|
||||
float& OutT, float& OutDistanceSquared)
|
||||
@@ -1229,76 +1206,6 @@ namespace
|
||||
RoomFloorOwnership);
|
||||
}
|
||||
|
||||
static bool VF_ProjectSweptTunnelFloor(
|
||||
const FVector& Position,
|
||||
const FCachedTunnel& Tunnel,
|
||||
bool bWorldChain,
|
||||
float& OutFloorZ,
|
||||
float& OutSupportRadius,
|
||||
const void* CacheIdentity, int32 TunnelIndex,
|
||||
const FVFRoomFloorOwnership* RoomFloorOwnership = nullptr)
|
||||
{
|
||||
const FVFFloorReliefColumnKey ReliefColumn =
|
||||
VF_MakeFloorReliefColumnKey(
|
||||
static_cast<float>(Position.X), static_cast<float>(Position.Y));
|
||||
const TArray<FVector>& ControlPoints = bWorldChain
|
||||
? Tunnel.WorldControlPoints : Tunnel.ControlPoints;
|
||||
const TArray<float>& ControlRadii = bWorldChain
|
||||
? Tunnel.WorldControlRadii : Tunnel.ControlRadii;
|
||||
if (ControlPoints.Num() < 2
|
||||
|| ControlRadii.Num() != ControlPoints.Num())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32 ControlPointCount = ControlPoints.Num();
|
||||
const int32 NumSegments = ControlPointCount - 1;
|
||||
const FVector* ControlPointData = ControlPoints.GetData();
|
||||
const float* ControlRadiusData = ControlRadii.GetData();
|
||||
const TArray<FTunnelFloorSegmentProfile>* FloorProfiles = bWorldChain
|
||||
? &Tunnel.WorldFloorProfiles : &Tunnel.FloorProfiles;
|
||||
const FTunnelFloorSegmentProfile* FloorProfileData =
|
||||
FloorProfiles->Num() == NumSegments ? FloorProfiles->GetData() : nullptr;
|
||||
float BestDistanceSquared = FLT_MAX;
|
||||
bool bFound = false;
|
||||
for (int32 SegmentIndex = 0;
|
||||
SegmentIndex < NumSegments;
|
||||
++SegmentIndex)
|
||||
{
|
||||
float T = 0.0f;
|
||||
float DistanceSquared = FLT_MAX;
|
||||
if (!VF_ProjectTunnelSegmentXY(
|
||||
Position,
|
||||
ControlPointData[SegmentIndex], ControlPointData[SegmentIndex + 1],
|
||||
T, DistanceSquared)
|
||||
|| DistanceSquared >= BestDistanceSquared)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const float RadiusA = ControlRadiusData[SegmentIndex];
|
||||
const float RadiusB = ControlRadiusData[SegmentIndex + 1];
|
||||
OutFloorZ = VF_TunnelFloorAtSegment(
|
||||
ControlPointData[SegmentIndex], RadiusA,
|
||||
ControlPointData[SegmentIndex + 1], RadiusB,
|
||||
T, SegmentIndex, NumSegments, Position, Tunnel,
|
||||
CacheIdentity, TunnelIndex, /*bEvaluateRelief=*/true,
|
||||
ReliefColumn,
|
||||
FloorProfileData != nullptr ? FloorProfileData + SegmentIndex : nullptr,
|
||||
RoomFloorOwnership);
|
||||
OutSupportRadius = FMath::Max(
|
||||
FMath::Min(FMath::Abs(RadiusA), FMath::Abs(RadiusB)) - 0.5f,
|
||||
VoxelPassageGeometry::PlayerRadiusVoxels);
|
||||
BestDistanceSquared = DistanceSquared;
|
||||
bFound = true;
|
||||
}
|
||||
|
||||
return bFound
|
||||
&& VoxelMath::IsFinite(OutFloorZ)
|
||||
&& VoxelMath::IsFinite(OutSupportRadius)
|
||||
&& BestDistanceSquared <= FMath::Square(OutSupportRadius);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FChunkSDFSpatialIndex::Reset()
|
||||
@@ -8960,50 +8867,6 @@ float VoxelCaveMorphology::EvaluateSDFCached(
|
||||
return MinSDF;
|
||||
}
|
||||
|
||||
float VoxelCaveMorphology::EvaluateTunnelCoreSDF(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
bool bUseSpatialIndex)
|
||||
{
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
return FLT_MAX;
|
||||
}
|
||||
const FVector Pos(WorldX, WorldY, WorldZ);
|
||||
float MinSDF = FLT_MAX;
|
||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
||||
|
||||
auto EvaluateTunnel = [&](int32 TunnelIdx)
|
||||
{
|
||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
||||
if (Tunnel.SDFInfluenceRadius > 0.0f
|
||||
&& VF_DistanceSquaredToAabb(
|
||||
WorldX, WorldY, WorldZ,
|
||||
Tunnel.SDFCenterlineMin, Tunnel.SDFCenterlineMax)
|
||||
> FMath::Square(Tunnel.SDFInfluenceRadius))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (VF_FloatDistSquared(WorldX, WorldY, WorldZ, Tunnel.BoundCenter)
|
||||
> Tunnel.BoundRadiusSq)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MinSDF = FMath::Min(
|
||||
MinSDF,
|
||||
VF_EvaluateSweptTunnel(
|
||||
Pos, Tunnel, /*bWorldChain=*/false, Cache.SDFBlendRadius,
|
||||
/*bApplyFloorCut=*/false, &Cache, TunnelIdx).SDF);
|
||||
};
|
||||
|
||||
VF_ForEachSpatialCandidate(
|
||||
Cache.TunnelSpatialIndex, Cache.Tunnels.Num(), WorldX, WorldY, EvaluateTunnel,
|
||||
bUseSpatialIndex);
|
||||
|
||||
return MinSDF;
|
||||
}
|
||||
|
||||
FTunnelCoreWorldEvaluation VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
@@ -9454,7 +9317,7 @@ bool VoxelCaveMorphology::AnyTunnelCoreWorldNearLattice(
|
||||
// The broad sphere already encloses the swept radius and finite floor band. Add the
|
||||
// vertical relief and room-mouth ownership envelopes before asking whether the lattice
|
||||
// box can touch it. A miss is therefore an identity proof for the core evaluator and
|
||||
// its support/room-floor tail; its only field writes are bSupportFloor, bRoomFloor, or
|
||||
// its support/room-floor tail; its only field writes are bRoomFloor or
|
||||
// CoreSDF < -inset, all of which are inside this envelope.
|
||||
const float Reach = (
|
||||
FMath::Sqrt(FMath::Max(BoundRadiusSq, 0.0f))
|
||||
@@ -9477,254 +9340,6 @@ float VoxelCaveMorphology::EvaluateTunnelCoreWorldSDF(
|
||||
WorldX, WorldY, WorldZ, Cache, nullptr, bUseSpatialIndex).SDF;
|
||||
}
|
||||
|
||||
bool VoxelCaveMorphology::IsTunnelSupportFloorWorldPoint(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
bool bUseSpatialIndex)
|
||||
{
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const FVector Pos(WorldX, WorldY, WorldZ);
|
||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
||||
|
||||
auto TestTunnel = [&](int32 TunnelIdx) -> bool
|
||||
{
|
||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
||||
const bool bHasWorldChain = Tunnel.WorldControlPoints.Num() >= 2
|
||||
&& Tunnel.WorldControlRadii.Num() == Tunnel.WorldControlPoints.Num();
|
||||
const FVector& CenterlineMin = bHasWorldChain
|
||||
? Tunnel.WorldCenterlineMin : Tunnel.SDFCenterlineMin;
|
||||
const FVector& CenterlineMax = bHasWorldChain
|
||||
? Tunnel.WorldCenterlineMax : Tunnel.SDFCenterlineMax;
|
||||
const float InfluenceRadius = bHasWorldChain
|
||||
? Tunnel.WorldInfluenceRadius : Tunnel.SDFInfluenceRadius;
|
||||
if (InfluenceRadius > 0.0f
|
||||
&& VF_DistanceSquaredToAabb(
|
||||
WorldX, WorldY, WorldZ, CenterlineMin, CenterlineMax)
|
||||
> FMath::Square(InfluenceRadius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FVector& BoundCenter = bHasWorldChain
|
||||
? Tunnel.WorldBoundCenter : Tunnel.BoundCenter;
|
||||
const float BoundRadiusSq = bHasWorldChain
|
||||
? Tunnel.WorldBoundRadiusSq : Tunnel.BoundRadiusSq;
|
||||
if (BoundRadiusSq > 0.0f
|
||||
&& VF_FloatDistSquared(WorldX, WorldY, WorldZ, BoundCenter) > BoundRadiusSq)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FVFRoomFloorOwnership RoomMouthOwnership =
|
||||
VF_FindWorldTunnelMouthOwnership(Pos, Tunnel, Cache.SDFBlendRadius);
|
||||
if (RoomMouthOwnership.bValid)
|
||||
{
|
||||
float ProjectedFloorZ = 0.0f;
|
||||
float SupportRadius = 0.0f;
|
||||
if (VF_ProjectSweptTunnelFloor(
|
||||
Pos, Tunnel, bHasWorldChain, ProjectedFloorZ, SupportRadius,
|
||||
&Cache, TunnelIdx, &RoomMouthOwnership)
|
||||
&& ProjectedFloorZ > RoomMouthOwnership.FloorZ + KINDA_SMALL_NUMBER)
|
||||
{
|
||||
// Only a raised tunnel apron is clipped. If the tunnel is lower, the room's
|
||||
// SmoothMax floor already wins naturally and retaining this support band is
|
||||
// capability-safe for legacy callers.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return VF_EvaluateSweptTunnel(
|
||||
Pos, Tunnel, bHasWorldChain, Cache.SDFBlendRadius,
|
||||
/*bApplyFloorCut=*/true, &Cache, TunnelIdx,
|
||||
&RoomMouthOwnership).bSupportFloor;
|
||||
};
|
||||
|
||||
bool bSupport = false;
|
||||
int32 CandidateCount = 0;
|
||||
auto TestRange = [&](int32 Begin, int32 End)
|
||||
{
|
||||
const int32* ItemIndexData = Cache.TunnelSpatialIndex.ItemIndices.GetData();
|
||||
for (int32 Cursor = Begin; Cursor < End; ++Cursor)
|
||||
{
|
||||
const int32 TunnelIdx = ItemIndexData[Cursor];
|
||||
if (!Cache.Tunnels.IsValidIndex(TunnelIdx))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
++CandidateCount;
|
||||
if (TestTunnel(TunnelIdx))
|
||||
{
|
||||
bSupport = true;
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelCoreEvaluated);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int32 Begin = 0;
|
||||
int32 End = 0;
|
||||
if (bUseSpatialIndex && Cache.TunnelSpatialIndex.GetRange(WorldX, WorldY, Begin, End))
|
||||
{
|
||||
TestRange(Begin, End);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 TunnelIdx = 0; TunnelIdx < Cache.Tunnels.Num() && !bSupport; ++TunnelIdx)
|
||||
{
|
||||
++CandidateCount;
|
||||
if (TestTunnel(TunnelIdx))
|
||||
{
|
||||
bSupport = true;
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelCoreEvaluated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelCoreCandidates,
|
||||
static_cast<uint64>(CandidateCount));
|
||||
}
|
||||
return bSupport;
|
||||
}
|
||||
|
||||
void VoxelCaveMorphology::BuildTunnelSupportFloorColumn(
|
||||
float WorldX, float WorldY,
|
||||
const FChunkSDFCache& Cache,
|
||||
FTunnelSupportFloorColumn& OutColumn,
|
||||
bool bUseSpatialIndex)
|
||||
{
|
||||
if (VoxelDensityAblation::IsTunnelCoreOff())
|
||||
{
|
||||
OutColumn.Reset();
|
||||
return;
|
||||
}
|
||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||
VoxelDensityProfile::EBucket::TunnelCoreSupport);
|
||||
OutColumn.Reset();
|
||||
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelSupportColumnBuilds);
|
||||
}
|
||||
|
||||
const FVector ColumnPosition(WorldX, WorldY, 0.0f);
|
||||
const FCachedTunnel* TunnelData = Cache.Tunnels.GetData();
|
||||
|
||||
auto EvaluateTunnel = [&](int32 TunnelIdx)
|
||||
{
|
||||
const FCachedTunnel& Tunnel = TunnelData[TunnelIdx];
|
||||
const FVFRoomFloorOwnership RoomMouthOwnership =
|
||||
VF_FindWorldTunnelMouthOwnership(ColumnPosition, Tunnel, Cache.SDFBlendRadius);
|
||||
float FloorZ = 0.0f;
|
||||
float SupportRadius = 0.0f;
|
||||
if (!VF_ProjectSweptTunnelFloor(
|
||||
ColumnPosition, Tunnel, /*bWorldChain=*/true,
|
||||
FloorZ, SupportRadius, &Cache, TunnelIdx, &RoomMouthOwnership))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float MinZ = FloorZ - VoxelPassageGeometry::LandingFloorThicknessVoxels;
|
||||
float MaxZ = FloorZ + VoxelPassageGeometry::WalkableTunnelFloorAirClearanceVoxels;
|
||||
|
||||
// Preserve the public point predicate's world bounding sphere exactly, while resolving
|
||||
// its Z interval once. The XY projection already proves the support-radius condition.
|
||||
if (Tunnel.WorldBoundRadiusSq > 0.0f)
|
||||
{
|
||||
const float DX = WorldX - static_cast<float>(Tunnel.WorldBoundCenter.X);
|
||||
const float DY = WorldY - static_cast<float>(Tunnel.WorldBoundCenter.Y);
|
||||
const float Remaining = Tunnel.WorldBoundRadiusSq - (DX * DX + DY * DY);
|
||||
if (Remaining < 0.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const float HalfZ = FMath::Sqrt(Remaining);
|
||||
MinZ = FMath::Max(MinZ, static_cast<float>(Tunnel.WorldBoundCenter.Z) - HalfZ);
|
||||
MaxZ = FMath::Min(MaxZ, static_cast<float>(Tunnel.WorldBoundCenter.Z) + HalfZ);
|
||||
}
|
||||
|
||||
if (MinZ <= MaxZ)
|
||||
{
|
||||
FTunnelSupportFloorInterval& Interval =
|
||||
OutColumn.Intervals.Emplace_GetRef();
|
||||
Interval.TunnelIndex = TunnelIdx;
|
||||
Interval.FloorZ = FloorZ;
|
||||
Interval.MinZ = MinZ;
|
||||
Interval.MaxZ = MaxZ;
|
||||
}
|
||||
};
|
||||
const int32 CandidateCount = VF_ForEachSpatialCandidate(
|
||||
Cache.TunnelSpatialIndex, Cache.Tunnels.Num(), WorldX, WorldY, EvaluateTunnel,
|
||||
bUseSpatialIndex);
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::TunnelSupportColumnCandidates,
|
||||
static_cast<uint64>(CandidateCount));
|
||||
}
|
||||
|
||||
// Candidate IDs are deterministic and allow the world evaluator to find a
|
||||
// tunnel's own band without re-running the XY projection. The public union
|
||||
// query below simply tests every band; graph columns normally contain only a
|
||||
// handful of candidates.
|
||||
OutColumn.Intervals.Sort(
|
||||
[](const FTunnelSupportFloorInterval& A,
|
||||
const FTunnelSupportFloorInterval& B)
|
||||
{
|
||||
return A.TunnelIndex < B.TunnelIndex;
|
||||
});
|
||||
}
|
||||
|
||||
bool VoxelCaveMorphology::IsTunnelSupportFloorColumnZ(
|
||||
float WorldZ,
|
||||
const FTunnelSupportFloorColumn& Column)
|
||||
{
|
||||
for (const FTunnelSupportFloorInterval& Interval : Column.Intervals)
|
||||
{
|
||||
if (WorldZ <= Interval.MaxZ)
|
||||
{
|
||||
if (WorldZ >= Interval.MinZ)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VoxelCaveMorphology::GetTunnelSupportFloorColumnBand(
|
||||
int32 TunnelIndex,
|
||||
const FTunnelSupportFloorColumn& Column,
|
||||
float& OutFloorZ,
|
||||
float& OutMinZ,
|
||||
float& OutMaxZ)
|
||||
{
|
||||
for (const FTunnelSupportFloorInterval& Interval : Column.Intervals)
|
||||
{
|
||||
if (Interval.TunnelIndex == TunnelIndex)
|
||||
{
|
||||
OutFloorZ = Interval.FloorZ;
|
||||
OutMinZ = Interval.MinZ;
|
||||
OutMaxZ = Interval.MaxZ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// CONVENIENCE WRAPPER (backward compatible)
|
||||
//=============================================================================
|
||||
@@ -9734,35 +9349,3 @@ bool VoxelCaveMorphology::GetTunnelSupportFloorColumnBand(
|
||||
// internally widens the COLLECT region to (2*MaxTunnelLength + MaxInfluence) so the
|
||||
// graph it builds is the same one the chunk path would build at this point.
|
||||
|
||||
float VoxelCaveMorphology::EvaluateSDF(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FStrateGenerationParams& Params,
|
||||
uint32 Seed, int32 StrateIndex)
|
||||
{
|
||||
const float RoomRadiusEnvelope = FMath::Max(
|
||||
FMath::Abs(Params.MinRoomRadius), FMath::Abs(Params.MaxRoomRadius));
|
||||
const float TunnelRadiusEnvelope = FMath::Max(
|
||||
0.5f,
|
||||
FMath::Max(FMath::Abs(Params.TunnelMinRadius), FMath::Abs(Params.TunnelMaxRadius))
|
||||
* 1.18f);
|
||||
const float FloorReliefEnvelope = FMath::Abs(Params.FloorReliefStrength)
|
||||
* VOXEL_NOISE_SCALE * 1.5f;
|
||||
const float BlendEnvelope = FMath::Max(Params.SDFBlendRadius, 0.0f);
|
||||
const float Margin = FMath::Max(
|
||||
RoomRadiusEnvelope + FloorReliefEnvelope,
|
||||
FMath::Abs(Params.TunnelWarpStrength) + TunnelRadiusEnvelope
|
||||
) + BlendEnvelope * 3.0f;
|
||||
|
||||
FChunkSDFCache TempCache;
|
||||
BuildChunkCache(
|
||||
TempCache,
|
||||
WorldX - Margin, WorldY - Margin,
|
||||
WorldX + Margin, WorldY + Margin,
|
||||
Params, Seed, StrateIndex
|
||||
);
|
||||
|
||||
return EvaluateSDFCached(
|
||||
WorldX, WorldY, WorldZ,
|
||||
TempCache, Params.SDFBlendRadius
|
||||
);
|
||||
}
|
||||
@@ -361,33 +361,6 @@ namespace
|
||||
// STAGE B5 DECISION: repeated early-out in each op, NOT a scoping container — the stack is a flat
|
||||
// list that ClassifyBox folds op by op, and an op that only exists inside a container is not
|
||||
// composable. Cost stated honestly: twelve predictable compares instead of one branch.
|
||||
/** Distance d'un point à un SEGMENT (pas à une droite). Écrite ici plutôt que prise dans
|
||||
* `FMath` : cinq lignes, aucune ambiguïté d'API, et elle sert une borne de correction — le
|
||||
* genre d'endroit où « je crois que cette fonction fait ça » n'est pas suffisant. */
|
||||
FORCEINLINE float VF_DistPointSegment(const FVector& P, const FVector& A, const FVector& B)
|
||||
{
|
||||
const FVector AB = B - A;
|
||||
const double LenSq = FVector::DotProduct(AB, AB);
|
||||
const double T = (LenSq > KINDA_SMALL_NUMBER)
|
||||
? FMath::Clamp(FVector::DotProduct(P - A, AB) / LenSq, 0.0, 1.0)
|
||||
: 0.0;
|
||||
return (float)FVector::Dist(P, A + AB * T);
|
||||
}
|
||||
|
||||
/** La même chose en 2D, pour les connecteurs de puits : ce sont des capsules HORIZONTALES, donc
|
||||
* Z se teste exactement et seul XY demande une distance point-segment. */
|
||||
FORCEINLINE float VF_DistPointSegment2D(const FVector2D& P, const FVector2D& A, const FVector2D& B)
|
||||
{
|
||||
const FVector2D AB = B - A;
|
||||
const double LenSq = (double)AB.X * AB.X + (double)AB.Y * AB.Y;
|
||||
const double T = (LenSq > KINDA_SMALL_NUMBER)
|
||||
? FMath::Clamp(((double)(P.X - A.X) * AB.X + (double)(P.Y - A.Y) * AB.Y) / LenSq, 0.0, 1.0)
|
||||
: 0.0;
|
||||
const double DX = (double)P.X - ((double)A.X + AB.X * T);
|
||||
const double DY = (double)P.Y - ((double)A.Y + AB.Y * T);
|
||||
return (float)FMath::Sqrt(DX * DX + DY * DY);
|
||||
}
|
||||
|
||||
FORCEINLINE bool VF_NearCaveSurface(float Sdf, float SDFBlendRadius)
|
||||
{
|
||||
// Transcrit tel quel, ordre des comparaisons compris :
|
||||
@@ -795,16 +768,6 @@ namespace
|
||||
return FVector((X + 0.5f) * CellSize, (Y + 0.5f) * CellSize, (Z + 0.5f) * CellSize);
|
||||
}
|
||||
|
||||
// Sur-approximation volontaire : boîte englobante du segment contre la boîte élargie.
|
||||
// Un test capsule/AABB exact serait plus serré ; il coûterait plus cher pour un gain nul
|
||||
// ici, car la réponse ne sert qu'à un rejet grossier par tuile.
|
||||
static bool SegmentHitsBox(const FVector& A, const FVector& B, const FVector& Min, const FVector& Max)
|
||||
{
|
||||
return FMath::Min(A.X, B.X) <= Max.X && FMath::Max(A.X, B.X) >= Min.X
|
||||
&& FMath::Min(A.Y, B.Y) <= Max.Y && FMath::Max(A.Y, B.Y) >= Min.Y
|
||||
&& FMath::Min(A.Z, B.Z) <= Max.Z && FMath::Max(A.Z, B.Z) >= Min.Z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Le cache par CELLULE, partagé avec le même contrat que GetMazeDensity. Il est `thread_local` et non
|
||||
* membre parce que la pile est PARTAGÉE entre workers en lecture — un membre mutable serait
|
||||
@@ -1120,12 +1083,6 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
/** Sans biomes — délègue, pour qu'il n'existe qu'UN corps de construction et UN compteur
|
||||
* d'identité. Deux constructeurs qui s'initialisent chacun de leur côté, c'est deux
|
||||
* endroits où oublier un membre. */
|
||||
FSurfaceColumnSource(const FSurfaceGenerationParams& InP, int32 Seed)
|
||||
: FSurfaceColumnSource(InP, Seed, TArray<FSurfaceGenerationParams>(), nullptr) {}
|
||||
|
||||
void BuildSingleBiome(const FSurfaceGenerationParams& InP, int32 Seed)
|
||||
{
|
||||
// Construite à la main (pas via BuildSurfaceHeightStack) pour GARDER le pointeur vers la
|
||||
@@ -1342,8 +1299,6 @@ namespace
|
||||
return S.Height;
|
||||
}
|
||||
|
||||
const FSurfaceGenerationParams& GetParams() const { return P; }
|
||||
|
||||
EVoxelOpRole GetRole() const override { return EVoxelOpRole::FieldSource; }
|
||||
EVoxelOpChannelMask ChannelReads() const override { return VoxelOpChannels::None; }
|
||||
EVoxelOpChannelMask ChannelWrites() const override { return VoxelOpChannels::Density; }
|
||||
@@ -4313,7 +4268,6 @@ namespace
|
||||
// room's own volume.
|
||||
InOut.bHasTunnelCoreWorldEvaluation = true;
|
||||
InOut.TunnelCoreWorldSDF = S.LastTunnelCoreWorldEvaluation.SDF;
|
||||
InOut.bTunnelCoreSupportFloor = false;
|
||||
InOut.bTunnelCoreRoomFloor =
|
||||
S.LastTunnelCoreWorldEvaluation.bRoomFloor;
|
||||
InOut.bHasTunnelCoreSweptFloor =
|
||||
@@ -4322,8 +4276,6 @@ namespace
|
||||
S.LastTunnelCoreWorldEvaluation.SweptFloorZ;
|
||||
InOut.TunnelCoreSweptFloorRadius =
|
||||
S.LastTunnelCoreWorldEvaluation.SweptFloorRadius;
|
||||
InOut.bProtectedStructuralFloor = false;
|
||||
InOut.StructuralFloorMinimumDensity = 0.0f;
|
||||
}
|
||||
|
||||
// These cache hand-offs remain valid when tunnel core is off; detail operators still
|
||||
@@ -4445,7 +4397,6 @@ namespace
|
||||
bool bMayHaveTunnelCoreTail = false;
|
||||
uint32 ExactTailQueries = 0;
|
||||
uint32 ExactTailEvaluated = 0;
|
||||
uint32 ExactTailCacheHits = 0;
|
||||
uint64 ExactTailCycles = 0;
|
||||
uint64 PropagateCycles = 0;
|
||||
uint64 ExactPrimitiveCycles = 0;
|
||||
@@ -4534,12 +4485,6 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasRoomColumnsForLastBox() const
|
||||
{
|
||||
const FBoxState& B = BoxState();
|
||||
return !B.bValid || GetBoxCache().Columns.Num() > 0;
|
||||
}
|
||||
|
||||
float RoomColumnFillSupremumForLastBox() const
|
||||
{
|
||||
const FBoxState& B = BoxState();
|
||||
@@ -5623,18 +5568,6 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
auto EffectiveZRangeToWorld = [&](float MinEffectiveZ,
|
||||
float MaxEffectiveZ) -> FVector2D
|
||||
{
|
||||
if (P.VerticalScale > 0.0f && P.VerticalScale != 1.0f)
|
||||
{
|
||||
const float WorldA = MinEffectiveZ * P.VerticalScale;
|
||||
const float WorldB = MaxEffectiveZ * P.VerticalScale;
|
||||
return FVector2D(FMath::Min(WorldA, WorldB), FMath::Max(WorldA, WorldB));
|
||||
}
|
||||
return FVector2D(MinEffectiveZ, MaxEffectiveZ);
|
||||
};
|
||||
|
||||
auto DistanceBlockToInfiniteLineLower = [&](const FExactLatticeBlock& Block,
|
||||
const FVector& A,
|
||||
const FVector& BPoint) -> float
|
||||
@@ -9463,11 +9396,6 @@ namespace VoxelDensityOps
|
||||
return MakeUnique<FGridColumnMod>(P, Seed);
|
||||
}
|
||||
|
||||
TUniquePtr<IVoxelDensityOp> MakeSurfaceColumnSource(const FSurfaceGenerationParams& P, int32 Seed)
|
||||
{
|
||||
return MakeUnique<FSurfaceColumnSource>(P, Seed);
|
||||
}
|
||||
|
||||
void BuildSurfaceStack(FVoxelOpStack& OutStack, const FSurfaceGenerationParams& P,
|
||||
int32 Seed, float SpineRadius, const UVoxelStrateManager* StrateManager,
|
||||
const TArray<FSurfaceGenerationParams>& PerBiomeParams,
|
||||
|
||||
@@ -218,11 +218,6 @@ namespace VoxelDensityProfile
|
||||
}
|
||||
}
|
||||
|
||||
void SetEnabled(bool bEnabled)
|
||||
{
|
||||
SetMode(bEnabled ? EMode::Sampled : EMode::Disabled, DefaultSampleInterval);
|
||||
}
|
||||
|
||||
void SetMode(EMode Mode, uint32 SampleInterval)
|
||||
{
|
||||
if (SampleInterval == 0)
|
||||
|
||||
@@ -3287,7 +3287,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
float BlockDensity = 0.f;
|
||||
bool bBlockHasTunnelCore = false;
|
||||
float BlockTunnelCoreSDF = FLT_MAX;
|
||||
bool bBlockTunnelCoreSupportFloor = false;
|
||||
bool bBlockTunnelCoreRoomFloor = false;
|
||||
bool bBlockHasTunnelCoreSweptFloor = false;
|
||||
float BlockTunnelCoreSweptFloorZ = -FLT_MAX;
|
||||
@@ -3362,7 +3361,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
BlockDensity = BlockCoreSample.Density;
|
||||
bBlockHasTunnelCore = BlockCoreSample.bHasTunnelCoreWorldEvaluation;
|
||||
BlockTunnelCoreSDF = BlockCoreSample.TunnelCoreWorldSDF;
|
||||
bBlockTunnelCoreSupportFloor = BlockCoreSample.bTunnelCoreSupportFloor;
|
||||
bBlockTunnelCoreRoomFloor = BlockCoreSample.bTunnelCoreRoomFloor;
|
||||
bBlockHasTunnelCoreSweptFloor =
|
||||
BlockCoreSample.bHasTunnelCoreSweptFloor;
|
||||
@@ -3466,7 +3464,6 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
else if (bUsedOpBlockSample && bBlockHasTunnelCore)
|
||||
{
|
||||
PreDisturbanceTunnelCore.SDF = BlockTunnelCoreSDF;
|
||||
PreDisturbanceTunnelCore.bSupportFloor = bBlockTunnelCoreSupportFloor;
|
||||
PreDisturbanceTunnelCore.bRoomFloor = bBlockTunnelCoreRoomFloor;
|
||||
PreDisturbanceTunnelCore.bHasSweptFloor =
|
||||
bBlockHasTunnelCoreSweptFloor;
|
||||
|
||||
@@ -1410,59 +1410,6 @@ namespace VoxelSeasonManifestPrivate
|
||||
return bValid;
|
||||
}
|
||||
|
||||
bool SaveJson(const FString& FilePath, const TSharedPtr<FJsonObject>& Root,
|
||||
FString& OutReport)
|
||||
{
|
||||
const FString Directory = FPaths::GetPath(FilePath);
|
||||
if (!Directory.IsEmpty() && !IFileManager::Get().MakeDirectory(*Directory, true))
|
||||
{
|
||||
OutReport = FString::Printf(TEXT("could not create manifest directory %s"), *Directory);
|
||||
return false;
|
||||
}
|
||||
FString JsonText;
|
||||
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer =
|
||||
TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonText);
|
||||
if (!FJsonSerializer::Serialize(Root.ToSharedRef(), Writer) || !Writer->Close()
|
||||
|| !FFileHelper::SaveStringToFile(JsonText, *FilePath))
|
||||
{
|
||||
OutReport = FString::Printf(TEXT("could not write season manifest %s"), *FilePath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadJson(const FString& FilePath, TSharedPtr<FJsonObject>& OutRoot,
|
||||
FString& OutReport, FString* OutJsonText = nullptr)
|
||||
{
|
||||
FString JsonText;
|
||||
if (!FFileHelper::LoadFileToString(JsonText, *FilePath))
|
||||
{
|
||||
OutReport = FString::Printf(TEXT("could not read season manifest %s"), *FilePath);
|
||||
return false;
|
||||
}
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonText);
|
||||
if (!FJsonSerializer::Deserialize(Reader, OutRoot) || !OutRoot.IsValid())
|
||||
{
|
||||
OutReport = FString::Printf(TEXT("invalid JSON in season manifest %s"), *FilePath);
|
||||
return false;
|
||||
}
|
||||
if (OutJsonText != nullptr)
|
||||
{
|
||||
*OutJsonText = MoveTemp(JsonText);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const TCHAR* VF_GetVoxelSeasonSelectionReasonName(EVoxelSeasonSelectionReason Reason)
|
||||
{
|
||||
switch (Reason)
|
||||
{
|
||||
case EVoxelSeasonSelectionReason::Grounded: return TEXT("grounded");
|
||||
case EVoxelSeasonSelectionReason::Outlier: return TEXT("outlier");
|
||||
case EVoxelSeasonSelectionReason::Fixed: return TEXT("fixed");
|
||||
}
|
||||
return TEXT("unknown");
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@@ -863,12 +863,6 @@ void FVoxelStackSampler::Shutdown()
|
||||
StopAndWrite();
|
||||
}
|
||||
|
||||
bool FVoxelStackSampler::IsRunning() const
|
||||
{
|
||||
FScopeLock LifecycleLock(&LifecycleMutex);
|
||||
return Impl != nullptr;
|
||||
}
|
||||
|
||||
bool FVoxelStackSampler::RegisterCurrentThread(int32 LODLevel)
|
||||
{
|
||||
// Keep this as the first and only operation in the disabled fast path. In particular, do not
|
||||
|
||||
@@ -3800,55 +3800,6 @@ bool FVoxelStrateCorpus::LoadFromAssetRegistry(
|
||||
return bLoaded && NumUnresolved == 0 && bPromotedLoaded;
|
||||
}
|
||||
|
||||
bool FVoxelStrateCorpus::LoadFromSettings(const UVoxelSettings* Settings, FString& OutReport)
|
||||
{
|
||||
// Compatibility/audit entry point. It intentionally does not load any soft reference: the
|
||||
// Asset Registry is the corpus source, while the settings pool is reported as the reason the
|
||||
// first Tier 4a run saw only one vector.
|
||||
TArray<FString> SettingsPaths;
|
||||
if (Settings != nullptr)
|
||||
{
|
||||
TSet<FString> UniquePaths;
|
||||
for (const TPair<int32, TSoftObjectPtr<UVoxelStrateDefinition>>& Pair : Settings->FixedStrates)
|
||||
{
|
||||
const FString Path = Pair.Value.ToSoftObjectPath().ToString();
|
||||
if (!Path.IsEmpty())
|
||||
{
|
||||
UniquePaths.Add(Path);
|
||||
}
|
||||
}
|
||||
for (const TSoftObjectPtr<UVoxelStrateDefinition>& Reference : Settings->StratePool)
|
||||
{
|
||||
const FString Path = Reference.ToSoftObjectPath().ToString();
|
||||
if (!Path.IsEmpty())
|
||||
{
|
||||
UniquePaths.Add(Path);
|
||||
}
|
||||
}
|
||||
for (const FString& Path : UniquePaths)
|
||||
{
|
||||
SettingsPaths.Add(Path);
|
||||
}
|
||||
SettingsPaths.Sort();
|
||||
}
|
||||
|
||||
FString RegistryReport;
|
||||
const bool bLoaded = LoadFromAssetRegistry(RegistryReport);
|
||||
OutReport = FString::Printf(
|
||||
TEXT("Settings audit: %d unique fixed/pool soft paths"), SettingsPaths.Num());
|
||||
for (const FString& Path : SettingsPaths)
|
||||
{
|
||||
OutReport += FString::Printf(TEXT(" [%s]"), *Path);
|
||||
}
|
||||
if (Settings == nullptr)
|
||||
{
|
||||
OutReport += TEXT(" [settings object was null]");
|
||||
}
|
||||
OutReport += TEXT("; settings references are diagnostic only. ");
|
||||
OutReport += RegistryReport;
|
||||
return bLoaded;
|
||||
}
|
||||
|
||||
int32 FVoxelStrateCorpus::NumForArchetype(ECaveGeneratorType Archetype) const
|
||||
{
|
||||
int32 Count = 0;
|
||||
@@ -5301,12 +5252,6 @@ bool VF_ValidateStrateCorpusFreeConstraints(
|
||||
return false;
|
||||
}
|
||||
|
||||
FStrateGenerationParams VF_RollStrateParams(const FVoxelStrateCorpus& Corpus,
|
||||
int32 Seed, int32 Index)
|
||||
{
|
||||
return VF_RollStrateParamsDetailed(Corpus, Seed, Index).Params;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const TCHAR* VF_RecipeOpCode(EVoxelStrateOpClass OpClass)
|
||||
@@ -5532,15 +5477,6 @@ FVoxelStrateRegionManifest VF_RollStrateRegionManifest(
|
||||
ECaveGeneratorType::VerticalShafts,
|
||||
ECaveGeneratorType::FloatingIslands,
|
||||
};
|
||||
static const EVoxelStrateParamBlock BlockIds[] =
|
||||
{
|
||||
EVoxelStrateParamBlock::TunnelNetwork,
|
||||
EVoxelStrateParamBlock::Slab,
|
||||
EVoxelStrateParamBlock::Maze,
|
||||
EVoxelStrateParamBlock::Surface,
|
||||
EVoxelStrateParamBlock::VerticalShaft,
|
||||
EVoxelStrateParamBlock::FloatingIsland,
|
||||
};
|
||||
static const uint32 BlockSalts[] = { 0x1001u, 0x1003u, 0x1005u,
|
||||
0x1007u, 0x1009u, 0x100Bu };
|
||||
|
||||
|
||||
@@ -3023,20 +3023,6 @@ void UVoxelStrateManager::ApplyPassageLandingAir(
|
||||
VF_ApplyPassageLandingCarving(Density, MinLandingSDF, BaseDensity, SealThickness);
|
||||
}
|
||||
|
||||
void UVoxelStrateManager::ApplyPassageLandingAirMC(
|
||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const
|
||||
{
|
||||
// ApplyDisturbances is deliberately an MC-space post-process and can add a bridge or ridge
|
||||
// on top of the structural passage. Reassert only landing air here; the support slab is
|
||||
// restored by ApplyPassageLandingFloorMC immediately afterwards. This stays on the same
|
||||
// thread-local passage shortlist as the hot voxel path and performs no source/topology work.
|
||||
float InternalDensity = -Density;
|
||||
ApplyPassageLandingAir(
|
||||
InternalDensity, WorldX, WorldY, WorldZ, BaseDensity, SealThickness);
|
||||
Density = -InternalDensity;
|
||||
}
|
||||
|
||||
void UVoxelStrateManager::ApplyPassageTunnelAir(
|
||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const
|
||||
@@ -3070,18 +3056,6 @@ void UVoxelStrateManager::ApplyPassageTunnelAir(
|
||||
}
|
||||
}
|
||||
|
||||
void UVoxelStrateManager::ApplyPassageTunnelAirMC(
|
||||
float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const
|
||||
{
|
||||
// The disturbance layer uses MC polarity (negative = solid), so reuse the exact internal
|
||||
// tunnel-air operation rather than maintaining a second polarity-specific formula.
|
||||
float InternalDensity = -Density;
|
||||
ApplyPassageTunnelAir(
|
||||
InternalDensity, WorldX, WorldY, WorldZ, BaseDensity, SealThickness);
|
||||
Density = -InternalDensity;
|
||||
}
|
||||
|
||||
void UVoxelStrateManager::ApplyPassageLandingFloorMC(
|
||||
float& Density, float WorldX, float WorldY, float WorldZ, float BaseDensity) const
|
||||
{
|
||||
@@ -6712,7 +6686,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
||||
// Three transition styles:
|
||||
//
|
||||
// GRADIENT (default):
|
||||
// Classic linear lerp of all params across BlendChunks. Smooth,
|
||||
// Classic linear lerp of all params across TransitionBlendChunks. Smooth,
|
||||
// invisible boundary. Cave shape morphs gradually from one strate
|
||||
// to the next over several chunks.
|
||||
//
|
||||
@@ -6720,7 +6694,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
||||
// No blending at all — params switch instantly at the boundary.
|
||||
// The abrupt change in density, room size, roughness, etc. creates
|
||||
// a natural cliff, ledge, or visible material discontinuity.
|
||||
// BlendChunks is ignored (effectively 0).
|
||||
// TransitionBlendChunks is ignored (effectively 0).
|
||||
//
|
||||
// INTERLEAVED:
|
||||
// 3D Perlin noise warps the effective boundary Z position per XY column.
|
||||
@@ -6740,7 +6714,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
||||
// CHECK BOTTOM BOUNDARY (transitioning to strate below)
|
||||
//---------------------------------------------------------------------
|
||||
// DistFromBottom = how many chunks above the bottom edge of this strate.
|
||||
// When 0, we're right at the boundary. When == BlendChunks, we're at
|
||||
// When 0, we're right at the boundary. When == TransitionBlendChunks, we're at
|
||||
// the outer edge of the transition zone.
|
||||
int32 DistFromBottom = ChunkCoord.Z - Slot.BottomChunkZ;
|
||||
|
||||
@@ -6749,7 +6723,7 @@ FStrateGenerationParams UVoxelStrateManager::GetGenerationParams(const FIntVecto
|
||||
// The upper strate (this one) controls the transition type at its lower edge
|
||||
const EVoxelStrateTransition TransType = Slot.Definition->TransitionType;
|
||||
|
||||
// Per-definition blend distance (overrides the manager's default BlendChunks)
|
||||
// Per-definition blend distance.
|
||||
const int32 EffectiveBlend = Slot.Definition->TransitionBlendChunks;
|
||||
|
||||
// Prepare the neighbor's params (only used for Gradient and Interleaved)
|
||||
@@ -6952,93 +6926,3 @@ FStrateGenerationParams UVoxelStrateManager::BuildParamsFromDefinition(const UVo
|
||||
return Result;
|
||||
}
|
||||
|
||||
uint64 UVoxelStrateManager::GetGenerationParamsFingerprint() const
|
||||
{
|
||||
// The diagnostic command-line override changes density inputs without changing an asset. Do
|
||||
// not let a verdict from the unoverridden layout survive into an overridden session (or vice
|
||||
// versa); a zero fingerprint conservatively disables persistence for that session.
|
||||
const FRuntimeRoughnessOverrides& RoughnessOverrides = VF_GetRuntimeRoughnessOverrides();
|
||||
if (RoughnessOverrides.bSurfaceRoughness
|
||||
|| RoughnessOverrides.bFrequency
|
||||
|| RoughnessOverrides.bNoiseType)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The session cache is deliberately conservative. These inputs are valid density inputs but
|
||||
// are not represented by the fixed-size hash below, so returning zero disables verdict reuse
|
||||
// instead of pretending that a partial key is complete.
|
||||
if (IsUsingSeason())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#if WITH_EDITOR
|
||||
if (ComposerOverrides.Num() > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32 A = 0x9E3779B9u;
|
||||
uint32 B = 0x85EBCA6Bu;
|
||||
auto HashBytes = [&A, &B](const void* Data, int32 Size)
|
||||
{
|
||||
A = FCrc::MemCrc32(Data, Size, A);
|
||||
B = FCrc::MemCrc32(Data, Size, B ^ 0xA511E9B3u);
|
||||
};
|
||||
auto HashValue = [&HashBytes](const auto& Value)
|
||||
{
|
||||
HashBytes(&Value, sizeof(Value));
|
||||
};
|
||||
|
||||
HashValue(CachedSeed);
|
||||
HashValue(bOpenSurfaceEntry);
|
||||
HashValue(OriginSpineRadius);
|
||||
HashValue(InterStrateGapChunks);
|
||||
const int32 LayoutCount = StrateLayout.Num();
|
||||
HashValue(LayoutCount);
|
||||
|
||||
for (const FStrateSlot& Slot : StrateLayout)
|
||||
{
|
||||
if (Slot.Definition == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// BuildChunkCache resolves these arrays into the room cache. Hashing UObject pointers or
|
||||
// asset names would not prove the asset contents, so dynamic operation/biome layouts
|
||||
// conservatively opt out. The normal synthetic/runtime profile has neither array.
|
||||
if (Slot.Definition->TerrainOperations.Num() > 0
|
||||
|| Slot.Definition->Biomes.Num() > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
HashValue(Slot.StrateIndex);
|
||||
HashValue(Slot.TopChunkZ);
|
||||
HashValue(Slot.BottomChunkZ);
|
||||
HashValue(Slot.HeightInChunks);
|
||||
HashValue(Slot.Definition->GeneratorType);
|
||||
HashValue(Slot.Definition->bUseOperatorStack);
|
||||
HashValue(Slot.Definition->bEnableWorms);
|
||||
HashValue(VF_WormsForceOff());
|
||||
// Development-only stage ablations change the field and therefore belong in every
|
||||
// persistent/verdict key even though they are not authored generation parameters.
|
||||
HashValue(VoxelDensityAblation::GetResolvedMask());
|
||||
HashValue(Slot.Definition->StrateHeightInChunks);
|
||||
HashValue(Slot.Definition->TransitionType);
|
||||
HashValue(Slot.Definition->TransitionBlendChunks);
|
||||
HashValue(Slot.Definition->GenerationParams);
|
||||
HashValue(Slot.Definition->SlabParams);
|
||||
HashValue(Slot.Definition->MazeParams);
|
||||
HashValue(Slot.Definition->SurfaceParams);
|
||||
HashValue(Slot.Definition->VerticalShaftParams);
|
||||
HashValue(Slot.Definition->FloatingIslandParams);
|
||||
HashValue(Slot.Definition->PassageConfig);
|
||||
HashValue(Slot.Definition->bHasWater);
|
||||
HashValue(Slot.Definition->BiomeMapParams);
|
||||
}
|
||||
|
||||
const uint64 Result = (static_cast<uint64>(B) << 32) | static_cast<uint64>(A);
|
||||
return Result != 0 ? Result : 1;
|
||||
}
|
||||
@@ -2973,24 +2973,6 @@ namespace VoxelStrateMeasurePrivate
|
||||
return Result;
|
||||
}
|
||||
|
||||
int32 GetSixNeighbour(const FSampleGrid& Grid, int32 Cell, int32 Direction)
|
||||
{
|
||||
int32 X = 0;
|
||||
int32 Y = 0;
|
||||
int32 Z = 0;
|
||||
DecodeIndex(Grid, Cell, X, Y, Z);
|
||||
switch (Direction)
|
||||
{
|
||||
case 0: return X + 1 < Grid.NumX ? Grid.Index(X + 1, Y, Z) : INDEX_NONE;
|
||||
case 1: return X > 0 ? Grid.Index(X - 1, Y, Z) : INDEX_NONE;
|
||||
case 2: return Y + 1 < Grid.NumY ? Grid.Index(X, Y + 1, Z) : INDEX_NONE;
|
||||
case 3: return Y > 0 ? Grid.Index(X, Y - 1, Z) : INDEX_NONE;
|
||||
case 4: return Z + 1 < Grid.NumZ ? Grid.Index(X, Y, Z + 1) : INDEX_NONE;
|
||||
case 5: return Z > 0 ? Grid.Index(X, Y, Z - 1) : INDEX_NONE;
|
||||
default: return INDEX_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
int32 CountPlayerFitNeighbours(
|
||||
const FSampleGrid& Grid,
|
||||
const TArray<uint8>& PlayerFitMask,
|
||||
@@ -3458,26 +3440,6 @@ FVoxelConnectivityDiagnostics VF_DiagnoseConnectivityWithSampler(
|
||||
return Result;
|
||||
}
|
||||
|
||||
EVoxelConnectivityResult VF_ArePlayerFitConnectedWithSampler(
|
||||
const IVoxelStrateDensitySampler& Sampler,
|
||||
int32 StrateBottomWorldZ,
|
||||
int32 StrateTopWorldZ,
|
||||
float BoundarySealThickness,
|
||||
const FVector& AVoxel,
|
||||
const FVector& BVoxel,
|
||||
const FVoxelStrateMeasureSettings& Settings,
|
||||
bool& bOutStartSnapped,
|
||||
bool& bOutGoalSnapped,
|
||||
FVoxelConnectivityDiagnostics* OutDiagnostics)
|
||||
{
|
||||
int32 NumRouteRetries = 0;
|
||||
return VoxelStrateMeasurePrivate::QueryConnectivity(
|
||||
nullptr, nullptr, &Sampler, INDEX_NONE,
|
||||
StrateBottomWorldZ, StrateTopWorldZ, BoundarySealThickness, true,
|
||||
AVoxel, BVoxel, Settings, bOutStartSnapped, bOutGoalSnapped,
|
||||
NumRouteRetries, OutDiagnostics, true, nullptr);
|
||||
}
|
||||
|
||||
FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
||||
const IVoxelStrateDensitySampler& Sampler,
|
||||
int32 StrateBottomWorldZ,
|
||||
|
||||
@@ -76,16 +76,6 @@ namespace
|
||||
|
||||
namespace VoxelWormField
|
||||
{
|
||||
float EvaluateExact(
|
||||
float WorldX,
|
||||
float WorldY,
|
||||
float WorldZ,
|
||||
float Threshold,
|
||||
const FParameters& Parameters)
|
||||
{
|
||||
return EvaluateExactField(WorldX, WorldY, WorldZ, Threshold, Parameters);
|
||||
}
|
||||
|
||||
float Evaluate(
|
||||
float WorldX,
|
||||
float WorldY,
|
||||
|
||||
@@ -637,9 +637,8 @@ struct FCachedRoomFloorJoin
|
||||
|
||||
// One immutable floor segment authored while the tunnel chain is built. The floor is continuous
|
||||
// unless bLedgeTransition is set; that marker means the segment terminates at a deliberate
|
||||
// dramatic ledge and the vertical riser is placed at the next control-point boundary. NumSteps is
|
||||
// retained as a compatibility/diagnostic field and is always zero for newly authored tunnels: a
|
||||
// steep floor is never quantised into a staircase. ReliefScale is baked with a derivative bound,
|
||||
// dramatic ledge and the vertical riser is placed at the next control-point boundary. A steep
|
||||
// floor is never quantised into a staircase. ReliefScale is baked with a derivative bound,
|
||||
// so evaluation only reads this profile and never decides a floor shape per voxel.
|
||||
struct FTunnelFloorSegmentProfile
|
||||
{
|
||||
@@ -652,9 +651,6 @@ struct FTunnelFloorSegmentProfile
|
||||
float NaturalEndFloorZ = 0.0f;
|
||||
float ReliefScale = 0.0f;
|
||||
bool bLedgeTransition = false;
|
||||
// Deprecated staircase count. New profiles leave this at zero; keep the member so old
|
||||
// diagnostic consumers can still compile while the authored representation has one meaning.
|
||||
int32 NumSteps = 0;
|
||||
};
|
||||
|
||||
// A pre-computed wandering tunnel chain — all connection decisions and hash-derived properties
|
||||
@@ -938,8 +934,6 @@ struct FChunkSDFCache
|
||||
struct FTunnelCoreWorldEvaluation
|
||||
{
|
||||
float SDF = FLT_MAX;
|
||||
// Deprecated compatibility output. The separate graph-tunnel support slab was removed.
|
||||
bool bSupportFloor = false;
|
||||
// Room geometry owns the lower side while the world-space tunnel is inside a room. The
|
||||
// tunnel SDF may still reopen air there, but its swept bottom must not turn that room air back
|
||||
// into a shelf or wall.
|
||||
@@ -1065,15 +1059,6 @@ namespace VoxelCaveMorphology
|
||||
bool* OutRoomOwnsBottom = nullptr
|
||||
);
|
||||
|
||||
// Evaluate the raw union of cached graph-tunnel capsules. This is intentionally separate from
|
||||
// the SmoothMin morphology: the generator uses it after terrain/passage posts to reassert the
|
||||
// tunnel's walkable air core without reintroducing a connector or changing room ownership.
|
||||
VOXELFORGE_API float EvaluateTunnelCoreSDF(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
bool bUseSpatialIndex = true
|
||||
);
|
||||
|
||||
// Evaluate the final structural air contract against the world-space wandering chain. Room
|
||||
// SDFs remain evaluated in warped coordinates; only this post uses world coordinates so its
|
||||
// walkable floor follows the authored chain exactly.
|
||||
@@ -1106,46 +1091,6 @@ namespace VoxelCaveMorphology
|
||||
float ReachScale = 1.0f
|
||||
);
|
||||
|
||||
// Deprecated compatibility query for the removed graph-tunnel support slab. Production
|
||||
// generation does not call this predicate; the tunnel's own swept shape owns its floor.
|
||||
VOXELFORGE_API bool IsTunnelSupportFloorWorldPoint(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FChunkSDFCache& Cache,
|
||||
bool bUseSpatialIndex = true
|
||||
);
|
||||
|
||||
// Deprecated compatibility helper for callers that still inspect the old support-band
|
||||
// diagnostic. It is detached from production density generation.
|
||||
VOXELFORGE_API void BuildTunnelSupportFloorColumn(
|
||||
float WorldX, float WorldY,
|
||||
const FChunkSDFCache& Cache,
|
||||
FTunnelSupportFloorColumn& OutColumn,
|
||||
bool bUseSpatialIndex = true
|
||||
);
|
||||
|
||||
VOXELFORGE_API bool IsTunnelSupportFloorColumnZ(
|
||||
float WorldZ,
|
||||
const FTunnelSupportFloorColumn& Column
|
||||
);
|
||||
|
||||
// Returns the legacy projected band for one tunnel at this XY column. The world evaluator no
|
||||
// longer uses it to write a support slab.
|
||||
VOXELFORGE_API bool GetTunnelSupportFloorColumnBand(
|
||||
int32 TunnelIndex,
|
||||
const FTunnelSupportFloorColumn& Column,
|
||||
float& OutFloorZ,
|
||||
float& OutMinZ,
|
||||
float& OutMaxZ
|
||||
);
|
||||
|
||||
// CONVENIENCE WRAPPER: builds a temporary cache and evaluates in one call.
|
||||
// Use this for one-off queries (debug visualization, single-point sampling).
|
||||
// For chunk generation, use BuildChunkCache + EvaluateSDFCached instead.
|
||||
float EvaluateSDF(
|
||||
float WorldX, float WorldY, float WorldZ,
|
||||
const FStrateGenerationParams& Params,
|
||||
uint32 Seed, int32 StrateIndex
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -337,11 +337,6 @@ struct FVoxelOpSample
|
||||
// FLT_MAX = "no surface nearby" — the initial state, and the early-out placed sources use.
|
||||
float Sdf = FLT_MAX;
|
||||
|
||||
// Deprecated structural-floor compatibility fields. Graph tunnels now carry their floor in
|
||||
// the swept shape itself; the production stack does not use these fields to write a slab.
|
||||
bool bProtectedStructuralFloor = false;
|
||||
float StructuralFloorMinimumDensity = 0.0f;
|
||||
|
||||
// Block evaluation keeps the room source's per-sample selection explicit. The scalar path
|
||||
// still uses the source's worker-local state, but a later block-capable modifier must never
|
||||
// observe the state belonging to the last sample of the preceding operator.
|
||||
@@ -353,7 +348,6 @@ struct FVoxelOpSample
|
||||
// consulting a last-sample TLS value after an op-major evaluation.
|
||||
bool bHasTunnelCoreWorldEvaluation = false;
|
||||
float TunnelCoreWorldSDF = FLT_MAX;
|
||||
bool bTunnelCoreSupportFloor = false;
|
||||
bool bTunnelCoreRoomFloor = false;
|
||||
bool bHasTunnelCoreSweptFloor = false;
|
||||
float TunnelCoreSweptFloorZ = -FLT_MAX;
|
||||
|
||||
@@ -568,12 +568,6 @@ namespace VoxelDensityOps
|
||||
* `FillOnly` quand une colonne atteint la boîte, `Identity` (le cas courant) sinon. */
|
||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeGridColumnMod(const FSlabGenerationParams& P, int32 Seed);
|
||||
|
||||
/** Rôle 1 — le pont entre les deux espaces : consomme les piles de HAUTEUR (sol + voûte,
|
||||
* `VoxelHeightOp.h`) et en fait une densité. `IsXYPure()` est **false** — les hauteurs sont
|
||||
* pures en XY, la densité est une distance à celles-ci et ne peut pas l'être. */
|
||||
VOXELFORGE_API TUniquePtr<IVoxelDensityOp> MakeSurfaceColumnSource(const FSurfaceGenerationParams& P,
|
||||
int32 Seed);
|
||||
|
||||
/**
|
||||
* SurfaceWorld, COMPLET : colonne (sol + voûte) → densité, overhang 3D, post structurel, et le
|
||||
* mélange de biomes quand `PerBiomeParams` est non vide.
|
||||
|
||||
@@ -300,7 +300,6 @@ FORCEINLINE void VF_ApplyXYEdgeSealMC(float& Density, float WorldX, float WorldY
|
||||
// mathematical inner edge the helper is a true no-op, so claiming AllSolid there would be false.
|
||||
namespace VoxelDensityReach
|
||||
{
|
||||
constexpr float SpineBlend = 3.0f;
|
||||
constexpr float PassageBlend = 4.0f;
|
||||
constexpr float EdgeProofMargin = 1.0f;
|
||||
}
|
||||
|
||||
@@ -312,7 +312,6 @@ namespace VoxelDensityProfile
|
||||
FCacheMemoryBreakdown RoomGraphCacheBreakdown;
|
||||
};
|
||||
|
||||
VOXELFORGE_API void SetEnabled(bool bEnabled);
|
||||
VOXELFORGE_API void SetMode(EMode Mode, uint32 SampleInterval = DefaultSampleInterval);
|
||||
// Counters are collected only while a diagnostic mode is enabled. In the ordinary clean
|
||||
// path this is a single relaxed load, so the measurement hooks stay dormant.
|
||||
|
||||
@@ -45,10 +45,6 @@ namespace VoxelPassageGeometry
|
||||
// ownership band: the floor writer owns the plane, while the air writer owns the capsule
|
||||
// volume above it even when two overlapping passage projections differ by a fraction.
|
||||
constexpr float WalkableTunnelFloorAirClearanceVoxels = 0.5f;
|
||||
// The graph-tunnel post owns the interior above its floor after terrain and passage-floor
|
||||
// writers have run. The support-floor predicate is also an exclusion mask for the air post,
|
||||
// so overlapping graph tubes cannot erase one another's walkable support band.
|
||||
constexpr float CaveTunnelAirCoreInsetVoxels = 0.5f;
|
||||
|
||||
// A 15 degree ramp is comfortably below the 44 degree engine walkability ceiling. The
|
||||
// latter is a scramble limit, not a sensible default for a tunnel the player walks through.
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
int32 GetSeasonSeed() const { return SeasonSeed; }
|
||||
float GetOriginSpineRadius() const { return OriginSpineRadius; }
|
||||
float GetWorldRadiusVoxels() const { return WorldRadiusVoxels; }
|
||||
const FString& GetManifestContentHash() const { return ManifestContentHash; }
|
||||
|
||||
/** Create the asset in Content Browser, choose a JSON file, then press this button. */
|
||||
UFUNCTION(CallInEditor, Category = "Season")
|
||||
|
||||
@@ -134,10 +134,6 @@ struct VOXELFORGE_API FVoxelSeasonCompositionSettings
|
||||
}
|
||||
};
|
||||
|
||||
// Friendly aliases for callers that use the task's shorter naming.
|
||||
using FVoxelSeasonComposerSettings = FVoxelSeasonCompositionSettings;
|
||||
using FVoxelSeasonComposeSettings = FVoxelSeasonCompositionSettings;
|
||||
|
||||
/** Compact audit row; the full vectors live only for selected strates. */
|
||||
struct VOXELFORGE_API FVoxelSeasonCandidateAudit
|
||||
{
|
||||
@@ -260,10 +256,6 @@ struct VOXELFORGE_API FVoxelSeasonManifest
|
||||
}
|
||||
};
|
||||
|
||||
/** Human-readable enum names used by JSON and the review page. */
|
||||
VOXELFORGE_API const TCHAR* VF_GetVoxelSeasonSelectionReasonName(
|
||||
EVoxelSeasonSelectionReason Reason);
|
||||
|
||||
/** Compose, validate, select, serialize, and (by default) write one season. Editor/build-box only. */
|
||||
#if WITH_EDITOR
|
||||
VOXELFORGE_API FVoxelSeasonManifest VF_ComposeSeason(
|
||||
|
||||
@@ -48,15 +48,6 @@ public:
|
||||
uint64 RetainedSamples = 0;
|
||||
uint64 DroppedSamples = 0;
|
||||
uint64 TotalFrames = 0;
|
||||
// Kept for source compatibility with the earlier in-process summary. Raw sessions leave
|
||||
// these zero; the offline summary owns all resolved-frame counts and tables.
|
||||
uint64 ResolvedFrames = 0;
|
||||
uint64 UnknownFrames = 0;
|
||||
uint64 WaitLikeFrames = 0;
|
||||
uint64 SamplesWithResolvedLeaf = 0;
|
||||
uint64 SamplesWithWaitLikeFrame = 0;
|
||||
uint64 UniqueProgramCounters = 0;
|
||||
uint64 InlineSymbols = 0;
|
||||
uint64 MaxActiveRegisteredThreads = 0;
|
||||
uint64 ModuleCount = 0;
|
||||
double RunSeconds = 0.0;
|
||||
@@ -78,8 +69,6 @@ public:
|
||||
/** Used by the module shutdown path as a final lifecycle backstop. */
|
||||
void Shutdown();
|
||||
|
||||
bool IsRunning() const;
|
||||
|
||||
/** Called only by FScopedVoxelStackRegistration; cheap when disabled. */
|
||||
static bool RegisterCurrentThread(int32 LODLevel = INDEX_NONE);
|
||||
static void DeregisterCurrentThread();
|
||||
|
||||
@@ -594,11 +594,6 @@ public:
|
||||
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. */
|
||||
@@ -625,7 +620,6 @@ public:
|
||||
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;
|
||||
@@ -804,10 +798,6 @@ VOXELFORGE_API uint32 VF_HashStrateStructureRecipe(const FVoxelOpStackRecipe& Re
|
||||
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);
|
||||
|
||||
@@ -249,15 +249,6 @@ public:
|
||||
* live edit) can never serve a stale strate index or passage shortlist. */
|
||||
uint32 GetLayoutVersion() const { return PassagesVersion; }
|
||||
|
||||
/**
|
||||
* Fingerprint of the immutable density inputs used by the generator.
|
||||
*
|
||||
* Returns zero when the manager has dynamic inputs that this compact cache key intentionally
|
||||
* does not serialize (seasons, composer recipes, biome maps, or terrain-op assets). Zero is a
|
||||
* fail-closed answer: callers must skip verdict reuse rather than risk an old all-air proof.
|
||||
*/
|
||||
uint64 GetGenerationParamsFingerprint() const;
|
||||
|
||||
/** Diagnostic-only switch for isolating the inter-strate support writer. */
|
||||
void SetPassageSupportFloorWritesEnabledForDiagnostics(bool bEnabled)
|
||||
{
|
||||
@@ -289,7 +280,7 @@ public:
|
||||
* Get generation params for a chunk, with boundary blending.
|
||||
*
|
||||
* BLENDING CONCEPT:
|
||||
* When a chunk is near a strate boundary (within BlendChunks of the edge),
|
||||
* When a chunk is near a strate boundary (within the definition's TransitionBlendChunks of the edge),
|
||||
* the params are lerped between the two adjacent strates. This prevents
|
||||
* hard visual seams where one strate ends and another begins.
|
||||
*
|
||||
@@ -419,14 +410,6 @@ public:
|
||||
void ApplyPassageTunnelAir(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const;
|
||||
|
||||
/** Re-assert landing air after MC-space disturbances, still before the final XY seal. */
|
||||
void ApplyPassageLandingAirMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const;
|
||||
|
||||
/** Re-assert walkable tunnel air after MC-space disturbances, still before the final XY seal. */
|
||||
void ApplyPassageTunnelAirMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const;
|
||||
|
||||
/** Apply the landing/tunnel MC post in one cached passage scan after disturbances. */
|
||||
void ApplyPassageStructuralPostsMC(float& Density, float WorldX, float WorldY, float WorldZ,
|
||||
float BaseDensity, float SealThickness) const;
|
||||
@@ -530,9 +513,6 @@ protected:
|
||||
// allocator address reuse must not make a stale worker-local stack look current.
|
||||
uint64 CacheLifetimeId = 0;
|
||||
|
||||
// How many chunks at strate boundaries are blended (transition zone)
|
||||
int32 BlendChunks = 2;
|
||||
|
||||
// World seed (stored for passage generation)
|
||||
int32 CachedSeed = 0;
|
||||
|
||||
|
||||
@@ -510,23 +510,6 @@ VOXELFORGE_API FVoxelConnectivityDiagnostics VF_DiagnoseConnectivityWithSampler(
|
||||
const FVector& BVoxel,
|
||||
const FVoxelStrateMeasureSettings& Settings);
|
||||
|
||||
/**
|
||||
* Player-fit connectivity over a custom stack. This is deliberately a separate API from the
|
||||
* legacy air route: it refuses unless Settings.SampleStep == 1, resolves endpoints against the
|
||||
* direct capsule-occupancy/floor mask, and flood-fills/routes only through player-fit cells.
|
||||
*/
|
||||
VOXELFORGE_API EVoxelConnectivityResult VF_ArePlayerFitConnectedWithSampler(
|
||||
const IVoxelStrateDensitySampler& Sampler,
|
||||
int32 StrateBottomWorldZ,
|
||||
int32 StrateTopWorldZ,
|
||||
float BoundarySealThickness,
|
||||
const FVector& AVoxel,
|
||||
const FVector& BVoxel,
|
||||
const FVoxelStrateMeasureSettings& Settings,
|
||||
bool& bOutStartSnapped,
|
||||
bool& bOutGoalSnapped,
|
||||
FVoxelConnectivityDiagnostics* OutDiagnostics = nullptr);
|
||||
|
||||
/** Full diagnostics variant for the player-fit custom-stack route. */
|
||||
VOXELFORGE_API FVoxelConnectivityDiagnostics VF_DiagnosePlayerFitConnectivityWithSampler(
|
||||
const IVoxelStrateDensitySampler& Sampler,
|
||||
|
||||
@@ -411,14 +411,4 @@ namespace VoxelGenLOD
|
||||
Density = Before;
|
||||
}
|
||||
|
||||
/** Compare a scalar proof input such as EvaluateModifierSDF without changing the field. */
|
||||
FORCEINLINE void CompareSkippedPostValue(
|
||||
float Candidate, float Canonical,
|
||||
ETilePostComparisonKind Kind = ETilePostComparisonKind::Other)
|
||||
{
|
||||
if (bTilePostReachDebug && !bTilePostReachBypass)
|
||||
{
|
||||
RecordSkippedPostComparison(Kind, !SameFloatBits(Candidate, Canonical));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,9 +209,7 @@ namespace VoxelMath
|
||||
// règle côté RENDU (ombres off sur LOD lointain, voir ApplyMeshToChunk), pas via la
|
||||
// taille de chunk. La taille de chunk reste le levier streaming-vs-draws si besoin.
|
||||
|
||||
constexpr int32 CHUNK_SIZE = 32;
|
||||
constexpr int32 CHUNK_SIZE_SQUARED = CHUNK_SIZE * CHUNK_SIZE; // 1024
|
||||
constexpr int32 CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; // 32768
|
||||
constexpr int32 CHUNK_SIZE = 32;
|
||||
|
||||
constexpr float VOXEL_SIZE = 25.0f;
|
||||
|
||||
@@ -276,26 +274,6 @@ enum class EVoxelFace : uint8
|
||||
NegativeZ, // Down (-Z)
|
||||
};
|
||||
|
||||
inline FIntVector GetFaceDirection(EVoxelFace Face)
|
||||
{
|
||||
switch (Face)
|
||||
{
|
||||
case EVoxelFace::PositiveX: return FIntVector( 1, 0, 0);
|
||||
case EVoxelFace::NegativeX: return FIntVector(-1, 0, 0);
|
||||
case EVoxelFace::PositiveY: return FIntVector( 0, 1, 0);
|
||||
case EVoxelFace::NegativeY: return FIntVector( 0, -1, 0);
|
||||
case EVoxelFace::PositiveZ: return FIntVector( 0, 0, 1);
|
||||
case EVoxelFace::NegativeZ: return FIntVector( 0, 0, -1);
|
||||
default: return FIntVector( 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline FVector GetFaceNormal(EVoxelFace Face)
|
||||
{
|
||||
const FIntVector Dir = GetFaceDirection(Face);
|
||||
return FVector(Dir.X, Dir.Y, Dir.Z);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// COORDINATE CONVERSION
|
||||
//=============================================================================
|
||||
@@ -319,53 +297,6 @@ inline FIntVector WorldToChunkCoord(const FVector& WorldPos)
|
||||
);
|
||||
}
|
||||
|
||||
inline FIntVector WorldToLocalCoord(const FVector& WorldPos)
|
||||
{
|
||||
// ((x % n) + n) % n → modulo positif même pour x négatif.
|
||||
// (-5 % 32) = -5 en C++, mais on veut 27.
|
||||
return FIntVector(
|
||||
((FMath::FloorToInt(WorldPos.X / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE,
|
||||
((FMath::FloorToInt(WorldPos.Y / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE,
|
||||
((FMath::FloorToInt(WorldPos.Z / VOXEL_SIZE) % CHUNK_SIZE) + CHUNK_SIZE) % CHUNK_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
inline FVector ChunkToWorldPos(const FIntVector& ChunkCoord)
|
||||
{
|
||||
return FVector(
|
||||
ChunkCoord.X * CHUNK_SIZE * VOXEL_SIZE,
|
||||
ChunkCoord.Y * CHUNK_SIZE * VOXEL_SIZE,
|
||||
ChunkCoord.Z * CHUNK_SIZE * VOXEL_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
// Index 3D → 1D pour un tableau plat (voir doc CLAUDE.md: "x + y*SizeX + z*SizeX*SizeY").
|
||||
inline int32 LocalToIndex(int32 X, int32 Y, int32 Z)
|
||||
{
|
||||
return X + (Y * CHUNK_SIZE) + (Z * CHUNK_SIZE_SQUARED);
|
||||
}
|
||||
|
||||
inline FIntVector IndexToLocal(int32 Index)
|
||||
{
|
||||
return FIntVector(
|
||||
Index % CHUNK_SIZE,
|
||||
(Index / CHUNK_SIZE) % CHUNK_SIZE,
|
||||
Index / CHUNK_SIZE_SQUARED
|
||||
);
|
||||
}
|
||||
|
||||
inline bool IsValidLocalCoord(int32 X, int32 Y, int32 Z)
|
||||
{
|
||||
return X >= 0 && X < CHUNK_SIZE
|
||||
&& Y >= 0 && Y < CHUNK_SIZE
|
||||
&& Z >= 0 && Z < CHUNK_SIZE;
|
||||
}
|
||||
|
||||
inline bool IsValidLocalCoord(const FIntVector& Coord)
|
||||
{
|
||||
return IsValidLocalCoord(Coord.X, Coord.Y, Coord.Z);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MATH HELPERS (partagés entre générateur, morphologie, manager)
|
||||
//=============================================================================
|
||||
|
||||
@@ -17,14 +17,6 @@ namespace VoxelWormField
|
||||
};
|
||||
|
||||
/** Evaluate the exact two-noise field, retaining the N1 threshold short-circuit. */
|
||||
VOXELFORGE_API float EvaluateExact(
|
||||
float WorldX,
|
||||
float WorldY,
|
||||
float WorldZ,
|
||||
float Threshold,
|
||||
const FParameters& Parameters);
|
||||
|
||||
/** Evaluate the exact two-noise field. */
|
||||
VOXELFORGE_API float Evaluate(
|
||||
float WorldX,
|
||||
float WorldY,
|
||||
|
||||
@@ -4243,76 +4243,6 @@ bool WriteObjHeader(FArchive& Archive)
|
||||
return bOk && !Archive.IsError();
|
||||
}
|
||||
|
||||
bool WriteObjTile(
|
||||
FArchive& Archive,
|
||||
const FVoxelMeshData& MeshData,
|
||||
int32 VertexOffset,
|
||||
FString& OutError)
|
||||
{
|
||||
if (!ValidateCanonicalTile(MeshData, OutError))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool bOk = true;
|
||||
for (const FVector& Vertex : MeshData.Vertices)
|
||||
{
|
||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
||||
TEXT("v %.9f %.9f %.9f\n"),
|
||||
Vertex.X / 100.0,
|
||||
Vertex.Y / 100.0,
|
||||
Vertex.Z / 100.0));
|
||||
}
|
||||
for (const FVector2D& UV : MeshData.UVs)
|
||||
{
|
||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
||||
TEXT("vt %.9f %.9f\n"), UV.X, UV.Y));
|
||||
}
|
||||
for (const FVector& Normal : MeshData.Normals)
|
||||
{
|
||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
||||
TEXT("vn %.9f %.9f %.9f\n"), Normal.X, Normal.Y, Normal.Z));
|
||||
}
|
||||
|
||||
const int32 NumTriangles = MeshData.Triangles.Num() / 3;
|
||||
const int32 FirstCeilingTriangle = FMath::Clamp(
|
||||
NumTriangles - MeshData.NumCeilingTriangles, 0, NumTriangles);
|
||||
if (NumTriangles > 0)
|
||||
{
|
||||
bOk = bOk && WriteUtf8(Archive, TEXT("usemtl VoxelGround\n"));
|
||||
}
|
||||
for (int32 Triangle = 0; Triangle < NumTriangles; ++Triangle)
|
||||
{
|
||||
if (Triangle == FirstCeilingTriangle)
|
||||
{
|
||||
bOk = bOk && WriteUtf8(Archive, TEXT("usemtl VoxelCeiling\n"));
|
||||
}
|
||||
const int32 Base = Triangle * 3;
|
||||
const int32 SourceA = MeshData.Triangles[Base];
|
||||
const int32 SourceB = MeshData.Triangles[Base + 1];
|
||||
const int32 SourceC = MeshData.Triangles[Base + 2];
|
||||
if (SourceA < 0 || SourceB < 0 || SourceC < 0
|
||||
|| SourceA >= MeshData.Vertices.Num()
|
||||
|| SourceB >= MeshData.Vertices.Num()
|
||||
|| SourceC >= MeshData.Vertices.Num())
|
||||
{
|
||||
OutError = TEXT("Canonical mesher returned an out-of-range triangle index.");
|
||||
return false;
|
||||
}
|
||||
const int32 A = SourceA + 1 + VertexOffset;
|
||||
const int32 B = SourceB + 1 + VertexOffset;
|
||||
const int32 C = SourceC + 1 + VertexOffset;
|
||||
bOk = bOk && WriteUtf8(Archive, FString::Printf(
|
||||
TEXT("f %d/%d/%d %d/%d/%d %d/%d/%d\n"),
|
||||
A, A, A, B, B, B, C, C, C));
|
||||
}
|
||||
if (!bOk || Archive.IsError())
|
||||
{
|
||||
OutError = TEXT("Could not write a canonical OBJ tile.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteObjMesh(
|
||||
FArchive& Archive,
|
||||
const FVoxelMeshData& MeshData,
|
||||
@@ -7091,29 +7021,6 @@ FString BuildExploreJson(
|
||||
return Writer->Close() ? Json : FString();
|
||||
}
|
||||
|
||||
const TCHAR* ExploreEffectName(EVoxelOpEffect Effect)
|
||||
{
|
||||
switch (Effect)
|
||||
{
|
||||
case EVoxelOpEffect::Identity: return TEXT("Identity");
|
||||
case EVoxelOpEffect::CarveOnly: return TEXT("CarveOnly");
|
||||
case EVoxelOpEffect::FillOnly: return TEXT("FillOnly");
|
||||
case EVoxelOpEffect::Both: return TEXT("Both");
|
||||
default: return TEXT("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
const TCHAR* ExploreTileClassName(EVoxelTileClass Class)
|
||||
{
|
||||
switch (Class)
|
||||
{
|
||||
case EVoxelTileClass::AllSolid: return TEXT("AllSolid");
|
||||
case EVoxelTileClass::AllAir: return TEXT("AllAir");
|
||||
case EVoxelTileClass::Mixed: return TEXT("Mixed");
|
||||
default: return TEXT("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
// Density-bound APIs use FLT_MAX as the documented "unknown/unbounded" sentinel. It is finite
|
||||
// according to IEEE-754, so FMath::IsFinite alone would misreport the very failure this audit is
|
||||
// intended to expose as a real numeric envelope.
|
||||
|
||||
Reference in new issue
Block a user