chore(prototype): try jumping follower past leader via MovePath component exchange
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e77fabb772
commit
39f2c63667
1 file changed
+32
-4
@@ -9,7 +9,9 @@ local TAG = "[overtake_probe] "
|
|||||||
local INTERVAL = 2.0
|
local INTERVAL = 2.0
|
||||||
local MAX_GAP = 40.0
|
local MAX_GAP = 40.0
|
||||||
local MAX_REBUILDS = 0 -- rebuild disabled: proposals were silently rejected (segments kept their ids)
|
local MAX_REBUILDS = 0 -- rebuild disabled: proposals were silently rejected (segments kept their ids)
|
||||||
local MAX_SETLINES = 5 -- EXPERIMENT: re-assign the follower to its own line + current stop to force a re-path
|
local MAX_SETLINES = 0 -- set-line disabled: lanes ahead get re-planned by the engine anyway, no forced lane change
|
||||||
|
local MAX_JUMPS = 3 -- EXPERIMENT: debug component exchange of MovePath with pathPos moved past the leader
|
||||||
|
local JUMP_AHEAD = 15.0
|
||||||
local elapsed = 0.0
|
local elapsed = 0.0
|
||||||
local ticks = 0
|
local ticks = 0
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ end
|
|||||||
local record Car
|
local record Car
|
||||||
v : integer
|
v : integer
|
||||||
pos : number
|
pos : number
|
||||||
|
pos01 : number
|
||||||
speed : number
|
speed : number
|
||||||
dir : boolean
|
dir : boolean
|
||||||
end
|
end
|
||||||
@@ -40,6 +43,7 @@ end
|
|||||||
local record ProbeState
|
local record ProbeState
|
||||||
rebuilds : integer
|
rebuilds : integer
|
||||||
setlines : integer
|
setlines : 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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -97,17 +101,31 @@ local function setLine(v : integer)
|
|||||||
api.cmd.sendCommand(api.cmd.makeVehicleSetLineCmd(v, tv.line, tv.stopIndex))
|
api.cmd.sendCommand(api.cmd.makeVehicleSetLineCmd(v, tv.line, tv.stopIndex))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- returns false when the target doesn't fit on the current edge (we don't jump across edges)
|
||||||
|
local function jumpPast(follower : Car, leader : Car) : boolean, string
|
||||||
|
if leader.pos01 <= 0 then return false, "leader pos01=0" end
|
||||||
|
local len = leader.pos / leader.pos01
|
||||||
|
local target = leader.pos + JUMP_AHEAD
|
||||||
|
if target >= len then return false, string.format("target %.1f beyond edge length %.1f", target, len) end
|
||||||
|
local mp = api.engine.getComponent(follower.v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath
|
||||||
|
mp.dyn.pathPos.pos = target
|
||||||
|
mp.dyn.pathPos.pos01 = target / len
|
||||||
|
api.cmd.sendCommand(api.cmd.debug.makeComponentExchangeCmd(follower.v, mp as Engine.Component))
|
||||||
|
return true, string.format("pos %.1f -> %.1f (leader %.1f, edge length %.1f)", follower.pos, target, leader.pos, len)
|
||||||
|
end
|
||||||
|
|
||||||
local function dump(dt : number, state : GameScriptState<ProbeState>)
|
local function dump(dt : number, state : GameScriptState<ProbeState>)
|
||||||
local st = state:get()
|
local st = state:get()
|
||||||
st.rebuilds = st.rebuilds or 0
|
st.rebuilds = st.rebuilds or 0
|
||||||
st.setlines = st.setlines or 0
|
st.setlines = st.setlines or 0
|
||||||
|
st.jumps = st.jumps or 0
|
||||||
st.watch = st.watch or {}
|
st.watch = st.watch or {}
|
||||||
local watched : {integer : boolean} = {}
|
local watched : {integer : boolean} = {}
|
||||||
for _, w in ipairs(st.watch) do watched[w] = true end
|
for _, w in ipairs(st.watch) do watched[w] = true end
|
||||||
|
|
||||||
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 })
|
||||||
p(string.format("tick=%d dt=%s playerVehicles=%d rebuilds=%d setlines=%d", ticks, tostring(dt), #vehicles, st.rebuilds, st.setlines))
|
p(string.format("tick=%d dt=%s playerVehicles=%d rebuilds=%d setlines=%d jumps=%d", ticks, tostring(dt), #vehicles, st.rebuilds, st.setlines, st.jumps))
|
||||||
|
|
||||||
local byLane : {string : {Car}} = {}
|
local byLane : {string : {Car}} = {}
|
||||||
local laneSeg : {string : integer} = {}
|
local laneSeg : {string : integer} = {}
|
||||||
@@ -128,12 +146,12 @@ local function dump(dt : number, state : GameScriptState<ProbeState>)
|
|||||||
local key = seg .. ":" .. edge.index
|
local key = seg .. ":" .. edge.index
|
||||||
byLane[key] = byLane[key] or {}
|
byLane[key] = byLane[key] or {}
|
||||||
laneSeg[key] = seg
|
laneSeg[key] = seg
|
||||||
table.insert(byLane[key], { v = v, pos = mp.dyn.pathPos.pos, speed = mp.dyn.speed, dir = dir })
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if st.rebuilds >= MAX_REBUILDS and st.setlines >= MAX_SETLINES then return end
|
if st.rebuilds >= MAX_REBUILDS and st.setlines >= MAX_SETLINES and st.jumps >= MAX_JUMPS then return end
|
||||||
for key, cars in pairs(byLane) do
|
for key, cars in pairs(byLane) do
|
||||||
for i = 1, #cars do
|
for i = 1, #cars do
|
||||||
for j = 1, #cars do
|
for j = 1, #cars do
|
||||||
@@ -143,6 +161,16 @@ local function dump(dt : number, state : GameScriptState<ProbeState>)
|
|||||||
-- leader must be moving, otherwise it's a queue at a stop or junction, not a slow vehicle
|
-- leader must be moving, otherwise it's a queue at a stop or junction, not a slow vehicle
|
||||||
if i ~= j and ahead and math.abs(b.pos - a.pos) < MAX_GAP and b.speed > 1.0 then
|
if i ~= j and ahead and math.abs(b.pos - a.pos) < MAX_GAP and b.speed > 1.0 then
|
||||||
local seg = laneSeg[key]
|
local seg = laneSeg[key]
|
||||||
|
if st.jumps < MAX_JUMPS then
|
||||||
|
local ok, why = jumpPast(a, b)
|
||||||
|
p(string.format("JUMP_TEST seg=%d follower=%d leader=%d sent=%s %s", seg, a.v, b.v, tostring(ok), why))
|
||||||
|
if ok then
|
||||||
|
st.jumps = st.jumps + 1
|
||||||
|
st.watch = { a.v, b.v }
|
||||||
|
state:set(st)
|
||||||
|
return -- one experiment per dump
|
||||||
|
end
|
||||||
|
end
|
||||||
if st.setlines < MAX_SETLINES then
|
if st.setlines < MAX_SETLINES then
|
||||||
local amp = api.engine.getComponent(a.v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath
|
local amp = api.engine.getComponent(a.v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath
|
||||||
p(string.format("SETLINE_TEST candidate seg=%d follower=%d (v=%.2f) leader=%d (v=%.2f) lanesAhead before: %s",
|
p(string.format("SETLINE_TEST candidate seg=%d follower=%d (v=%.2f) leader=%d (v=%.2f) lanesAhead before: %s",
|
||||||
|
|||||||
Reference in new issue
Block a user