Implement trains blocking sections
This commit is contained in:
parent
86fa420500
commit
820503ba81
|
@ -69,6 +69,8 @@ function advtrains.print_concat_table(a)
|
|||
if type(t)=="table" then
|
||||
if t.x and t.y and t.z then
|
||||
str=str..minetest.pos_to_string(t)
|
||||
elseif t.p and t.s then -- interlocking sigd
|
||||
str=str.."("..t.p.."/"..t.s..")"
|
||||
else
|
||||
str=str..dump(t)
|
||||
end
|
||||
|
@ -270,7 +272,8 @@ advtrains.avt_save = function(remove_players_from_wagons)
|
|||
"last_pos", "last_connid", "last_frac", "velocity", "tarvelocity",
|
||||
"trainparts", "recently_collided_with_env",
|
||||
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
|
||||
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line"
|
||||
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line",
|
||||
"il_sections"
|
||||
})
|
||||
--then save it
|
||||
tmp_trains[id]=v
|
||||
|
|
|
@ -174,6 +174,7 @@ end
|
|||
|
||||
-- Occupation Callback system
|
||||
-- see occupation.lua
|
||||
-- signature is advtrains.te_register_on_<?>(function(id, train) ... end)
|
||||
|
||||
local function mkcallback(name)
|
||||
local callt = {}
|
||||
|
@ -468,23 +469,49 @@ end
|
|||
-- (remember, train.end_index is set separately because callbacks are
|
||||
-- asserted to rely on this)
|
||||
|
||||
local function tnc_call_enter_callback(pos, train_id)
|
||||
local function mknodecallback(name)
|
||||
local callt = {}
|
||||
advtrains["tnc_register_on_"..name] = function(func)
|
||||
assertt(func, "function")
|
||||
table.insert(callt, func)
|
||||
end
|
||||
return callt, function(pos, id, train, index)
|
||||
for _,f in ipairs(callt) do
|
||||
f(pos, id, train, index)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- enter/leave-node callbacks
|
||||
-- signature is advtrains.tnc_register_on_enter/leave(function(pos, id, train, index) ... end)
|
||||
local callbacks_enter_node, run_callbacks_enter_node = mknodecallback("enter")
|
||||
local callbacks_leave_node, run_callbacks_leave_node = mknodecallback("leave")
|
||||
|
||||
|
||||
local function tnc_call_enter_callback(pos, train_id, train, index)
|
||||
--atdebug("tnc enter",pos,train_id)
|
||||
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_enter then
|
||||
mregnode.advtrains.on_train_enter(pos, train_id)
|
||||
mregnode.advtrains.on_train_enter(pos, train_id, train, index)
|
||||
end
|
||||
|
||||
-- call other registered callbacks
|
||||
run_callbacks_enter_node(pos, train_id, train, index)
|
||||
end
|
||||
local function tnc_call_leave_callback(pos, train_id)
|
||||
local function tnc_call_leave_callback(pos, train_id, train, index)
|
||||
--atdebug("tnc leave",pos,train_id)
|
||||
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_leave then
|
||||
mregnode.advtrains.on_train_leave(pos, train_id)
|
||||
end
|
||||
mregnode.advtrains.on_train_leave(pos, train_id, train, index)
|
||||
end
|
||||
|
||||
-- call other registered callbacks
|
||||
run_callbacks_leave_node(pos, train_id, train, index)
|
||||
end
|
||||
|
||||
|
||||
advtrains.te_register_on_new_path(function(id, train)
|
||||
train.tnc = {
|
||||
old_index = atround(train.index),
|
||||
|
@ -501,11 +528,11 @@ advtrains.te_register_on_update(function(id, train)
|
|||
while old_index < new_index do
|
||||
old_index = old_index + 1
|
||||
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,old_index))
|
||||
tnc_call_enter_callback(pos, id)
|
||||
tnc_call_enter_callback(pos, id, train, old_index)
|
||||
end
|
||||
while old_end_index < new_end_index do
|
||||
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,old_end_index))
|
||||
tnc_call_leave_callback(pos, id)
|
||||
tnc_call_leave_callback(pos, id, train, old_end_index)
|
||||
old_end_index = old_end_index + 1
|
||||
end
|
||||
train.tnc.old_index = new_index
|
||||
|
@ -517,7 +544,7 @@ advtrains.te_register_on_create(function(id, train)
|
|||
local end_index = atround(train.end_index)
|
||||
while end_index <= index do
|
||||
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,end_index))
|
||||
tnc_call_enter_callback(pos, id)
|
||||
tnc_call_enter_callback(pos, id, train, end_index)
|
||||
end_index = end_index + 1
|
||||
end
|
||||
--atdebug(id,"tnc create",train.index,train.end_index)
|
||||
|
@ -528,7 +555,7 @@ advtrains.te_register_on_remove(function(id, train)
|
|||
local end_index = atround(train.end_index)
|
||||
while end_index <= index do
|
||||
local pos = advtrains.round_vector_floor_y(advtrains.path_get(train,end_index))
|
||||
tnc_call_leave_callback(pos, id)
|
||||
tnc_call_leave_callback(pos, id, train, end_index)
|
||||
end_index = end_index + 1
|
||||
end
|
||||
--atdebug(id,"tnc remove",train.index,train.end_index)
|
||||
|
|
|
@ -382,7 +382,7 @@ end
|
|||
|
||||
-- Utilize the traverser to find the track section at the specified position
|
||||
-- Returns:
|
||||
-- ts_id - the first found ts
|
||||
-- ts_id, origin - the first found ts and the sigd of the found tcb
|
||||
-- nil - there were no TCBs in TRAVERSER_MAX range of the position, or track ends were reached
|
||||
-- false - the first found TCB stated End-Of-Interlocking
|
||||
function ildb.get_ts_at_pos(pos)
|
||||
|
@ -397,7 +397,7 @@ function ildb.get_ts_at_pos(pos)
|
|||
local tcbs = ildb.get_tcbs(found_tcbs[1])
|
||||
local ts
|
||||
if tcbs.ts_id then
|
||||
return tcbs.ts_id
|
||||
return tcbs.ts_id, found_tcbs[1]
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
|
|
@ -244,6 +244,15 @@ function advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
|
|||
form = form.."button[5.5,5;4,1;del_tcb;Unlink selected TCB]"
|
||||
hint = 2
|
||||
end
|
||||
|
||||
-- occupying trains
|
||||
if ts.trains and #ts.trains>0 then
|
||||
form = form.."label[0.5,6.1;Trains on this section:]"
|
||||
form = form.."textlist[0.5,6.7;3,2;trnlist;"..table.concat(ts.trains, ",").."]"
|
||||
else
|
||||
form = form.."label[0.5,6.1;No trains on this section.]"
|
||||
end
|
||||
|
||||
if hint == 1 then
|
||||
form = form.."label[0.5,0.75;Use the 'Join' button to designate rail crosses and link not listed far-away TCBs]"
|
||||
elseif hint == 2 then
|
||||
|
@ -327,7 +336,7 @@ minetest.register_entity("advtrains_interlocking:tcbmarker", {
|
|||
})
|
||||
|
||||
function advtrains.interlocking.show_tcb_marker(pos)
|
||||
atdebug("showing tcb marker",pos)
|
||||
--atdebug("showing tcb marker",pos)
|
||||
local tcb = advtrains.interlocking.db.get_tcb(pos)
|
||||
if not tcb then return end
|
||||
local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
|
||||
|
|
|
@ -1,2 +1,152 @@
|
|||
-- train_related.lua
|
||||
-- Occupation of track sections - mainly implementation of train callbacks
|
||||
|
||||
--[[
|
||||
Track section occupation is saved as follows
|
||||
|
||||
In train:
|
||||
train.il_sections = {
|
||||
[n] = {ts_id = <...> (origin = <sigd>)}
|
||||
}
|
||||
-- "origin" is the TCB (signal describer) the train initially entered this section
|
||||
|
||||
In track section
|
||||
ts.trains = {
|
||||
[n] = <train_id>
|
||||
}
|
||||
|
||||
When any inconsistency is detected, we will assume the most restrictive setup.
|
||||
It will be possible to indicate a section "free" via the GUI.
|
||||
]]
|
||||
|
||||
local ildb = advtrains.interlocking.db
|
||||
|
||||
|
||||
local function itexist(tbl, com)
|
||||
for _,item in ipairs(tbl) do
|
||||
if (item==com) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
local function itkexist(tbl, ikey, com)
|
||||
for _,item in ipairs(tbl) do
|
||||
if item[ikey] == com then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function itremove(tbl, com)
|
||||
local i=1
|
||||
while i <= #tbl do
|
||||
if tbl[i] == com then
|
||||
table.remove(tbl, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
local function itkremove(tbl, ikey, com)
|
||||
local i=1
|
||||
while i <= #tbl do
|
||||
if tbl[i][ikey] == com then
|
||||
table.remove(tbl, i)
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setsection(tid, train, ts_id, ts, origin)
|
||||
-- train
|
||||
if not train.il_sections then train.il_sections = {} end
|
||||
if not itkexist(train.il_sections, "ts_id", ts_id) then
|
||||
table.insert(train.il_sections, {ts_id = ts_id, origin = origin})
|
||||
end
|
||||
|
||||
-- ts
|
||||
if not ts.trains then ts.trains = {} end
|
||||
if not itexist(ts.trains, tid) then
|
||||
table.insert(ts.trains, tid)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function freesection(tid, train, ts_id, ts)
|
||||
-- train
|
||||
if not train.il_sections then train.il_sections = {} end
|
||||
itkremove(train.il_sections, "ts_id", ts_id)
|
||||
|
||||
-- ts
|
||||
if not ts.trains then ts.trains = {} end
|
||||
itremove(ts.trains, tid)
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- This is regular operation
|
||||
-- The train is on a track and drives back and forth
|
||||
|
||||
-- This sets the section for both directions, to be failsafe
|
||||
advtrains.tnc_register_on_enter(function(pos, id, train, index)
|
||||
local tcb = ildb.get_tcb(pos)
|
||||
if tcb then
|
||||
for connid=1,2 do
|
||||
local ts = tcb[connid].ts_id and ildb.get_ts(tcb[connid].ts_id)
|
||||
if ts then
|
||||
setsection(id, train, tcb[connid].ts_id, ts, {p=pos, s=connid})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
-- this time, of course, only clear the backside (cp connid)
|
||||
advtrains.tnc_register_on_leave(function(pos, id, train, index)
|
||||
local tcb = ildb.get_tcb(pos)
|
||||
if tcb and train.path_cp[index] then
|
||||
local connid = train.path_cp[index]
|
||||
local ts = tcb[connid].ts_id and ildb.get_ts(tcb[connid].ts_id)
|
||||
if ts then
|
||||
freesection(id, train, tcb[connid].ts_id, ts)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- those callbacks are needed to account for created and removed trains (also regarding coupling)
|
||||
|
||||
advtrains.te_register_on_create(function(id, train)
|
||||
-- let's see what track sections we find here
|
||||
local index = atround(train.index)
|
||||
local pos = advtrains.path_get(train, index)
|
||||
local ts_id, origin = ildb.get_ts_at_pos(pos)
|
||||
if ts_id then
|
||||
local ts = ildb.get_ts(ts_id)
|
||||
if ts then
|
||||
setsection(id, train, ts_id, ts, origin)
|
||||
else
|
||||
atwarn("ILDB corruption: TCB",origin," has invalid TS reference")
|
||||
end
|
||||
elseif ts_id==nil then
|
||||
atwarn("Train",id,": Unable to determine whether to block a track section!")
|
||||
else
|
||||
atdebug("Train",id,": Outside of interlocked area!")
|
||||
end
|
||||
end)
|
||||
|
||||
advtrains.te_register_on_remove(function(id, train)
|
||||
if train.il_sections then
|
||||
for idx, item in ipairs(train.il_sections) do
|
||||
|
||||
local ts = item.ts_id and ildb.get_ts(item.ts_id)
|
||||
|
||||
if ts and ts.trains then
|
||||
itremove(ts.trains, id)
|
||||
end
|
||||
end
|
||||
train.il_sections = nil
|
||||
end
|
||||
end)
|
||||
|
|
Loading…
Reference in New Issue