-- Verify the SHARED-TRUNK PA ramps as actually BUILT (not as solved offline). -- -- The offline solver + /tmp/verify_shared.py agreed on the numbers, but they -- both worked from the parameter table. This measures the real Roblox parts -- that MapBuilder emits, which is the only thing the player can hit. -- -- Runs on a CLONE parented to workspace so spatial queries work, with an -- Include filter so the LIVE map can never contribute a false collision. -- SAFETY (learned the hard way, 2026-08-03): MapBuilder.build() begins by -- destroying Workspace.Map. A verifier that calls build() therefore DELETES -- THE LIVE MAP as a side effect, and its own map:Destroy() at the end then -- leaves the workspace with no map at all. Snapshot the live map aside first -- and restore it in a finally-style block so the user's session survives even -- if this script errors halfway through. local ServerScriptService = game:GetService("ServerScriptService") local live = workspace:FindFirstChild("Map") local stash = nil if live then stash = Instance.new("Folder") stash.Name = "__MAP_STASH__" stash.Parent = ServerScriptService live.Parent = stash -- reparent, do NOT clone: 24k parts end local function restoreLive() if stash then local held = stash:FindFirstChild("Map") local rebuilt = workspace:FindFirstChild("Map") if rebuilt then rebuilt:Destroy() end if held then held.Parent = workspace end stash:Destroy() end end local out = {} local function log(...) table.insert(out, table.concat({ ... }, " ")) end local pass, fail = 0, 0 local function check(name, ok, detail) if ok then pass += 1 log("PASS", name, detail or "") else fail += 1 log("FAIL", name, detail or "") end end local src = ServerScriptService:FindFirstChild("Server") src = src and src:FindFirstChild("MapBuilder") or ServerScriptService:FindFirstChild("MapBuilder", true) if not src then return "FATAL: MapBuilder module not found" end local MapBuilder = require(src:Clone()) local map = MapBuilder.build and MapBuilder.build() or MapBuilder.Build() map.Name = "VERIFY_CLONE" map.Parent = workspace local RUNS = { "PAEntryRampTrunk", "PAEntryRampNear", "PAEntryRampCross", "PAEntryRampMerge", "PAExitRampTrunk", "PAExitRampNear", "PAExitRampCross", "PAExitRampMerge", } -- Collect the deck parts of each run, in segment order. local deckOf = {} for _, r in ipairs(RUNS) do deckOf[r] = {} end local everything = map:GetDescendants() for _, d in ipairs(everything) do if d:IsA("BasePart") then for _, r in ipairs(RUNS) do local idx = d.Name:match("^" .. r .. "_(%d+)$") if idx then table.insert(deckOf[r], { i = tonumber(idx), p = d }) end end end end for _, r in ipairs(RUNS) do table.sort(deckOf[r], function(a, b) return a.i < b.i end) end log("=== 0. RUNS BUILT ===") local allBuilt = true for _, r in ipairs(RUNS) do local n = #deckOf[r] if n == 0 then allBuilt = false end log(string.format(" %-20s %d segments", r, n)) end check("all 8 runs emitted", allBuilt) -- What counts as "our own structure" rather than an obstacle. local function isRampPart(p) local n = p.Name if n:find("PARamp") or n:find("PARing") then return true end for _, r in ipairs(RUNS) do if n:sub(1, #r) == r then return true end end return false end log("") log("=== 1. SOLID-OBSTACLE HITS ===") -- A run's first and last few segments are MOUTHS: they are supposed to touch -- the ring deck / the mainline carriageway. Everything in between must be in -- clear air. local MOUTH = 6 local totalHits = 0 for _, r in ipairs(RUNS) do local segs = deckOf[r] local hits, sample = 0, nil for k, e in ipairs(segs) do if k > MOUTH and k <= #segs - MOUTH then local params = OverlapParams.new() params.FilterType = Enum.RaycastFilterType.Include params.FilterDescendantsInstances = { map } params.MaxParts = 40 for _, o in ipairs(workspace:GetPartsInPart(e.p, params)) do if o ~= e.p and not isRampPart(o) then hits += 1 if not sample then sample = string.format("seg %d vs %s", k, o.Name) end end end end end totalHits += hits check(string.format("%s clear of solid obstacles", r), hits == 0, sample or "0 hits") end log("") log("=== 2. GRADE ===") -- Limit is 9%; the solve claimed <= 8.28% entry, <= 5.29% exit. local LIMIT = 9.0 for _, r in ipairs(RUNS) do local segs = deckOf[r] local worst, atK = 0, 0 for k = 1, #segs - 1 do local a, b = segs[k].p.Position, segs[k + 1].p.Position local horiz = Vector3.new(b.X - a.X, 0, b.Z - a.Z).Magnitude if horiz > 0.5 then local g = math.abs(b.Y - a.Y) / horiz * 100 if g > worst then worst, atK = g, k end end end check( string.format("%s grade <= %.0f%%", r, LIMIT), worst <= LIMIT, string.format("max %.2f%% at seg %d", worst, atK) ) end log("") log("=== 3. UNDER-DECK CLEARANCE (cross runs) ===") -- The crossing must fit between the ground and the girder soffit, with a car -- on it. Measured against the ACTUAL mainline deck parts overhead, not against -- the assumed profile. local roadParts = {} for _, d in ipairs(everything) do if d:IsA("BasePart") and (d.Name:sub(1, 5) == "Road_" or d.Name:sub(1, 4) == "Deck") then table.insert(roadParts, d) end end local GIRDER = 8 local CAR = 9 for _, r in ipairs({ "PAEntryRampCross", "PAExitRampCross" }) do local segs = deckOf[r] local worst, overhead = math.huge, 0 for _, e in ipairs(segs) do local p = e.p.Position for _, rp in ipairs(roadParts) do local dx = math.abs(p.X - rp.Position.X) - rp.Size.X / 2 local dz = math.abs(p.Z - rp.Position.Z) - rp.Size.Z / 2 if dx < 20 and dz < 20 and rp.Position.Y > p.Y then overhead += 1 local gap = (rp.Position.Y - GIRDER) - (p.Y + 1) worst = math.min(worst, gap) end end end if overhead == 0 then check( string.format("%s passes under the deck", r), false, "NO overhead deck found -- crossing may miss the mainline" ) else check( string.format("%s clears the soffit with a car (%d st)", r, CAR), worst >= CAR, string.format("min gap %.1f st over %d overhead samples", worst, overhead) ) end end log("") log("=== 4. MERGE ACCURACY ===") -- The last segment of each slip must land ON its carriageway, not beside it. local samples = {} for _, d in ipairs(everything) do if d:IsA("BasePart") and d.Name:sub(1, 5) == "Road_" then table.insert(samples, d) end end for _, r in ipairs({ "PAEntryRampNear", "PAEntryRampMerge", "PAExitRampNear", "PAExitRampMerge" }) do local segs = deckOf[r] if #segs > 0 then local tip = segs[#segs].p.Position local best, bestName = math.huge, "?" for _, rp in ipairs(samples) do local d = (Vector3.new(rp.Position.X, 0, rp.Position.Z) - Vector3.new(tip.X, 0, tip.Z)).Magnitude if d < best then best, bestName = d, rp.Name end end -- Must be within half a carriageway of a road sample, and at its height. local dy = math.huge for _, rp in ipairs(samples) do if rp.Name == bestName then dy = math.abs(rp.Position.Y - tip.Y) end end check( string.format("%s lands on the carriageway", r), best <= 40 and dy <= 6, string.format("%.1f st from %s, dY %.1f", best, bestName, dy) ) end end log("") log("=== 5. TRUNK SEPARATION ===") -- The two trunks spiral concentrically about the same centre; where they pass -- close in plan they must be well apart vertically (32-stud decks). local a, b = deckOf.PAEntryRampTrunk, deckOf.PAExitRampTrunk local worstSep, closePairs = math.huge, 0 for _, ea in ipairs(a) do for _, eb in ipairs(b) do local pa2, pb2 = ea.p.Position, eb.p.Position local plan = Vector3.new(pa2.X - pb2.X, 0, pa2.Z - pb2.Z).Magnitude if plan < 40 then closePairs += 1 worstSep = math.min(worstSep, math.abs(pa2.Y - pb2.Y)) end end end if closePairs == 0 then check("trunks never pass within 40 st in plan", true, "0 close pairs -- no conflict") else check( "trunks vertically separated where they pass close", worstSep >= 20, string.format("min %.1f st vertical over %d close pairs", worstSep, closePairs) ) end log("") log("=== 6. PILLARS NOT IN THE EXPRESSWAY ===") local badPillars, worstPil = 0, nil for _, d in ipairs(everything) do if d:IsA("BasePart") and d.Name == "PARampPillar" then for _, rp in ipairs(roadParts) do local dx = math.abs(d.Position.X - rp.Position.X) - rp.Size.X / 2 local dz = math.abs(d.Position.Z - rp.Position.Z) - rp.Size.Z / 2 if dx < 0 and dz < 0 then badPillars += 1 worstPil = worstPil or string.format("pillar at %.0f,%.0f under %s", d.Position.X, d.Position.Z, rp.Name) break end end end end check("no ramp pillar planted in the mainline footprint", badPillars == 0, worstPil or "0") map:Destroy() restoreLive() log("") log(string.format("RESULT %d passed, %d failed (obstacle hits total: %d)", pass, fail, totalHits)) log(string.format("live map restored: %s", tostring(workspace:FindFirstChild("Map") ~= nil))) return table.concat(out, "\n")