Move LZB system to core and unify approach callback mechanism
This commit is contained in:
parent
c50224e05c
commit
ea33ad9de0
|
@ -180,8 +180,9 @@ minetest.register_node(nodename, {
|
|||
^- called when a train leaves the rail
|
||||
|
||||
-- The following function is only in effect when interlocking is enabled:
|
||||
on_train_approach = function(pos, train_id, train, index)
|
||||
on_train_approach = function(pos, train_id, train, index, lzbdata)
|
||||
^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time)
|
||||
^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail.
|
||||
^- lzbdata should be ignored and nothing should be assigned to it
|
||||
}
|
||||
})
|
||||
|
|
|
@ -25,6 +25,7 @@ local no_action=false
|
|||
local function reload_saves()
|
||||
atwarn("Restoring saved state in 1 second...")
|
||||
no_action=true
|
||||
advtrains.lock_path_inval = false
|
||||
--read last save state and continue, as if server was restarted
|
||||
for aoi, le in pairs(minetest.luaentities) do
|
||||
if le.is_wagon then
|
||||
|
@ -192,6 +193,8 @@ dofile(advtrains.modpath.."/craft_items.lua")
|
|||
dofile(advtrains.modpath.."/log.lua")
|
||||
dofile(advtrains.modpath.."/passive.lua")
|
||||
|
||||
dofile(advtrains.modpath.."/lzb.lua")
|
||||
|
||||
|
||||
--load/save
|
||||
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
-- lzb.lua
|
||||
-- Enforced and/or automatic train override control, providing the on_train_approach callback
|
||||
|
||||
--[[
|
||||
Documentation of train.lzb table
|
||||
train.lzb = {
|
||||
trav = Current index that the traverser has advanced so far
|
||||
oncoming = table containing oncoming signals, in order of appearance on the path
|
||||
{
|
||||
pos = position of the point
|
||||
idx = where this is on the path
|
||||
spd = speed allowed to pass
|
||||
fun = function(pos, id, train, index, speed, lzbdata)
|
||||
-- Function that determines what to do on the train in the moment it drives over that point.
|
||||
}
|
||||
}
|
||||
each step, for every item in "oncoming", we need to determine the location to start braking (+ some safety margin)
|
||||
and, if we passed this point for at least one of the items, initiate brake.
|
||||
When speed has dropped below, say 3, decrease the margin to zero, so that trains actually stop at the signal IP.
|
||||
The spd variable and travsht need to be updated on every aspect change. it's probably best to reset everything when any aspect changes
|
||||
]]
|
||||
|
||||
|
||||
local params = {
|
||||
BRAKE_SPACE = 10,
|
||||
AWARE_ZONE = 50,
|
||||
|
||||
ADD_STAND = 2.5,
|
||||
ADD_SLOW = 1.5,
|
||||
ADD_FAST = 7,
|
||||
ZONE_ROLL = 2,
|
||||
ZONE_HOLD = 5, -- added on top of ZONE_ROLL
|
||||
ZONE_VSLOW = 3, -- When speed is <2, still allow accelerating
|
||||
|
||||
DST_FACTOR = 1.5,
|
||||
|
||||
SHUNT_SPEED_MAX = advtrains.SHUNT_SPEED_MAX,
|
||||
}
|
||||
|
||||
function advtrains.set_lzb_param(par, val)
|
||||
if params[par] and tonumber(val) then
|
||||
params[par] = tonumber(val)
|
||||
else
|
||||
error("Inexistant param or not a number")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function look_ahead(id, train)
|
||||
|
||||
local acc = advtrains.get_acceleration(train, 1)
|
||||
local vel = train.velocity
|
||||
local brakedst = ( -(vel*vel) / (2*acc) ) * params.DST_FACTOR
|
||||
|
||||
local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE)
|
||||
--local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE)
|
||||
|
||||
local lzb = train.lzb
|
||||
local trav = lzb.trav
|
||||
|
||||
--train.debug = lspd
|
||||
|
||||
while trav <= brake_i do
|
||||
trav = trav + 1
|
||||
local pos = advtrains.path_get(train, trav)
|
||||
-- check offtrack
|
||||
if trav > train.path_trk_f then
|
||||
table.insert(lzb.oncoming, {
|
||||
pos = pos,
|
||||
idx = trav-1,
|
||||
spd = 0,
|
||||
})
|
||||
else
|
||||
-- run callbacks
|
||||
-- Note: those callbacks are defined in trainlogic.lua for consistency with the other node callbacks
|
||||
advtrains.tnc_call_approach_callback(pos, id, train, trav, lzb.data)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
lzb.trav = trav
|
||||
|
||||
end
|
||||
|
||||
--[[
|
||||
Distance needed to accelerate from v0 to v1 with constant acceleration a:
|
||||
|
||||
v1 - v0 a / v1 - v0 \ 2
|
||||
s = v0 * ------- + - * | ------- |
|
||||
a 2 \ a /
|
||||
]]
|
||||
|
||||
local function apply_control(id, train)
|
||||
local lzb = train.lzb
|
||||
|
||||
local i = 1
|
||||
while i<=#lzb.oncoming do
|
||||
if lzb.oncoming[i].idx < train.index then
|
||||
local ent = lzb.oncoming[i]
|
||||
if ent.fun then
|
||||
ent.fun(ent.pos, id, train, ent.idx, ent.spd, lzb.data)
|
||||
end
|
||||
|
||||
table.remove(lzb.oncoming, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
for i, it in ipairs(lzb.oncoming) do
|
||||
local a = advtrains.get_acceleration(train, 1) --should be negative
|
||||
local v0 = train.velocity
|
||||
local v1 = it.spd
|
||||
if v1 and v1 <= v0 then
|
||||
local f = (v1-v0) / a
|
||||
local s = v0*f + a*f*f/2
|
||||
|
||||
local st = s + params.ADD_SLOW
|
||||
if v0 > 3 then
|
||||
st = s + params.ADD_FAST
|
||||
end
|
||||
if v0<=0 then
|
||||
st = s + params.ADD_STAND
|
||||
end
|
||||
|
||||
local i = advtrains.path_get_index_by_offset(train, it.idx, -st)
|
||||
|
||||
--train.debug = dump({v0f=v0*f, aff=a*f*f,v0=v0, v1=v1, f=f, a=a, s=s, st=st, i=i, idx=train.index})
|
||||
if i <= train.index then
|
||||
-- Gotcha! Braking...
|
||||
train.ctrl.lzb = 1
|
||||
--train.debug = train.debug .. "BRAKE!!!"
|
||||
return
|
||||
end
|
||||
|
||||
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_ROLL)
|
||||
if i <= train.index and v0>1 then
|
||||
-- roll control
|
||||
train.ctrl.lzb = 2
|
||||
return
|
||||
end
|
||||
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_HOLD)
|
||||
if i <= train.index and v0>1 then
|
||||
-- hold speed
|
||||
train.ctrl.lzb = 3
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
train.ctrl.lzb = nil
|
||||
end
|
||||
|
||||
local function invalidate(train)
|
||||
train.lzb = {
|
||||
trav = atfloor(train.index),
|
||||
data = {},
|
||||
oncoming = {},
|
||||
}
|
||||
end
|
||||
|
||||
function advtrains.lzb_invalidate(train)
|
||||
invalidate(train)
|
||||
end
|
||||
|
||||
-- Add LZB control point
|
||||
-- udata: User-defined additional data
|
||||
function advtrains.lzb_add_checkpoint(train, index, speed, callback, udata)
|
||||
local lzb = train.lzb
|
||||
local pos = advtrains.path_get(train, index)
|
||||
table.insert(lzb.oncoming, {
|
||||
pos = pos,
|
||||
idx = index,
|
||||
spd = speed,
|
||||
fun = callback,
|
||||
data = udata,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
advtrains.te_register_on_new_path(function(id, train)
|
||||
invalidate(train)
|
||||
look_ahead(id, train)
|
||||
end)
|
||||
|
||||
advtrains.te_register_on_update(function(id, train)
|
||||
if not train.path or not train.lzb then
|
||||
atprint("LZB run: no path on train, skip step")
|
||||
return
|
||||
end
|
||||
look_ahead(id, train)
|
||||
apply_control(id, train)
|
||||
end, true)
|
|
@ -585,9 +585,9 @@ local function mknodecallback(name)
|
|||
table.insert(callt, func)
|
||||
end
|
||||
end
|
||||
return callt, function(pos, id, train, index)
|
||||
return callt, function(pos, id, train, index, paramx1, paramx2, paramx3)
|
||||
for _,f in ipairs(callt) do
|
||||
f(pos, id, train, index)
|
||||
f(pos, id, train, index, paramx1, paramx2, paramx3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -597,6 +597,14 @@ end
|
|||
local callbacks_enter_node, run_callbacks_enter_node = mknodecallback("enter")
|
||||
local callbacks_leave_node, run_callbacks_leave_node = mknodecallback("leave")
|
||||
|
||||
-- Node callback for approaching
|
||||
-- Might be called multiple times, whenever path is recalculated
|
||||
-- signature is function(pos, id, train, index, lzbdata)
|
||||
-- lzbdata: arbitrary data (shared between all callbacks), deleted when LZB is restarted.
|
||||
-- These callbacks are called in order of distance as train progresses along tracks, so lzbdata can be used to
|
||||
-- keep track of a train's state once it passes this point
|
||||
local callbacks_approach_node, run_callbacks_approach_node = mknodecallback("approach")
|
||||
|
||||
|
||||
local function tnc_call_enter_callback(pos, train_id, train, index)
|
||||
--atdebug("tnc enter",pos,train_id)
|
||||
|
@ -621,6 +629,18 @@ local function tnc_call_leave_callback(pos, train_id, train, index)
|
|||
run_callbacks_leave_node(pos, train_id, train, index)
|
||||
end
|
||||
|
||||
function advtrains.tnc_call_approach_callback(pos, train_id, train, index, lzbdata)
|
||||
--atdebug("tnc approach",pos,train_id, lzbdata)
|
||||
local node = advtrains.ndb.get_node(pos) --this spares the check if node is nil, it has a name in any case
|
||||
local mregnode=minetest.registered_nodes[node.name]
|
||||
if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_approach then
|
||||
mregnode.advtrains.on_train_approach(pos, train_id, train, index, lzbdata)
|
||||
end
|
||||
|
||||
-- call other registered callbacks
|
||||
run_callbacks_approach_node(pos, train_id, train, index, lzbdata)
|
||||
end
|
||||
|
||||
|
||||
advtrains.te_register_on_new_path(function(id, train)
|
||||
train.tnc = {
|
||||
|
|
|
@ -846,8 +846,8 @@ function wagon:show_bordcom(pname)
|
|||
local i=1
|
||||
while train.lzb.oncoming[i] do
|
||||
local oci = train.lzb.oncoming[i]
|
||||
if oci.pos then
|
||||
if advtrains.interlocking.db.get_sigd_for_signal(oci.pos) then
|
||||
if oci.udata and oci.udata.signal_pos then
|
||||
if advtrains.interlocking.db.get_sigd_for_signal(oci.udata.signal_pos) then
|
||||
form = form .. "button[4.5,8;5,1;ilrs;Remote Routesetting]"
|
||||
break
|
||||
end
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
-- Interlocking counterpart of LZB, which has been moved into the core...
|
||||
-- Registers LZB callback for signal management.
|
||||
|
||||
--[[
|
||||
usage of lzbdata:
|
||||
{
|
||||
travsht = boolean indicating whether the train will be a shunt move at "trav"
|
||||
travspd = speed restriction at end of traverser
|
||||
travwspd = warning speed res.t
|
||||
}
|
||||
]]
|
||||
|
||||
local SHUNT_SPEED_MAX = advtrains.SHUNT_SPEED_MAX
|
||||
|
||||
local il = advtrains.interlocking
|
||||
|
||||
local function get_over_function(speed, shunt)
|
||||
return function(pos, id, train, index, speed, lzbdata)
|
||||
if speed == 0 and minetest.settings:get_bool("at_il_force_lzb_halt") then
|
||||
atwarn(id,"overrun LZB 0 restriction (red signal) ",ent.pos)
|
||||
-- Set train 1 index backward. Hope this does not lead to bugs...
|
||||
train.index = index - 0.5
|
||||
train.velocity = 0
|
||||
train.ctrl.lzb = 0
|
||||
minetest.after(0, advtrains.invalidate_path, id)
|
||||
else
|
||||
train.speed_restriction = speed
|
||||
train.is_shunt = shunt
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
advtrains.tnc_register_on_approach(function(pos, id, train, index, lzbdata)
|
||||
|
||||
--atdebug(id,"IL ApprC",pos,index,lzbdata)
|
||||
--train.debug = advtrains.print_concat_table({train.is_shunt,"|",index,"|",lzbdata})
|
||||
|
||||
local pts = advtrains.roundfloorpts(pos)
|
||||
local cn = train.path_cn[index]
|
||||
local travsht = lzbdata.travsht
|
||||
|
||||
if travsht==nil then
|
||||
travsht = train.is_shunt
|
||||
end
|
||||
|
||||
local travspd = lzbdata.travspd
|
||||
local travwspd = lzbdata.travwspd
|
||||
|
||||
-- check for signal
|
||||
local asp, spos = il.db.get_ip_signal_asp(pts, cn)
|
||||
|
||||
-- do ARS if needed
|
||||
if spos then
|
||||
--atdebug(id,"IL Spos (ARS)",spos,asp)
|
||||
local sigd = il.db.get_sigd_for_signal(spos)
|
||||
if sigd then
|
||||
il.ars_check(sigd, train)
|
||||
end
|
||||
end
|
||||
--atdebug("trav: ",pos, cn, asp, spos, "travsht=", lzb.travsht)
|
||||
local lspd
|
||||
if asp then
|
||||
--atdebug(id,"IL Signal",spos,asp)
|
||||
local nspd = 0
|
||||
--interpreting aspect and determining speed to proceed
|
||||
if travsht then
|
||||
--shunt move
|
||||
if asp.shunt.free then
|
||||
nspd = SHUNT_SPEED_MAX
|
||||
elseif asp.shunt.proceed_as_main and asp.main.free then
|
||||
nspd = asp.main.speed
|
||||
travsht = false
|
||||
end
|
||||
else
|
||||
--train move
|
||||
if asp.main.free then
|
||||
nspd = asp.main.speed
|
||||
elseif asp.shunt.free then
|
||||
nspd = SHUNT_SPEED_MAX
|
||||
travsht = true
|
||||
end
|
||||
end
|
||||
-- nspd can now be: 1. !=0: new speed restriction, 2. =0: stop here or 3. nil: keep travspd
|
||||
if nspd then
|
||||
if nspd == -1 then
|
||||
travspd = nil
|
||||
else
|
||||
travspd = nspd
|
||||
end
|
||||
end
|
||||
|
||||
local nwspd = asp.info.w_speed
|
||||
if nwspd then
|
||||
if nwspd == -1 then
|
||||
travwspd = nil
|
||||
else
|
||||
travwspd = nwspd
|
||||
end
|
||||
end
|
||||
--atdebug("ns,wns,ts,wts", nspd, nwspd, travspd, travwspd)
|
||||
lspd = travspd
|
||||
if travwspd and (not lspd or lspd>travwspd) then
|
||||
lspd = travwspd
|
||||
end
|
||||
|
||||
local udata = {signal_pos = spos}
|
||||
local callback = get_over_function(lspd, travsht)
|
||||
advtrains.lzb_add_checkpoint(train, index, lspd, callback)
|
||||
end
|
||||
lzbdata.travsht = travsht
|
||||
lzbdata.travspd = travspd
|
||||
lzbdata.travwspd = travwspd
|
||||
end)
|
|
@ -22,7 +22,7 @@ dofile(modpath.."tcb_ts_ui.lua")
|
|||
dofile(modpath.."route_ui.lua")
|
||||
dofile(modpath.."tool.lua")
|
||||
|
||||
dofile(modpath.."lzb.lua")
|
||||
dofile(modpath.."approach.lua")
|
||||
dofile(modpath.."ars.lua")
|
||||
dofile(modpath.."tsr_rail.lua")
|
||||
|
||||
|
|
|
@ -1,292 +0,0 @@
|
|||
-- lzb.lua
|
||||
-- Enforced and/or automatic train override control, obeying signals
|
||||
|
||||
local function approach_callback(parpos, train_id, train, index)
|
||||
local pos = advtrains.round_vector_floor_y(parpos)
|
||||
|
||||
local node=pnode or advtrains.ndb.get_node(pos)
|
||||
local ndef=minetest.registered_nodes[node.name]
|
||||
if ndef and ndef.advtrains and ndef.advtrains.on_train_approach then
|
||||
ndef.advtrains.on_train_approach(pos, train_id, train, index)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Documentation of train.lzb table
|
||||
train.lzb = {
|
||||
trav = Current index that the traverser has advanced so far
|
||||
travsht = boolean indicating whether the train will be a shunt move at "trav"
|
||||
travspd = speed restriction at end of traverser
|
||||
travwspd = warning speed res.t
|
||||
oncoming = table containing oncoming signals, in order of appearance on the path
|
||||
{
|
||||
pos = position of the signal (not the IP!). Can be nil
|
||||
idx = where this is on the path
|
||||
spd = speed allowed to pass (determined dynamically)
|
||||
npr = <boolean> "No permanent restriction" If true, this is only a punctual restriction.
|
||||
speed_restriction is not set then, and train can accelerate after passing point
|
||||
This is (as of Nov 2017) used by "lines" to brake the train down to 2 when approaching a stop
|
||||
The actual "stop" command is given when the train passes the rail (on_train_enter callback)
|
||||
}
|
||||
}
|
||||
each step, for every item in "oncoming", we need to determine the location to start braking (+ some safety margin)
|
||||
and, if we passed this point for at least one of the items, initiate brake.
|
||||
When speed has dropped below, say 3, decrease the margin to zero, so that trains actually stop at the signal IP.
|
||||
The spd variable and travsht need to be updated on every aspect change. it's probably best to reset everything when any aspect changes
|
||||
|
||||
The traverser stops at signals that result in spd==0, because changes beyond there are likely.
|
||||
]]
|
||||
|
||||
local il = advtrains.interlocking
|
||||
|
||||
local params = {
|
||||
BRAKE_SPACE = 10,
|
||||
AWARE_ZONE = 50,
|
||||
|
||||
ADD_STAND = 2.5,
|
||||
ADD_SLOW = 1.5,
|
||||
ADD_FAST = 7,
|
||||
ZONE_ROLL = 2,
|
||||
ZONE_HOLD = 5, -- added on top of ZONE_ROLL
|
||||
ZONE_VSLOW = 3, -- When speed is <2, still allow accelerating
|
||||
|
||||
DST_FACTOR = 1.5,
|
||||
|
||||
SHUNT_SPEED_MAX = advtrains.SHUNT_SPEED_MAX,
|
||||
}
|
||||
|
||||
function advtrains.interlocking.set_lzb_param(par, val)
|
||||
if params[par] and tonumber(val) then
|
||||
params[par] = tonumber(val)
|
||||
else
|
||||
error("Inexistant param or not a number")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function look_ahead(id, train)
|
||||
|
||||
local acc = advtrains.get_acceleration(train, 1)
|
||||
local vel = train.velocity
|
||||
local brakedst = ( -(vel*vel) / (2*acc) ) * params.DST_FACTOR
|
||||
|
||||
local brake_i = advtrains.path_get_index_by_offset(train, train.index, brakedst + params.BRAKE_SPACE)
|
||||
--local aware_i = advtrains.path_get_index_by_offset(train, brake_i, AWARE_ZONE)
|
||||
|
||||
local lzb = train.lzb
|
||||
local trav = lzb.trav
|
||||
local travspd = lzb.travspd
|
||||
local travwspd = lzb.travwspd
|
||||
local lspd
|
||||
|
||||
--train.debug = lspd
|
||||
|
||||
while trav <= brake_i and (not lspd or lspd>0) do
|
||||
trav = trav + 1
|
||||
local pos = advtrains.path_get(train, trav)
|
||||
local pts = advtrains.roundfloorpts(pos)
|
||||
local cn = train.path_cn[trav]
|
||||
-- check offtrack
|
||||
if trav > train.path_trk_f then
|
||||
lspd = 0
|
||||
table.insert(lzb.oncoming, {
|
||||
idx = trav-1,
|
||||
spd = 0,
|
||||
})
|
||||
else
|
||||
-- run callback, if exists
|
||||
approach_callback(pos, id, train, trav)
|
||||
|
||||
-- check for signal
|
||||
local asp, spos = il.db.get_ip_signal_asp(pts, cn)
|
||||
|
||||
-- do ARS if needed
|
||||
if spos then
|
||||
local sigd = il.db.get_sigd_for_signal(spos)
|
||||
if sigd then
|
||||
il.ars_check(sigd, train)
|
||||
end
|
||||
end
|
||||
--atdebug("trav: ",pos, cn, asp, spos, "travsht=", lzb.travsht)
|
||||
if asp then
|
||||
local nspd = 0
|
||||
--interpreting aspect and determining speed to proceed
|
||||
if lzb.travsht then
|
||||
--shunt move
|
||||
if asp.shunt.free then
|
||||
nspd = params.SHUNT_SPEED_MAX
|
||||
elseif asp.shunt.proceed_as_main and asp.main.free then
|
||||
nspd = asp.main.speed
|
||||
lzb.travsht = false
|
||||
end
|
||||
else
|
||||
--train move
|
||||
if asp.main.free then
|
||||
nspd = asp.main.speed
|
||||
elseif asp.shunt.free then
|
||||
nspd = params.SHUNT_SPEED_MAX
|
||||
lzb.travsht = true
|
||||
end
|
||||
end
|
||||
-- nspd can now be: 1. !=0: new speed restriction, 2. =0: stop here or 3. nil: keep travspd
|
||||
if nspd then
|
||||
if nspd == -1 then
|
||||
travspd = nil
|
||||
else
|
||||
travspd = nspd
|
||||
end
|
||||
end
|
||||
|
||||
local nwspd = asp.info.w_speed
|
||||
if nwspd then
|
||||
if nwspd == -1 then
|
||||
travwspd = nil
|
||||
else
|
||||
travwspd = nwspd
|
||||
end
|
||||
end
|
||||
--atdebug("ns,wns,ts,wts", nspd, nwspd, travspd, travwspd)
|
||||
lspd = travspd
|
||||
if travwspd and (not lspd or lspd>travwspd) then
|
||||
lspd = travwspd
|
||||
end
|
||||
|
||||
table.insert(lzb.oncoming, {
|
||||
pos = spos,
|
||||
idx = trav,
|
||||
spd = lspd,
|
||||
sht = lzb.travsht,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lzb.trav = trav
|
||||
lzb.travspd = travspd
|
||||
lzb.travwspd = travwspd
|
||||
|
||||
--train.debug = dump(lzb)
|
||||
|
||||
end
|
||||
|
||||
--[[
|
||||
Distance needed to accelerate from v0 to v1 with constant acceleration a:
|
||||
|
||||
v1 - v0 a / v1 - v0 \ 2
|
||||
s = v0 * ------- + - * | ------- |
|
||||
a 2 \ a /
|
||||
]]
|
||||
|
||||
local function apply_control(id, train)
|
||||
local lzb = train.lzb
|
||||
|
||||
local i = 1
|
||||
while i<=#lzb.oncoming do
|
||||
if lzb.oncoming[i].idx < train.index then
|
||||
local ent = lzb.oncoming[i]
|
||||
local nodelete
|
||||
if not ent.npr then
|
||||
if ent.spd == 0 and minetest.settings:get_bool("at_il_force_lzb_halt") then
|
||||
atwarn(train.id,"overrun LZB 0 restriction (red signal) ",ent.pos)
|
||||
-- Set train 1 index backward. Hope this does not lead to bugs...
|
||||
train.index = ent.idx - 0.5
|
||||
train.velocity = 0
|
||||
train.ctrl.lzb = 0
|
||||
nodelete = true
|
||||
else
|
||||
train.speed_restriction = ent.spd
|
||||
train.is_shunt = ent.sht
|
||||
end
|
||||
end
|
||||
if not nodelete then
|
||||
table.remove(lzb.oncoming, i)
|
||||
end
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
for i, it in ipairs(lzb.oncoming) do
|
||||
local a = advtrains.get_acceleration(train, 1) --should be negative
|
||||
local v0 = train.velocity
|
||||
local v1 = it.spd
|
||||
if v1 and v1 <= v0 then
|
||||
local f = (v1-v0) / a
|
||||
local s = v0*f + a*f*f/2
|
||||
|
||||
local st = s + params.ADD_SLOW
|
||||
if v0 > 3 then
|
||||
st = s + params.ADD_FAST
|
||||
end
|
||||
if v0<=0 then
|
||||
st = s + params.ADD_STAND
|
||||
end
|
||||
|
||||
local i = advtrains.path_get_index_by_offset(train, it.idx, -st)
|
||||
|
||||
--train.debug = dump({v0f=v0*f, aff=a*f*f,v0=v0, v1=v1, f=f, a=a, s=s, st=st, i=i, idx=train.index})
|
||||
if i <= train.index then
|
||||
-- Gotcha! Braking...
|
||||
train.ctrl.lzb = 1
|
||||
--train.debug = train.debug .. "BRAKE!!!"
|
||||
return
|
||||
end
|
||||
|
||||
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_ROLL)
|
||||
if i <= train.index and v0>1 then
|
||||
-- roll control
|
||||
train.ctrl.lzb = 2
|
||||
return
|
||||
end
|
||||
i = advtrains.path_get_index_by_offset(train, i, -params.ZONE_HOLD)
|
||||
if i <= train.index and v0>1 then
|
||||
-- hold speed
|
||||
train.ctrl.lzb = 3
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
train.ctrl.lzb = nil
|
||||
end
|
||||
|
||||
local function invalidate(train)
|
||||
train.lzb = {
|
||||
trav = atfloor(train.index),
|
||||
travsht = train.is_shunt,
|
||||
oncoming = {}
|
||||
}
|
||||
-- possible FIX: do not clear LZB control when invalidating. This will be cleared when apply_control is run next time
|
||||
--train.ctrl.lzb = nil
|
||||
end
|
||||
|
||||
function advtrains.interlocking.lzb_invalidate(train)
|
||||
invalidate(train)
|
||||
end
|
||||
|
||||
-- Add an (extra) lzb control point that is not a permanent restriction (see above)
|
||||
-- (permanent restrictions are only to be imposed by signal ip's)
|
||||
function advtrains.interlocking.lzb_add_oncoming_npr(train, idx, spd)
|
||||
local lzb = train.lzb
|
||||
|
||||
table.insert(lzb.oncoming, {
|
||||
idx = idx,
|
||||
spd = spd,
|
||||
npr = true,
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
advtrains.te_register_on_new_path(function(id, train)
|
||||
invalidate(train)
|
||||
look_ahead(id, train)
|
||||
end)
|
||||
|
||||
advtrains.te_register_on_update(function(id, train)
|
||||
if not train.path or not train.lzb then
|
||||
atprint("LZB run: no path on train, skip step")
|
||||
return
|
||||
end
|
||||
look_ahead(id, train)
|
||||
apply_control(id, train)
|
||||
end, true)
|
|
@ -226,9 +226,9 @@ function advtrains.interlocking.signal_on_aspect_changed(pos)
|
|||
|
||||
local tns = advtrains.occ.get_trains_over(ipos)
|
||||
for id, sidx in pairs(tns) do
|
||||
local train = advtrains.trains[id]
|
||||
-- local train = advtrains.trains[id]
|
||||
--if train.index <= sidx then
|
||||
advtrains.interlocking.lzb_invalidate(train)
|
||||
minetest.after(0, advtrains.invalidate_path, id)
|
||||
--end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ local adefunc = function(def, preset, suffix, rotation)
|
|||
if train.path_cn[index] == 1 then
|
||||
local pe = advtrains.encode_pos(pos)
|
||||
local npr = advtrains.interlocking.npr_rails[pe] or 2
|
||||
advtrains.interlocking.lzb_add_oncoming_npr(train, index, npr)
|
||||
advtrains.lzb_add_checkpoint(train, index, npr, nil)
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
|
|
@ -151,7 +151,7 @@ local adefunc = function(def, preset, suffix, rotation)
|
|||
stdata.ars = {default=true}
|
||||
end
|
||||
if stdata.ars and (stdata.ars.default or advtrains.interlocking.ars_check_rule_match(stdata.ars, train) ) then
|
||||
advtrains.interlocking.lzb_add_oncoming_npr(train, index, 2)
|
||||
advtrains.lzb_add_checkpoint(train, index, 2, nil)
|
||||
local stn = advtrains.lines.stations[stdata.stn]
|
||||
local stnname = stn and stn.name or "Unknown Station"
|
||||
train.text_inside = "Next Stop:\n"..stnname
|
||||
|
|
Loading…
Reference in New Issue