aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororwell96 <orwell@bleipb.de>2018-06-29 16:16:55 +0200
committerorwell96 <orwell@bleipb.de>2018-06-29 16:16:55 +0200
commit820503ba81b709cecd86d621dd68e7701fe10222 (patch)
treeae73d7a852b5606e78533eddc907862c1bf50783
parent86fa42050057af4e4129b8347c10d330842e4489 (diff)
downloadadvtrains-820503ba81b709cecd86d621dd68e7701fe10222.tar.gz
advtrains-820503ba81b709cecd86d621dd68e7701fe10222.tar.bz2
advtrains-820503ba81b709cecd86d621dd68e7701fe10222.zip
Implement trains blocking sections
-rw-r--r--advtrains/init.lua5
-rw-r--r--advtrains/trainlogic.lua45
-rw-r--r--advtrains_interlocking/database.lua4
-rw-r--r--advtrains_interlocking/tcb_ts_ui.lua11
-rw-r--r--advtrains_interlocking/train_related.lua150
5 files changed, 202 insertions, 13 deletions
diff --git a/advtrains/init.lua b/advtrains/init.lua
index 228ad5d..4559dfe 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -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
diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua
index df3ec92..6c00fa5 100644
--- a/advtrains/trainlogic.lua
+++ b/advtrains/trainlogic.lua
@@ -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)
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index e9e484c..f4a6871 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -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
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index 7e4d904..0ebe767 100644
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -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)
diff --git a/advtrains_interlocking/train_related.lua b/advtrains_interlocking/train_related.lua
index 3e1c05b..3d7e280 100644
--- a/advtrains_interlocking/train_related.lua
+++ b/advtrains_interlocking/train_related.lua
@@ -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)