chore(prototype): per-tick trace after rebuild, multilane only; record two-way result
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d4fab92fd4
commit
90829ee9b9
2 files changed
+28
-1
No files matched your search
@@ -75,3 +75,8 @@ Scanned: the 9 mods in `C:\Users\Public\mod.io\10640\mods\` (e.g. `devers_1`, `m
|
|||||||
- Likely cause (human's hypothesis): the vehicles' `MovePath` refers to lanes of the removed segment, so the engine must re-attach them to the new segment and re-plan, and a vehicle can land in a different lane.
|
- Likely cause (human's hypothesis): the vehicles' `MovePath` refers to lanes of the removed segment, so the engine must re-attach them to the new segment and re-plan, and a vehicle can land in a different lane.
|
||||||
- **Debug `MovePath` exchange is unusable from engine state**: `api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(v, movePath))` fails with `Error decoding argument #3` even **without** a callback. So the earlier error wasn't caused by the callback. The only untried route is the GUI thread.
|
- **Debug `MovePath` exchange is unusable from engine state**: `api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(v, movePath))` fails with `Error decoding argument #3` even **without** a callback. So the earlier error wasn't caused by the callback. The only untried route is the GUI thread.
|
||||||
- Not yet tested: a rebuild on a two-way (one lane per direction) road.
|
- Not yet tested: a rebuild on a two-way (one lane per direction) road.
|
||||||
|
|
||||||
|
## Rebuild on a two-way road (run 2026-10-05 ~21:12 UTC)
|
||||||
|
|
||||||
|
- 3 `replaceSegment` rebuilds on `country_new_small` (one lane per direction), segments 30213, 29776 and 30215, follower 25.8 m behind leader. **No effect**: the next snapshot had the same gap (22.6/48.4 → 49.3/75.1), both vehicles stayed in lane 2, same speeds, same order for 10+ snapshots. Rebuilding does not move vehicles past each other on single-lane roads.
|
||||||
|
- How the multilane lane change happens is still uncaught: snapshots every 2 s only show before (both lane 4) and after (the leader in lane 3 two segments later). The probe now traces the two vehicles on every update for ~30 s after a rebuild (`TRACE` lines), and rebuilds only multilane segments.
|
||||||
@@ -12,6 +12,7 @@ local MAX_REBUILDS = 3 -- hand-built proposals were silently rejected; now via a
|
|||||||
local MAX_SETLINES = 0 -- set-line disabled: lanes ahead get re-planned by the engine anyway, no forced lane change
|
local MAX_SETLINES = 0 -- set-line disabled: lanes ahead get re-planned by the engine anyway, no forced lane change
|
||||||
local MAX_JUMPS = 0 -- dead: sendCommand(makeComponentExchangeCmd(...)) fails in engine state even without a callback
|
local MAX_JUMPS = 0 -- dead: sendCommand(makeComponentExchangeCmd(...)) fails in engine state even without a callback
|
||||||
local JUMP_AHEAD = 15.0
|
local JUMP_AHEAD = 15.0
|
||||||
|
local WATCH_TICKS = 150 -- ~30 s of game time at dt=0.2: log watched vehicles every update after a rebuild
|
||||||
local elapsed = 0.0
|
local elapsed = 0.0
|
||||||
local ticks = 0
|
local ticks = 0
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ local record ProbeState
|
|||||||
setlines : integer
|
setlines : integer
|
||||||
jumps : integer
|
jumps : integer
|
||||||
watch : {integer} -- vehicles involved in the last rebuild, flagged in later dumps
|
watch : {integer} -- vehicles involved in the last rebuild, flagged in later dumps
|
||||||
|
watchLeft : integer -- updates left for per-tick logging of the watched vehicles
|
||||||
end
|
end
|
||||||
|
|
||||||
-- No edge objects (stops, signals),
|
-- No edge objects (stops, signals),
|
||||||
@@ -61,7 +63,8 @@ local function rebuildable(seg : integer) : boolean, string
|
|||||||
if on and (tonumber(tostring(k)) or 0) >= 2 then driving = driving + 1 break end
|
if on and (tonumber(tostring(k)) or 0) >= 2 then driving = driving + 1 break end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- any lane count: what a rebuild does to vehicles on the segment doesn't depend on it
|
-- one lane per direction: 3 rebuilds there changed nothing (same gap, same lane), so trace multilane only
|
||||||
|
if driving < 4 then return false, "driving lanes=" .. driving .. " (single-lane rebuilds showed no effect)" end
|
||||||
return true, string.format("drivingLanes=%d template=%s length=%.1f", driving, tostring(be.roadTemplate), be.distance)
|
return true, string.format("drivingLanes=%d template=%s length=%.1f", driving, tostring(be.roadTemplate), be.distance)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -176,6 +179,7 @@ local function dump(dt : number, state : GameScriptState<ProbeState>)
|
|||||||
rebuild(seg)
|
rebuild(seg)
|
||||||
st.rebuilds = st.rebuilds + 1
|
st.rebuilds = st.rebuilds + 1
|
||||||
st.watch = { a.v, b.v }
|
st.watch = { a.v, b.v }
|
||||||
|
st.watchLeft = WATCH_TICKS
|
||||||
state:set(st)
|
state:set(st)
|
||||||
p(string.format("REBUILD_TEST sent #%d seg=%d", st.rebuilds, seg))
|
p(string.format("REBUILD_TEST sent #%d seg=%d", st.rebuilds, seg))
|
||||||
return -- one rebuild per dump
|
return -- one rebuild per dump
|
||||||
@@ -186,10 +190,28 @@ local function dump(dt : number, state : GameScriptState<ProbeState>)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- per-update trace of the watched vehicles, to catch the moment a lane changes
|
||||||
|
local function trace(state : GameScriptState<ProbeState>)
|
||||||
|
local st = state:get()
|
||||||
|
if (st.watchLeft or 0) <= 0 or st.watch == nil then return end
|
||||||
|
for _, v in ipairs(st.watch) do
|
||||||
|
local mp = api.engine.getComponent(v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath
|
||||||
|
if mp ~= nil then
|
||||||
|
local edge, _dir = edgeAt(mp)
|
||||||
|
p(string.format("TRACE t=%d veh=%d seg=%s lane=%s pos=%.1f v=%.2f ahead=%s",
|
||||||
|
WATCH_TICKS - st.watchLeft, v, tostring(edge and edge.entity), tostring(edge and edge.index),
|
||||||
|
mp.dyn.pathPos.pos, mp.dyn.speed, lanesAhead(mp)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
st.watchLeft = st.watchLeft - 1
|
||||||
|
state:set(st)
|
||||||
|
end
|
||||||
|
|
||||||
local ret : GameScript<ProbeState> = {
|
local ret : GameScript<ProbeState> = {
|
||||||
update = function(_userParams : table, state : GameScriptState<ProbeState>, dt : number) : nil
|
update = function(_userParams : table, state : GameScriptState<ProbeState>, dt : number) : nil
|
||||||
ticks = ticks + 1
|
ticks = ticks + 1
|
||||||
elapsed = elapsed + dt
|
elapsed = elapsed + dt
|
||||||
|
if dt > 0 then xpcall(trace, function(err : any) p("ERROR trace " .. tostring(err)) end, state) end
|
||||||
if ticks == 1 then p("update running, first dt=" .. tostring(dt)) end
|
if ticks == 1 then p("update running, first dt=" .. tostring(dt)) end
|
||||||
if elapsed < INTERVAL then return end
|
if elapsed < INTERVAL then return end
|
||||||
elapsed = 0.0
|
elapsed = 0.0
|
||||||
|
|||||||
Reference in new issue
Block a user