wip: cave planner route support fixed (L134 design 3); clearance at edge joints open
Arrival edge floor aligned to the passage mouth, 0.75 m backbone floor-support budget, anchors on the planned floor: 0 unsupported, 0 grade failures. Open: 196/50,967 capsule samples blocked where a higher descending edge's floor backing meets the next edge (route-edge-6/7). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
75c6ad251d
commit
379093401e
8 files changed
+102
-54
No files matched your search
@@ -498,7 +498,7 @@ namespace VoxelForgeCore
|
|||||||
// voxels for every broadphase and proof bound. Version 227 uses the exact smooth-max
|
// voxels for every broadphase and proof bound. Version 227 uses the exact smooth-max
|
||||||
// support width/6 when deriving that reach. Version 228 composes deterministic cave
|
// support width/6 when deriving that reach. Version 228 composes deterministic cave
|
||||||
// graphs from fixed passage mouths and the owner Tunnel Network settings.
|
// graphs from fixed passage mouths and the owner Tunnel Network settings.
|
||||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 228;
|
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 229;
|
||||||
|
|
||||||
enum class FieldChannel : std::uint32_t
|
enum class FieldChannel : std::uint32_t
|
||||||
{
|
{
|
||||||
@@ -1001,6 +1001,9 @@ namespace VoxelForgeCore
|
|||||||
std::int64_t minimumRoomRadiusMicrometres = 2000000;
|
std::int64_t minimumRoomRadiusMicrometres = 2000000;
|
||||||
std::int64_t maximumRoomRadiusMicrometres = 5000000;
|
std::int64_t maximumRoomRadiusMicrometres = 5000000;
|
||||||
std::int64_t destinationRadiusMicrometres = 6000000;
|
std::int64_t destinationRadiusMicrometres = 6000000;
|
||||||
|
// Solid floor backing below the planned edge floor, preserved after graph
|
||||||
|
// unions and passage composition. This is separate from bore height.
|
||||||
|
std::int64_t floorSupportDepthMicrometres = 750000;
|
||||||
std::int64_t minimumTunnelRadiusMicrometres = 750000;
|
std::int64_t minimumTunnelRadiusMicrometres = 750000;
|
||||||
std::int64_t maximumTunnelRadiusMicrometres = 1000000;
|
std::int64_t maximumTunnelRadiusMicrometres = 1000000;
|
||||||
std::int64_t maximumTunnelLengthMicrometres = 45000000;
|
std::int64_t maximumTunnelLengthMicrometres = 45000000;
|
||||||
|
|||||||
@@ -2048,6 +2048,8 @@ bool PlanResolvedCavernNetworkV1(const ResolvedLayoutSnapshotV3& layout,
|
|||||||
||settings.maximumRoomRadiusMicrometres>100000000
|
||settings.maximumRoomRadiusMicrometres>100000000
|
||||||
||settings.destinationRadiusMicrometres<settings.maximumRoomRadiusMicrometres
|
||settings.destinationRadiusMicrometres<settings.maximumRoomRadiusMicrometres
|
||||||
||settings.destinationRadiusMicrometres>100000000
|
||settings.destinationRadiusMicrometres>100000000
|
||||||
|
||settings.floorSupportDepthMicrometres<250000
|
||||||
|
||settings.floorSupportDepthMicrometres>2000000
|
||||||
||settings.maximumTunnelLengthMicrometres<=0
|
||settings.maximumTunnelLengthMicrometres<=0
|
||||||
||settings.minimumTunnelRadiusMicrometres<0
|
||settings.minimumTunnelRadiusMicrometres<0
|
||||||
||settings.maximumTunnelRadiusMicrometres<settings.minimumTunnelRadiusMicrometres
|
||settings.maximumTunnelRadiusMicrometres<settings.minimumTunnelRadiusMicrometres
|
||||||
@@ -2081,7 +2083,6 @@ bool PlanResolvedCavernNetworkV1(const ResolvedLayoutSnapshotV3& layout,
|
|||||||
constexpr std::int64_t MinimumBoreHeight=2200000;
|
constexpr std::int64_t MinimumBoreHeight=2200000;
|
||||||
constexpr std::int64_t PlannedBoreHeight=4500000;
|
constexpr std::int64_t PlannedBoreHeight=4500000;
|
||||||
constexpr std::int64_t MouthOverlap=3000000;
|
constexpr std::int64_t MouthOverlap=3000000;
|
||||||
constexpr std::int64_t MouthFloorOffset=750000;
|
|
||||||
constexpr std::int64_t MaximumBoreRadius=10000000;
|
constexpr std::int64_t MaximumBoreRadius=10000000;
|
||||||
constexpr std::int64_t MaximumWalkGradeDenominator=5; // 1:5 = 11.31 degrees.
|
constexpr std::int64_t MaximumWalkGradeDenominator=5; // 1:5 = 11.31 degrees.
|
||||||
const auto integerSqrt=[](std::uint64_t value)
|
const auto integerSqrt=[](std::uint64_t value)
|
||||||
@@ -2113,7 +2114,6 @@ bool PlanResolvedCavernNetworkV1(const ResolvedLayoutSnapshotV3& layout,
|
|||||||
for(std::size_t axis=0;axis<3;++axis)
|
for(std::size_t axis=0;axis<3;++axis)
|
||||||
point[axis]=qToMicrometres(lowerSide?passage.lowerMouthSubvoxels[axis]
|
point[axis]=qToMicrometres(lowerSide?passage.lowerMouthSubvoxels[axis]
|
||||||
:passage.upperMouthSubvoxels[axis]);
|
:passage.upperMouthSubvoxels[axis]);
|
||||||
point[2]-=MouthFloorOffset;
|
|
||||||
if(passage.controlPoints.size()<2)return false;
|
if(passage.controlPoints.size()<2)return false;
|
||||||
const std::size_t mouthIndex=lowerSide
|
const std::size_t mouthIndex=lowerSide
|
||||||
?std::min(passage.lowerMouthControlIndex,passage.controlPoints.size()-1):0;
|
?std::min(passage.lowerMouthControlIndex,passage.controlPoints.size()-1):0;
|
||||||
@@ -2381,7 +2381,7 @@ bool PlanResolvedCavernNetworkV1(const ResolvedLayoutSnapshotV3& layout,
|
|||||||
edge.endRoomStableId=componentRoomId(endNode);edge.strateIndex=strateIndex;
|
edge.endRoomStableId=componentRoomId(endNode);edge.strateIndex=strateIndex;
|
||||||
edge.boreRadiusMicrometres=boreRadius;
|
edge.boreRadiusMicrometres=boreRadius;
|
||||||
edge.boreHeightMicrometres=std::max(PlannedBoreHeight,MinimumBoreHeight);
|
edge.boreHeightMicrometres=std::max(PlannedBoreHeight,MinimumBoreHeight);
|
||||||
edge.floorSupportDepthMicrometres=0;
|
edge.floorSupportDepthMicrometres=settings.floorSupportDepthMicrometres;
|
||||||
edge.smoothWidthMicrometres=smooth;
|
edge.smoothWidthMicrometres=smooth;
|
||||||
edge.irregularityAmplitudeMicrometres=irregularity;
|
edge.irregularityAmplitudeMicrometres=irregularity;
|
||||||
edge.irregularityWavelengthMicrometres=settings.irregularityWavelengthMicrometres;
|
edge.irregularityWavelengthMicrometres=settings.irregularityWavelengthMicrometres;
|
||||||
@@ -2447,12 +2447,17 @@ bool PlanResolvedCavernNetworkV1(const ResolvedLayoutSnapshotV3& layout,
|
|||||||
makeCompound(branch,false,rooms);
|
makeCompound(branch,false,rooms);
|
||||||
const std::string branchEdgeId="tunnel-network/strate-"
|
const std::string branchEdgeId="tunnel-network/strate-"
|
||||||
+std::to_string(strateIndex)+"/side-edge-"+std::to_string(branchCount);
|
+std::to_string(strateIndex)+"/side-edge-"+std::to_string(branchCount);
|
||||||
|
ResolvedCavernEdgeV1 branchEdge;
|
||||||
if(settings.tunnelsFlowTowardOrigin)
|
if(settings.tunnelsFlowTowardOrigin)
|
||||||
edges.push_back(makeEdge(branchEdgeId,componentRoomId(branch),
|
branchEdge=makeEdge(branchEdgeId,componentRoomId(branch),
|
||||||
branch.point,parent,selectedBoreRadius(branchEdgeId)));
|
branch.point,parent,selectedBoreRadius(branchEdgeId));
|
||||||
else
|
else
|
||||||
edges.push_back(makeEdge(branchEdgeId,componentRoomId(parent),
|
branchEdge=makeEdge(branchEdgeId,componentRoomId(parent),
|
||||||
parent.point,branch,selectedBoreRadius(branchEdgeId)));
|
parent.point,branch,selectedBoreRadius(branchEdgeId));
|
||||||
|
// Side branches retain their cave floor SDF, but they do not cap the
|
||||||
|
// descending backbone when their tubes overlap it near a junction.
|
||||||
|
branchEdge.floorSupportDepthMicrometres=0;
|
||||||
|
edges.push_back(std::move(branchEdge));
|
||||||
++branchCount;
|
++branchCount;
|
||||||
}
|
}
|
||||||
if(nodes.empty()||rooms.empty()||edges.empty())
|
if(nodes.empty()||rooms.empty()||edges.empty())
|
||||||
|
|||||||
@@ -1513,13 +1513,13 @@ public:
|
|||||||
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
|
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
|
||||||
{
|
{
|
||||||
float graphDensity=0.0f;
|
float graphDensity=0.0f;
|
||||||
float nativeLatticeFloorSupport=std::numeric_limits<float>::lowest();
|
float nativeGraphFloorSupport=std::numeric_limits<float>::lowest();
|
||||||
{
|
{
|
||||||
VoxelForgeCore::Linux77Profiler::FScopedPhase l77GraphPhase(
|
VoxelForgeCore::Linux77Profiler::FScopedPhase l77GraphPhase(
|
||||||
VoxelForgeCore::Linux77Profiler::EPhase::CompositionGraph);
|
VoxelForgeCore::Linux77Profiler::EPhase::CompositionGraph);
|
||||||
FScopedLegacyFieldTermTimer TermTimer(ELegacyFieldTerm::ComposerCavern);
|
FScopedLegacyFieldTermTimer TermTimer(ELegacyFieldTerm::ComposerCavern);
|
||||||
graphDensity=ApplyResolvedCavernGraph(density,X,Y,Z,
|
graphDensity=ApplyResolvedCavernGraph(density,X,Y,Z,
|
||||||
&nativeLatticeFloorSupport);
|
&nativeGraphFloorSupport);
|
||||||
}
|
}
|
||||||
const auto* bound=FindBoundStratumForManagerZ(Z);
|
const auto* bound=FindBoundStratumForManagerZ(Z);
|
||||||
const bool nativeLattice=bound&&bound->Resolved
|
const bool nativeLattice=bound&&bound->Resolved
|
||||||
@@ -1573,7 +1573,7 @@ public:
|
|||||||
const float nativeTunnelFieldDensity=nativeTunnelField
|
const float nativeTunnelFieldDensity=nativeTunnelField
|
||||||
?graphDensity:std::numeric_limits<float>::lowest();
|
?graphDensity:std::numeric_limits<float>::lowest();
|
||||||
stamped=ApplyResolvedStratePassageCarves(stamped,X,Y,Z,
|
stamped=ApplyResolvedStratePassageCarves(stamped,X,Y,Z,
|
||||||
nativeTunnelFieldDensity,nativeLatticeFloorSupport);
|
nativeTunnelFieldDensity,nativeGraphFloorSupport);
|
||||||
}
|
}
|
||||||
if(bTraceTnComposition)
|
if(bTraceTnComposition)
|
||||||
std::printf("[L75TNCompositionTrace] input=%.9g graph=%.9g boundary=%.9g passage=%.9g stamp=%.9g native=1\n",
|
std::printf("[L75TNCompositionTrace] input=%.9g graph=%.9g boundary=%.9g passage=%.9g stamp=%.9g native=1\n",
|
||||||
@@ -5284,11 +5284,7 @@ public:
|
|||||||
FMetricInterval caveVoid{std::numeric_limits<double>::infinity(),
|
FMetricInterval caveVoid{std::numeric_limits<double>::infinity(),
|
||||||
std::numeric_limits<double>::infinity(),true};
|
std::numeric_limits<double>::infinity(),true};
|
||||||
bool haveFeature=false;
|
bool haveFeature=false;
|
||||||
double latticeFloorSupportLowerBound=std::numeric_limits<double>::infinity();
|
double nativeFloorSupportLowerBound=std::numeric_limits<double>::infinity();
|
||||||
const auto* resolvedStratum=FindResolvedLayoutStratum(strateIndex);
|
|
||||||
const bool nativeLattice=resolvedStratum
|
|
||||||
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*resolvedStratum)
|
|
||||||
&&resolvedStratum->passageCapabilities.hasNativeLatticeField;
|
|
||||||
for(const std::uint32_t index:candidates)
|
for(const std::uint32_t index:candidates)
|
||||||
{
|
{
|
||||||
if(index>=CavernRuntime.size())continue;
|
if(index>=CavernRuntime.size())continue;
|
||||||
@@ -5440,21 +5436,19 @@ public:
|
|||||||
SmoothMaxMetres(tube.maximum,floor.maximum,width),true};
|
SmoothMaxMetres(tube.maximum,floor.maximum,width),true};
|
||||||
}
|
}
|
||||||
else return {0.0,0.0,false};
|
else return {0.0,0.0,false};
|
||||||
if(nativeLattice)
|
if(feature.edge)
|
||||||
{
|
{
|
||||||
const double supportDepth=feature.edge
|
const double supportDepth=
|
||||||
?feature.edge->floorSupportDepthMicrometres/1000000.0:0.0;
|
feature.edge->floorSupportDepthMicrometres/1000000.0;
|
||||||
const double floorMinimum=feature.edge
|
const double floorMinimum=feature.minimumFloorMetres;
|
||||||
?feature.minimumFloorMetres:std::numeric_limits<double>::infinity();
|
const double floorMaximum=feature.maximumFloorMetres;
|
||||||
const double floorMaximum=feature.edge
|
|
||||||
?feature.maximumFloorMetres:-std::numeric_limits<double>::infinity();
|
|
||||||
const bool overlapsXY=hi[0]>=feature.boundsMinimumMicrometres[0]/1.0e6
|
const bool overlapsXY=hi[0]>=feature.boundsMinimumMicrometres[0]/1.0e6
|
||||||
&&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6
|
&&lo[0]<=feature.boundsMaximumMicrometres[0]/1.0e6
|
||||||
&&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6
|
&&hi[1]>=feature.boundsMinimumMicrometres[1]/1.0e6
|
||||||
&&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6;
|
&&lo[1]<=feature.boundsMaximumMicrometres[1]/1.0e6;
|
||||||
if(supportDepth>0.0&&overlapsXY
|
if(supportDepth>0.0&&overlapsXY
|
||||||
&&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum)
|
&&hi[2]>=floorMinimum-supportDepth&&lo[2]<=floorMaximum)
|
||||||
latticeFloorSupportLowerBound=std::min(latticeFloorSupportLowerBound,
|
nativeFloorSupportLowerBound=std::min(nativeFloorSupportLowerBound,
|
||||||
std::max(-supportDepth,lo[2]-floorMaximum));
|
std::max(-supportDepth,lo[2]-floorMaximum));
|
||||||
}
|
}
|
||||||
if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum))
|
if(!std::isfinite(featureVoid.minimum)||!std::isfinite(featureVoid.maximum))
|
||||||
@@ -5483,11 +5477,11 @@ public:
|
|||||||
result.minimum=std::max(HostRockMetres,-caveVoid.maximum);
|
result.minimum=std::max(HostRockMetres,-caveVoid.maximum);
|
||||||
result.maximum=std::max(HostRockMetres,-caveVoid.minimum);
|
result.maximum=std::max(HostRockMetres,-caveVoid.minimum);
|
||||||
}
|
}
|
||||||
// The final lattice field owns an extra support cap after feature union.
|
// Native graph edges may own a support cap after feature union.
|
||||||
// Lower only the interval minimum when a box could touch that cap; the
|
// Lower only the interval minimum when a box could touch that cap; the
|
||||||
// untouched maximum remains a sound bound when only part of the box does.
|
// untouched maximum remains a sound bound when only part of the box does.
|
||||||
if(std::isfinite(latticeFloorSupportLowerBound))
|
if(std::isfinite(nativeFloorSupportLowerBound))
|
||||||
result.minimum=std::min(result.minimum,latticeFloorSupportLowerBound);
|
result.minimum=std::min(result.minimum,nativeFloorSupportLowerBound);
|
||||||
// Cover floating-point rounding in interval endpoints and the field's fixed-point
|
// Cover floating-point rounding in interval endpoints and the field's fixed-point
|
||||||
// coordinate conversion while keeping the interval tight compared with one micron.
|
// coordinate conversion while keeping the interval tight compared with one micron.
|
||||||
constexpr double OutwardPaddingMetres=1.0e-6;
|
constexpr double OutwardPaddingMetres=1.0e-6;
|
||||||
@@ -7465,10 +7459,10 @@ private:
|
|||||||
candidates=&localCandidates;
|
candidates=&localCandidates;
|
||||||
}
|
}
|
||||||
double caveVoid=std::numeric_limits<double>::infinity();
|
double caveVoid=std::numeric_limits<double>::infinity();
|
||||||
double latticeFloorSupportMinimum=std::numeric_limits<double>::infinity();
|
double nativeFloorSupportMinimum=std::numeric_limits<double>::infinity();
|
||||||
const bool nativeLattice=bound.Resolved
|
double floorSupportScore=std::numeric_limits<double>::infinity();
|
||||||
&&VoxelForgeCore::IsNativeLatticeFieldStratum(*bound.Resolved)
|
double floorSupportDepth=0.0,floorSupportFloor=0.0,floorSupportGrade=0.0;
|
||||||
&&bound.Resolved->passageCapabilities.hasNativeLatticeField;
|
const std::string* floorSupportEdgeId=nullptr;
|
||||||
for(const std::uint32_t index:*candidates)
|
for(const std::uint32_t index:*candidates)
|
||||||
{
|
{
|
||||||
if(index>=CavernRuntime.size())continue;
|
if(index>=CavernRuntime.size())continue;
|
||||||
@@ -7598,11 +7592,25 @@ private:
|
|||||||
}
|
}
|
||||||
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
|
else for(std::uint32_t segment=0;segment<feature.segments.size();++segment)
|
||||||
evaluateSegment(segment);
|
evaluateSegment(segment);
|
||||||
const double supportDepth=feature.edge->floorSupportDepthMicrometres/1000000.0;
|
const double candidateSupportDepth=
|
||||||
if(nativeLattice&&supportDepth>0.0&&nearestRadial<radius-0.12
|
feature.edge->floorSupportDepthMicrometres/1000000.0;
|
||||||
&&point[2]<nearestFloor&&nearestFloor-point[2]<=supportDepth)
|
if(candidateSupportDepth>0.0&&nearestRadial<radius-0.12
|
||||||
latticeFloorSupportMinimum=std::min(latticeFloorSupportMinimum,
|
&&std::abs(point[2]-nearestFloor)<=height)
|
||||||
(point[2]-nearestFloor)/std::sqrt(1.0+nearestGrade*nearestGrade));
|
{
|
||||||
|
const double deltaZ=point[2]-nearestFloor;
|
||||||
|
const double candidateScore=nearestRadial*nearestRadial+deltaZ*deltaZ;
|
||||||
|
if(candidateScore<floorSupportScore
|
||||||
|
||(candidateScore==floorSupportScore
|
||||||
|
&&(!floorSupportEdgeId
|
||||||
|
||feature.edge->stableId<*floorSupportEdgeId)))
|
||||||
|
{
|
||||||
|
floorSupportScore=candidateScore;
|
||||||
|
floorSupportDepth=candidateSupportDepth;
|
||||||
|
floorSupportFloor=nearestFloor;
|
||||||
|
floorSupportGrade=nearestGrade;
|
||||||
|
floorSupportEdgeId=&feature.edge->stableId;
|
||||||
|
}
|
||||||
|
}
|
||||||
const double floor=(nearestFloor-point[2])
|
const double floor=(nearestFloor-point[2])
|
||||||
/std::sqrt(1.0+nearestGrade*nearestGrade);
|
/std::sqrt(1.0+nearestGrade*nearestGrade);
|
||||||
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
|
const double width=feature.edge->smoothWidthMicrometres/1000000.0;
|
||||||
@@ -7619,6 +7627,10 @@ private:
|
|||||||
?feature.edge->unionWidthMicrometres
|
?feature.edge->unionWidthMicrometres
|
||||||
:feature.edge->smoothWidthMicrometres)/1000000.0);
|
:feature.edge->smoothWidthMicrometres)/1000000.0);
|
||||||
}
|
}
|
||||||
|
if(std::isfinite(floorSupportScore)&&point[2]<floorSupportFloor
|
||||||
|
&&floorSupportFloor-point[2]<=floorSupportDepth)
|
||||||
|
nativeFloorSupportMinimum=(point[2]-floorSupportFloor)
|
||||||
|
/std::sqrt(1.0+floorSupportGrade*floorSupportGrade);
|
||||||
// A versioned native caves recipe owns a solid host-rock field. The
|
// A versioned native caves recipe owns a solid host-rock field. The
|
||||||
// resolved interval oracle uses the same finite -32 m solid value; using
|
// resolved interval oracle uses the same finite -32 m solid value; using
|
||||||
// the underlying legacy generator density here would leak its unrelated
|
// the underlying legacy generator density here would leak its unrelated
|
||||||
@@ -7627,13 +7639,13 @@ private:
|
|||||||
const double hostDistance=HostRockMetres;
|
const double hostDistance=HostRockMetres;
|
||||||
double composed=std::isfinite(caveVoid)
|
double composed=std::isfinite(caveVoid)
|
||||||
?SmoothMaxMetres(hostDistance,-caveVoid,0.0):hostDistance;
|
?SmoothMaxMetres(hostDistance,-caveVoid,0.0):hostDistance;
|
||||||
// Keep the floor support owned by the lattice route after smooth-unioning
|
// Preserve each native graph edge's planned floor backing after smooth
|
||||||
// neighboring room and corridor voids. This cap is limited to each record's
|
// unions. The record's finite depth keeps independent routes from sealing
|
||||||
// explicit support depth so separated helix turns remain independent.
|
// one another when they pass at different elevations.
|
||||||
if(std::isfinite(latticeFloorSupportMinimum))
|
if(std::isfinite(nativeFloorSupportMinimum))
|
||||||
composed=std::min(composed,latticeFloorSupportMinimum);
|
composed=std::min(composed,nativeFloorSupportMinimum);
|
||||||
if(nativeFloorSupport&&std::isfinite(latticeFloorSupportMinimum))
|
if(nativeFloorSupport&&std::isfinite(nativeFloorSupportMinimum))
|
||||||
*nativeFloorSupport=static_cast<float>(latticeFloorSupportMinimum/metresPerVoxel);
|
*nativeFloorSupport=static_cast<float>(nativeFloorSupportMinimum/metresPerVoxel);
|
||||||
return static_cast<float>(composed/metresPerVoxel);
|
return static_cast<float>(composed/metresPerVoxel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
# Linux134 — Tunnel Network cave planner
|
# Linux134 — Tunnel Network cave planner
|
||||||
|
|
||||||
The second design fixed the incoming passage at its source. Native cave composition already called the shared passage composer, but that composer skipped passages whose lower layer used `hasNativeCaveField`. Removing that skip lets the passage field join the cave field through the boundary and also applies to native lattice layers. Tunnel Network dispatches `Caves-native` (`Core.Caves.PrimitiveField` v1).
|
Tunnel Network dispatches `Caves-native` (`Core.Caves.PrimitiveField` v1). The seed-0 plan is strict-valid: 30 compound rooms, 72 primitives, 31 edges, 3 side branches, and one larger destination chamber. The arrival-to-departure route is 387.067 m long, has a 59.021 m floor delta, and reaches 8.670° maximum grade. The planner maps 21 of the 47 legacy generation fields; the other 26 do not map to resolved room or edge record fields.
|
||||||
|
|
||||||
The seed-0 plan is strict-valid: 27 route nodes, 72 primitives in 30 compound rooms, 3 branches, 31 edges, and a 6.75 m destination chamber. The route is 387.067 m long with 59.021 m floor delta and 8.670° maximum grade. The passage centerline check now passes 21,425/21,425 samples. All three passage interfaces, shell/floor, ripple, and blocked controls pass.
|
The second design fixed the incoming passage at its source. Shared passage composition now applies passages when the lower stratum has a native cave field; the unchanged walkability audit passes 21,425/21,425 samples.
|
||||||
|
|
||||||
**Stopped at the Tunnel Network route-support gate.** `ResolvedStrateRouteAudit` reports 0 blocked capsule samples and 0 grade failures, but 380 unsupported samples. The first support failures are just inside the arrival mouth at `(19.166,-14.650,-754.254) m`, then `(19.080,-15.135,-754.327) m` through `(18.909,-16.106,-754.473) m`. Another failing sample cluster starts at `(17.364,-24.839,-755.788) m`. Overall: 795 center samples, 6,957 support probes, `mouth_binding=PASS`, `status=FAIL`. The arrival-to-departure route is therefore not yet walkable under the support audit. I stopped before the remaining bar.
|
The third design aligned the arrival-edge floor to the passage mouth, added a 0.75 m backbone floor-support budget to the resolved edge records, and raised route anchors to follow the planned edge floor. The route audit now reports 0 unsupported samples and 0 grade failures. It still fails clearance: 196/50,967 capsule samples are solid. The first is `(-14.548,-104.858,-768.115) m`, density `-0.042135`, at the route-edge-6/7 junction. Its closest planned floor is route-edge-6 at approximately `z=-768.104 m`; the probe is about 1.1 cm below that floor. The player center interpolated along the next route segment is only about 0.79 m above this higher neighboring floor, while the capsule samples extend 0.84 m below center. The native field is returning the intended solid floor backing, which intrudes into the capsule near the overlapping descending edges. The remaining issue is clearance planning across neighboring edge floors, not missing floor support, a room floor cut, or the inter-strate passage.
|
||||||
|
|
||||||
The planner maps 21/47 legacy fields into room/edge records: `RoomSpacing`, `RoomDensity`, `MinRoomRadius`, `MaxRoomRadius`, `RoomHeightRatio`, `RoomFloorCutMin`, `RoomFloorCutMax`, `RoomShapeVariety`, `OriginRoomRadius`, `OriginRoomMaxConnections`, `TunnelMinRadius`, `TunnelMaxRadius`, `TunnelDensity`, `MaxTunnelLength`, `TunnelWarpStrength`, `TunnelHorizontalBias`, `bTunnelsFlowTowardOrigin`, `CaveWarpStrength`, `SurfaceRoughness`, `RoughnessFrequency`, and `SDFBlendRadius`. The other 26 do not map: `BaseDensity`, `BoundarySealThickness`, `CaveWarpFrequency`, `DomainWarpFrequency`, `DomainWarpStrength`, `FloorBias`, `FloorReliefFrequency`, `FloorReliefStrength`, `RoomMouthRiseBlendVoxels`, `RoomMouthRiseStrength`, `TunnelEndpointZOffset`, `TunnelFloorGentleSlopeThreshold`, `TunnelFloorLedgeCountPreference`, `TunnelFloorMaxLedgeHeight`, `TunnelFloorMaxLedges`, `TunnelFloorTerraceStepHeight`, `VerticalScale`, `WaterLevelRelative`, `WormFrequency`, `WormHorizontalBias`, `WormNetworkRange`, `WormStrength`, `WormThreshold`, `bTunnelFloorEnabled`, `bTunnelFloorTerracingEnabled`, and `RoughnessNoiseType`.
|
I stopped at this failed route gate, as requested. Shell, floor, ripple, and blocked-route negative controls pass; the route's blocked control also detects the blockage. The rest of the bar was not run: seams, fast tier, Clang/GCC W1/W8/W12 determinism and baselines, captures, L80 timing, and the post-timing UE host build. Clang headless build passed; source stamp `9845de5d3d614db620bf99aa3bd7b4fd66a440d76676e38ccad3d198b851e476`.
|
||||||
|
|
||||||
Clang headless build passed (source stamp `e2cf59ad7ff10c1650c0f1cc5b99dab1c53439d128c9f263eb9848b3882723f5`). No GCC build, baselines, determinism matrix, captures, seams/fast tier, timing, or UE host build were run after the route-support failure. Logs: `Saved/Linux/l134/build-clang-second-design.log` and `Saved/Linux/l134/walk-gate-second-design.log`.
|
Logs: `Saved/Linux/l134/build-clang-support-fix.log` and `Saved/Linux/l134/walk-gate-support-fix.log`. Resolved layout: `layout-seed0-final-gate.json`.
|
||||||
|
|
||||||
|
Legacy field mapping: `RoomSpacing`, `RoomDensity`, `MinRoomRadius`, `MaxRoomRadius`, `RoomHeightRatio`, `RoomFloorCutMin`, `RoomFloorCutMax`, `RoomShapeVariety`, `OriginRoomRadius`, `OriginRoomMaxConnections`, `TunnelMinRadius`, `TunnelMaxRadius`, `TunnelDensity`, `MaxTunnelLength`, `TunnelWarpStrength`, `TunnelHorizontalBias`, `bTunnelsFlowTowardOrigin`, `CaveWarpStrength`, `SurfaceRoughness`, `RoughnessFrequency`, and `SDFBlendRadius`. Unmapped: `BaseDensity`, `BoundarySealThickness`, `CaveWarpFrequency`, `DomainWarpFrequency`, `DomainWarpStrength`, `FloorBias`, `FloorReliefFrequency`, `FloorReliefStrength`, `RoomMouthRiseBlendVoxels`, `RoomMouthRiseStrength`, `TunnelEndpointZOffset`, `TunnelFloorGentleSlopeThreshold`, `TunnelFloorLedgeCountPreference`, `TunnelFloorMaxLedgeHeight`, `TunnelFloorMaxLedges`, `TunnelFloorTerraceStepHeight`, `VerticalScale`, `WaterLevelRelative`, `WormFrequency`, `WormHorizontalBias`, `WormNetworkRange`, `WormStrength`, `WormThreshold`, `bTunnelFloorEnabled`, `bTunnelFloorTerracingEnabled`, and `RoughnessNoiseType`.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"schema_version":3,"world_identity":"owner-world/seed/0","owner_voxel_size_um":125000,"core_voxel_size_um":250000,"strate_layout_chunk_size_um":8000000,"strate_layout_chunk_width_subvoxels":8192,"strates":[{"stable_id":"owner-world/seed/0/strate/0/generator/SurfaceWorld","order":0,"strate_index":0,"generator_kind":"SurfaceWorld","recipe_id":"SurfaceWorld.Heightfield2D","recipe_version":2,"interior_bottom_um":-504000000,"interior_top_um":8000000,"voxel_size_um":250000,"lattice_origin_um":[0,0,0],"ceiling":{"kind":"ceiling","bottom_um":7500000,"top_um":8000000,"present":true,"diggable":true,"protected":false,"solid_density_q16":524288,"behaviour":"solid ceiling from strate BoundarySealThickness; breakable by default","density_side":"interior-facing lower surface","cap_path":"shared resolved-layout density band"},"content":{"kind":"content","bottom_um":-503500000,"top_um":7500000,"present":true,"diggable":true,"protected":false,"solid_density_q16":65536,"behaviour":"resolved generator interior","density_side":"none","cap_path":"none"},"bedrock":{"kind":"bedrock","bottom_um":-504000000,"top_um":-503500000,"present":true,"diggable":true,"protected":false,"solid_density_q16":524288,"behaviour":"solid bedrock floor from strate BoundarySealThickness; breakable by default","density_side":"interior-facing upper surface","cap_path":"shared resolved-layout density band"},"transition_mode":"Gradient","transition_blend_chunks":1,"transition_width_um":8000000,"transition_warp_amplitude_um":0,"transition_interpenetration_um":2000000,"transition_honoured_in_core":true,"transition_falls_back_to_hard":false,"transition_dispatch_path":"shared composition moves both band faces together with the smooth declared-width transition field","bound_dispatch_path":"BuildSurfaceStratumPlan uses resolved layout chunk width from ResolvedLayoutSnapshotV3","query_dispatch_path":"NativeSurfaceDensityAt selects floor(CoreZ / resolved layout chunk width) from ResolvedLayoutSnapshotV3","manager_lookup":"UVoxelStrateManager::GetGeneratorTypeForChunk; transition is controlled by upper strate","manager_chunk_width_um":8000000,"dispatch_chunk_width_um":8000000,"anchors":[{"kind":"cap_profile","stable_id":"biome/4097","units":"1/256 Core voxel","values":[-18022,0,64000,1536,0]},{"kind":"route_point","stable_id":"route/0","units":"1/256 Core voxel","values":[8192,24576,-381223,1024]},{"kind":"route_point","stable_id":"route/1","units":"1/256 Core voxel","values":[8192,24320,-381254,1024]},{"kind":"route_point","stable_id":"route/2","units":"1/256 Core voxel","values":[8192,24064,-381284,1024]},{"kind":"route_point","stable_id":"route/3","units":"1/256 Core voxel","values":[8192,23808,-381302,1024]},{"kind":"route_point","stable_id":"route/4","units":"1/256 Core voxel","values":[8192,23552,-381304,1024]},{"kind":"route_point","stable_id":"route/5","units":"1/256 Core voxel","values":[8192,23296,-381291,1024]},{"kind":"route_point","stable_id":"route/6","units":"1/256 Core voxel","values":[8192,23040,-381270,1024]},{"kind":"route_point","stable_id":"route/7","units":"1/256 Core voxel","values":[8192,22784,-381242,1024]},{"kind":"route_point","stable_id":"route/8","units":"1/256 Core voxel","values":[8192,22528,-381218,1024]},{"kind":"route_point","stable_id":"route/9","units":"1/256 Core voxel","values":[8192,22272,-381192,1024]},{"kind":"route_point","stable_id":"route/10","units":"1/256 Core voxel","values":[8192,22016,-381161,1024]},{"kind":"route_point","stable_id":"route/11","units":"1/256 Core voxel","values":[8192,21760,-381118,1024]},{"kind":"route_point","stable_id":"route/12","units":"1/256 Core voxel","values":[8192,21504,-381122,1024]},{"kind":"route_point","stable_id":"route/13","units":"1/256 Core voxel","values":[8192,21248,-381155,1024]},{"kind":"route_point","stable_id":"route/14","units":"1/256 Core voxel","values":[8192,20992,-381183,1024]},{"kind":"route_point","stable_id":"route/15","units":"1/256 Core voxel","values":[8192,20736,-381207,1024]},{"kind":"route_point","stable_id":"route/16","units":"1/256 Core voxel","values":[8192,20480,-381219,1024]},{"kind":"route_point","stable_id":"route/17","units":"1/256 Core voxel","values":[8192,20224,-381220,1024]},{"kind":"route_point","stable_id":"route/18","units":"1/256 Core voxel","values":[8192,19968,-381202,1024]},{"kind":"route_point","stable_id":"route/19","units":"1/256 Core voxel","values":[8192,19712,-381167,1024]},{"kind":"route_point","stable_id":"route/20","units":"1/256 Core voxel","values":[8192,19456,-381130,1024]},{"kind":"route_point","stable_id":"route/21","units":"1/256 Core voxel","values":[8192,19200,-381101,1024]},{"kind":"route_point","stable_id":"route/22","units":"1/256 Core voxel","values":[8192,18944,-381072,1024]},{"kind":"route_point","stable_id":"route/23","units":"1/256 Core voxel","values":[8192,18688,-381092,1024]},{"kind":"route_point","stable_id":"route/24","units":"1/256 Core voxel","values":[8192,18432,-381149,1024]},{"kind":"route_point","stable_id"Line truncated
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"schema_version":3,"world_identity":"owner-world/seed/0","owner_voxel_size_um":125000,"core_voxel_size_um":250000,"strate_layout_chunk_size_um":8000000,"strate_layout_chunk_width_subvoxels":8192,"strates":[{"stable_id":"owner-world/seed/0/strate/0/generator/SurfaceWorld","order":0,"strate_index":0,"generator_kind":"SurfaceWorld","recipe_id":"SurfaceWorld.Heightfield2D","recipe_version":2,"interior_bottom_um":-504000000,"interior_top_um":8000000,"voxel_size_um":250000,"lattice_origin_um":[0,0,0],"ceiling":{"kind":"ceiling","bottom_um":7500000,"top_um":8000000,"present":true,"diggable":true,"protected":false,"solid_density_q16":524288,"behaviour":"solid ceiling from strate BoundarySealThickness; breakable by default","density_side":"interior-facing lower surface","cap_path":"shared resolved-layout density band"},"content":{"kind":"content","bottom_um":-503500000,"top_um":7500000,"present":true,"diggable":true,"protected":false,"solid_density_q16":65536,"behaviour":"resolved generator interior","density_side":"none","cap_path":"none"},"bedrock":{"kind":"bedrock","bottom_um":-504000000,"top_um":-503500000,"present":true,"diggable":true,"protected":false,"solid_density_q16":524288,"behaviour":"solid bedrock floor from strate BoundarySealThickness; breakable by default","density_side":"interior-facing upper surface","cap_path":"shared resolved-layout density band"},"transition_mode":"Gradient","transition_blend_chunks":1,"transition_width_um":8000000,"transition_warp_amplitude_um":0,"transition_interpenetration_um":2000000,"transition_honoured_in_core":true,"transition_falls_back_to_hard":false,"transition_dispatch_path":"shared composition moves both band faces together with the smooth declared-width transition field","bound_dispatch_path":"BuildSurfaceStratumPlan uses resolved layout chunk width from ResolvedLayoutSnapshotV3","query_dispatch_path":"NativeSurfaceDensityAt selects floor(CoreZ / resolved layout chunk width) from ResolvedLayoutSnapshotV3","manager_lookup":"UVoxelStrateManager::GetGeneratorTypeForChunk; transition is controlled by upper strate","manager_chunk_width_um":8000000,"dispatch_chunk_width_um":8000000,"anchors":[{"kind":"cap_profile","stable_id":"biome/4097","units":"1/256 Core voxel","values":[-18022,0,64000,1536,0]},{"kind":"route_point","stable_id":"route/0","units":"1/256 Core voxel","values":[8192,24576,-381223,1024]},{"kind":"route_point","stable_id":"route/1","units":"1/256 Core voxel","values":[8192,24320,-381254,1024]},{"kind":"route_point","stable_id":"route/2","units":"1/256 Core voxel","values":[8192,24064,-381284,1024]},{"kind":"route_point","stable_id":"route/3","units":"1/256 Core voxel","values":[8192,23808,-381302,1024]},{"kind":"route_point","stable_id":"route/4","units":"1/256 Core voxel","values":[8192,23552,-381304,1024]},{"kind":"route_point","stable_id":"route/5","units":"1/256 Core voxel","values":[8192,23296,-381291,1024]},{"kind":"route_point","stable_id":"route/6","units":"1/256 Core voxel","values":[8192,23040,-381270,1024]},{"kind":"route_point","stable_id":"route/7","units":"1/256 Core voxel","values":[8192,22784,-381242,1024]},{"kind":"route_point","stable_id":"route/8","units":"1/256 Core voxel","values":[8192,22528,-381218,1024]},{"kind":"route_point","stable_id":"route/9","units":"1/256 Core voxel","values":[8192,22272,-381192,1024]},{"kind":"route_point","stable_id":"route/10","units":"1/256 Core voxel","values":[8192,22016,-381161,1024]},{"kind":"route_point","stable_id":"route/11","units":"1/256 Core voxel","values":[8192,21760,-381118,1024]},{"kind":"route_point","stable_id":"route/12","units":"1/256 Core voxel","values":[8192,21504,-381122,1024]},{"kind":"route_point","stable_id":"route/13","units":"1/256 Core voxel","values":[8192,21248,-381155,1024]},{"kind":"route_point","stable_id":"route/14","units":"1/256 Core voxel","values":[8192,20992,-381183,1024]},{"kind":"route_point","stable_id":"route/15","units":"1/256 Core voxel","values":[8192,20736,-381207,1024]},{"kind":"route_point","stable_id":"route/16","units":"1/256 Core voxel","values":[8192,20480,-381219,1024]},{"kind":"route_point","stable_id":"route/17","units":"1/256 Core voxel","values":[8192,20224,-381220,1024]},{"kind":"route_point","stable_id":"route/18","units":"1/256 Core voxel","values":[8192,19968,-381202,1024]},{"kind":"route_point","stable_id":"route/19","units":"1/256 Core voxel","values":[8192,19712,-381167,1024]},{"kind":"route_point","stable_id":"route/20","units":"1/256 Core voxel","values":[8192,19456,-381130,1024]},{"kind":"route_point","stable_id":"route/21","units":"1/256 Core voxel","values":[8192,19200,-381101,1024]},{"kind":"route_point","stable_id":"route/22","units":"1/256 Core voxel","values":[8192,18944,-381072,1024]},{"kind":"route_point","stable_id":"route/23","units":"1/256 Core voxel","values":[8192,18688,-381092,1024]},{"kind":"route_point","stable_id":"route/24","units":"1/256 Core voxel","values":[8192,18432,-381149,1024]},{"kind":"route_point","stable_id"Line truncated
|
||||||
@@ -1684,7 +1684,7 @@ namespace StandaloneStreamBenchmark
|
|||||||
if(mouthBinding)
|
if(mouthBinding)
|
||||||
{
|
{
|
||||||
const auto qOffset=static_cast<std::int64_t>(std::llround(
|
const auto qOffset=static_cast<std::int64_t>(std::llround(
|
||||||
250000.0*WorldAssemblySubvoxelsPerVoxel/layout.coreVoxelSizeMicrometres));
|
1000000.0*WorldAssemblySubvoxelsPerVoxel/layout.coreVoxelSizeMicrometres));
|
||||||
const auto& start=routeAnchors.front()->values;
|
const auto& start=routeAnchors.front()->values;
|
||||||
const auto& end=routeAnchors.back()->values;
|
const auto& end=routeAnchors.back()->values;
|
||||||
mouthBinding=start[0]==arrival->lowerMouthSubvoxels[0]
|
mouthBinding=start[0]==arrival->lowerMouthSubvoxels[0]
|
||||||
@@ -5071,7 +5071,7 @@ namespace StandaloneStreamBenchmark
|
|||||||
return equalPosition(authored,mouth);
|
return equalPosition(authored,mouth);
|
||||||
auto expected=mouth;
|
auto expected=mouth;
|
||||||
expected[2]+=static_cast<std::int64_t>(std::llround(
|
expected[2]+=static_cast<std::int64_t>(std::llround(
|
||||||
250000.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
|
1000000.0*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel
|
||||||
/World.CoreVoxelSizeMicrons));
|
/World.CoreVoxelSizeMicrons));
|
||||||
return equalPosition(authored,expected);
|
return equalPosition(authored,expected);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1137,6 +1137,8 @@ namespace StandaloneWorldAssemblyPrototype
|
|||||||
toMicrometres(params.CaveWarpStrength));
|
toMicrometres(params.CaveWarpStrength));
|
||||||
settings.smoothWidthMicrometres=std::max<std::int64_t>(1500000,
|
settings.smoothWidthMicrometres=std::max<std::int64_t>(1500000,
|
||||||
toMicrometres(params.SDFBlendRadius));
|
toMicrometres(params.SDFBlendRadius));
|
||||||
|
settings.floorSupportDepthMicrometres=std::clamp<std::int64_t>(
|
||||||
|
settings.smoothWidthMicrometres/2,750000,2000000);
|
||||||
settings.irregularityAmplitudeMicrometres=std::max<std::int64_t>(0,
|
settings.irregularityAmplitudeMicrometres=std::max<std::int64_t>(0,
|
||||||
toMicrometres(params.SurfaceRoughness));
|
toMicrometres(params.SurfaceRoughness));
|
||||||
settings.irregularityWavelengthMicrometres=params.RoughnessFrequency>0.0f
|
settings.irregularityWavelengthMicrometres=params.RoughnessFrequency>0.0f
|
||||||
@@ -1202,9 +1204,9 @@ namespace StandaloneWorldAssemblyPrototype
|
|||||||
anchor.values={point[0],point[1],point[2]};
|
anchor.values={point[0],point[1],point[2]};
|
||||||
stratum->anchors.push_back(std::move(anchor));
|
stratum->anchors.push_back(std::move(anchor));
|
||||||
};
|
};
|
||||||
constexpr std::int64_t PlayerCenterAboveMouthFloorMicrometres=250000;
|
constexpr std::int64_t PlayerCenterAboveFloorMicrometres=1000000;
|
||||||
auto start=arrival->lowerMouthSubvoxels;
|
auto start=arrival->lowerMouthSubvoxels;
|
||||||
start[2]+=toCoreSubvoxels(PlayerCenterAboveMouthFloorMicrometres);
|
start[2]+=toCoreSubvoxels(PlayerCenterAboveFloorMicrometres);
|
||||||
appendRoutePoint("000-arrival",start);
|
appendRoutePoint("000-arrival",start);
|
||||||
for(std::size_t edgeIndex=0;edgeIndex<256;++edgeIndex)
|
for(std::size_t edgeIndex=0;edgeIndex<256;++edgeIndex)
|
||||||
{
|
{
|
||||||
@@ -1216,14 +1218,36 @@ namespace StandaloneWorldAssemblyPrototype
|
|||||||
{return value.strateIndex==slot.StrateIndex
|
{return value.strateIndex==slot.StrateIndex
|
||||||
&&value.stableId==stableId;});
|
&&value.stableId==stableId;});
|
||||||
if(edge==layout.cavernEdges.end())break;
|
if(edge==layout.cavernEdges.end())break;
|
||||||
|
if(edgeIndex==0)
|
||||||
|
{
|
||||||
|
auto inner=edge->controlPointsMicrometres.front();
|
||||||
|
inner[2]+=PlayerCenterAboveFloorMicrometres;
|
||||||
|
appendRoutePoint("000-edge-start",
|
||||||
|
{toCoreSubvoxels(inner[0]),toCoreSubvoxels(inner[1]),
|
||||||
|
toCoreSubvoxels(inner[2])});
|
||||||
|
}
|
||||||
auto point=edge->controlPointsMicrometres.back();
|
auto point=edge->controlPointsMicrometres.back();
|
||||||
point[2]+=1000000;
|
point[2]+=PlayerCenterAboveFloorMicrometres;
|
||||||
appendRoutePoint(std::to_string(edgeIndex+1),
|
appendRoutePoint(std::to_string(edgeIndex+1),
|
||||||
{toCoreSubvoxels(point[0]),toCoreSubvoxels(point[1]),
|
{toCoreSubvoxels(point[0]),toCoreSubvoxels(point[1]),
|
||||||
toCoreSubvoxels(point[2])});
|
toCoreSubvoxels(point[2])});
|
||||||
}
|
}
|
||||||
|
const std::string departureEdgeId="tunnel-network/strate-"
|
||||||
|
+std::to_string(slot.StrateIndex)+"/departure-edge";
|
||||||
|
const auto departureEdge=std::find_if(layout.cavernEdges.begin(),
|
||||||
|
layout.cavernEdges.end(),[&](const auto& value)
|
||||||
|
{return value.strateIndex==slot.StrateIndex
|
||||||
|
&&value.stableId==departureEdgeId;});
|
||||||
|
if(departureEdge!=layout.cavernEdges.end())
|
||||||
|
{
|
||||||
|
auto inner=departureEdge->controlPointsMicrometres.front();
|
||||||
|
inner[2]+=PlayerCenterAboveFloorMicrometres;
|
||||||
|
appendRoutePoint("998-departure-inner",
|
||||||
|
{toCoreSubvoxels(inner[0]),toCoreSubvoxels(inner[1]),
|
||||||
|
toCoreSubvoxels(inner[2])});
|
||||||
|
}
|
||||||
auto end=departure->upperMouthSubvoxels;
|
auto end=departure->upperMouthSubvoxels;
|
||||||
end[2]+=toCoreSubvoxels(PlayerCenterAboveMouthFloorMicrometres);
|
end[2]+=toCoreSubvoxels(PlayerCenterAboveFloorMicrometres);
|
||||||
appendRoutePoint("999-departure",end);
|
appendRoutePoint("999-departure",end);
|
||||||
}
|
}
|
||||||
return layout.finalize(error);
|
return layout.finalize(error);
|
||||||
|
|||||||
Reference in new issue
Block a user