aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking/signal_aspect_accessors.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains_interlocking/signal_aspect_accessors.lua')
-rw-r--r--advtrains_interlocking/signal_aspect_accessors.lua163
1 files changed, 163 insertions, 0 deletions
diff --git a/advtrains_interlocking/signal_aspect_accessors.lua b/advtrains_interlocking/signal_aspect_accessors.lua
new file mode 100644
index 0000000..d91df31
--- /dev/null
+++ b/advtrains_interlocking/signal_aspect_accessors.lua
@@ -0,0 +1,163 @@
+--- Signal aspect accessors
+-- @module advtrains.interlocking
+
+local A = advtrains.interlocking.aspect
+local D = advtrains.distant
+local I = advtrains.interlocking
+local N = advtrains.ndb
+local pts = advtrains.roundfloorpts
+
+local get_aspect
+
+local supposed_aspects = {}
+
+--- Replace the signal aspect cache.
+-- @function load_supposed_aspects
+-- @param db The new database.
+function I.load_supposed_aspects(tbl)
+ if tbl then
+ supposed_aspects = {}
+ for k, v in pairs(tbl) do
+ supposed_aspects[k] = A(v)
+ end
+ end
+end
+
+--- Retrieve the signal aspect cache.
+-- @function save_supposed_aspects
+-- @return The current database in use.
+function I.save_supposed_aspects()
+ local t = {}
+ for k, v in pairs(supposed_aspects) do
+ t[k] = v:plain(true)
+ end
+ return t
+end
+
+--- Read the aspect of a signal strictly from cache.
+-- @param pos The position of the signal.
+-- @return[1] The aspect of the signal (if present in cache).
+-- @return[2] The nil constant (otherwise).
+local function get_supposed_aspect(pos)
+ return supposed_aspects[pts(pos)]
+end
+
+--- Update the signal aspect information in cache.
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect
+local function set_supposed_aspect(pos, asp)
+ supposed_aspects[pts(pos)] = asp
+end
+
+--- Get the definition of a node.
+-- @param pos The position of the node.
+-- @return[1] The definition of the node (if present).
+-- @return[2] An empty table (otherwise).
+local function get_ndef(pos)
+ local node = N.get_node(pos)
+ return (minetest.registered_nodes[node.name] or {}), node
+end
+
+--- Get the aspects supported by a signal.
+-- @function signal_get_supported_aspects
+-- @param pos The position of the signal.
+-- @return[1] The table of supported aspects (if present).
+-- @return[2] The nil constant (otherwise).
+local function get_supported_aspects(pos)
+ local ndef = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.supported_aspects then
+ return ndef.advtrains.supported_aspects
+ end
+ return nil
+end
+
+--- Adjust a new signal aspect to fit a signal.
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect.
+-- @return The adjusted signal aspect.
+-- @return The information to pass to the `advtrains.set_aspect` field in the node definitions.
+local function adjust_aspect(pos, asp)
+ local asp = A(asp)
+
+ local mainpos = D.get_main(pos)
+ local nxtasp
+ if mainpos then
+ nxtasp = get_aspect(mainpos)
+ end
+ local suppasp = get_supported_aspects(pos)
+ if not suppasp then
+ return asp
+ end
+ return asp:adjust_distant(nxtasp, suppasp.dst_shift):to_group(suppasp.group)
+end
+
+--- Get the aspect of a signal without accessing the cache.
+-- For most cases, `get_aspect` should be used instead.
+-- @function signal_get_real_aspect
+-- @param pos The position of the signal.
+-- @return[1] The signal aspect adjusted using `adjust_aspect` (if present).
+-- @return[2] The nil constant (otherwise).
+local function get_real_aspect(pos)
+ local ndef, node = get_ndef(pos)
+ if ndef.advtrains and ndef.advtrains.get_aspect then
+ local asp = ndef.advtrains.get_aspect(pos, node) or I.DANGER
+ return adjust_aspect(pos, asp)
+ end
+ return nil
+end
+
+--- Get the aspect of a signal.
+-- @function signal_get_aspect
+-- @param pos The position of the signal.
+-- @return[1] The aspect of the signal (if present).
+-- @return[2] The nil constant (otherwise).
+get_aspect = function(pos)
+ local asp = get_supposed_aspect(pos)
+ if not asp then
+ asp = get_real_aspect(pos)
+ set_supposed_aspect(pos, asp)
+ end
+ return asp
+end
+
+--- Set the aspect of a signal.
+-- @function signal_set_aspect
+-- @param pos The position of the signal.
+-- @param asp The new signal aspect.
+-- @param[opt=false] skipdst Whether to skip updating distant signals.
+local function set_aspect(pos, asp, skipdst)
+ local node = N.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name]
+ if ndef and ndef.advtrains and ndef.advtrains.set_aspect then
+ local oldasp = I.signal_get_aspect(pos) or DANGER
+ local newasp = adjust_aspect(pos, asp)
+ set_supposed_aspect(pos, newasp)
+ ndef.advtrains.set_aspect(pos, node, newasp)
+ I.signal_on_aspect_changed(pos)
+ local aspect_changed = oldasp ~= newasp
+ if (not skipdst) and aspect_changed then
+ D.update_main(pos)
+ end
+ end
+end
+
+--- Remove a signal from cache.
+-- @function signal_clear_aspect
+-- @param pos The position of the signal.
+local function clear_aspect(pos)
+ set_supposed_aspect(pos, nil)
+end
+
+--- Readjust the aspect of a signal.
+-- @function signal_readjust_aspect
+-- @param pos The position of the signal.
+local function readjust_aspect(pos)
+ set_aspect(pos, get_aspect(pos))
+end
+
+I.signal_get_supported_aspects = get_supported_aspects
+I.signal_get_real_aspect = get_real_aspect
+I.signal_get_aspect = get_aspect
+I.signal_set_aspect = set_aspect
+I.signal_clear_aspect = clear_aspect
+I.signal_readjust_aspect = readjust_aspect