From 122cb53e4412e119ade4b654eeaf14a3ddb3fc20 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Fri, 12 Apr 2024 12:28:24 +0000 Subject: [PATCH] Fix hopper-minecart interaction, convert ipairs(table) to use for i=1,#table instead --- mods/ENTITIES/mcl_minecarts/carts.lua | 51 ++++-- .../mcl_minecarts/carts/with_hopper.lua | 4 +- mods/ENTITIES/mcl_minecarts/functions.lua | 9 +- mods/ENTITIES/mcl_minecarts/movement.lua | 11 +- mods/ITEMS/mcl_hoppers/init.lua | 154 ++++++++++++------ 5 files changed, 158 insertions(+), 71 deletions(-) diff --git a/mods/ENTITIES/mcl_minecarts/carts.lua b/mods/ENTITIES/mcl_minecarts/carts.lua index 63dde3a53..26a95f826 100644 --- a/mods/ENTITIES/mcl_minecarts/carts.lua +++ b/mods/ENTITIES/mcl_minecarts/carts.lua @@ -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) diff --git a/mods/ENTITIES/mcl_minecarts/carts/with_hopper.lua b/mods/ENTITIES/mcl_minecarts/carts/with_hopper.lua index cb16b4cc6..ac86cfe7f 100644 --- a/mods/ENTITIES/mcl_minecarts/carts/with_hopper.lua +++ b/mods/ENTITIES/mcl_minecarts/carts/with_hopper.lua @@ -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) diff --git a/mods/ENTITIES/mcl_minecarts/functions.lua b/mods/ENTITIES/mcl_minecarts/functions.lua index c4694cc06..556af3dc5 100644 --- a/mods/ENTITIES/mcl_minecarts/functions.lua +++ b/mods/ENTITIES/mcl_minecarts/functions.lua @@ -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 diff --git a/mods/ENTITIES/mcl_minecarts/movement.lua b/mods/ENTITIES/mcl_minecarts/movement.lua index 198a2fede..f750a4ad0 100644 --- a/mods/ENTITIES/mcl_minecarts/movement.lua +++ b/mods/ENTITIES/mcl_minecarts/movement.lua @@ -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 diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index 0ba1ca9a6..73860cad1 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -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({