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
105 lines
3.5 KiB
Luau
105 lines
3.5 KiB
Luau
-- What do the slip ramps ACTUALLY do? Elevation + lateral profile per segment,
|
|
-- and do they intersect the mainline deck?
|
|
-- The user says: "on and off ramps go to the bottom and through the highway".
|
|
-- Measure that claim directly rather than assuming.
|
|
local ws = game:GetService("Workspace")
|
|
local RS = game:GetService("ReplicatedStorage")
|
|
local Circuit = require(RS:WaitForChild("Shared"):WaitForChild("Circuit"))
|
|
local samples = Circuit.samples
|
|
local map = ws:FindFirstChild("Map")
|
|
if not map then return "NOMAP" end
|
|
|
|
local out = {}
|
|
local function say(s) table.insert(out, s) end
|
|
|
|
-- Collect ramp deck segments in build order.
|
|
local ramps = {}
|
|
for _, d in ipairs(map:GetDescendants()) do
|
|
if d:IsA("BasePart") then
|
|
local name, idx = d.Name:match("^(PA%a+Slip)_Deck_(%d+)$")
|
|
if name then
|
|
ramps[name] = ramps[name] or {}
|
|
table.insert(ramps[name], { i = tonumber(idx), p = d })
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Nearest mainline sample + signed lateral offset for a world point.
|
|
local function nearestSample(p)
|
|
local bd, bi = math.huge, -1
|
|
for i = 1, #samples do
|
|
local s = samples[i]
|
|
local dd = (Vector3.new(p.X, 0, p.Z) - Vector3.new(s.pos.X, 0, s.pos.Z)).Magnitude
|
|
if dd < bd then bd, bi = dd, i end
|
|
end
|
|
return bi, bd
|
|
end
|
|
local function lateralAt(i, p)
|
|
local n = #samples
|
|
local a = samples[((i - 1) % n) + 1]
|
|
local b = samples[(i % n) + 1]
|
|
local f = b.pos - a.pos
|
|
f = Vector3.new(f.X, 0, f.Z).Unit
|
|
local r = Vector3.new(-f.Z, 0, f.X)
|
|
local rel = Vector3.new(p.X - a.pos.X, 0, p.Z - a.pos.Z)
|
|
return rel:Dot(r), a.pos.Y
|
|
end
|
|
|
|
for _, name in ipairs({ "PAWestSlip", "PAEastSlip" }) do
|
|
local segs = ramps[name]
|
|
if not segs then
|
|
say(name .. ": MISSING")
|
|
else
|
|
table.sort(segs, function(x, y) return x.i < y.i end)
|
|
say(("=== %s (%d segs) ==="):format(name, #segs))
|
|
say("seg | rampY | deckY | dY(ramp-deck) | lateral | note")
|
|
local under = 0
|
|
for k, s in ipairs(segs) do
|
|
if k == 1 or k % 6 == 0 or k == #segs then
|
|
local si = nearestSample(s.p.Position)
|
|
local lat, deckY = lateralAt(si, s.p.Position)
|
|
local dy = s.p.Position.Y - deckY
|
|
local note = ""
|
|
-- |lateral| < 30 means it is horizontally UNDER/INSIDE the deck slab.
|
|
if math.abs(lat) < 30 then
|
|
note = (math.abs(dy) < 8) and "*** THROUGH DECK ***" or "under/over deck footprint"
|
|
end
|
|
say(("%3d | %6.1f | %6.1f | %+7.1f | %+7.1f | %s")
|
|
:format(s.i, s.p.Position.Y, deckY, dy, lat, note))
|
|
end
|
|
local si = nearestSample(s.p.Position)
|
|
local lat = lateralAt(si, s.p.Position)
|
|
if math.abs(lat) < 30 then under += 1 end
|
|
end
|
|
say(("%s: %d/%d segments sit within the deck footprint (|lateral| < 30)")
|
|
:format(name, under, #segs))
|
|
end
|
|
end
|
|
|
|
-- Does any ramp part actually overlap a Road part in 3D?
|
|
local roads = {}
|
|
for _, d in ipairs(map:GetDescendants()) do
|
|
if d:IsA("BasePart") and d.Name:match("^Road_%d+$") then
|
|
table.insert(roads, d)
|
|
end
|
|
end
|
|
local clashes, tested = {}, 0
|
|
for _, name in ipairs({ "PAWestSlip", "PAEastSlip" }) do
|
|
for _, s in ipairs(ramps[name] or {}) do
|
|
for _, r in ipairs(roads) do
|
|
tested += 1
|
|
local d = s.p.Position - r.Position
|
|
local sx = (s.p.Size.X + r.Size.X) / 2
|
|
local sy = (s.p.Size.Y + r.Size.Y) / 2
|
|
local sz = (s.p.Size.Z + r.Size.Z) / 2
|
|
if math.abs(d.X) < sx and math.abs(d.Y) < sy and math.abs(d.Z) < sz then
|
|
table.insert(clashes, ("%s x %s (dY=%.1f)"):format(s.p.Name, r.Name, d.Y))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
say(("ramp-vs-road AABB tests: %d, overlaps: %d"):format(tested, #clashes))
|
|
for k = 1, math.min(#clashes, 12) do say(" " .. clashes[k]) end
|
|
if tested == 0 then say("CONTROL FAIL: nothing tested") end
|
|
return table.concat(out, "\n")
|