Implement trains blocking sections

master
orwell96 2018-06-29 16:16:55 +02:00
parent 86fa420500
commit 820503ba81
5 changed files with 202 additions and 13 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)