~gpcf/advtrains-devel

Turn loading tracks into loading ramps v1 PROPOSED

Maverick2797: 2
 Turn loading tracks into loading ramps when within the loaded area
 Turn loading tracks into loading ramps when within the loaded area

 4 files changed, 240 insertions(+), 65 deletions(-)
Hi Maverick,

Thanks for reporting this, I oversaw one call in path_invalidate_ahead.
Should be fixed now, please try again whether the unloading rails now
work correctly in track loops.

Regards, orwell
Hi,

- (?)TODO ramp doesn't activate if track is a closed loop.

Oh no. This issue is slowly becoming a nightmare. It breaks the
coupling system, it breaks path projection, it breaks the loading
rails...

There needs to be done a change in the occupation system, so that it
can handle the same train having this position at multiple path
items (or at least make the lowest index take precedence)

I need to think about that separately.

orwell
Hi Maverick,

I have pushed a commit to master fixing the issue with the track loops.
Can you rebase your patch onto this and test it? Once it works I would
like to merge it and maybe even publish a release (there hasn't been
one for some time). Thank you!

Regards, orwell
The commit doesn't seem to have affected the loading ramps at all, 
however it does cause a crash if the track ahead of the train is changed.

I first noticed it when a detector track changed state underneath the 
loco, and was able to reproduce it both by changing a turnout and 
replacing track ahead of the train.

2023-06-24 21:46:45: ERROR[Main]: ServerError: AsyncErr: Lua: Runtime 
error from mod '' in callback item_OnPlace(): 
...0-release-win64\bin\..\mods\advtrains\advtrains/path.lua:165: attempt 
to call field 'clear_item' (a nil value)
2023-06-24 21:46:45: ERROR[Main]: stack traceback:
2023-06-24 21:46:45: ERROR[Main]: 
...0-release-win64\bin\..\mods\advtrains\advtrains/path.lua:165: in 
function 'path_invalidate_ahead'
2023-06-24 21:46:45: ERROR[Main]: 
...ase-win64\bin\..\mods\advtrains\advtrains/trainlogic.lua:1263: in 
function 'invalidate_all_paths_ahead'
2023-06-24 21:46:45: ERROR[Main]: 
...release-win64\bin\..\mods\advtrains\advtrains/nodedb.lua:251: in 
function 'update'
2023-06-24 21:46:45: ERROR[Main]: 
...release-win64\bin\..\mods\advtrains\advtrains/nodedb.lua:231: in 
function 'swap_node'
2023-06-24 21:46:45: ERROR[Main]: 
...se-win64\bin\..\mods\advtrains\advtrains/trackplacer.lua:220: in 
function 'placetrack'
2023-06-24 21:46:45: ERROR[Main]: 
...se-win64\bin\..\mods\advtrains\advtrains/trackplacer.lua:298: in 
function <...se-win64\bin\..\mods\advtrains\advtrains/trackplacer.lua:277>
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~gpcf/advtrains-devel/patches/41455/mbox | git am -3
Learn more about email & git

[PATCH] Turn loading tracks into loading ramps when within the loaded area Export this patch

 - Partially addresses Hemiptera #165 / Notabug #6
 - Will recalculate wagon textures when the inventory is modified
 - Only acts as a loading ramp when in a loaded area.
 - Retains previous flood loading of entire train when area unloaded
 - (?)TODO ramp doesn't activate if track is a closed loop.
---
 advtrains_train_track/init.lua         | 164 ++++++++++++++++++++-----
 advtrains_train_track/settingtypes.txt |   4 +
 2 files changed, 136 insertions(+), 32 deletions(-)
 mode change 100755 => 100644 advtrains_train_track/init.lua
 create mode 100644 advtrains_train_track/settingtypes.txt

diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua
old mode 100755
new mode 100644
index 5065155..a1fd0b1
--- a/advtrains_train_track/init.lua
+++ b/advtrains_train_track/init.lua
@@ -678,8 +678,49 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
	end
end)

local function load_wagon(wagon_id, node_inv, node_fc, unload)
	local inv_modified = false
	local w_inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..wagon_id})
	if w_inv and w_inv:get_list("box") then
	
		local wagon_data = advtrains.wagons[wagon_id]
		local wagon_fc
		if wagon_data.fc then
			if not wagon_data.fcind then wagon_data.fcind = 1 end
			wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
		end
		
		if node_fc == "" or wagon_fc == node_fc then
			if not unload then
-- atdebug("wagon id: "..wagon_id.." loaded")
				for _, item in ipairs(node_inv:get_list("main")) do
					if w_inv:get_list("box") and w_inv:room_for_item("box", item)  then
						w_inv:add_item("box", item)
						node_inv:remove_item("main", item)
						if item.name ~= "" then inv_modified = true end
					end
				end
			else
