-- PROTOTYPE (ticket "Probe vehicle data and native passing in game"): throwaway, lives only on branch prototype/vehicle-probe. -- Every INTERVAL it dumps every player-owned road vehicle, then groups them by street segment -- so lanes (edge index) and oncoming traffic (opposite direction / turnaround edge) are visible in stdout.txt. -- ponytail: module-local timer, not GameScriptState; fine for a probe, resets on reload. local TAG = "[overtake_probe] " local INTERVAL = 5.0 local elapsed = 0.0 local ticks = 0 local function p(s : string) print(TAG .. s) end local function edgeAt(mp : Engine.Component.MovePath) : EdgeId, boolean -- path.edges is 1-based, elements are EdgeIdDir userdata (tealdef says {EdgeId, boolean}) local e = (mp.path.edges as {any})[mp.dyn.pathPos.edgeIndex + 1] as UtilPathfinding.EdgeIdDir if e == nil then return nil, nil end return e.edgeId, e.dir end local function turnaround(edge : EdgeId) : integer local tn = api.engine.getComponent(edge.entity, api.type.ComponentType.TRANSPORT_NETWORK) as Engine.Component.TransportNetwork if tn == nil or tn.turnaroundEdges == nil then return nil end return tn.turnaroundEdges[edge.index + 1] end local function modes(m : {TransportMode : boolean}) : string local out : {string} = {} for k, v in pairs(m or {}) do if v then table.insert(out, tostring(k)) end end return table.concat(out, ",") end -- per street segment: BaseEdge lane layout + TransportNetwork lanes (modes, speed, opposite lane) local function segmentInfo(seg : integer) : string local be = api.engine.getComponent(seg, api.type.ComponentType.BASE_EDGE) as Engine.Component.BaseEdge local tn = api.engine.getComponent(seg, api.type.ComponentType.TRANSPORT_NETWORK) as Engine.Component.TransportNetwork local parts : {string} = {} if be ~= nil then table.insert(parts, string.format("roadType=%s template=%s laneConfigs=%d", tostring(be.roadType), tostring(be.roadTemplate), #be.laneConfigs)) for i, lc in ipairs(be.laneConfigs) do table.insert(parts, string.format(" lc%d fwd=%s off=%.1f w=%.1f modes=[%s]", i, tostring(lc.forward), lc.offset, lc.width, modes(lc.transportModes))) end end if tn ~= nil then table.insert(parts, string.format("tnEdges=%d", #tn.edges)) for i, e in ipairs(tn.edges) do table.insert(parts, string.format(" tn%d modes=[%s] speedLimit=%.1f curSpeed=%.1f turnaround=%s", i - 1, modes(e.transportModes), e.speedLimit, e.curSpeed, tostring(tn.turnaroundEdges[i]))) end end return table.concat(parts, "\n" .. TAG .. " ") end local function dump(dt : number) local player = api.engine.util.getPlayer() local vehicles = api.engine.getEntitiesWithComponent(api.type.ComponentType.TRANSPORT_VEHICLE, { requireOwnedByPlayer = player }) p(string.format("tick=%d dt=%s playerVehicles=%d", ticks, tostring(dt), #vehicles)) local bySegment : {integer : {string}} = {} for _, v in ipairs(vehicles) do local lv = api.engine.getComponent(v, api.type.ComponentType.LAND_VEHICLE) as Engine.Component.LandVehicle local mp = api.engine.getComponent(v, api.type.ComponentType.MOVE_PATH) as Engine.Component.MovePath if lv ~= nil and not lv.isTram and mp ~= nil then local edge, dir = edgeAt(mp) local info = api.engine.system.landVehicleMoveSystem.getVehicleInfo(v) local seg = edge and edge.entity or -1 local line = string.format( "veh=%d seg=%d lane=%s dir=%s turnaround=%s pos=%.1f speed=%.2f accel=%.2f blocked=%s state=%s standing=%.1f timeToIgnore=%.2f timeUntilAccel=%.2f occ=%s..%s brake=%.1f power=%s traction=%s", v, seg, tostring(edge and edge.index), tostring(dir), tostring(edge and turnaround(edge)), mp.dyn.pathPos.pos, mp.dyn.speed, mp.dyn.accel, tostring(mp.blocked), tostring(mp.state), mp.dyn.timeStanding, mp.dyn.timeToIgnore, mp.dyn.timeUntilAccel, tostring(mp.occupiedBackIndex), tostring(mp.occupiedFrontIndex), lv.dyn.brakingTimer, tostring(info and info.availPower), tostring(info and info.traction)) p(line) bySegment[seg] = bySegment[seg] or {} table.insert(bySegment[seg], string.format("%d(lane=%s,dir=%s,v=%.1f,blk=%s)", v, tostring(edge and edge.index), tostring(dir), mp.dyn.speed, tostring(mp.blocked))) end end for seg, list in pairs(bySegment) do if #list > 1 then p(string.format("SHARED seg=%d: %s", seg, table.concat(list, " "))) p(" SEGMENT " .. seg .. " " .. segmentInfo(seg)) end end end local ret : GameScript = { update = function(_userParams : table, _state : GameScriptState
, dt : number) : nil ticks = ticks + 1 elapsed = elapsed + dt if ticks == 1 then p("update running, first dt=" .. tostring(dt)) end if elapsed < INTERVAL then return end elapsed = 0.0 xpcall(dump, function(err : any) p("ERROR " .. tostring(err)) end, dt) end, } return ret