-- Triage the obstacle hits: WHAT is hit, on WHICH segments, and how far -- through the run. Contact with the apron at the ring mouth and with the -- carriageway at the merge is intended; contact with a pier is never. -- SAFETY: MapBuilder.build() destroys Workspace.Map first. Stash the live map -- aside and restore it afterwards -- see verify_shared_ramps.luau. 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 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 src = ServerScriptService:FindFirstChild("Server") src = src and src:FindFirstChild("MapBuilder") or ServerScriptService:FindFirstChild("MapBuilder", true) local MapBuilder = require(src:Clone()) local map = MapBuilder.build and MapBuilder.build() or MapBuilder.Build() map.Name = "TRIAGE_CLONE" map.Parent = workspace local RUNS = { "PAEntryRampTrunk", "PAEntryRampNear", "PAEntryRampCross", "PAEntryRampMerge", "PAExitRampTrunk", "PAExitRampNear", "PAExitRampCross", "PAExitRampMerge", } local deckOf = {} for _, r in ipairs(RUNS) do deckOf[r] = {} end for _, d in ipairs(map:GetDescendants()) 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 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 -- Normalise an obstacle name to its class (Road_537 -> Road_). local function klass(n) if n:sub(1, 5) == "Road_" then return "Road_*" end return (n:gsub("_%d+$", "_*")) end for _, r in ipairs(RUNS) do local segs = deckOf[r] local byClass = {} for k, e in ipairs(segs) do local params = OverlapParams.new() params.FilterType = Enum.RaycastFilterType.Include params.FilterDescendantsInstances = { map } params.MaxParts = 60 for _, o in ipairs(workspace:GetPartsInPart(e.p, params)) do if o ~= e.p and not isRampPart(o) then local c = klass(o.Name) local rec = byClass[c] if not rec then rec = { lo = k, hi = k, n = 0 } byClass[c] = rec end rec.lo = math.min(rec.lo, k) rec.hi = math.max(rec.hi, k) rec.n += 1 end end end local any = false for c, rec in pairs(byClass) do any = true log( string.format( "%-18s %-16s segs %d..%d of %d (%.0f%%..%.0f%% along) %d contacts", r, c, rec.lo, rec.hi, #segs, rec.lo / #segs * 100, rec.hi / #segs * 100, rec.n ) ) end if not any then log(string.format("%-18s CLEAN", r)) end end map:Destroy() restoreLive() log(string.format("live map restored: %s", tostring(workspace:FindFirstChild("Map") ~= nil))) return table.concat(out, "\n")