1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
-- ars.lua
-- automatic routesetting
--[[
The "ARS table" and its effects:
Every route has (or can have) an associated ARS table. This can either be
ars = { [n] = {ln="<line>"}/{rc="<routingcode>"}/{c="<a comment>"} }
a list of rules involving either line or routingcode matchers (or comments, those are ignored)
The first matching rule determines the route to set.
- or -
ars = {default = true}
this means that all trains that no other rule matches on should use this route
Compound ("and") conjunctions are not supported (--TODO should they?)
For editing, those tables are transformed into lines in a text area:
{ln=...} -> LN ...
{rc=...} -> RC ...
{c=...} -> #...
{default=true} -> *
See also route_ui.lua
]]
local il = advtrains.interlocking
-- The ARS data are saved in a table format, but are entered in text format. Utility functions to transform between both.
function il.ars_to_text(arstab)
if not arstab then
return ""
end
local txt = {}
for i, arsent in ipairs(arstab) do
if arsent.ln then
txt[#txt+1] = "LN "..arsent.ln
elseif arsent.rc then
txt[#txt+1] = "RC "..arsent.rc
elseif arsent.c then
txt[#txt+1] = "#"..arsent.c
end
end
if arstab.default then
return "*\n" .. table.concat(txt, "\n")
end
return table.concat(txt, "\n")
end
function il.text_to_ars(t)
if t=="" then
return nil
elseif t=="*" then
return {default=true}
end
local arstab = {}
for line in string.gmatch(t, "[^\r\n]+") do
if line=="*" then
arstab.default = true
else
local c, v = string.match(line, "^(..)%s(.*)$")
if c and v then
local tt=string.upper(c)
if tt=="LN" then
arstab[#arstab+1] = {ln=v}
elseif tt=="RC" then
arstab[#arstab+1] = {rc=v}
end
else
local ct = string.match(line, "^#(.*)$")
if ct then arstab[#arstab+1] = {c = ct} end
end
end
end
return arstab
end
local function find_rtematch(routes, train)
local default
for rteid, route in ipairs(routes) do
if route.ars then
if route.ars.default then
default = rteid
else
if il.ars_check_rule_match(route.ars, train) then
return rteid
end
end
end
end
return default
end
-- Checks whether ARS rule explicitly matches. This does not take into account the "default" field, since a wider context is required for this.
-- Returns the rule number that matched, or nil if nothing matched
function il.ars_check_rule_match(ars, train)
if not ars then
return nil
end
local line = train.line
local routingcode = train.routingcode
for arskey, arsent in ipairs(ars) do
--atdebug(arsent, line, routingcode)
if arsent.ln and line and arsent.ln == line then
return arskey
elseif arsent.rc and routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true) then
return arskey
end
end
return nil
end
function advtrains.interlocking.ars_check(sigd, train)
local tcbs = il.db.get_tcbs(sigd)
if not tcbs or not tcbs.routes then return end
if tcbs.routeset then
-- ARS is not in effect when a route is already set
return
end
local rteid = find_rtematch(tcbs.routes, train)
if rteid then
--delay routesetting, it should not occur inside train step
-- using after here is OK because that gets called on every path recalculation
minetest.after(0, il.route.update_route, sigd, tcbs, rteid, nil)
end
end
|