Fix hopper-minecart interaction, convert ipairs(table) to use for i=1,#table instead

This commit is contained in:
teknomunk 2024-04-12 12:28:24 +00:00
parent ac8cdd5fe1
commit 122cb53e44
5 changed files with 158 additions and 71 deletions

View File

@ -156,8 +156,8 @@ function DEFAULT_CART_DEF:add_node_watch(pos)
local staticdata = self._staticdata local staticdata = self._staticdata
local watches = staticdata.node_watches or {} local watches = staticdata.node_watches or {}
for _,watch in ipairs(watches) do for i=1,#watches do
if watch == pos then return end if watches[i] == pos then return end
end end
watches[#watches+1] = pos watches[#watches+1] = pos
@ -168,9 +168,10 @@ function DEFAULT_CART_DEF:remove_node_watch(pos)
local watches = staticdata.node_watches or {} local watches = staticdata.node_watches or {}
local new_watches = {} local new_watches = {}
for _,node_pos in ipairs(watches) do for i=1,#watches do
local node_pos = watches[i]
if node_pos ~= pos then if node_pos ~= pos then
new_watches[#new_watches] = node_pos new_watches[#new_watches + 1] = node_pos
end end
end end
staticdata.node_watches = new_watches staticdata.node_watches = new_watches
@ -256,7 +257,7 @@ function DEFAULT_CART_DEF:on_step(dtime)
mod.update_cart_orientation(self) mod.update_cart_orientation(self)
end end
function mod.kill_cart(staticdata) function mod.kill_cart(staticdata, killer)
local pos local pos
minetest.log("action", "cart #"..staticdata.uuid.." was killed") minetest.log("action", "cart #"..staticdata.uuid.." was killed")
@ -288,16 +289,33 @@ function mod.kill_cart(staticdata)
-- Drop items -- Drop items
if not staticdata.dropped then if not staticdata.dropped then
-- Try to drop the cart
local entity_def = minetest.registered_entities[staticdata.cart_type] local entity_def = minetest.registered_entities[staticdata.cart_type]
if entity_def then if entity_def then
local drop = entity_def.drop local drop_cart = true
for d=1, #drop do if killer and minetest.is_creative_enabled(killer:get_player_name()) then
minetest.add_item(pos, drop[d]) drop_cart = false
end end
-- Prevent item duplication if drop_cart then
staticdata.dropped = true local drop = entity_def.drop
for d=1, #drop do
minetest.add_item(pos, drop[d])
end
end
end end
-- Drop any items in the inventory
local inventory = staticdata.inventory
if inventory then
for i=1,#inventory do
minetest.add_item(pos, inventory[i])
end
end
-- Prevent item duplication
staticdata.dropped = true
end end
-- Remove data -- Remove data
@ -306,7 +324,7 @@ end
local kill_cart = mod.kill_cart local kill_cart = mod.kill_cart
function DEFAULT_CART_DEF:on_death(killer) function DEFAULT_CART_DEF:on_death(killer)
kill_cart(self._staticdata) kill_cart(self._staticdata, killer)
end end
-- Create a minecart -- Create a minecart
@ -551,6 +569,8 @@ end
local timer = 0 local timer = 0
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
-- Periodically respawn carts that come into range of a player
timer = timer - dtime timer = timer - dtime
if timer <= 0 then if timer <= 0 then
local start_time = minetest.get_us_time() local start_time = minetest.get_us_time()
@ -559,11 +579,13 @@ minetest.register_globalstep(function(dtime)
local duration = (stop_time - start_time) / 1e6 local duration = (stop_time - start_time) / 1e6
timer = duration / 250e-6 -- Schedule 50us per second timer = duration / 250e-6 -- Schedule 50us per second
if timer > 5 then timer = 5 end if timer > 5 then timer = 5 end
--print("Took "..tostring(duration).." seconds, rescheduling for "..tostring(timer).." seconds in the future")
end end
-- Handle periodically updating out-of-range carts -- Handle periodically updating out-of-range carts
-- TODO: change how often cart positions are updated based on velocity -- TODO: change how often cart positions are updated based on velocity
local start_time
if DEBUG then start_time = minetest.get_us_time() end
for uuid,staticdata in mod.carts() do for uuid,staticdata in mod.carts() do
local pos = mod.get_cart_position(staticdata) local pos = mod.get_cart_position(staticdata)
--[[ --[[
@ -580,5 +602,10 @@ minetest.register_globalstep(function(dtime)
do_movement(staticdata, dtime) do_movement(staticdata, dtime)
end end
end end
if DEBUG then
local stop_time = minetest.get_us_time()
print("Update took "..((stop_time-start_time)*1e-6).." seconds")
end
end) end)

View File

@ -156,13 +156,13 @@ mod.register_minecart({
groups = { container = 1 }, groups = { container = 1 },
on_rightclick = nil, on_rightclick = nil,
on_activate_by_rail = nil, on_activate_by_rail = nil,
_mcl_minecarts_on_enter = function(self, pos) _mcl_minecarts_on_enter = function(self, pos, staticdata)
local staticdata = self._staticdata
if (staticdata.hopper_delay or 0) > 0 then if (staticdata.hopper_delay or 0) > 0 then
return return
end end
-- try to pull from containers into our inventory -- try to pull from containers into our inventory
if not self then return end
local inv = mcl_entity_invs.load_inv(self,5) local inv = mcl_entity_invs.load_inv(self,5)
local above_pos = pos + vector.new(0,1,0) local above_pos = pos + vector.new(0,1,0)
mcl_util.hopper_pull_to_inventory(inv, 'main', above_pos, pos) mcl_util.hopper_pull_to_inventory(inv, 'main', above_pos, pos)

View File

@ -185,7 +185,8 @@ local function get_rail_connections(pos, opt)
local ignore_neighbor_connections = opt and opt.ignore_neighbor_connections local ignore_neighbor_connections = opt and opt.ignore_neighbor_connections
local connections = 0 local connections = 0
for i,dir in ipairs(CONNECTIONS) do for i = 1,#CONNECTIONS do
dir = CONNECTIONS[i]
local neighbor = vector.add(pos, dir) local neighbor = vector.add(pos, dir)
local node = minetest.get_node(neighbor) local node = minetest.get_node(neighbor)
local nodedef = minetest.registered_nodes[node.name] local nodedef = minetest.registered_nodes[node.name]
@ -223,7 +224,8 @@ local function update_rail_connections(pos, opt)
local connections = get_rail_connections(pos, opt) local connections = get_rail_connections(pos, opt)
-- Check for rasing rails to slopes -- Check for rasing rails to slopes
for i,dir in ipairs(CONNECTIONS) do for i = 1,#CONNECTIONS do
local dir = CONNECTIONS[i]
local neighbor = vector.add(pos, dir) local neighbor = vector.add(pos, dir)
make_sloped_if_straight( vector.offset(neighbor, 0, -1, 0), dir ) make_sloped_if_straight( vector.offset(neighbor, 0, -1, 0), dir )
end end
@ -258,7 +260,8 @@ local function update_rail_connections(pos, opt)
local node_def = minetest.registered_nodes[node.name] local node_def = minetest.registered_nodes[node.name]
if get_path(node_def, "_mcl_minecarts", "can_slope") then if get_path(node_def, "_mcl_minecarts", "can_slope") then
for _,dir in ipairs(CONNECTIONS) do for i=1,#CONNECTIONS do
local dir = CONNECTIONS[i]
local higher_rail_pos = vector.offset(pos,dir.x,1,dir.z) local higher_rail_pos = vector.offset(pos,dir.x,1,dir.z)
local rev_dir = vector.direction(dir,vector.new(0,0,0)) local rev_dir = vector.direction(dir,vector.new(0,0,0))
if mcl_minecarts:is_rail(higher_rail_pos) and is_connection(higher_rail_pos, rev_dir) then if mcl_minecarts:is_rail(higher_rail_pos) and is_connection(higher_rail_pos, rev_dir) then

View File

@ -55,7 +55,9 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event)
local dir = staticdata.dir local dir = staticdata.dir
local right = vector.new( dir.z, dir.y, -dir.x) local right = vector.new( dir.z, dir.y, -dir.x)
local up = vector.new(0,1,0) local up = vector.new(0,1,0)
for _,check in ipairs(enter_exit_checks) do for i=1,#enter_exit_checks do
local check = enter_exit_checks[i]
local check_pos = pos + dir * check[1] + right * check[2] + up * check[3] local check_pos = pos + dir * check[1] + right * check[2] + up * check[3]
local node = minetest.get_node(check_pos) local node = minetest.get_node(check_pos)
local node_def = minetest.registered_nodes[node.name] local node_def = minetest.registered_nodes[node.name]
@ -74,7 +76,7 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event)
-- Handle cart-specific behaviors -- Handle cart-specific behaviors
if luaentity then if luaentity then
local hook = luaentity["_mcl_minecarts_"..event] local hook = luaentity["_mcl_minecarts_"..event]
if hook then hook(self, pos) end if hook then hook(luaentity, pos, staticdata) end
else else
--minetest.log("warning", "TODO: change _mcl_minecarts_"..event.." calling so it is not dependent on the existence of a luaentity") --minetest.log("warning", "TODO: change _mcl_minecarts_"..event.." calling so it is not dependent on the existence of a luaentity")
end end
@ -99,12 +101,13 @@ local function handle_cart_node_watches(staticdata, dtime)
local watches = staticdata.node_watches or {} local watches = staticdata.node_watches or {}
local new_watches = {} local new_watches = {}
local luaentity = mcl_util.get_luaentity_from_uuid(staticdata.uuid) local luaentity = mcl_util.get_luaentity_from_uuid(staticdata.uuid)
for _,node_pos in ipairs(watches) do for i=1,#watches do
local node_pos = watches[i]
local node = minetest.get_node(node_pos) local node = minetest.get_node(node_pos)
local node_def = minetest.registered_nodes[node.name] local node_def = minetest.registered_nodes[node.name]
if node_def then if node_def then
local hook = node_def._mcl_minecarts_node_on_step local hook = node_def._mcl_minecarts_node_on_step
if hook and hook(node_pos, luaentity, dtime) then if hook and hook(node_pos, luaentity, dtime, staticdata) then
new_watches[#new_watches+1] = node_pos new_watches[#new_watches+1] = node_pos
end end
end end

View File

@ -136,6 +136,47 @@ local function hopper_push_to_mc(mc_ent, dest_pos, inv_size)
end end
end end
end end
local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size)
local inv = mcl_entity_invs.load_inv(mc_ent, inv_size)
if not inv then
mcl_log("No inv")
return false
end
local dest_meta = minetest.get_meta(dest_pos)
local dest_inv = dest_meta:get_inventory()
if not dest_inv then
mcl_log("No dest inv")
return false
end
mcl_log("inv. size: " .. mc_ent._inv_size)
for i = 1, mc_ent._inv_size, 1 do
local stack = inv:get_stack("main", i)
mcl_log("i: " .. tostring(i))
mcl_log("Name: [" .. tostring(stack:get_name()) .. "]")
mcl_log("Count: " .. tostring(stack:get_count()))
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
if not stack:get_name() or stack:get_name() ~= "" then
if dest_inv:room_for_item("main", stack:peek_item()) then
mcl_log("Room so unload")
dest_inv:add_item("main", stack:take_item())
inv:set_stack("main", i, stack)
-- Take one item and stop until next time, report that we took something
return true
else
mcl_log("no Room")
end
else
mcl_log("nothing there")
end
end
end
mcl_hoppers.pull_from_minecart = hopper_pull_from_mc
-- Downwards hopper (base definition) -- Downwards hopper (base definition)
@ -243,16 +284,29 @@ local def_hopper = {
minetest.log("action", player:get_player_name() .. minetest.log("action", player:get_player_name() ..
" takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos)) " takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos))
end, end,
_mcl_minecarts_on_enter_above = function(pos, cart, next_dir) _mcl_minecarts_on_enter_below = function(pos, cart, next_dir)
-- Only push to containers print("Cart entered above "..tostring(pos))
if cart.groups and (cart.groups.container or 0) ~= 0 then -- Only pull to containers
if cart and cart.groups and (cart.groups.container or 0) ~= 0 then
cart:add_node_watch(pos) cart:add_node_watch(pos)
hopper_push_to_mc(cart, pos, 5)
end
end,
_mcl_minecarts_on_enter_above = function(pos, cart, next_dir)
print("Cart entered below "..tostring(pos))
-- Only push to containers
if cart and cart.groups and (cart.groups.container or 0) ~= 0 then
cart:add_node_watch(pos)
hopper_pull_from_mc(cart, pos, 5)
end end
end, end,
_mcl_minecarts_on_leave_above = function(pos, cart, next_dir) _mcl_minecarts_on_leave_above = function(pos, cart, next_dir)
if not cart then return end
cart:remove_node_watch(pos) cart:remove_node_watch(pos)
end, end,
_mcl_minecarts_node_on_step = function(pos, cart, dtime) _mcl_minecarts_node_on_step = function(pos, cart, dtime, cartdata)
if not cart then if not cart then
minetest.log("warning", "trying to process hopper-to-minecart movement without luaentity") minetest.log("warning", "trying to process hopper-to-minecart movement without luaentity")
return return
@ -260,9 +314,18 @@ local def_hopper = {
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local cart_pos = mcl_minecarts.get_cart_position(cartdata)
local timer = meta:get_int("minecart_hopper_timer") local timer = meta:get_int("minecart_hopper_timer")
if timer < dtime then if timer < dtime then
hopper_push_to_mc(cart, pos, 5) if vector.direction(pos,cart_pos).y > 0 then
-- The cart is above us, pull from minecart
print("Pulling from cart above "..tostring(pos))
hopper_pull_from_mc(cart, pos, 5)
else
print("Pushing to cart below "..tostring(pos))
hopper_push_to_mc(cart, pos, 5)
end
timer = timer + 1 timer = timer + 1
else else
timer = timer - dtime timer = timer - dtime
@ -476,7 +539,23 @@ local def_hopper_side = {
on_rotate = on_rotate, on_rotate = on_rotate,
sounds = mcl_sounds.node_sound_metal_defaults(), sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_minecarts_on_enter_below = function(pos, cart, next_dir)
print("Cart entered above "..tostring(pos)..",cart="..tostring(cart))
-- Only push to containers
if cart and cart.groups and (cart.groups.container or 0) ~= 0 then
print("Pulling from cart above "..tostring(pos))
cart:add_node_watch(pos)
hopper_pull_from_mc(cart, pos, 5)
end
end,
_mcl_minecarts_on_leave_below = function(pos, cart, next_dir)
if not cart then return end
cart:remove_node_watch(pos)
end,
_mcl_minecarts_on_enter_side = function(pos, cart, next_dir, rail_pos) _mcl_minecarts_on_enter_side = function(pos, cart, next_dir, rail_pos)
if not cart then return end
-- Only try to push to minecarts when the spout position is pointed at the rail -- Only try to push to minecarts when the spout position is pointed at the rail
local face = minetest.get_node(pos).param2 local face = minetest.get_node(pos).param2
local dst_pos = {} local dst_pos = {}
@ -497,20 +576,37 @@ local def_hopper_side = {
end end
end, end,
_mcl_minecarts_on_leave_side = function(pos, cart, next_dir) _mcl_minecarts_on_leave_side = function(pos, cart, next_dir)
if not cart then return end
cart:remove_node_watch(pos) cart:remove_node_watch(pos)
end, end,
_mcl_minecarts_node_on_step = function(pos, cart, dtime) _mcl_minecarts_node_on_step = function(pos, cart, dtime, cartdata)
local meta = minetest.get_meta(pos) if not cart then return end
local tick = false
local meta = minetest.get_meta(pos)
local timer = meta:get_int("minecart_hopper_timer") local timer = meta:get_int("minecart_hopper_timer")
print("dtime="..dtime..",timer="..timer)
if timer < dtime then if timer < dtime then
hopper_push_to_mc(cart, pos, 5) tick = true
timer = timer + 1 timer = timer + 1
else else
timer = timer - dtime timer = timer - dtime
end end
meta:set_int("minecart_hopper_timer", timer) meta:set_int("minecart_hopper_timer", timer)
if tick then
local cart_pos = mcl_minecarts.get_cart_position(cartdata)
if not cart_pos then return false end
print("uuid="..cartdata.uuid)
if cart_pos.y == pos.y then
hopper_push_to_mc(cart, pos, 5)
elseif cart_pos.y > pos.y then
hopper_pull_from_mc(cart, pos, 5)
end
end
return true return true
end, end,
@ -546,48 +642,6 @@ minetest.register_node("mcl_hoppers:hopper_side_disabled", def_hopper_side_disab
--[[ END OF NODE DEFINITIONS ]] --[[ END OF NODE DEFINITIONS ]]
local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size)
local inv = mcl_entity_invs.load_inv(mc_ent, inv_size)
if not inv then
mcl_log("No inv")
return false
end
local dest_meta = minetest.get_meta(dest_pos)
local dest_inv = dest_meta:get_inventory()
if not dest_inv then
mcl_log("No dest inv")
return false
end
mcl_log("inv. size: " .. mc_ent._inv_size)
for i = 1, mc_ent._inv_size, 1 do
local stack = inv:get_stack("main", i)
mcl_log("i: " .. tostring(i))
mcl_log("Name: [" .. tostring(stack:get_name()) .. "]")
mcl_log("Count: " .. tostring(stack:get_count()))
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
if not stack:get_name() or stack:get_name() ~= "" then
if dest_inv:room_for_item("main", stack:peek_item()) then
mcl_log("Room so unload")
dest_inv:add_item("main", stack:take_item())
inv:set_stack("main", i, stack)
-- Take one item and stop until next time, report that we took something
return true
else
mcl_log("no Room")
end
else
mcl_log("nothing there")
end
end
end
mcl_hoppers.pull_from_minecart = hopper_pull_from_mc
--[[ BEGIN OF ABM DEFINITONS ]] --[[ BEGIN OF ABM DEFINITONS ]]
minetest.register_abm({ minetest.register_abm({