aboutsummaryrefslogtreecommitdiff
path: root/advtrains_interlocking/smartroute.lua
blob: 770c3796d273f9b9c14beeaa8a8dcaac3fc6e456 (plain)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
-- smartroute.lua
-- Implementation of the advtrains auto-route search

local atil = advtrains.interlocking
local ildb = atil.db
local sr = {}


local function otherside(s)
	if s==1 then return 2 else return 1 end
end

--route search implementation
-- Note this is similar to recursively_find_routes in database.lua, there used for the rscache

local function recursively_find_routes(s_pos, s_connid, searching_shunt, tcbseq, mark_pos, result_table, scan_limit)
	--atdebug("Recursively restarting at ",s_pos, s_connid, "limit left", scan_limit)
	local ti = advtrains.get_track_iterator(s_pos, s_connid, scan_limit, false)
	local pos, connid, bconnid = ti:next_branch()
	pos, connid, bconnid = ti:next_track()-- step once to get ahead of previous turnout
	local last_pos
	repeat
		-- record position in mark_pos
		local pts = advtrains.encode_pos(pos)
		mark_pos[pts] = true
		
		local node = advtrains.ndb.get_node_or_nil(pos)
		atdebug("(SmartRoute) Walk ",pos, "nodename", node.name, "entering at conn",bconnid)
		local ndef = minetest.registered_nodes[node.name]
		if ndef.advtrains and ndef.advtrains.node_state_map then
			-- Stop, this is a switchable node. Find out which conns we can go at
			atdebug("(SmartRoute) Found turnout ",pos, "nodename", node.name, "entering at conn",bconnid)
			local out_conns = ildb.get_possible_out_connids(node.name, bconnid)
			for oconnid, state in pairs(out_conns) do
				--atdebug("Going in direction",oconnid,"state",state)
				recursively_find_routes(pos, oconnid, searching_shunt, table.copy(tcbseq), table.copy(mark_pos), result_table, ti.limit)
			end
			return
		end
		--otherwise, this might be a tcb
		local tcb = ildb.get_tcb(pos)
		if tcb then
			local fsigd = { p = pos, s = connid }
			atdebug("(SmartRoute) Encounter TCB ",fsigd)
			tcbseq[#tcbseq+1] = fsigd
			-- check if this is a possible route endpoint
			local tcbs = tcb[connid]
			if tcbs.signal then
				local ndef = advtrains.ndb.get_ndef(tcbs.signal)
				if ndef and ndef.advtrains then
					if ndef.advtrains.route_role == "main" or ndef.advtrains.route_role == "main_distant"
							or ndef.advtrains.route_role == "end" or ndef.advtrains.route_role == "shunt" then
						-- signal is suitable target
						local is_mainsignal = ndef.advtrains.route_role ~= "shunt"
						-- record the found route in the results
						result_table[#result_table+1] = {
							tcbseq = table.copy(tcbseq),
							mark_pos = table.copy(mark_pos),
							shunt_route = not is_mainsignal,
							to_end_of_track = false,
							name = tcbs.signal_name or atil.sigd_to_string(fsigd)
						}
						-- if this is a main signal and/or we are only searching shunt routes, stop the search here
						if is_mainsignal or searching_shunt then
							atdebug("(SmartRoute) Terminating here because it is main or only shunt routes searched")
							return
						end
					end
				end
			end
		end
		-- Go forward
		last_pos = pos
		pos, connid, bconnid = ti:next_track()
	until not pos -- this stops the loop when either the track end is reached or the limit is hit
	--atdebug("recursively_find_routes: Reached track end or limit at", last_pos, ". This path is not saved, returning")
end

local function build_route_from_foundroute(froute, name)
	local route = {
		name = froute.name,
		use_rscache = true,
		smartroute_generated = true,
	}
	for _, sigd in ipairs(froute.tcbseq) do
		route[#route+1] = { next = sigd, locks = {} }
	end
	return route
end

-- Maximum scan length for track iterator
local TS_MAX_SCAN = 1000

function sr.init(pname, sigd)
	-- is start signal a shunt signal?
	local is_startsignal_shunt = false
	local tcbs = ildb.get_tcbs(sigd)
	if tcbs.signal then
		local ndef = advtrains.ndb.get_ndef(tcbs.signal)
		if ndef and ndef.advtrains then
			if ndef.advtrains.route_role == "shunt" then
				is_startsignal_shunt = true
			end
		end
	end
	local result_table = {}
	recursively_find_routes(sigd.p, sigd.s, is_startsignal_shunt, {}, {}, result_table, TS_MAX_SCAN)
	
	atdebug("Smartroute search finished:",result_table)
	
	-- Short-circuit logic right now for testing
	-- go through and delete all routes that are autogenerated
	local i = 1
	while i<=#tcbs.routes do
		if tcbs.routes[i].smartroute_generated then
			table.remove(tcbs.routes, i)
		else
			i=i+1
		end
	end
	-- just plainly create routes!
	for idx, froute in ipairs(result_table) do
		tcbs.routes[#tcbs.routes+1] = build_route_from_foundroute(froute)
	end
	atwarn("Smartroute done!")
end



--[[
	player1 = {
		origin = <sigd>
		found_routes = {
			{ tcbseq = {<sigd1>, <sigd2>, <end_sigd>}, mark_pos = { table with keys being encoded_pos of rails constituting route }, to_end_of_track = false, shunt_route = false }
		}
	}
]]--
local player_smartroute = {}

minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
	local pname = player:get_player_name()
	if not minetest.check_player_privs(pname, "interlocking") then
		return
	end
	-- TODO
end)


advtrains.interlocking.smartroute = sr