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

View File

@ -156,13 +156,13 @@ mod.register_minecart({
groups = { container = 1 },
on_rightclick = nil,
on_activate_by_rail = nil,
_mcl_minecarts_on_enter = function(self, pos)
local staticdata = self._staticdata
_mcl_minecarts_on_enter = function(self, pos, staticdata)
if (staticdata.hopper_delay or 0) > 0 then
return
end
-- try to pull from containers into our inventory
if not self then return end
local inv = mcl_entity_invs.load_inv(self,5)
local above_pos = pos + vector.new(0,1,0)
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 connections = 0
for i,dir in ipairs(CONNECTIONS) do
for i = 1,#CONNECTIONS do
dir = CONNECTIONS[i]
local neighbor = vector.add(pos, dir)
local node = minetest.get_node(neighbor)
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)
-- 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)
make_sloped_if_straight( vector.offset(neighbor, 0, -1, 0), dir )
end
@ -258,7 +260,8 @@ local function update_rail_connections(pos, opt)
local node_def = minetest.registered_nodes[node.name]
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 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

View File

@ -55,7 +55,9 @@ local function handle_cart_enter_exit(staticdata, pos, next_dir, event)
local dir = staticdata.dir
local right = vector.new( dir.z, dir.y, -dir.x)
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 node = minetest.get_node(check_pos)
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
if luaentity then
local hook = luaentity["_mcl_minecarts_"..event]
if hook then hook(self, pos) end
if hook then hook(luaentity, pos, staticdata) end
else
--minetest.log("warning", "TODO: change _mcl_minecarts_"..event.." calling so it is not dependent on the existence of a luaentity")
end
@ -99,12 +101,13 @@ local function handle_cart_node_watches(staticdata, dtime)
local watches = staticdata.node_watches or {}
local new_watches = {}
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_def = minetest.registered_nodes[node.name]
if node_def then
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
end
end

View File

@ -136,6 +136,47 @@ local function hopper_push_to_mc(mc_ent, dest_pos, inv_size)
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)
@ -243,16 +284,29 @@ local def_hopper = {
minetest.log("action", player:get_player_name() ..
" takes stuff from mcl_hoppers at " .. minetest.pos_to_string(pos))
end,
_mcl_minecarts_on_enter_above = function(pos, cart, next_dir)
-- Only push to containers
if cart.groups and (cart.groups.container or 0) ~= 0 then
_mcl_minecarts_on_enter_below = function(pos, cart, next_dir)
print("Cart entered above "..tostring(pos))
-- Only pull to containers
if cart and cart.groups and (cart.groups.container or 0) ~= 0 then
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,
_mcl_minecarts_on_leave_above = function(pos, cart, next_dir)
if not cart then return end
cart:remove_node_watch(pos)
end,
_mcl_minecarts_node_on_step = function(pos, cart, dtime)
_mcl_minecarts_node_on_step = function(pos, cart, dtime, cartdata)
if not cart then
minetest.log("warning", "trying to process hopper-to-minecart movement without luaentity")
return
@ -260,9 +314,18 @@ local def_hopper = {
local meta = minetest.get_meta(pos)
local cart_pos = mcl_minecarts.get_cart_position(cartdata)
local timer = meta:get_int("minecart_hopper_timer")
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
else
timer = timer - dtime
@ -476,7 +539,23 @@ local def_hopper_side = {
on_rotate = on_rotate,
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)
if not cart then return end
-- Only try to push to minecarts when the spout position is pointed at the rail
local face = minetest.get_node(pos).param2
local dst_pos = {}
@ -497,20 +576,37 @@ local def_hopper_side = {
end
end,
_mcl_minecarts_on_leave_side = function(pos, cart, next_dir)
if not cart then return end
cart:remove_node_watch(pos)
end,
_mcl_minecarts_node_on_step = function(pos, cart, dtime)
local meta = minetest.get_meta(pos)
_mcl_minecarts_node_on_step = function(pos, cart, dtime, cartdata)
if not cart then return end
local tick = false
local meta = minetest.get_meta(pos)
local timer = meta:get_int("minecart_hopper_timer")
print("dtime="..dtime..",timer="..timer)
if timer < dtime then
hopper_push_to_mc(cart, pos, 5)
tick = true
timer = timer + 1
else
timer = timer - dtime
end
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
end,
@ -546,48 +642,6 @@ minetest.register_node("mcl_hoppers:hopper_side_disabled", def_hopper_side_disab
--[[ 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 ]]
minetest.register_abm({