aboutsummaryrefslogtreecommitdiff
path: root/advtrains
diff options
context:
space:
mode:
authororwell96 <orwell@bleipb.de>2022-01-13 21:03:55 +0100
committerorwell96 <orwell@bleipb.de>2023-05-27 12:26:10 +0200
commitf284d395d700ffb0fad29c18a9cfe466ed92961b (patch)
treec64f5310a9adf28ce8e6503c57ad4230386a9281 /advtrains
parent283efc44ce78001ebd17f64555eb795e36b27a61 (diff)
downloadadvtrains-f284d395d700ffb0fad29c18a9cfe466ed92961b.tar.gz
advtrains-f284d395d700ffb0fad29c18a9cfe466ed92961b.tar.bz2
advtrains-f284d395d700ffb0fad29c18a9cfe466ed92961b.zip
Add TrackIterator interface as a common framework for walking along tracks (also for third-party libs)
This will replace the interlocking traverser and will be used in the new itrainmap implementation
Diffstat (limited to 'advtrains')
-rw-r--r--advtrains/couple.lua4
-rw-r--r--advtrains/debugitems.lua37
-rw-r--r--advtrains/helpers.lua116
-rw-r--r--advtrains/init.lua3
-rw-r--r--advtrains/settingtypes.txt4
5 files changed, 162 insertions, 2 deletions
diff --git a/advtrains/couple.lua b/advtrains/couple.lua
index 3e6c432..49c8a5d 100644
--- a/advtrains/couple.lua
+++ b/advtrains/couple.lua
@@ -475,7 +475,7 @@ minetest.register_entity("advtrains:couple", {
self.object:remove()
end,
on_step=function(self, dtime)
- if advtrains.wagon_outside_range(self.object:getpos()) then
+ if advtrains.wagon_outside_range(self.object:get_pos()) then
--atdebug("Couple Removing outside range")
self.object:remove()
return
@@ -514,7 +514,7 @@ minetest.register_entity("advtrains:couple", {
tp2=advtrains.path_get_interpolated(train2, train2.end_index)
end
local pos_median=advtrains.pos_median(tp1, tp2)
- if not vector.equals(pos_median, self.object:getpos()) then
+ if not vector.equals(pos_median, self.object:get_pos()) then
self.object:set_pos(pos_median)
end
self.position_set=true
diff --git a/advtrains/debugitems.lua b/advtrains/debugitems.lua
index e598216..a59efc7 100644
--- a/advtrains/debugitems.lua
+++ b/advtrains/debugitems.lua
@@ -81,3 +81,40 @@ minetest.register_tool("advtrains:wagonpos_tester",
end,
}
)
+
+
+local function trackitest(initial_pos, initial_connid)
+ local ti, pos, connid, ok
+ ti = advtrains.get_track_iterator(initial_pos, initial_connid, 500, true)
+ atdebug("Starting at pos:",initial_pos,initial_connid)
+ while ti:has_next_branch() do
+ pos, connid = ti:next_branch() -- in first iteration, this will be the node at initial_pos. In subsequent iterations this will be the switch node from which we are branching off
+ atdebug("Next Branch:",pos, connid)
+ ok = true
+ while ok do
+ ok, pos, connid = ti:next_track()
+ atdebug("Next Track:", ok, pos, connid)
+ end
+ end
+ atdebug("End of traverse. Visited: ",table.concat(ti.visited, ","))
+end
+
+minetest.register_tool("advtrains:trackitest",
+{
+ description = "Track Iterator Tester (leftclick conn 1, rightclick conn 2)",
+ groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
+ inventory_image = "advtrains_track_swlcr_45.png",
+ wield_image = "advtrains_track_swlcr_45.png",
+ stack_max = 1,
+ range = 7.0,
+
+ on_place = function(itemstack, placer, pointed_thing)
+ if pointed_thing.type ~= "node" then return end
+ trackitest(pointed_thing.under, 2)
+ end,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "node" then return end
+ trackitest(pointed_thing.under, 1)
+ end,
+}
+)
diff --git a/advtrains/helpers.lua b/advtrains/helpers.lua
index cf890ca..bef4903 100644
--- a/advtrains/helpers.lua
+++ b/advtrains/helpers.lua
@@ -470,3 +470,119 @@ else
end
end
end
+
+
+-- TrackIterator interface --
+
+-- Metatable:
+local trackiter_mt = {
+ -- get whether there are still unprocessed branches
+ has_next_branch = function(self)
+ return #self.branches > 0
+ end,
+ -- go to the next unprocessed branch
+ -- returns track_pos, track_connid of the switch/crossing node where the track branches off
+ next_branch = function(self)
+ local br = table.remove(self.branches, 1)
+ -- Advance internal state
+ local adj_pos, adj_connid, _, _, adj_conns = advtrains.get_adjacent_rail(br.pos, nil, br.connid)
+ self.pos = adj_pos
+ self.bconnid = adj_connid
+ self.tconns = adj_conns
+ self.limit = br.limit - 1
+ self.visited[advtrains.encode_pos(br.pos)] = true
+ return br.pos, br.connid
+ end,
+ -- get the next track along the current branch,
+ -- potentially adding branching tracks to the unprocessed branches list
+ -- returns status, track_pos, track_connid
+ -- status is true(ok), false(track has ended), nil(traversing limit has been reached) (when status~=true, track_pos and track_connid are nil)
+ next_track = function(self)
+ local pos = self.pos
+ if not pos then
+ -- last run found track end. Return false
+ return false, "track_end"
+ end
+ -- if limit hit, return nil to signal this
+ if self.limit <= 0 then
+ return nil, "limit_hit"
+ end
+ if self.visited[advtrains.encode_pos(pos)] then
+ -- node was already seen. do not continue
+ return nil, "already_visited"
+ end
+ -- select next conn (main conn to follow is the associated connection)
+ local mconnid = advtrains.get_matching_conn(self.bconnid, #self.tconns)
+ -- If there are more connections, add these to branches
+ for nconnid,_ in ipairs(self.tconns) do
+ if nconnid~=mconnid and nconnid~=self.bconnid then
+ table.insert(self.branches, {pos = self.pos, connid = nconnid, limit=self.limit})
+ end
+ end
+ -- Advance internal state
+ local adj_pos, adj_connid, _, _, adj_conns = advtrains.get_adjacent_rail(pos, self.tconns, mconnid)
+ self.pos = adj_pos
+ self.bconnid = adj_connid
+ self.tconns = adj_conns
+ self.limit = self.limit - 1
+ self.visited[advtrains.encode_pos(pos)] = true
+ return pos, mconnid
+ end,
+}
+
+-- Returns a new TrackIterator object
+
+-- Parameters:
+-- initial_pos: the initial track position of the track iterator
+-- initial_connid: the connection index in which to traverse. If nil, adds a "branch" for every connection of the track (traverse in all directions)
+-- limit: maximum distance from the start point after which the traverser stops
+-- follow_all: if true, follows all branches at multi-connection tracks, even the ones pointing backwards or the crossing track on crossings. If false, follows only switches in driving direction.
+
+-- Functions of the returned TrackIterator can be called via the Lua : notation, such as ti:next_track()
+-- If only the main track needs to be followed, use only the ti:next_track() function and do not call ti:next_branch().
+function advtrains.get_track_iterator(initial_pos, initial_connid, limit, follow_all)
+ local ti = {
+ visited = {}
+ }
+ if initial_connid then
+ ti.branches = { {pos = initial_pos, connid = initial_connid, limit=limit} }
+ else
+ -- get track info here
+ local node_ok, conns, rail_y=advtrains.get_rail_info_at(initial_pos)
+ assert(node_ok, "get_track_iterator called with non-track node!")
+ ti.branches = {}
+ for coni, _ in pairs(conns) do
+ table.insert(ti.branches, {pos = initial_pos, connid = coni, limit=limit})
+ end
+ end
+ setmetatable(ti, {__index=trackiter_mt})
+ return ti
+end
+
+--[[
+Example TrackIterator usage structure:
+
+local ti, pos, connid, ok
+ti = advtrains.get_track_iterator(initial_pos, initial_connid, 500, true)
+while ti:has_next_branch() do
+ pos, connid = ti:next_branch() -- in first iteration, this will be the node at initial_pos. In subsequent iterations this will be the switch node from which we are branching off
+ repeat
+ <do something with the track>
+ if <track satisfies an abort condition> then break end --for example, when traversing should stop at TCBs this can check if there is a tcb here
+ ok, pos, connid = ti:next_track()
+ until not ok -- this stops the loop when either the track end is reached or the limit is hit
+ -- while loop continues with the next branch ( diverging branch of one of the switches/crossings) until no more are left
+end
+
+Example for walking only a single track (without branching):
+
+local ti, pos, connid, ok
+ti = advtrains.get_track_iterator(initial_pos, initial_connid, 500, true)
+
+pos, connid = ti:next_branch() -- this always needs to be done at least one time, and gets the track at initial_pos
+repeat
+ <do something with the track>
+ if <track satisfies an abort condition> then break end --for example, when traversing should stop at TCBs this can check if there is a tcb here
+ ok, pos, connid = ti:next_track()
+until not ok -- this stops the loop when either the track end is reached or the limit is hit
+]]
diff --git a/advtrains/init.lua b/advtrains/init.lua
index a7e5764..2213937 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -229,6 +229,9 @@ end
dofile(advtrains.modpath.."/lzb.lua")
+if minetest.settings:get_bool("advtrains_register_debugitems") then
+ dofile(advtrains.modpath.."/debugitems.lua")
+end
--load/save
diff --git a/advtrains/settingtypes.txt b/advtrains/settingtypes.txt
index 2b627cb..79a1e4c 100644
--- a/advtrains/settingtypes.txt
+++ b/advtrains/settingtypes.txt
@@ -7,6 +7,10 @@ advtrains_show_ids (Show ID's in infotext) bool false
# You probably want to leave this setting set to false.
advtrains_enable_debugging (Enable debugging) bool false
+# Register certain debug items, for example the tunnelborer
+# Do not use on productive servers!
+advtrains_register_debugitems (Register Debug Items) bool false
+
# Enable the logging of certain events related to advtrains
# Logs are saved in the world directory as advtrains.log
# This setting is useful for multiplayer servers