From 6c6bfcfcb2b2a187524e863ad83f103df8f56c3d Mon Sep 17 00:00:00 2001 From: teknomunk Date: Sat, 16 Mar 2024 09:17:09 +0000 Subject: [PATCH] Refactor enter/leave hook processing, add node watches for implementing hopper-to-minecart functionality (should properly handle heavy server lag without missing any time), temporarily disable hopper push/pull to minecart in mcl_hoppers, prepare to move minecart-specific on_step behavior out of main on_step function and to a minecart-specific handler --- mods/ENTITIES/mcl_minecarts/functions.lua | 2 +- mods/ENTITIES/mcl_minecarts/init.lua | 149 ++++++++++++++-------- mods/ITEMS/mcl_hoppers/init.lua | 5 +- 3 files changed, 103 insertions(+), 53 deletions(-) diff --git a/mods/ENTITIES/mcl_minecarts/functions.lua b/mods/ENTITIES/mcl_minecarts/functions.lua index 48392cbee..3aff98b81 100644 --- a/mods/ENTITIES/mcl_minecarts/functions.lua +++ b/mods/ENTITIES/mcl_minecarts/functions.lua @@ -68,7 +68,7 @@ end --[[ - An array of (u,v,w) positions to check. Actual direction is u * dir + v * right + w * vector.new(0,1,0) + An array of (u,v,w) positions to check. Actual direction is u * dir + v * right + w * up ]] local rail_checks = { { 1, 0, 0 }, -- forwards diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 22b3f49f0..48ca22215 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -21,59 +21,79 @@ local function mcl_log(message) end end -local function handle_cart_enter(self, pos, next_dir) - local staticdata = self._staticdata - local node = minetest.get_node(pos) +mcl_minecarts.on_enter_below = function(pos, cart, next_dir, node_def) + local staticdata = cart._staticdata + if (node_def.groups.hopper or 0) == 0 then return end - -- Handle track behaviors - local node_def = minetest.registered_nodes[node.name] - if node_def._mcl_minecarts_on_enter then - node_def._mcl_minecarts_on_enter(pos, self) - end + local hopper_pulled = mcl_hoppers.pull_from_minecart( cart, pos, cart._inv_size or 0 ) + if DEBUG then print( "Attempt pull_from_minecart, hopper_pulled="..tostring(hopper_pulled) ) end - -- check for hopper under the rail - local under_pos = pos - vector.new(0,1,0) - local under_node_name = minetest.get_node(under_pos).name - local under_node_def = minetest.registered_nodes[under_node_name] - if under_node_def._mcl_minecarts_on_enter_above then - under_node_def._mcl_minecarts_on_enter_above(under_pos, self) - else - local hopper_pulled = false - if DEBUG then print( "under_node_name="..under_node_name..", hopper="..tostring(under_node_def.groups.hopper)) end - if under_node_def and under_node_def.groups.hopper ~= 0 then - hopper_pulled = mcl_hoppers.pull_from_minecart( self, under_pos, self._inv_size or 0 ) - if DEBUG then print( "Attempt pull_from_minecart, hopper_pulled="..tostring(hopper_pulled) ) end - - if hopper_pulled and next_dir ~= staticdata.dir then - -- If there was an item pulled by a hopper under the rails force the cart to stay put for 1.5 seconds - -- to allow redstone time to process - if hopper_pulled then - staticdata.delay = 1.5 - end - end + if hopper_pulled and next_dir ~= staticdata.dir then + -- If there was an item pulled by a hopper under the rails force the cart to stay put for 1.5 seconds + -- to allow redstone time to process + if hopper_pulled then + staticdata.delay = 1.5 end end - - -- Handle above-track behaviors (to ensure hoppers can transfer at least one item) - local above_pos = pos + vector.new(0,1,0) - local above_node_name = minetest.get_node(above_pos).name - local above_node_def = minetest.registered_nodes[above_node_name] - if above_node_def._mcl_minecarts_on_enter_below then - above_node_def._mcl_minecarts_on_enter_below(above_pos, self) - end - - -- Handle cart-specific behaviors - if self._mcl_minecarts_on_enter then - self._mcl_minecarts_on_enter(self, pos) - end end -local function handle_cart_leave(pos) - local node_name = minetest.get_node(pos).name - local node_def = minetest.registered_nodes[node_name] - if node_def._mcl_minecarts_on_leave then - node_def._mcl_minecarts_on_leave(pos, self) +--[[ + Array of hooks { {u,v,w}, name } + Actual position is pos + u * dir + v * right + w * up +]] +local enter_exit_checks = { + { 0, 0, 0, "" }, + { 0, 0, 1, "_above" }, + { 0, 0,-1, "_below" }, + { 0, 1, 0, "_side" }, + { 0,-1, 0, "_side" }, +} + +local function handle_cart_enter_exit(self, pos, next_dir, event) + local staticdata = self._staticdata + + 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 + 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] + + -- node-specific hook + local hook = node_def["_mcl_minecarts_"..event..check[4]] + if hook then hook(check_pos, self, next_dir) end + + -- global minecart hook + hook = mcl_minecarts[event..check[4]] + if hook then hook(check_pos, self, next_dir, node_def) end end + + -- Handle cart-specific behaviors + local hook = self["_mcl_minecarts_"..event] + if hook then hook(self, pos) end +end +local function handle_cart_enter(self, pos, next_dir) + handle_cart_enter_exit(self, pos, next_dir, "on_enter" ) +end +local function handle_cart_leave(self, pos, next_dir) + handle_cart_enter_exit(self, pos, next_dir, "on_leave" ) +end + +local function handle_cart_node_watches(self, dtime) + local staticdata = self._staticdata + local watches = staticdata.node_watches or {} + local new_watches = {} + for _,node_pos in ipairs(watches) do + local node = minetest.get_node(node_pos) + local node_def = minetest.registered_nodes[node.name] + local hook = node_def._mcl_minecarts_node_on_step + if hook and hook(node_pos, self, dtime) then + new_watches[#new_watches] = node_pos + end + end + + staticdata.node_watches = new_watches end local function update_cart_orientation(self,staticdata) @@ -276,10 +296,8 @@ local function do_movement_step(self, dtime) if x_1 >= 0.99 then staticdata.distance = 0 - -- Leave the old node - handle_cart_leave(pos) - -- Anchor at the next node + local old_pos = pos pos = pos + staticdata.dir staticdata.connected_at = pos @@ -289,6 +307,9 @@ local function do_movement_step(self, dtime) print( "Changing direction from "..tostring(staticdata.dir).." to "..tostring(next_dir)) end + -- Leave the old node + handle_cart_leave(self, old_pos, next_dir ) + -- Enter the new node handle_cart_enter(self, pos, next_dir) @@ -362,7 +383,12 @@ local function do_movement( self, dtime ) -- it impossible to jump across gaps due to server lag -- causing large timesteps while dtime > 0 do - dtime = do_movement_step(self, dtime) + local new_dtime = do_movement_step(self, dtime) + + -- Handle node watches here in steps to prevent server lag from changing behavior + handle_cart_node_watches(self, dtime - new_dtime) + + dtime = new_dtime end -- Clear punched flag now that movement for this step has been completed @@ -581,6 +607,7 @@ local function register_entity(entity_id, def) on_activate_by_rail = def.on_activate_by_rail, _mcl_minecarts_on_enter = def._mcl_minecarts_on_enter, _mcl_minecarts_on_place = def._mcl_minecarts_on_place, + _mcl_minecarts_on_step = def._mcl_minecarts_on_step, _driver = nil, -- player who sits in and controls the minecart (only for minecart!) _passenger = nil, -- for mobs @@ -728,8 +755,20 @@ local function register_entity(entity_id, def) local passenger_attach_position = vector.new(0, -1.75, 0) + function cart:add_node_watch(pos) + local staticdata = self._staticdata + local watches = staticdata.watches + for _,watch in ipairs(watches) do + if watch == pos then return end + end + + watches[#watches+1] = pos + end + function cart:on_step(dtime) + -- TODO: move to _mcl_minecarts_on_step handler and on_enter handler for hopper minecart hopper_take_item(self, dtime) + local staticdata = self._staticdata -- Make sure all carts have an ID to isolate them @@ -787,6 +826,7 @@ local function register_entity(entity_id, def) end end + -- TODO: move to _mcl_minecarts_on_step handler for plain minecart -- Grab mob if math.random(1,20) > 15 and not self._passenger then if self.name == "mcl_minecarts:minecart" then @@ -811,6 +851,7 @@ local function register_entity(entity_id, def) end -- Drop minecart if it isn't on a rail anymore + --[[ Remove this entirely once off-cart minecart behavior is implemented if self._last_float_check == nil then self._last_float_check = 0 else @@ -837,7 +878,14 @@ local function register_entity(entity_id, def) end self._last_float_check = 0 end + ]] + local hook = cart._mcl_minecarts_on_step + if hook then hook(cart,dtime) end + + -- TODO: move the below into cart-specific hooks + + -- TODO: move to _mcl_minecarts_on_step handler for furnace minecart -- Update furnace stuff if self._fueltime and self._fueltime > 0 then self._fueltime = self._fueltime - dtime @@ -857,6 +905,7 @@ local function register_entity(entity_id, def) end local has_fuel = self._fueltime and self._fueltime > 0 + -- TODO: move to _mcl_minecarts_on_step handler for TNT minecart -- Update TNT stuff if self._boomtimer then -- Explode diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index 31a0bc49b..07971c42f 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -437,6 +437,7 @@ 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 @@ -558,7 +559,7 @@ minetest.register_abm({ and (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("Minecart close enough") if entity.name == "mcl_minecarts:hopper_minecart" then - hopper_pull_from_mc(entity, pos, 5) + --hopper_pull_from_mc(entity, pos, 5) elseif entity.name == "mcl_minecarts:chest_minecart" or entity.name == "mcl_boats:chest_boat" then hopper_pull_from_mc(entity, pos, 27) end @@ -567,7 +568,7 @@ minetest.register_abm({ and (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("Minecart close enough") if entity.name == "mcl_minecarts:hopper_minecart" then - hopper_push_to_mc(entity, pos, 5) + --hopper_push_to_mc(entity, pos, 5) elseif entity.name == "mcl_minecarts:chest_minecart" or entity.name == "mcl_boats:chest_boat" then hopper_push_to_mc(entity, pos, 27) end