chore(prototype): remove GUI position flip; MovePath exchange refused on both threads

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
haylanandClaude Bot committed 2026-10-05 23:27:39 +02:00
1 parent 0465a93e04
commit 9623abb868
3 files changed
+11 -108

No files matched your search

-3
View File
@@ -4,8 +4,5 @@ function data()
updateScript = {
fileName = "overtake_probe.script@update",
},
guiUpdateScript = {
fileName = "overtake_probe.script@guiUpdate",
},
}
end
+4 -105
View File
@@ -1,14 +1,11 @@
-- PROTOTYPE (ticket "Can a script swap the positions of a follower and its leader?"): throwaway,
-- lives only on branch prototype/vehicle-probe.
-- Engine thread: every INTERVAL it logs every player-owned road vehicle (segment, lane, position, speed).
-- GUI thread: EXPERIMENT flipping the positions of a follower and its leader (see below).
-- Earlier experiments (timeToIgnore, engine-side jump, set-line, segment rebuild) are in git history and
-- PROTOTYPE: throwaway, lives only on branch prototype/vehicle-probe.
-- Every INTERVAL it logs every player-owned road vehicle (segment, lane, position, speed).
-- All experiments (timeToIgnore, jump, set-line, segment rebuild, GUI position flip) are in git history and
-- docs/research/vehicle-probe.md; none moved a vehicle past another on a single-lane road.
-- ponytail: module-local timer, not GameScriptState; fine for a probe (state resets between calls anyway).
local TAG = "[overtake_probe] "
local INTERVAL = 2.0
local MAX_GAP = 40.0
local elapsed = 0.0
local ticks = 0
@@ -29,14 +26,6 @@ local function turnaround(edge : EdgeId) : integer
return tn.turnaroundEdges[edge.index + 1]
end
local record Car
v : integer
pos : number
pos01 : number
speed : number
dir : boolean
end
local function dump(dt : number)
local player = api.engine.util.getPlayer()
local vehicles = api.engine.getEntitiesWithComponent(api.type.ComponentType.TRANSPORT_VEHICLE, { requireOwnedByPlayer = player })
@@ -56,94 +45,7 @@ local function dump(dt : number)
end
end
-- EXPERIMENT (GUI thread, where sendCommand callbacks work): flip the positions of a follower and its leader by
-- exchanging their MovePath components (route + position) with api.cmd.debug.makeComponentExchangeCmd.
local MAX_FLIPS = 2
local FLIP_SCAN_FRAMES = 60 -- scan for a pair about once per second
local FLIP_TRACE_FRAMES = 600 -- then log both vehicles every 10 frames for ~10 s
local record GuiState
frames : integer
flips : integer
traceLeft : integer
a : integer
b : integer
end
local function movePathOf(v : integer) : Engine.Component.MovePath
return api.engine.getComponent(v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath
end
local function flipLine(v : integer) : string
local mp = movePathOf(v)
if mp == nil then return "veh=" .. v .. " no MovePath" end
local edge, _dir = edgeAt(mp)
return string.format("veh=%d seg=%s lane=%s pos=%.1f v=%.2f", v, tostring(edge and edge.entity), tostring(edge and edge.index), mp.dyn.pathPos.pos, mp.dyn.speed)
end
local function sendFlip(gs : GuiState, follower : integer, leader : integer)
local mpF, mpL = movePathOf(follower), movePathOf(leader)
p("FLIP_TEST before " .. flipLine(follower) .. " | " .. flipLine(leader))
local function done(label : string) : function(any, boolean)
return function(res : any, success : boolean)
p(string.format("FLIP_TEST result %s success=%s res=%s", label, tostring(success), tostring(res)))
end
end
api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(follower, mpL as Engine.Component), done("follower<-leader"))
api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(leader, mpF as Engine.Component), done("leader<-follower"))
gs.flips = gs.flips + 1
gs.traceLeft = FLIP_TRACE_FRAMES
gs.a, gs.b = follower, leader
end
-- same pair rule as the engine-side probe: same segment + lane, follower < MAX_GAP behind a moving leader
local function findPair() : integer, integer
local player = api.engine.util.getPlayer()
local byLane : {string : {Car}} = {}
for _, v in ipairs(api.engine.getEntitiesWithComponent(api.type.ComponentType.TRANSPORT_VEHICLE, { requireOwnedByPlayer = player })) do
local lv = api.engine.getComponent(v, api.type.ComponentType.LAND_VEHICLE) as Engine.Component.LandVehicle
local mp = movePathOf(v)
if lv ~= nil and not lv.isTram and mp ~= nil then
local edge, dir = edgeAt(mp)
if edge ~= nil then
local key = edge.entity .. ":" .. edge.index
byLane[key] = byLane[key] or {}
table.insert(byLane[key], { v = v, pos = mp.dyn.pathPos.pos, pos01 = mp.dyn.pathPos.pos01, speed = mp.dyn.speed, dir = dir })
end
end
end
for _, cars in pairs(byLane) do
for i = 1, #cars do
for j = 1, #cars do
local a, b = cars[i], cars[j]
local ahead = (a.dir and b.pos > a.pos) or (not a.dir and b.pos < a.pos)
if i ~= j and ahead and math.abs(b.pos - a.pos) < MAX_GAP and b.speed > 1.0 then
return a.v, b.v
end
end
end
end
return nil, nil
end
local function guiStep(gsState : GameScriptState<GuiState>)
local gs = gsState:get()
gs.frames = (gs.frames or 0) + 1
gs.flips = gs.flips or 0
gs.traceLeft = gs.traceLeft or 0
if gs.traceLeft > 0 then
if gs.traceLeft % 10 == 0 then
p(string.format("FLIP_TRACE f=%d %s | %s", FLIP_TRACE_FRAMES - gs.traceLeft, flipLine(gs.a), flipLine(gs.b)))
end
gs.traceLeft = gs.traceLeft - 1
elseif gs.flips < MAX_FLIPS and gs.frames % FLIP_SCAN_FRAMES == 0 then
local follower, leader = findPair()
if follower ~= nil then sendFlip(gs, follower, leader) end
end
gsState:set(gs)
end
local ret : GameScriptWithGui<table, GuiState> = {
local ret : GameScript<table> = {
update = function(_userParams : table, _state : GameScriptState<table>, dt : number) : nil
ticks = ticks + 1
elapsed = elapsed + dt
@@ -152,9 +54,6 @@ local ret : GameScriptWithGui<table, GuiState> = {
elapsed = 0.0
xpcall(dump, function(err : any) p("ERROR " .. tostring(err)) end, dt)
end,
guiUpdate = function(_userParams : table, _state : GameScriptStateReadOnly<table>, guiState : GameScriptState<GuiState>)
xpcall(guiStep, function(err : any) p("ERROR gui " .. tostring(err)) end, guiState)
end,
}
return ret