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,106 @@
|
||||
-- Re-verify after un-pinning index 2, and settle the 4 "bare" samples:
|
||||
-- 525L/526L/549L/550L sit at the ramp MOUTHS (west join=525, east join=551).
|
||||
-- An open parapet at a mouth is correct -- that is the doorway cars drive
|
||||
-- through, and the ramp deck's own walls take over. So check whether ramp deck
|
||||
-- + ramp wall actually cover those samples. If yes: not a hole. If no: a hole.
|
||||
local SS = game:GetService("ServerScriptService")
|
||||
local out = {}
|
||||
local function say(s) table.insert(out, s) end
|
||||
|
||||
local mod = SS:FindFirstChild("MapBuilder", true)
|
||||
if not mod then return "MapBuilder NOT FOUND" end
|
||||
local fresh = mod:Clone()
|
||||
fresh.Name = "MB_fresh_" .. tostring(math.random(1e6))
|
||||
fresh.Parent = SS
|
||||
local ok, MB = pcall(require, fresh)
|
||||
if not ok then fresh:Destroy() return "require FAILED: " .. tostring(MB) end
|
||||
local ok2, err = pcall(function() MB.build() end)
|
||||
fresh:Destroy()
|
||||
if not ok2 then return "build ERROR: " .. tostring(err) end
|
||||
say("build OK")
|
||||
|
||||
local map = workspace:FindFirstChild("Map")
|
||||
local parts = 0
|
||||
for _, d in ipairs(map:GetDescendants()) do
|
||||
if d:IsA("BasePart") then parts += 1 end
|
||||
end
|
||||
say(("parts=%d"):format(parts))
|
||||
|
||||
local deck, bars, slipAll = {}, {}, {}
|
||||
for _, d in ipairs(map:GetDescendants()) do
|
||||
if d:IsA("BasePart") then
|
||||
local k = d.Name:match("^Road_(%d+)$") or d.Name:match("^Deck_(%d+)$")
|
||||
if k then deck[tonumber(k)] = d end
|
||||
if d.Name == "Barrier" or d.Name == "EdgeRail" then table.insert(bars, d) end
|
||||
if d.Name:match("^PA[EW][ae]stSlip") then table.insert(slipAll, d) end
|
||||
end
|
||||
end
|
||||
|
||||
local UP = Vector3.new(0, 1, 0)
|
||||
local function flat(v) return Vector3.new(v.X, 0, v.Z) end
|
||||
local function nearest(list, p, ytol)
|
||||
local best = math.huge
|
||||
for _, b in ipairs(list) do
|
||||
if math.abs(b.Position.Y - p.Y) < (ytol or 14) then
|
||||
local dd = (flat(b.Position) - flat(p)).Magnitude
|
||||
if dd < best then best = dd end
|
||||
end
|
||||
end
|
||||
return best
|
||||
end
|
||||
|
||||
say("--- edge audit 520..555 (L side) ---")
|
||||
local realHoles = {}
|
||||
for i = 520, 555 do
|
||||
local d = deck[i]
|
||||
if d then
|
||||
local right = d.CFrame.LookVector:Cross(UP).Unit
|
||||
local edge = d.Position - right * (d.Size.X / 2 + 2)
|
||||
local bd = nearest(bars, edge)
|
||||
local sd = nearest(slipAll, edge, 20)
|
||||
local covered = bd < 12 or sd < 30
|
||||
if not covered then table.insert(realHoles, i) end
|
||||
if bd >= 12 then
|
||||
say((" %d: barrier=%.1f slipStruct=%.1f -> %s"):format(
|
||||
i, bd, sd, covered and "OK (ramp mouth)" or "HOLE"))
|
||||
end
|
||||
end
|
||||
end
|
||||
say(("REAL holes: %d %s"):format(#realHoles,
|
||||
#realHoles > 0 and table.concat(realHoles, ",") or "(none)"))
|
||||
|
||||
say("--- smoothness ---")
|
||||
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)
|
||||
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
|
||||
say(("%s: total=%.1fdeg worst=%.1f@%d over5=%d level=%d"):format(
|
||||
s, total, worst, worstAt, over, level))
|
||||
say((" start=(%.0f,%.0f,%.0f) end=(%.0f,%.0f,%.0f)"):format(
|
||||
segs[1].p.X, segs[1].p.Y, segs[1].p.Z, segs[#segs].p.X, segs[#segs].p.Y, segs[#segs].p.Z))
|
||||
end
|
||||
|
||||
local aux = 0
|
||||
for _, d in ipairs(map:GetDescendants()) do
|
||||
if d:IsA("BasePart") and d.Name:match("^AuxLane_%d+$") then aux += 1 end
|
||||
end
|
||||
say(("AuxLane total=%d (want 30)"):format(aux))
|
||||
|
||||
return table.concat(out, "\n")
|
||||
Reference in New Issue
Block a user