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
110 lines
4.1 KiB
Luau
110 lines
4.1 KiB
Luau
-- Measure the envelope a SIMPLE straight slip-ramp must live in.
|
|
-- User's drawing: short stubs peeling off the mainline at a shallow angle,
|
|
-- running roughly PARALLEL to the highway in the strip between the mainline
|
|
-- edge and the PA lot's north edge, descending an S onto the apron.
|
|
--
|
|
-- We need to know, in real numbers:
|
|
-- 1. Where the mainline actually runs across the PA frontage (samples,
|
|
-- heading, deck Y) -- is it straight enough for a parallel slip?
|
|
-- 2. Where the lot's north edge is, and how wide the clear strip is
|
|
-- between the mainline's south edge and that lot edge.
|
|
-- 3. Deck Y vs apron Y (the height the S-curve must lose).
|
|
-- 4. What is already sitting in that strip that a ramp would hit.
|
|
|
|
local RS = game:GetService("ReplicatedStorage")
|
|
local HttpService = game:GetService("HttpService")
|
|
local Circuit = require(RS:WaitForChild("Shared"):WaitForChild("Circuit"))
|
|
|
|
local samples = Circuit.samples
|
|
local n = #samples
|
|
local c = Circuit.PA_CENTER
|
|
|
|
-- Nearest mainline sample to the PA centre.
|
|
local bestIdx, bestD = 1, math.huge
|
|
for i = 1, n do
|
|
local p = samples[i].pos
|
|
local d = (Vector3.new(p.X, 0, p.Z) - Vector3.new(c.X, 0, c.Z)).Magnitude
|
|
if d < bestD then bestD, bestIdx = d, i end
|
|
end
|
|
|
|
-- Walk a band around the PA frontage and report heading + deck Y, so we can
|
|
-- see how straight the mainline is and where a parallel slip could sit.
|
|
local band = {}
|
|
for k = -40, 40, 5 do
|
|
local i = ((bestIdx - 1 + k) % n) + 1
|
|
local s = samples[i].pos
|
|
local nx = samples[(i % n) + 1].pos
|
|
local hdg = math.deg(math.atan2(nx.Z - s.Z, nx.X - s.X))
|
|
local d = (Vector3.new(s.X, 0, s.Z) - Vector3.new(c.X, 0, c.Z)).Magnitude
|
|
table.insert(band, {
|
|
k = k, idx = i,
|
|
x = math.floor(s.X), y = math.floor(s.Y + 0.5), z = math.floor(s.Z),
|
|
hdg = math.floor(hdg + 0.5),
|
|
distPA = math.floor(d),
|
|
})
|
|
end
|
|
|
|
-- The apron / lot floor: bounds and surface height.
|
|
local map = workspace:FindFirstChild("Map")
|
|
local floor = map and map:FindFirstChild("PAFloor", true)
|
|
local lot = nil
|
|
if floor then
|
|
lot = {
|
|
name = floor.Name,
|
|
surfaceY = floor.Position.Y + floor.Size.Y / 2,
|
|
x_min = math.floor(floor.Position.X - floor.Size.X / 2),
|
|
x_max = math.floor(floor.Position.X + floor.Size.X / 2),
|
|
z_min = math.floor(floor.Position.Z - floor.Size.Z / 2),
|
|
z_max = math.floor(floor.Position.Z + floor.Size.Z / 2),
|
|
}
|
|
end
|
|
|
|
-- What already occupies the strip between the mainline and the lot's north
|
|
-- edge? Anything here is a collision candidate for a parallel slip ramp.
|
|
-- Strip = north third of the lot bbox, i.e. Z above (z_max - 220).
|
|
local obstacles = {}
|
|
if lot then
|
|
local stripZ = lot.z_max - 220
|
|
for _, d in ipairs(workspace:GetDescendants()) do
|
|
if d:IsA("BasePart") then
|
|
local p = d.Position
|
|
if p.Z >= stripZ and p.Z <= lot.z_max + 160
|
|
and p.X >= lot.x_min - 60 and p.X <= lot.x_max + 60 then
|
|
local key = d.Name
|
|
local e = obstacles[key]
|
|
if not e then
|
|
e = { n = 0, x_min = 1e9, x_max = -1e9, z_min = 1e9,
|
|
z_max = -1e9, y_max = -1e9 }
|
|
obstacles[key] = e
|
|
end
|
|
e.n += 1
|
|
e.x_min = math.min(e.x_min, p.X); e.x_max = math.max(e.x_max, p.X)
|
|
e.z_min = math.min(e.z_min, p.Z); e.z_max = math.max(e.z_max, p.Z)
|
|
e.y_max = math.max(e.y_max, p.Y + d.Size.Y / 2)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local obsOut = {}
|
|
for k, e in pairs(obstacles) do
|
|
table.insert(obsOut, {
|
|
name = k, n = e.n,
|
|
x = math.floor(e.x_min) .. ".." .. math.floor(e.x_max),
|
|
z = math.floor(e.z_min) .. ".." .. math.floor(e.z_max),
|
|
ytop = math.floor(e.y_max),
|
|
})
|
|
end
|
|
table.sort(obsOut, function(a, b) return a.n > b.n end)
|
|
while #obsOut > 25 do table.remove(obsOut) end
|
|
|
|
return HttpService:JSONEncode({
|
|
bestIdx = bestIdx,
|
|
nearestDist = math.floor(bestD),
|
|
pa_center = { math.floor(c.X), math.floor(c.Y), math.floor(c.Z) },
|
|
pa_radius = Circuit.PA_RADIUS,
|
|
band = band,
|
|
lot = lot,
|
|
strip_obstacles = obsOut,
|
|
})
|