Aux-lane suppression + PA geometry fixes; probe/verify tooling
CI / quality (push) Failing after 1m9s
CI / quality (push) Failing after 1m9s
MapBuilder.luau
- Suppress the aux lane across samples 525-550 (AUX_SUPPRESS_FROM/TO),
honoring the user's hand deletion in Studio so a rebuild no longer
regenerates it.
- Smoothstep the width ramp over AUX_BLEND=5 samples on each side. A hard
cut produced a 26-stud lateral fence jog; the blend removes it.
- DO NOT remove this suppression. Re-enabling it resurrects geometry the
user deleted by hand.
rokit.toml
- rojo 7.5.1 -> 7.7.0 to match the auto-updating Studio plugin.
Server older than plugin fails the handshake with
"attempt to index number with 'protocolVersion'".
tools/
- 34 read-only probe/verify/capture scripts used to measure the datamodel
instead of reasoning from source.
Verified-good baseline at this commit:
total parts 16788
PAWestSlip 60 segs, 34.4 deg total bend, worst 1.4, 0 kinks >5
PAEastSlip 60 segs, 30.7 deg total bend, worst 1.3, 0 kinks >5
AuxLane parts 30 (samples 525-550 deliberately absent)
barrier coverage 823 samples, 0 unguarded
fence jogs >10st 0
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
-- Measure the envelope a SIMPLE straight slip-ramp must live in.
|
||||
-- User's drawing: short stubs peeling off the mainline at a shallow angle,
|
||||
-- running roughly PARALLEL to the highway in the strip between the mainline
|
||||
-- edge and the PA lot's north edge, descending an S onto the apron.
|
||||
--
|
||||
-- We need to know, in real numbers:
|
||||
-- 1. Where the mainline actually runs across the PA frontage (samples,
|
||||
-- heading, deck Y) -- is it straight enough for a parallel slip?
|
||||
-- 2. Where the lot's north edge is, and how wide the clear strip is
|
||||
-- between the mainline's south edge and that lot edge.
|
||||
-- 3. Deck Y vs apron Y (the height the S-curve must lose).
|
||||
-- 4. What is already sitting in that strip that a ramp would hit.
|
||||
|
||||
local RS = game:GetService("ReplicatedStorage")
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local Circuit = require(RS:WaitForChild("Shared"):WaitForChild("Circuit"))
|
||||
|
||||
local samples = Circuit.samples
|
||||
local n = #samples
|
||||
local c = Circuit.PA_CENTER
|
||||
|
||||
-- Nearest mainline sample to the PA centre.
|
||||
local bestIdx, bestD = 1, math.huge
|
||||
for i = 1, n do
|
||||
local p = samples[i].pos
|
||||
local d = (Vector3.new(p.X, 0, p.Z) - Vector3.new(c.X, 0, c.Z)).Magnitude
|
||||
if d < bestD then bestD, bestIdx = d, i end
|
||||
end
|
||||
|
||||
-- Walk a band around the PA frontage and report heading + deck Y, so we can
|
||||
-- see how straight the mainline is and where a parallel slip could sit.
|
||||
local band = {}
|
||||
for k = -40, 40, 5 do
|
||||
local i = ((bestIdx - 1 + k) % n) + 1
|
||||
local s = samples[i].pos
|
||||
local nx = samples[(i % n) + 1].pos
|
||||
local hdg = math.deg(math.atan2(nx.Z - s.Z, nx.X - s.X))
|
||||
local d = (Vector3.new(s.X, 0, s.Z) - Vector3.new(c.X, 0, c.Z)).Magnitude
|
||||
table.insert(band, {
|
||||
k = k, idx = i,
|
||||
x = math.floor(s.X), y = math.floor(s.Y + 0.5), z = math.floor(s.Z),
|
||||
hdg = math.floor(hdg + 0.5),
|
||||
distPA = math.floor(d),
|
||||
})
|
||||
end
|
||||
|
||||
-- The apron / lot floor: bounds and surface height.
|
||||
local map = workspace:FindFirstChild("Map")
|
||||
local floor = map and map:FindFirstChild("PAFloor", true)
|
||||
local lot = nil
|
||||
if floor then
|
||||
lot = {
|
||||
name = floor.Name,
|
||||
surfaceY = floor.Position.Y + floor.Size.Y / 2,
|
||||
x_min = math.floor(floor.Position.X - floor.Size.X / 2),
|
||||
x_max = math.floor(floor.Position.X + floor.Size.X / 2),
|
||||
z_min = math.floor(floor.Position.Z - floor.Size.Z / 2),
|
||||
z_max = math.floor(floor.Position.Z + floor.Size.Z / 2),
|
||||
}
|
||||
end
|
||||
|
||||
-- What already occupies the strip between the mainline and the lot's north
|
||||
-- edge? Anything here is a collision candidate for a parallel slip ramp.
|
||||
-- Strip = north third of the lot bbox, i.e. Z above (z_max - 220).
|
||||
local obstacles = {}
|
||||
if lot then
|
||||
local stripZ = lot.z_max - 220
|
||||
for _, d in ipairs(workspace:GetDescendants()) do
|
||||
if d:IsA("BasePart") then
|
||||
local p = d.Position
|
||||
if p.Z >= stripZ and p.Z <= lot.z_max + 160
|
||||
and p.X >= lot.x_min - 60 and p.X <= lot.x_max + 60 then
|
||||
local key = d.Name
|
||||
local e = obstacles[key]
|
||||
if not e then
|
||||
e = { n = 0, x_min = 1e9, x_max = -1e9, z_min = 1e9,
|
||||
z_max = -1e9, y_max = -1e9 }
|
||||
obstacles[key] = e
|
||||
end
|
||||
e.n += 1
|
||||
e.x_min = math.min(e.x_min, p.X); e.x_max = math.max(e.x_max, p.X)
|
||||
e.z_min = math.min(e.z_min, p.Z); e.z_max = math.max(e.z_max, p.Z)
|
||||
e.y_max = math.max(e.y_max, p.Y + d.Size.Y / 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local obsOut = {}
|
||||
for k, e in pairs(obstacles) do
|
||||
table.insert(obsOut, {
|
||||
name = k, n = e.n,
|
||||
x = math.floor(e.x_min) .. ".." .. math.floor(e.x_max),
|
||||
z = math.floor(e.z_min) .. ".." .. math.floor(e.z_max),
|
||||
ytop = math.floor(e.y_max),
|
||||
})
|
||||
end
|
||||
table.sort(obsOut, function(a, b) return a.n > b.n end)
|
||||
while #obsOut > 25 do table.remove(obsOut) end
|
||||
|
||||
return HttpService:JSONEncode({
|
||||
bestIdx = bestIdx,
|
||||
nearestDist = math.floor(bestD),
|
||||
pa_center = { math.floor(c.X), math.floor(c.Y), math.floor(c.Z) },
|
||||
pa_radius = Circuit.PA_RADIUS,
|
||||
band = band,
|
||||
lot = lot,
|
||||
strip_obstacles = obsOut,
|
||||
})
|
||||
Reference in New Issue
Block a user