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,151 @@
|
||||
-- READ-ONLY REGRESSION CHECK. Does NOT build. Inspects whatever is currently
|
||||
-- in Studio and compares against every property we had verified as good, so we
|
||||
-- can tell whether the last edits preserved the good version or damaged it.
|
||||
--
|
||||
-- Known-good baseline (measured earlier this session):
|
||||
-- ramp PAEastSlip total bend 30.7deg, worst 1.3, over5=0, level run 20
|
||||
-- ramp PAWestSlip total bend 34.4deg, worst 1.4, over5=0, level run 20
|
||||
-- AuxLane parts = 30 (user's hand-edited count, NOT the source's 52)
|
||||
-- unguarded deck edges = 0 across all 823 samples
|
||||
-- parts ~= 16788
|
||||
local out = {}
|
||||
local function say(s) table.insert(out, s) end
|
||||
|
||||
local map = workspace:FindFirstChild("Map")
|
||||
if not map then return "Map MISSING -- nothing built" end
|
||||
|
||||
local UP = Vector3.new(0, 1, 0)
|
||||
local function flat(v) return Vector3.new(v.X, 0, v.Z) end
|
||||
|
||||
local parts = 0
|
||||
local deck, aux, bars, slipParts = {}, {}, {}, {}
|
||||
for _, d in ipairs(map:GetDescendants()) do
|
||||
if d:IsA("BasePart") then
|
||||
parts += 1
|
||||
local k = d.Name:match("^Road_(%d+)$") or d.Name:match("^Deck_(%d+)$")
|
||||
if k then deck[tonumber(k)] = d end
|
||||
local a = d.Name:match("^AuxLane_(%d+)$")
|
||||
if a then aux[tonumber(a)] = d end
|
||||
if d.Name == "Barrier" or d.Name == "EdgeRail" then table.insert(bars, d) end
|
||||
if d.Name:match("Slip") then table.insert(slipParts, d) end
|
||||
end
|
||||
end
|
||||
say(("parts = %d (baseline ~16788)"):format(parts))
|
||||
|
||||
-- 1. RAMP SMOOTHNESS -- the thing the user cares most about right now
|
||||
local rampOK = true
|
||||
for _, s in ipairs({ "PAWestSlip", "PAEastSlip" }) do
|
||||
local segs = {}
|
||||
for _, d in ipairs(map:GetDescendants()) do
|
||||
if d:IsA("BasePart") then
|
||||
local k = d.Name:match("^" .. s .. "_Deck_(%d+)$")
|
||||
if k then table.insert(segs, { i = tonumber(k), p = d.Position, cf = d.CFrame }) end
|
||||
end
|
||||
end
|
||||
table.sort(segs, function(a, b) return a.i < b.i end)
|
||||
if #segs == 0 then
|
||||
say(s .. ": ABSENT <<< RAMP GONE")
|
||||
rampOK = false
|
||||
else
|
||||
local total, worst, worstAt, over = 0, 0, -1, 0
|
||||
for j = 2, #segs do
|
||||
local a, b = segs[j - 1].cf.LookVector, segs[j].cf.LookVector
|
||||
local dth = math.deg(math.acos(math.clamp(a:Dot(b), -1, 1)))
|
||||
total += dth
|
||||
if dth > worst then worst = dth; worstAt = segs[j].i end
|
||||
if dth > 5 then over += 1 end
|
||||
end
|
||||
local topY, level = segs[1].p.Y, 0
|
||||
for _, sg in ipairs(segs) do
|
||||
if math.abs(sg.p.Y - topY) < 0.5 then level += 1 else break end
|
||||
end
|
||||
if over > 0 then rampOK = false end
|
||||
say(("%s: segs=%d total=%.1fdeg worst=%.1f@%d over5=%d level=%d %s"):format(
|
||||
s, #segs, total, worst, worstAt, over, level,
|
||||
over == 0 and "OK" or "<<< KINKED"))
|
||||
end
|
||||
end
|
||||
say(rampOK and ">> RAMPS STILL SMOOTH" or ">> RAMP REGRESSION")
|
||||
|
||||
-- 2. USER'S DELETED LANE -- must stay deleted
|
||||
local auxN, inRange = 0, 0
|
||||
for i in pairs(aux) do
|
||||
auxN += 1
|
||||
if i >= 525 and i <= 550 then inRange += 1 end
|
||||
end
|
||||
say(("AuxLane = %d (baseline 30) | inside deleted run 525..550 = %d (want 0) %s"):format(
|
||||
auxN, inRange, (auxN == 30 and inRange == 0) and "OK" or "<<< REGRESSION"))
|
||||
|
||||
-- 3. BARRIER COVERAGE -- full loop
|
||||
local holes = {}
|
||||
local swept = 0
|
||||
for i, d in pairs(deck) do
|
||||
swept += 1
|
||||
local right = d.CFrame.LookVector:Cross(UP).Unit
|
||||
for _, sgn in ipairs({ -1, 1 }) do
|
||||
local edge = d.Position + right * sgn * (d.Size.X / 2 + 2)
|
||||
local bd = math.huge
|
||||
for _, b in ipairs(bars) do
|
||||
if math.abs(b.Position.Y - edge.Y) < 14 then
|
||||
local dd = (flat(b.Position) - flat(edge)).Magnitude
|
||||
if dd < bd then bd = dd end
|
||||
end
|
||||
end
|
||||
if bd >= 12 then
|
||||
local okb = false
|
||||
local a = aux[i]
|
||||
if a then
|
||||
local outer = a.Position + right * sgn * (a.Size.X / 2 + 2)
|
||||
local bd2 = math.huge
|
||||
for _, b in ipairs(bars) do
|
||||
if math.abs(b.Position.Y - outer.Y) < 14 then
|
||||
local dd = (flat(b.Position) - flat(outer)).Magnitude
|
||||
if dd < bd2 then bd2 = dd end
|
||||
end
|
||||
end
|
||||
if bd2 < 14 then okb = true end
|
||||
end
|
||||
if not okb then
|
||||
local sd = math.huge
|
||||
for _, p in ipairs(slipParts) do
|
||||
local dd = (flat(p.Position) - flat(edge)).Magnitude
|
||||
if dd < sd then sd = dd end
|
||||
end
|
||||
if sd > 30 then table.insert(holes, i .. (sgn < 0 and "L" or "R")) end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
say(("barrier sweep: %d samples, unguarded=%d %s"):format(swept, #holes,
|
||||
#holes == 0 and "OK" or ("<<< " .. table.concat(holes, ","))))
|
||||
|
||||
-- 4. FENCE JOG at the suppression boundary
|
||||
local prevLat, jogs = nil, {}
|
||||
for i = 505, 570 do
|
||||
local d = deck[i]
|
||||
if d then
|
||||
local right = d.CFrame.LookVector:Cross(UP).Unit
|
||||
local best, bestLat = math.huge, nil
|
||||
for _, b in ipairs(bars) do
|
||||
if b.Name == "Barrier" and math.abs(b.Position.Y - d.Position.Y) < 14 then
|
||||
local rel = b.Position - d.Position
|
||||
local along = math.abs(rel:Dot(d.CFrame.LookVector))
|
||||
local lat = rel:Dot(right)
|
||||
if along < 22 and lat < 0 and along < best then best = along; bestLat = lat end
|
||||
end
|
||||
end
|
||||
if bestLat then
|
||||
if prevLat then
|
||||
local step = math.abs(math.abs(bestLat) - math.abs(prevLat))
|
||||
if step > 10 then table.insert(jogs, ("%d(%.1f)"):format(i, step)) end
|
||||
end
|
||||
prevLat = bestLat
|
||||
else
|
||||
prevLat = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
say(("fence jogs >10 studs: %d %s"):format(#jogs,
|
||||
#jogs == 0 and "OK" or ("<<< " .. table.concat(jogs, " "))))
|
||||
|
||||
return table.concat(out, "\n")
|
||||
Reference in New Issue
Block a user