-- atdebug("wagon id: "..wagon_id.." unloaded")
				for _, item in ipairs(w_inv:get_list("box")) do
					if node_inv:get_list("main") and node_inv:room_for_item("main", item)  then
						w_inv:remove_item("box", item)
						node_inv:add_item("main", item)
						if item.name ~= "" then inv_modified = true end
					end
				end
			end
		end
	end
	return inv_modified
end

local function train_load(pos, train_id, unload)
local function load_entire_train(pos, train_id, unload) -- flood load when not in an active area
	if advtrains.is_node_loaded(pos) then -- leave the loading to the nodetimer if area is loaded
-- atdebug("area loaded")
		return 
	end
-- atdebug("area unloaded ======================")
	local train=advtrains.trains[train_id]
	local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
	if not string.match(below.name, "chest") then
@@ -692,43 +733,88 @@ local function train_load(pos, train_id, unload)
		--track section is disabled
		return
	end
	
	local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if inv and train.velocity < 2 then
		for k, v in ipairs(train.trainparts) do
			local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v})
			if i and i:get_list("box") then
			
				local wagon_data = advtrains.wagons[v]
				local wagon_fc
				if wagon_data.fc then
					if not wagon_data.fcind then wagon_data.fcind = 1 end
					wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
				end
				
				if node_fc == "" or wagon_fc == node_fc then
					if not unload then
						for _, item in ipairs(inv:get_list("main")) do
							if i:get_list("box") and i:room_for_item("box", item)  then
								i:add_item("box", item)
								inv:remove_item("main", item)
							end
						end
					else
						for _, item in ipairs(i:get_list("box")) do
							if inv:get_list("main") and inv:room_for_item("main", item)  then
								i:remove_item("box", item)
								inv:add_item("main", item)
							end
-- atdebug("pre-checks passed")
	local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if node_inv and train.velocity <= 2 then
-- atdebug(train)
		for _, wagon_id in ipairs(train.trainparts) do
			load_wagon(wagon_id, node_inv, node_fc, unload)
		end
	end
-- atdebug("flood loading complete ==========================")
end

local function load_wagon_on_timer(pos, unload) -- loading ramp when in an active area
-- atdebug("=========")
-- atdebug((get_far_node(pos).name == "advtrains:dtrack_unload_st" and "unloader") or "loading track")
-- atdebug("ping")
	if not advtrains.is_node_loaded(pos) then -- leave the loading for the flood load function. we're out of area
		return true -- reset the nodetimer until the node is loaded again
	end
-- atdebug("area is loaded")
	local tid, tidx = advtrains.get_train_at_pos(pos)
-- atdebug("got train:")
-- atdebug(tostring(tid))
-- atdebug(tidx)
	if not tid or tid == "" then
-- atdebug("no train")
		return true
	end -- no train to load.
-- atdebug("is train: "..tostring(tid).." <--")
	local train = advtrains.trains[tid]
-- atdebug("train exists: ")
-- atdebug(train)
	local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
	if not string.match(below.name, "chest") then
		atprint("this is not a chest! at "..minetest.pos_to_string(pos))
		return true
	end
-- atdebug("is chest")
	local node_fc = minetest.get_meta(pos):get_string("fc") or ""
	if node_fc == "#" then
		--track section is disabled
		return true
	end
-- atdebug("FC: "..node_fc)
	local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if node_inv and train.velocity <= 2 then
-- atdebug("begin wagon checks")
		local _, wagon_id, wagon_data = advtrains.get_wagon_at_index(tid, tidx)
		if wagon_id then
			local inv_modified = load_wagon(wagon_id, node_inv, node_fc, unload)
			if inv_modified then
-- atdebug("==================INVENTORY MODIFIED " .. wagon_id .." - " .. tostring(inv_modified))
-- atdebug("=================Wagon Data")
-- atdebug(wagon_data)
-- atdebug("=================Wagon Prototype")
-- print(dump(advtrains.wagon_prototypes[advtrains.get_wagon_prototype(wagon_data)]))
				if advtrains.wagon_prototypes[advtrains.get_wagon_prototype(wagon_data)].set_textures then
-- atdebug("================has set_textures function")
					local wagon_object = advtrains.wagon_objects[wagon_id]
					if wagon_object and wagon_data then
-- atdebug("================obj and data ok")
						local ent = wagon_object:get_luaentity()
						if ent and ent.set_textures then
-- atdebug("================set_texture funtion found")
							ent:set_textures(wagon_data)
-- atdebug("===============textures updated")
						end
					end
				end
			end
-- atdebug(wagon_id.." "..tostring(unload))
		end
	end
-- atdebug("End loading ramp ===================")
	return true
end


local nodetimer_interval = minetest.settings:get("advtrains_loading_track_timer") or 1
local function start_nodetimer(pos)
	local timer = minetest.get_node_timer(pos)
	timer:start(nodetimer_interval)
-- atdebug("timer started at "..minetest.pos_to_string(pos))
end

advtrains.register_tracks("default", {
	nodename_prefix="advtrains:dtrack_unload",
@@ -747,9 +833,16 @@ advtrains.register_tracks("default", {
			on_rightclick = function(pos, node, player)
				show_fc_formspec(pos, player)
			end,
			after_place_node = function(pos)
				advtrains.ndb.update(pos)
				start_nodetimer(pos)
			end,
			on_timer = function(pos)
				return load_wagon_on_timer(pos, true)
			end,
			advtrains = {
				on_train_enter = function(pos, train_id)
					train_load(pos, train_id, true)
					load_entire_train(pos, train_id, true)
				end,
			},
		}
@@ -772,9 +865,16 @@ advtrains.register_tracks("default", {
			on_rightclick = function(pos, node, player)
				show_fc_formspec(pos, player)
			end,
			after_place_node = function(pos)
				advtrains.ndb.update(pos)
				start_nodetimer(pos)
			end,
			on_timer = function(pos)
				return load_wagon_on_timer(pos, false)
			end,
			advtrains = {
				on_train_enter = function(pos, train_id)
					train_load(pos, train_id, false)
					load_entire_train(pos, train_id, false)
				end,
			},
		}
diff --git a/advtrains_train_track/settingtypes.txt b/advtrains_train_track/settingtypes.txt
new file mode 100644
index 0000000..0af0081
--- /dev/null
+++ b/advtrains_train_track/settingtypes.txt
@@ -0,0 +1,4 @@
# Set the nodetimer delay for the loading tracks.
# A longer delay may cause wagons to be missed if the pass over too fast.
# A shorter delay may cause lag as wagons are checked multiple times as they pass over.
advtrains_loading_track_timer (Loading Track Timer) int 1
\ No newline at end of file
-- 
2.38.0

[PATCH] Turn loading tracks into loading ramps when within the loaded area Export this patch

 - Partially addresses Hemiptera #165 / Notabug #6
 - Will recalculate wagon textures when the inventory is modified
 - Only acts as a loading ramp when in a loaded area.
 - Retains previous flood loading of entire train when area unloaded
 - (?)TODO ramp doesn't activate if track is a closed loop.
---
 advtrains_train_track/init.lua         | 133 +++++++++++++++++++------
 advtrains_train_track/settingtypes.txt |   4 +
 2 files changed, 104 insertions(+), 33 deletions(-)
 mode change 100755 => 100644 advtrains_train_track/init.lua
 create mode 100644 advtrains_train_track/settingtypes.txt

diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua
old mode 100755
new mode 100644
index 5065155..32e1235
--- a/advtrains_train_track/init.lua
+++ b/advtrains_train_track/init.lua
@@ -678,8 +678,45 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
	end
end)

local function load_wagon(wagon_id, node_inv, node_fc, unload)
	local inv_modified = false
	local w_inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..wagon_id})
	if w_inv and w_inv:get_list("box") then
	
		local wagon_data = advtrains.wagons[wagon_id]
		local wagon_fc
		if wagon_data.fc then
			if not wagon_data.fcind then wagon_data.fcind = 1 end
			wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
		end
		
		if node_fc == "" or wagon_fc == node_fc then
			if not unload then
				for _, item in ipairs(node_inv:get_list("main")) do
					if w_inv:get_list("box") and w_inv:room_for_item("box", item)  then
						w_inv:add_item("box", item)
						node_inv:remove_item("main", item)
						if item.name ~= "" then inv_modified = true end
					end
				end
			else
				for _, item in ipairs(w_inv:get_list("box")) do
					if node_inv:get_list("main") and node_inv:room_for_item("main", item)  then
						w_inv:remove_item("box", item)
						node_inv:add_item("main", item)
						if item.name ~= "" then inv_modified = true end
					end
				end
			end
		end
	end
	return inv_modified
end

local function train_load(pos, train_id, unload)
local function load_entire_train(pos, train_id, unload) -- flood load when not in an active area
	if advtrains.is_node_loaded(pos) then -- leave the loading to the nodetimer if area is loaded
		return 
	end
	local train=advtrains.trains[train_id]
	local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
	if not string.match(below.name, "chest") then
@@ -692,43 +729,60 @@ local function train_load(pos, train_id, unload)
		--track section is disabled
		return
	end
	
	local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if inv and train.velocity < 2 then
		for k, v in ipairs(train.trainparts) do
			local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v})
			if i and i:get_list("box") then
			
				local wagon_data = advtrains.wagons[v]
				local wagon_fc
				if wagon_data.fc then
					if not wagon_data.fcind then wagon_data.fcind = 1 end
					wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or ""
				end
				
				if node_fc == "" or wagon_fc == node_fc then
					if not unload then
						for _, item in ipairs(inv:get_list("main")) do
							if i:get_list("box") and i:room_for_item("box", item)  then
								i:add_item("box", item)
								inv:remove_item("main", item)
							end
						end
					else
						for _, item in ipairs(i:get_list("box")) do
							if inv:get_list("main") and inv:room_for_item("main", item)  then
								i:remove_item("box", item)
								inv:add_item("main", item)
							end
	local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if node_inv and train.velocity <= 2 then
		for _, wagon_id in ipairs(train.trainparts) do
			load_wagon(wagon_id, node_inv, node_fc, unload)
		end
	end
