Add API documentation
This commit is contained in:
parent
30a0f86248
commit
7c9fd9179d
|
@ -0,0 +1,96 @@
|
||||||
|
# Interlocking for Advtrains
|
||||||
|
|
||||||
|
The `advtrains_interlocking` mod provides various interlocking and signaling features for Advtrains.
|
||||||
|
|
||||||
|
## Signal types
|
||||||
|
There are two types of signals in Advtrains:
|
||||||
|
|
||||||
|
* Type 1 (speed signals): These signals only give speed information.
|
||||||
|
* Type 2 (route signals): These signals mainly provide route information, but sometimes also provide speed information.
|
||||||
|
|
||||||
|
## Signal aspect tables
|
||||||
|
|
||||||
|
Signal aspects are represented using tables with the following (optional) fields:
|
||||||
|
|
||||||
|
* `main`: The main signal aspect. It provides information on the permitted speed after passing the signal.
|
||||||
|
* `dst`: The distant signal aspect. It provides information on the permitted speed after passing the next signal.
|
||||||
|
* `shunt`: Whether the train may proceed in shunt mode and, if the main aspect is danger, proceed in shunt mode.
|
||||||
|
* `proceed_as_main`: Whether the train should exit shunt mode when proceeding.
|
||||||
|
* `type2group`: The type 2 group of the signal.
|
||||||
|
* `type2name`: The type 2 signal aspect name.
|
||||||
|
|
||||||
|
The `main` and `dst` fields may be:
|
||||||
|
|
||||||
|
* An positive number indicating the permitted speed,
|
||||||
|
* The number 0, indicating that the train should expect to stop at the current signal (or, for the `dst` field, the next signal),
|
||||||
|
* The number -1, indicating that the train can proceed (or, for the `dst` field, expect to proceed) at maximum speed, or
|
||||||
|
* The constant `false` or `nil`, indicating no change to the speed restriction.
|
||||||
|
|
||||||
|
### Node definitions
|
||||||
|
|
||||||
|
Signals should belong the following node groups:
|
||||||
|
|
||||||
|
* `advtrains_signal`: `1` for static signals, `2` for signals with variable aspects.
|
||||||
|
* `save_in_at_nodedb`: This should be set to `1` to make sure that Advtrains always has access to the signal.
|
||||||
|
* `not_blocking_trains`: Setting this to `1` prevents trains from colliding with the signal. Setting this is not necessary, but recommended.
|
||||||
|
|
||||||
|
The node definition should contain an `advtrains` field.
|
||||||
|
|
||||||
|
The `advtrains` field of the node definition should contain a `supported_aspects` table for signals with variable aspects.
|
||||||
|
|
||||||
|
For type 1 signals, the `supported_aspects` table should contain the following fields:
|
||||||
|
|
||||||
|
* `main`: A list of values supported for the main aspect.
|
||||||
|
* `dst`: A list of values supported for the distant aspect.
|
||||||
|
* `shunt`: The value for the `shunt` field of the signal aspect or `nil` if the value is variable.
|
||||||
|
* `proceed_as_main`: The value for the `proceed_as_main` field of the signal aspect.
|
||||||
|
|
||||||
|
For type 2 signals, the `supported_aspects` table should contain the following fields:
|
||||||
|
|
||||||
|
* `type`: The numeric constant `2`.
|
||||||
|
* `group`: The type 2 signal group.
|
||||||
|
* `dst_shift`: The phase shift for distant/repeater signals. This field should not be set for main signals.
|
||||||
|
|
||||||
|
The `advtrains` field of the node definition should contain a `get_aspect` function. This function is given the position of the signal and the node at the position. It should return the signal aspect table or, in the case of type 2 signals, the name of the signal aspect.
|
||||||
|
|
||||||
|
For signals with variable aspects, a corresponding `set_aspect` function should also be defined. This function is given the position of the signal, the node at the position, and the new aspect (or, in the case of type 2 signals, the name of the new signal aspect). For type 1 signals, the new aspect is not guranteed to be supported by the signal itself.
|
||||||
|
|
||||||
|
Signals should also have the following callbacks set:
|
||||||
|
|
||||||
|
* `on_rightclick` should be set to `advtrains.interlocking.signal_rc_handler`
|
||||||
|
* `can_dig` should be set to `advtrains.interlocking.signal_can_dig`
|
||||||
|
* `after_dig_node` should be set to `advtrains.interlocking.signal_after_dig`
|
||||||
|
|
||||||
|
Alternatively, custom callbacks should call the respective functions.
|
||||||
|
|
||||||
|
## Type 2 signal groups
|
||||||
|
|
||||||
|
Type 2 signals belong to signal gruops, which are registered using `advtrains.interlocking.aspects.register_type2`.
|
||||||
|
|
||||||
|
Signal group definitions include the following fields:
|
||||||
|
|
||||||
|
* `name`: The internal name of the signal group. It is recommended to use the mod name as a prefix to avoid name collisions.
|
||||||
|
* `label`: The description of the signal group.
|
||||||
|
* `main`: A list of signal aspects, from the least restrictive (i.e. proceed) to the most restrictive (i.e. danger).
|
||||||
|
|
||||||
|
Each aspect in the signal group definition table should contain the following fields:
|
||||||
|
|
||||||
|
* `name`: The internal name of the signal aspect.
|
||||||
|
* `label`: The description of the signal aspect.
|
||||||
|
* `main`, `shunt`, `proceed_as_main`: The fields corresponding to the ones in signal aspect tables.
|
||||||
|
|
||||||
|
Type 2 signal aspects are then referred to with the aspect names within the group.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
It is allowed to provide other methods of setting the signal aspect. However:
|
||||||
|
|
||||||
|
* These changes are ignored by the routesetting system.
|
||||||
|
* Please call `advtrains.interlocking.signal_readjust_aspect` after the signal aspect has changed.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
An example of type 1 signals can be found in `advtrains_signals_ks`, which provides a subset of German signals.
|
||||||
|
|
||||||
|
An example of type 2 signals can be found in `advtrains_signals_japan`, which provides a subset of Japanese signals.
|
||||||
|
|
||||||
|
The mods mentioned above are also used for demonstation purposes and can also be used for testing.
|
|
@ -1,3 +1,8 @@
|
||||||
|
--- Distant signaling.
|
||||||
|
-- This module implements a database backend for distant signal assignments.
|
||||||
|
-- The actual modifications to signal aspects are still done by signal aspect accessors.
|
||||||
|
-- @module advtrains.interlocking.distant
|
||||||
|
|
||||||
local db_distant = {}
|
local db_distant = {}
|
||||||
local db_distant_of = {}
|
local db_distant_of = {}
|
||||||
|
|
||||||
|
@ -5,6 +10,9 @@ local A = advtrains.interlocking.aspects
|
||||||
local pts = advtrains.encode_pos
|
local pts = advtrains.encode_pos
|
||||||
local stp = advtrains.decode_pos
|
local stp = advtrains.decode_pos
|
||||||
|
|
||||||
|
--- Replace the distant signal assignment database.
|
||||||
|
-- @function load
|
||||||
|
-- @param db The new database to load.
|
||||||
local function db_load(x)
|
local function db_load(x)
|
||||||
if type(x) ~= "table" then
|
if type(x) ~= "table" then
|
||||||
return
|
return
|
||||||
|
@ -13,6 +21,9 @@ local function db_load(x)
|
||||||
db_distant_of = x.distant_of
|
db_distant_of = x.distant_of
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Retrieve the current distant signal assignment database.
|
||||||
|
-- @function save
|
||||||
|
-- @return The current database.
|
||||||
local function db_save()
|
local function db_save()
|
||||||
return {
|
return {
|
||||||
distant = db_distant,
|
distant = db_distant,
|
||||||
|
@ -22,6 +33,10 @@ end
|
||||||
|
|
||||||
local update_signal, update_main, update_dst
|
local update_signal, update_main, update_dst
|
||||||
|
|
||||||
|
--- Unassign a distant signal.
|
||||||
|
-- @function unassign_dst
|
||||||
|
-- @param dst The position of the distant signal.
|
||||||
|
-- @param[opt=false] force Whether to skip callbacks.
|
||||||
local function unassign_dst(dst, force)
|
local function unassign_dst(dst, force)
|
||||||
local pts_dst = pts(dst)
|
local pts_dst = pts(dst)
|
||||||
local main = db_distant_of[pts_dst]
|
local main = db_distant_of[pts_dst]
|
||||||
|
@ -38,6 +53,10 @@ local function unassign_dst(dst, force)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Unassign a main signal.
|
||||||
|
-- @function unassign_main
|
||||||
|
-- @param main The position of the main signal.
|
||||||
|
-- @param[opt=false] force Whether to skip callbacks.
|
||||||
local function unassign_main(main, force)
|
local function unassign_main(main, force)
|
||||||
local pts_main = pts(main)
|
local pts_main = pts(main)
|
||||||
local t = db_distant[pts_main]
|
local t = db_distant[pts_main]
|
||||||
|
@ -57,11 +76,21 @@ local function unassign_main(main, force)
|
||||||
db_distant[pts_main] = nil
|
db_distant[pts_main] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Remove all (main and distant) signal assignments from a signal.
|
||||||
|
-- @function unassign_all
|
||||||
|
-- @param pos The position of the signal.
|
||||||
|
-- @param[opt=false] force Whether to skip callbacks.
|
||||||
local function unassign_all(pos, force)
|
local function unassign_all(pos, force)
|
||||||
unassign_main(pos)
|
unassign_main(pos)
|
||||||
unassign_dst(pos, force)
|
unassign_dst(pos, force)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Assign a distant signal to a main signal.
|
||||||
|
-- @function assign
|
||||||
|
-- @param main The position of the main signal.
|
||||||
|
-- @param dst The position of the distant signal.
|
||||||
|
-- @param[opt="manual"] by The method of assignment.
|
||||||
|
-- @param[opt=false] skip_update Whether to skip callbacks.
|
||||||
local function assign(main, dst, by, skip_update)
|
local function assign(main, dst, by, skip_update)
|
||||||
local pts_main = pts(main)
|
local pts_main = pts(main)
|
||||||
local pts_dst = pts(dst)
|
local pts_dst = pts(dst)
|
||||||
|
@ -87,11 +116,20 @@ local function pre_occupy(dst, by)
|
||||||
db_distant_of[pts_dst] = {nil, by}
|
db_distant_of[pts_dst] = {nil, by}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the distant signals assigned to a main signal.
|
||||||
|
-- @function get_distant
|
||||||
|
-- @param main The position of the main signal.
|
||||||
|
-- @treturn {[pos]=by,...} A table of distant signals, with the positions encoded using `advtrains.encode_pos`.
|
||||||
local function get_distant(main)
|
local function get_distant(main)
|
||||||
local pts_main = pts(main)
|
local pts_main = pts(main)
|
||||||
return db_distant[pts_main] or {}
|
return db_distant[pts_main] or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the main signal assigned the a distant signal.
|
||||||
|
-- @function get_main
|
||||||
|
-- @param dst The position of the distant signal.
|
||||||
|
-- @return The position of the main signal.
|
||||||
|
-- @return The method of assignment.
|
||||||
local function get_main(dst)
|
local function get_main(dst)
|
||||||
local pts_dst = pts(dst)
|
local pts_dst = pts(dst)
|
||||||
local main = db_distant_of[pts_dst]
|
local main = db_distant_of[pts_dst]
|
||||||
|
@ -105,6 +143,9 @@ local function get_main(dst)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update all distant signals assigned to a main signal.
|
||||||
|
-- @function update_main
|
||||||
|
-- @param main The position of the main signal.
|
||||||
update_main = function(main)
|
update_main = function(main)
|
||||||
local pts_main = pts(main)
|
local pts_main = pts(main)
|
||||||
local t = get_distant(main)
|
local t = get_distant(main)
|
||||||
|
@ -114,10 +155,16 @@ update_main = function(main)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update the aspect of a distant signal.
|
||||||
|
-- @function update_dst
|
||||||
|
-- @param dst The position of the distant signal.
|
||||||
update_dst = function(dst)
|
update_dst = function(dst)
|
||||||
advtrains.interlocking.signal_readjust_aspect(dst)
|
advtrains.interlocking.signal_readjust_aspect(dst)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Update the aspect of a combined (main and distant) signal and all distant signals assigned to it.
|
||||||
|
-- @function update_signal
|
||||||
|
-- @param pos The position of the signal.
|
||||||
update_signal = function(pos)
|
update_signal = function(pos)
|
||||||
update_main(pos)
|
update_main(pos)
|
||||||
update_dst(pos)
|
update_dst(pos)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-- Advtrains interlocking system
|
--- Advtrains interlocking system.
|
||||||
-- See database.lua for a detailed explanation
|
-- @module advtrains.interlocking
|
||||||
|
|
||||||
advtrains.interlocking = {}
|
advtrains.interlocking = {}
|
||||||
|
|
||||||
|
|
|
@ -1,170 +1,5 @@
|
||||||
-- Signal API implementation
|
-- Signal API implementation
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Signal aspect table:
|
|
||||||
Note: All speeds are measured in m/s, aka the number of + signs in the HUD.
|
|
||||||
asp = {
|
|
||||||
main = <int speed>,
|
|
||||||
-- Main signal aspect, tells state and permitted speed of next section
|
|
||||||
-- 0 = section is blocked
|
|
||||||
-- >0 = section is free, speed limit is this value
|
|
||||||
-- -1 = section is free, maximum speed permitted
|
|
||||||
-- false/nil = Signal doesn't provide main signal information, retain current speed limit.
|
|
||||||
shunt = <boolean>,
|
|
||||||
-- Whether train may proceed as shunt move, on sight
|
|
||||||
-- main aspect takes precedence over this
|
|
||||||
-- When main==0, train switches to shunt move and is restricted to speed 6
|
|
||||||
proceed_as_main = <boolean>,
|
|
||||||
-- If an approaching train is a shunt move and 'shunt' is false,
|
|
||||||
-- the train may proceed as a train move under the "main" aspect
|
|
||||||
-- if the main aspect permits it (i.e. main!=0)
|
|
||||||
-- If this is not set, shunt moves are NOT allowed to switch to
|
|
||||||
-- a train move, and must stop even if "main" would permit passing.
|
|
||||||
-- This is intended to be used for "Halt for shunt moves" signs.
|
|
||||||
|
|
||||||
dst = <int speed>,
|
|
||||||
-- Distant signal aspect, tells state and permitted speed of the section after next section
|
|
||||||
-- The character of these information is purely informational
|
|
||||||
-- At this time, this field is not actively used
|
|
||||||
-- 0 = section is blocked
|
|
||||||
-- >0 = section is free, speed limit is this value
|
|
||||||
-- -1 = section is free, maximum speed permitted
|
|
||||||
-- false/nil = Signal doesn't provide distant signal information.
|
|
||||||
|
|
||||||
-- the character of call_on and dead_end is purely informative
|
|
||||||
call_on = <boolean>, -- Call-on route, expect train in track ahead (not implemented yet)
|
|
||||||
dead_end = <boolean>, -- Route ends on a dead end (e.g. bumper) (not implemented yet)
|
|
||||||
|
|
||||||
w_speed = <integer>,
|
|
||||||
-- "Warning speed restriction". Supposed for short-term speed
|
|
||||||
-- restrictions which always override any other restrictions
|
|
||||||
-- imposed by "speed" fields, until lifted by a value of -1
|
|
||||||
-- (Example: german Langsamfahrstellen-Signale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
== How signals actually work in here ==
|
|
||||||
Each signal (in the advtrains universe) is some node that has at least the
|
|
||||||
following things:
|
|
||||||
- An "influence point" that is set somewhere on a rail
|
|
||||||
- An aspect which trains that pass the "influence point" have to obey
|
|
||||||
|
|
||||||
There can be static and dynamic signals. Static signals are, roughly
|
|
||||||
spoken, signs, while dynamic signals are "real" signals which can display
|
|
||||||
different things.
|
|
||||||
|
|
||||||
The node definition of a signal node should contain those fields:
|
|
||||||
groups = {
|
|
||||||
advtrains_signal = 2,
|
|
||||||
save_in_at_nodedb = 1,
|
|
||||||
}
|
|
||||||
advtrains = {
|
|
||||||
set_aspect = function(pos, node, asp)
|
|
||||||
-- This function gets called whenever the signal should display
|
|
||||||
-- a new or changed signal aspect. It is not required that
|
|
||||||
-- the signal actually displays the exact same aspect, since
|
|
||||||
-- some signals can not do this by design. However, it must
|
|
||||||
-- display an aspect that is at least as restrictive as the passed
|
|
||||||
-- aspect as far as it is capable of doing so.
|
|
||||||
-- Examples:
|
|
||||||
-- - pure shunt signals can not display a "main" aspect
|
|
||||||
-- and have no effect on train moves, so they will only ever
|
|
||||||
-- honor the shunt.free field for their aspect.
|
|
||||||
-- - the german Hl system can only signal speeds of 40, 60
|
|
||||||
-- and 100 km/h, a speed of 80km/h should then be signalled
|
|
||||||
-- as 60 km/h instead.
|
|
||||||
-- In turn, it is not guaranteed that the aspect will fulfill the
|
|
||||||
-- criteria put down in supported_aspects.
|
|
||||||
-- If set_aspect is present, supported_aspects should also be declared.
|
|
||||||
|
|
||||||
-- The aspect passed in here can always be queried using the
|
|
||||||
-- advtrains.interlocking.signal_get_supposed_aspect(pos) function.
|
|
||||||
-- It is always DANGER when the signal is not used as route signal.
|
|
||||||
|
|
||||||
-- For static signals, this function should be completely omitted
|
|
||||||
-- If this function is omitted, it won't be possible to use
|
|
||||||
-- route setting on this signal.
|
|
||||||
end,
|
|
||||||
supported_aspects = {
|
|
||||||
-- A table which tells which different types of aspects this signal
|
|
||||||
-- is able to display. It is used to construct the "aspect editing"
|
|
||||||
-- formspec for route programming (and others) It should always be
|
|
||||||
-- present alongside with set_aspect. If this is not specified but
|
|
||||||
-- set_aspect is, the user will be allowed to select any aspect.
|
|
||||||
-- Any of the fields marked with <boolean/nil> support 3 types of values:
|
|
||||||
nil: if this signal can switch between free/blocked
|
|
||||||
false: always shows "blocked", unchangable
|
|
||||||
true: always shows "free", unchangable
|
|
||||||
-- Any of the "speed" fields should contain a list of possible values
|
|
||||||
-- to be set as restriction. If omitted, the value of the described
|
|
||||||
-- field is always assumed to be false (no information)
|
|
||||||
-- A speed of 0 means that the signal can show a "blocked" aspect
|
|
||||||
-- (which is probably the case for most signals)
|
|
||||||
-- If the signal can signal "no information" on one of the fields
|
|
||||||
-- (thus false is an acceptable value), include false in the list
|
|
||||||
-- If your signal can only display a single speed (may it be -1),
|
|
||||||
-- always enclose that single value into a list. (such as {-1})
|
|
||||||
main = {<speed1>, ..., <speedn>} or nil,
|
|
||||||
dst = {<speed1>, ..., <speedn>} or nil,
|
|
||||||
shunt = <boolean/nil>,
|
|
||||||
|
|
||||||
call_on = <boolean/nil>,
|
|
||||||
dead_end = <boolean/nil>,
|
|
||||||
w_speed = {<speed1>, ..., <speedn>} or nil,
|
|
||||||
|
|
||||||
},
|
|
||||||
Example for supported_aspects:
|
|
||||||
supported_aspects = {
|
|
||||||
main = {0, 6, -1}, -- can show either "Section blocked", "Proceed at speed 6" or "Proceed at maximum speed"
|
|
||||||
dst = {0, false}, -- can show only if next signal shows "blocked", no other information.
|
|
||||||
shunt = false, -- shunting by this signal is never allowed.
|
|
||||||
|
|
||||||
call_on = false,
|
|
||||||
dead_end = false,
|
|
||||||
w_speed = nil,
|
|
||||||
-- none of the information can be shown by the signal
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
get_aspect = function(pos, node)
|
|
||||||
-- This function gets called by the train safety system. It
|
|
||||||
should return the aspect that this signal actually displays,
|
|
||||||
not preferably the input of set_aspect.
|
|
||||||
-- For regular, full-featured light signals, they will probably
|
|
||||||
honor all entries in the original aspect, however, e.g.
|
|
||||||
simple shunt signals always return main=false regardless of
|
|
||||||
the set_aspect input because they can not signal "Halt" to
|
|
||||||
train moves.
|
|
||||||
-- advtrains.interlocking.DANGER contains a default "all-danger" aspect.
|
|
||||||
-- If your signal does not cover certain sub-tables of the aspect,
|
|
||||||
the following reasonable defaults are automatically assumed:
|
|
||||||
main = false (unchanged)
|
|
||||||
dst = false (unchanged)
|
|
||||||
shunt = false (shunting not allowed)
|
|
||||||
info = {} (no further information)
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
on_rightclick = advtrains.interlocking.signal_rc_handler
|
|
||||||
can_dig = advtrains.interlocking.signal_can_dig
|
|
||||||
after_dig_node = advtrains.interlocking.signal_after_dig
|
|
||||||
|
|
||||||
(If you need to specify custom can_dig or after_dig_node callbacks,
|
|
||||||
please call those functions anyway!)
|
|
||||||
|
|
||||||
Important note: If your signal should support external ways to set its
|
|
||||||
aspect (e.g. via mesecons), there are some things that need to be considered:
|
|
||||||
- advtrains.interlocking.signal_get_supposed_aspect(pos) won't respect this
|
|
||||||
- Whenever you change the signal aspect, and that aspect change
|
|
||||||
did not happen through a call to
|
|
||||||
advtrains.interlocking.signal_set_aspect(pos, asp), you are
|
|
||||||
*required* to call this function:
|
|
||||||
advtrains.interlocking.signal_on_aspect_changed(pos)
|
|
||||||
in order to notify trains about the aspect change.
|
|
||||||
This function will query get_aspect to retrieve the new aspect.
|
|
||||||
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local DANGER = {
|
local DANGER = {
|
||||||
main = 0,
|
main = 0,
|
||||||
shunt = false,
|
shunt = false,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
--- Signal aspect accessors
|
||||||
|
-- @module advtrains.interlocking
|
||||||
|
|
||||||
local A = advtrains.interlocking.aspects
|
local A = advtrains.interlocking.aspects
|
||||||
local D = advtrains.distant
|
local D = advtrains.distant
|
||||||
local I = advtrains.interlocking
|
local I = advtrains.interlocking
|
||||||
|
@ -29,6 +32,9 @@ local get_aspect
|
||||||
|
|
||||||
local supposed_aspects = {}
|
local supposed_aspects = {}
|
||||||
|
|
||||||
|
--- Replace the signal aspect cache.
|
||||||
|
-- @function load_supposed_aspects
|
||||||
|
-- @param db The new database.
|
||||||
function I.load_supposed_aspects(tbl)
|
function I.load_supposed_aspects(tbl)
|
||||||
if tbl then
|
if tbl then
|
||||||
supposed_aspects = tbl
|
supposed_aspects = tbl
|
||||||
|
@ -38,23 +44,42 @@ function I.load_supposed_aspects(tbl)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Retrieve the signal aspect cache.
|
||||||
|
-- @function save_supposed_aspects
|
||||||
|
-- @return The current database in use.
|
||||||
function I.save_supposed_aspects()
|
function I.save_supposed_aspects()
|
||||||
return supposed_aspects
|
return supposed_aspects
|
||||||
end
|
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)
|
local function get_supposed_aspect(pos)
|
||||||
return supposed_aspects[pts(pos)]
|
return supposed_aspects[pts(pos)]
|
||||||
end
|
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)
|
local function set_supposed_aspect(pos, asp)
|
||||||
supposed_aspects[pts(pos)] = asp
|
supposed_aspects[pts(pos)] = asp
|
||||||
end
|
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 function get_ndef(pos)
|
||||||
local node = N.get_node(pos)
|
local node = N.get_node(pos)
|
||||||
return minetest.registered_nodes[node.name] or {}
|
return minetest.registered_nodes[node.name] or {}
|
||||||
end
|
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 function get_supported_aspects(pos)
|
||||||
local ndef = get_ndef(pos)
|
local ndef = get_ndef(pos)
|
||||||
if ndef.advtrains and ndef.advtrains.supported_aspects then
|
if ndef.advtrains and ndef.advtrains.supported_aspects then
|
||||||
|
@ -63,6 +88,11 @@ local function get_supported_aspects(pos)
|
||||||
return nil
|
return nil
|
||||||
end
|
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 function adjust_aspect(pos, asp)
|
||||||
asp = table.copy(I.signal_convert_aspect_if_necessary(asp))
|
asp = table.copy(I.signal_convert_aspect_if_necessary(asp))
|
||||||
setmetatable(asp, signal_aspect_metatable)
|
setmetatable(asp, signal_aspect_metatable)
|
||||||
|
@ -103,6 +133,12 @@ local function adjust_aspect(pos, asp)
|
||||||
return asp, asp
|
return asp, asp
|
||||||
end
|
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 function get_real_aspect(pos)
|
||||||
local ndef = get_ndef(pos)
|
local ndef = get_ndef(pos)
|
||||||
if ndef.advtrains and ndef.advtrains.get_aspect then
|
if ndef.advtrains and ndef.advtrains.get_aspect then
|
||||||
|
@ -116,6 +152,11 @@ local function get_real_aspect(pos)
|
||||||
return nil
|
return nil
|
||||||
end
|
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)
|
get_aspect = function(pos)
|
||||||
local asp = get_supposed_aspect(pos)
|
local asp = get_supposed_aspect(pos)
|
||||||
if not asp then
|
if not asp then
|
||||||
|
@ -125,6 +166,11 @@ get_aspect = function(pos)
|
||||||
return asp
|
return asp
|
||||||
end
|
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 function set_aspect(pos, asp, skipdst)
|
||||||
local node = N.get_node(pos)
|
local node = N.get_node(pos)
|
||||||
local ndef = minetest.registered_nodes[node.name]
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
@ -141,10 +187,16 @@ local function set_aspect(pos, asp, skipdst)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Remove a signal from cache.
|
||||||
|
-- @function signal_clear_aspect
|
||||||
|
-- @param pos The position of the signal.
|
||||||
local function clear_aspect(pos)
|
local function clear_aspect(pos)
|
||||||
set_supposed_aspect(pos, nil)
|
set_supposed_aspect(pos, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Readjust the aspect of a signal.
|
||||||
|
-- @function signal_readjust_aspect
|
||||||
|
-- @param pos The position of the signal.
|
||||||
local function readjust_aspect(pos)
|
local function readjust_aspect(pos)
|
||||||
set_aspect(pos, get_aspect(pos))
|
set_aspect(pos, get_aspect(pos))
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
|
--- Signal aspect handling.
|
||||||
|
-- @module advtrains.interlocking.aspects
|
||||||
|
|
||||||
local type2defs = {}
|
local type2defs = {}
|
||||||
|
|
||||||
|
--- Register a type 2 signal group.
|
||||||
|
-- @function register_type2
|
||||||
|
-- @param def The definition table.
|
||||||
local function register_type2(def)
|
local function register_type2(def)
|
||||||
local t = {type = 2}
|
local t = {type = 2}
|
||||||
local name = def.name
|
local name = def.name
|
||||||
|
@ -42,19 +48,21 @@ local function register_type2(def)
|
||||||
type2defs[name] = t
|
type2defs[name] = t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the definition of a type 2 signal group.
|
||||||
|
-- @function get_type2_definition
|
||||||
|
-- @param name The name of the signal group.
|
||||||
|
-- @return[1] The definition for the signal group (if present).
|
||||||
|
-- @return[2] The nil constant (otherwise).
|
||||||
local function get_type2_definition(name)
|
local function get_type2_definition(name)
|
||||||
return type2defs[name]
|
return type2defs[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_type2_danger(group)
|
--- Get the name of the distant aspect before the current aspect.
|
||||||
local def = type2defs[group]
|
-- @function get_type2_dst
|
||||||
if not def then
|
-- @param group The name of the group.
|
||||||
return nil
|
-- @param name The name of the current aspect.
|
||||||
end
|
-- @return[1] The name of the distant aspect (if present).
|
||||||
local main = def.main
|
-- @return[2] The nil constant (otherwise).
|
||||||
return main[#main]
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_type2_dst(group, name)
|
local function get_type2_dst(group, name)
|
||||||
local def = type2defs[group]
|
local def = type2defs[group]
|
||||||
if not def then
|
if not def then
|
||||||
|
@ -67,6 +75,12 @@ local function get_type2_dst(group, name)
|
||||||
return def.main[math.max(1, aspidx-1)].name
|
return def.main[math.max(1, aspidx-1)].name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Convert a type 2 signal aspect to a type 1 signal aspect.
|
||||||
|
-- @function type2_to_type1
|
||||||
|
-- @param suppasp The table of supported aspects for the signal.
|
||||||
|
-- @param asp The name of the signal aspect.
|
||||||
|
-- @return[1] The type 1 signal aspect table (if present).
|
||||||
|
-- @return[2] The nil constant (otherwise).
|
||||||
local function type2_to_type1(suppasp, asp)
|
local function type2_to_type1(suppasp, asp)
|
||||||
local name = suppasp.group
|
local name = suppasp.group
|
||||||
local shift = suppasp.dst_shift
|
local shift = suppasp.dst_shift
|
||||||
|
@ -111,6 +125,13 @@ local function type2_to_type1(suppasp, asp)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Convert a type 1 signal aspect table to a type 2 signal aspect.
|
||||||
|
-- @function type1_to_type2main
|
||||||
|
-- @param asp The type 1 signal aspect table
|
||||||
|
-- @param group The signal aspect group
|
||||||
|
-- @param[opt=0] shift The shift for the signal aspect.
|
||||||
|
-- @return[1] The name of the signal aspect (if present).
|
||||||
|
-- @return[2] The nil constant (otherwise).
|
||||||
local function type1_to_type2main(asp, group, shift)
|
local function type1_to_type2main(asp, group, shift)
|
||||||
local def = type2defs[group]
|
local def = type2defs[group]
|
||||||
if not def then
|
if not def then
|
||||||
|
@ -130,6 +151,11 @@ local function type1_to_type2main(asp, group, shift)
|
||||||
return t_main[math.max(1, idx-(shift or 0))].name
|
return t_main[math.max(1, idx-(shift or 0))].name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Compare two signal aspect tables.
|
||||||
|
-- @function equalp
|
||||||
|
-- @param asp1 The first signal aspect table.
|
||||||
|
-- @param asp2 The second signal aspect table.
|
||||||
|
-- @return Whether the two signal aspect tables give the same (type 1 aspect) information.
|
||||||
local function equalp(asp1, asp2)
|
local function equalp(asp1, asp2)
|
||||||
if asp1 == asp2 then -- same reference
|
if asp1 == asp2 then -- same reference
|
||||||
return true
|
return true
|
||||||
|
@ -146,6 +172,11 @@ local function equalp(asp1, asp2)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Compare two signal aspect tables.
|
||||||
|
-- @function not_equalp
|
||||||
|
-- @param asp1 The first signal aspect table.
|
||||||
|
-- @param asp2 The second signal aspect table.
|
||||||
|
-- @return The negation of `equalp``(asp1, asp2)`.
|
||||||
local function not_equalp(asp1, asp2)
|
local function not_equalp(asp1, asp2)
|
||||||
return not equalp(asp1, asp2)
|
return not equalp(asp1, asp2)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue