aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororwell96 <orwell@bleipb.de>2019-12-09 12:18:54 +0100
committerorwell96 <orwell@bleipb.de>2021-02-10 16:34:34 +0100
commit74a219937dd031743c880510f10571adec0cf8a8 (patch)
treebf51d24f7be3103ed2f095ea4bc8c39186f25f88
parente935136d58dc863541a6a53c6f5e9f9d218e6661 (diff)
downloadadvtrains-74a219937dd031743c880510f10571adec0cf8a8.tar.gz
advtrains-74a219937dd031743c880510f10571adec0cf8a8.tar.bz2
advtrains-74a219937dd031743c880510f10571adec0cf8a8.zip
Add approach callback mechanism to LuaATC
-rw-r--r--advtrains_luaautomation/README.txt28
-rw-r--r--advtrains_luaautomation/atc_rail.lua123
2 files changed, 106 insertions, 45 deletions
diff --git a/advtrains_luaautomation/README.txt b/advtrains_luaautomation/README.txt
index 287a0bd..b565360 100644
--- a/advtrains_luaautomation/README.txt
+++ b/advtrains_luaautomation/README.txt
@@ -245,6 +245,34 @@ unset_autocouple()
set_shunt(), unset_shunt()
deprecated aliases for set_autocouple() and unset_autocouple(), will be removed from a later release.
+# Approach callbacks
+The LuaATC interface provides a way to hook into the approach callback system, which is for example used in the TSR rails (provided by advtrains_interlocking) or the station tracks (provided by advtrains_lines). However, for compatibility reasons, this behavior needs to be explicitly enabled.
+
+Enabling the receiving of approach events works by setting a variable in the local environment of the ATC rail, by inserting the following code:
+
+__approach_callback_mode = 1
+-- to receive approach callbacks only in arrow direction
+-- or alternatively
+__approach_callback_mode = 2
+-- to receive approach callbacks in both directions
+
+The following event will be emitted when a train approaches:
+{type="approach", approach=true, id="<train_id>"}
+
+Please note these important considerations when using approach callbacks:
+- Approach events might be generated multiple times for the same approaching train. If you are using atc_set_lzb_tsr(), you need to call this function on every run of the approach callback, even if you issued it before for the same train.
+- A reference to the train is available while executing this event, so that functions such as atc_send() or atc_set_text_outside() can be called. On any consecutive interrupts, that reference will no longer be available until the train enters the track ("train" event)
+- Unlike all other callbacks, approach callbacks are executed synchronous during the train step. This may cause unexpected side effects when performing certain actions (such as switching turnouts, setting signals/routes) from inside such a callback. I strongly encourage you to only run things that are absolutely necessary at this point in time, and defer anything else to an interrupt(). Be aware that certain things might trigger unexpected behavior.
+
+Operations that are safe to execute in approach callbacks:
+- anything related only to the global environment (setting things in S)
+- digiline_send()
+- atc_set_text_*()
+- atc_set_lzb_tsr() (see below)
+
+In the context of approach callbacks, one more function is available:
+atc_set_lzb_tsr(speed)
+ Impose a Temporary Speed Restriction at the location of this rail, making the train pass this rail at the specified speed. (Causes the same behavior as the TSR rail)
# Operator panel
This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications.
diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua
index 6083dfc..33b5d00 100644
--- a/advtrains_luaautomation/atc_rail.lua
+++ b/advtrains_luaautomation/atc_rail.lua
@@ -5,7 +5,10 @@
--Using subtable
local r={}
-function r.fire_event(pos, evtdata)
+-- Note on appr_internal:
+-- The Approach callback is a special corner case: the train is not on the node, and it is executed synchronized
+-- (in the train step right during LZB traversal). We therefore need access to the train id and the lzbdata table
+function r.fire_event(pos, evtdata, appr_internal)
local ph=minetest.pos_to_string(pos)
local railtbl = atlatc.active.nodes[ph]
@@ -27,6 +30,13 @@ function r.fire_event(pos, evtdata)
local train_id=advtrains.get_train_at_pos(pos)
local train, atc_arrow, tvel
if train_id then train=advtrains.trains[train_id] end
+
+ if not train and appr_internal then
+ -- also use the train when called as an approach callback
+ train_id = appr_internal.train_id
+ train = appr_internal.train
+ end
+
if train then
if not train.path then
--we happened to get in between an invalidation step
@@ -92,20 +102,9 @@ function r.fire_event(pos, evtdata)
advtrains.train_step_fc(train)
end,
set_shunt = function()
+ -- enable shunting mode
if not train_id then return false end
- train.autocouple = true
- end,
- unset_shunt = function()
- if not train_id then return false end
- train.autocouple = nil
- end,
- set_autocouple = function ()
- if not train_id then return false end
- train.autocouple = true
- end,
- unset_autocouple = function ()
- if not train_id then return false end
- train.autocouple = nil
+ train.is_shunt = true
end,
set_line = function(line)
if type(line)~="string" and type(line)~="number" then
@@ -150,45 +149,79 @@ function r.fire_event(pos, evtdata)
advtrains.trains[train_id].text_inside=text
return true
end,
+ atc_set_lzb_tsr = function(speed)
+ if not appr_internal then
+ error("atc_set_lzb_tsr() can only be used during 'approach' events!")
+ end
+
+ local index = appr_internal.index
+ advtrains.lzb_add_checkpoint(train, index, speed, nil)
+
+ return true
+ end,
}
atlatc.active.run_in_env(pos, evtdata, customfct)
end
-if minetest.get_modpath("advtrains_train_track") ~= nil then
- advtrains.register_tracks("default", {
- nodename_prefix="advtrains_luaautomation:dtrack",
- texture_prefix="advtrains_dtrack_atc",
- models_prefix="advtrains_dtrack",
- models_suffix=".b3d",
- shared_texture="advtrains_dtrack_shared_atc.png",
- description=atltrans("LuaAutomation ATC Rail"),
- formats={},
- get_additional_definiton = function(def, preset, suffix, rotation)
- return {
- after_place_node = atlatc.active.after_place_node,
- after_dig_node = atlatc.active.after_dig_node,
- on_receive_fields = function(pos, ...)
- atlatc.active.on_receive_fields(pos, ...)
- --set arrowconn (for ATC)
+advtrains.register_tracks("default", {
+ nodename_prefix="advtrains_luaautomation:dtrack",
+ texture_prefix="advtrains_dtrack_atc",
+ models_prefix="advtrains_dtrack",
+ models_suffix=".b3d",
+ shared_texture="advtrains_dtrack_shared_atc.png",
+ description=atltrans("LuaAutomation ATC Rail"),
+ formats={},
+ get_additional_definiton = function(def, preset, suffix, rotation)
+ return {
+ after_place_node = atlatc.active.after_place_node,
+ after_dig_node = atlatc.active.after_dig_node,
+
+ on_receive_fields = function(pos, ...)
+ atlatc.active.on_receive_fields(pos, ...)
+
+ --set arrowconn (for ATC)
+ local ph=minetest.pos_to_string(pos)
+ local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
+ atlatc.active.nodes[ph].arrowconn=conns[1].c
+ end,
+
+ advtrains = {
+ on_train_enter = function(pos, train_id)
+ --do async. Event is fired in train steps
+ atlatc.interrupt.add(0, pos, {type="train", train=true, id=train_id})
+ end,
+ on_train_approach = function(pos, train_id, train, index, lzbdata)
+ -- Insert an event only if the rail indicated that it supports approach callbacks
local ph=minetest.pos_to_string(pos)
- local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
- atlatc.active.nodes[ph].arrowconn=conns[1].c
+ local railtbl = atlatc.active.nodes[ph]
+ -- uses a "magic variable" in the local environment of the node
+ -- This hack is necessary because code might not be prepared to get approach events...
+ if railtbl and railtbl.data and railtbl.data.__approach_callback_mode then
+ local acm = railtbl.data.__approach_callback_mode
+ if acm==2 or (acm==1 and train.path_cn[index] == 1) then
+ local evtdata = {type="approach", approach=true, id=train_id}
+ -- This event is *required* to run synchronously, because it might set the ars_disable flag on the train and add LZB checkpoints,
+ -- although this is generally discouraged because this happens right in a train step
+ -- At this moment, I am not aware whether this may cause side effects, and I must encourage users not to do expensive calculations here.
+ r.fire_event(pos, evtdata, {train_id = train_id, train = train, index = index, lzbdata = lzbdata})
+ end
+ end
end,
- advtrains = atlatc.active.trackdef_advtrains_defs,
- luaautomation = {
- fire_event=r.fire_event
- },
- digiline = {
- receptor = {},
- effector = {
- action = atlatc.active.on_digiline_receive
- },
+ },
+ luaautomation = {
+ fire_event=r.fire_event
+ },
+ digiline = {
+ receptor = {},
+ effector = {
+ action = atlatc.active.on_digiline_receive
},
- }
- end,
- }, advtrains.trackpresets.t_30deg_straightonly)
-end
+ },
+ }
+ end,
+}, advtrains.trackpresets.t_30deg_straightonly)
+
atlatc.rail = r