end

local function load_wagon_on_timer(pos, unload) -- loading ramp when in an active area
	if not advtrains.is_node_loaded(pos) then -- leave the loading for the flood load function. we're out of area
		return true -- reset the nodetimer until the node is loaded again
	end
	local tid, tidx = advtrains.get_train_at_pos(pos)
	if not tid or tid == "" then
		return true
	end -- no train to load.

	local train = advtrains.trains[tid]
	local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z})
	if not string.match(below.name, "chest") then
		atprint("this is not a chest! at "..minetest.pos_to_string(pos))
		return true
	end
	local node_fc = minetest.get_meta(pos):get_string("fc") or ""
	if node_fc == "#" then
		--track section is disabled
		return true
	end
	local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}})
	if node_inv and train.velocity <= 2 then
		local _, wagon_id, wagon_data = advtrains.get_wagon_at_index(tid, tidx)
		if wagon_id then
			local inv_modified = load_wagon(wagon_id, node_inv, node_fc, unload)
			if inv_modified then
				if advtrains.wagon_prototypes[advtrains.get_wagon_prototype(wagon_data)].set_textures then
					local wagon_object = advtrains.wagon_objects[wagon_id]
					if wagon_object and wagon_data then
						local ent = wagon_object:get_luaentity()
						if ent and ent.set_textures then
							ent:set_textures(wagon_data)
						end
					end
				end
			end
		end
	end
	return true
end


local nodetimer_interval = minetest.settings:get("advtrains_loading_track_timer") or 1
local function start_nodetimer(pos)
	local timer = minetest.get_node_timer(pos)
	timer:start(nodetimer_interval)
end

advtrains.register_tracks("default", {
	nodename_prefix="advtrains:dtrack_unload",
@@ -747,9 +801,16 @@ advtrains.register_tracks("default", {
			on_rightclick = function(pos, node, player)
				show_fc_formspec(pos, player)
			end,
			after_place_node = function(pos)
				advtrains.ndb.update(pos)
				start_nodetimer(pos)
			end,
			on_timer = function(pos)
				return load_wagon_on_timer(pos, true)
			end,
			advtrains = {
				on_train_enter = function(pos, train_id)
					train_load(pos, train_id, true)
					load_entire_train(pos, train_id, true)
				end,
			},
		}
@@ -772,9 +833,16 @@ advtrains.register_tracks("default", {
			on_rightclick = function(pos, node, player)
				show_fc_formspec(pos, player)
			end,
			after_place_node = function(pos)
				advtrains.ndb.update(pos)
				start_nodetimer(pos)
			end,
			on_timer = function(pos)
				return load_wagon_on_timer(pos, false)
			end,
			advtrains = {
				on_train_enter = function(pos, train_id)
					train_load(pos, train_id, false)
					load_entire_train(pos, train_id, false)
				end,
			},
		}
@@ -788,7 +856,6 @@ if minetest.get_modpath("basic_materials") then
elseif minetest.get_modpath("technic") then
	loader_core = "technic:control_logic_unit"
end
---print("Loader Core: "..loader_core)

minetest.register_craft({
	type="shapeless",
diff --git a/advtrains_train_track/settingtypes.txt b/advtrains_train_track/settingtypes.txt
new file mode 100644
index 0000000..0af0081
--- /dev/null
+++ b/advtrains_train_track/settingtypes.txt
@@ -0,0 +1,4 @@
# Set the nodetimer delay for the loading tracks.
# A longer delay may cause wagons to be missed if the pass over too fast.
# A shorter delay may cause lag as wagons are checked multiple times as they pass over.
advtrains_loading_track_timer (Loading Track Timer) int 1
\ No newline at end of file
-- 
2.38.0