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:
1 parent
0465a93e04
commit
9623abb868
3 files changed
+11
-108
No files matched your search
@@ -84,3 +84,10 @@ Scanned: the 9 mods in `C:\Users\Public\mod.io\10640\mods\` (e.g. `devers_1`, `m
|
|||||||
## Segment rebuild dropped (2026-10-05)
|
## Segment rebuild dropped (2026-10-05)
|
||||||
|
|
||||||
The human confirmed in game what the log showed: rebuilding the segment under a held-back vehicle does not get it past the blocker on a single-lane road. The rebuild code is removed from the probe (it's still in git history, last in commit 5d3a254). The lane split after rebuilds on multilane roads (see above) is left as an observation for the multilane ticket, not pursued here.
|
The human confirmed in game what the log showed: rebuilding the segment under a held-back vehicle does not get it past the blocker on a single-lane road. The rebuild code is removed from the probe (it's still in git history, last in commit 5d3a254). The lane split after rebuilds on multilane roads (see above) is left as an observation for the multilane ticket, not pursued here.
|
||||||
|
|
||||||
|
## Position flip via `MovePath` exchange on the GUI thread (run 2026-10-05 ~21:23 UTC)
|
||||||
|
|
||||||
|
- On the GUI thread (`guiUpdate`, with a callback), `api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(follower, leaderMovePath), cb)` fails with the **same** `Error decoding argument #3: The lua object can't be cast to desired type`, and the callback is never reached. Debug mode was active.
|
||||||
|
- So the error is not about callbacks or threads: **the exchange refuses a `MovePath`**, consistent with its doc comment (`EmissionEmitter` or `ModelInstanceList` only).
|
||||||
|
- **Conclusion: no script API can write a road vehicle's position or route.** Moving a vehicle past another (jump, flip, teleport) is impossible for line vehicles. The only exception is `jumpToDepotEntity`, which can only target a depot.
|
||||||
|
- The probe retried every frame (5951 errors) because the error came before the counter was incremented. The experiment is removed, and the probe is logging-only again.
|
||||||
@@ -4,8 +4,5 @@ function data()
|
|||||||
updateScript = {
|
updateScript = {
|
||||||
fileName = "overtake_probe.script@update",
|
fileName = "overtake_probe.script@update",
|
||||||
},
|
},
|
||||||
guiUpdateScript = {
|
|
||||||
fileName = "overtake_probe.script@guiUpdate",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
-- PROTOTYPE (ticket "Can a script swap the positions of a follower and its leader?"): throwaway,
|
-- PROTOTYPE: throwaway, lives only on branch prototype/vehicle-probe.
|
||||||
-- lives only on branch prototype/vehicle-probe.
|
-- Every INTERVAL it logs every player-owned road vehicle (segment, lane, position, speed).
|
||||||
-- Engine thread: 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
|
||||||
-- 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
|
|
||||||
-- docs/research/vehicle-probe.md; none moved a vehicle past another on a single-lane road.
|
-- 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).
|
-- ponytail: module-local timer, not GameScriptState; fine for a probe (state resets between calls anyway).
|
||||||
|
|
||||||
local TAG = "[overtake_probe] "
|
local TAG = "[overtake_probe] "
|
||||||
local INTERVAL = 2.0
|
local INTERVAL = 2.0
|
||||||
local MAX_GAP = 40.0
|
|
||||||
local elapsed = 0.0
|
local elapsed = 0.0
|
||||||
local ticks = 0
|
local ticks = 0
|
||||||
|
|
||||||
@@ -29,14 +26,6 @@ local function turnaround(edge : EdgeId) : integer
|
|||||||
return tn.turnaroundEdges[edge.index + 1]
|
return tn.turnaroundEdges[edge.index + 1]
|
||||||
end
|
end
|
||||||
|
|
||||||
local record Car
|
|
||||||
v : integer
|
|
||||||
pos : number
|
|
||||||
pos01 : number
|
|
||||||
speed : number
|
|
||||||
dir : boolean
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dump(dt : number)
|
local function dump(dt : number)
|
||||||
local player = api.engine.util.getPlayer()
|
local player = api.engine.util.getPlayer()
|
||||||
local vehicles = api.engine.getEntitiesWithComponent(api.type.ComponentType.TRANSPORT_VEHICLE, { requireOwnedByPlayer = player })
|
local vehicles = api.engine.getEntitiesWithComponent(api.type.ComponentType.TRANSPORT_VEHICLE, { requireOwnedByPlayer = player })
|
||||||
@@ -56,94 +45,7 @@ local function dump(dt : number)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- EXPERIMENT (GUI thread, where sendCommand callbacks work): flip the positions of a follower and its leader by
|
local ret : GameScript<table> = {
|
||||||
-- 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> = {
|
|
||||||
update = function(_userParams : table, _state : GameScriptState<table>, dt : number) : nil
|
update = function(_userParams : table, _state : GameScriptState<table>, dt : number) : nil
|
||||||
ticks = ticks + 1
|
ticks = ticks + 1
|
||||||
elapsed = elapsed + dt
|
elapsed = elapsed + dt
|
||||||
@@ -152,9 +54,6 @@ local ret : GameScriptWithGui<table, GuiState> = {
|
|||||||
elapsed = 0.0
|
elapsed = 0.0
|
||||||
xpcall(dump, function(err : any) p("ERROR " .. tostring(err)) end, dt)
|
xpcall(dump, function(err : any) p("ERROR " .. tostring(err)) end, dt)
|
||||||
end,
|
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
|
return ret
|
||||||
Reference in new issue
Block a user