From b604cee9ff3122669c97fd9cc0740667fef4db63 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Sat, 23 Mar 2024 06:13:53 +0000 Subject: [PATCH] Add groups to minecart entities (for containers), fix cart node watch handling, relocate hopper_push_to_mc in mcl_hopper/init.lua, implement hopper-to-minecart push using enter/leave hooks for both straight and bent hoppers --- mods/ENTITIES/mcl_minecarts/init.lua | 36 +++++-- mods/ITEMS/mcl_hoppers/init.lua | 144 +++++++++++++++++++-------- 2 files changed, 129 insertions(+), 51 deletions(-) diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index bf51ba593..31a648c95 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -61,8 +61,9 @@ local function handle_cart_enter_exit(self, pos, next_dir, event) 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 + local hook_name = "_mcl_minecarts_"..event..check[4] + local hook = node_def[hook_name] + if hook then hook(check_pos, self, next_dir, pos) end -- global minecart hook hook = mcl_minecarts[event..check[4]] @@ -89,7 +90,7 @@ local function handle_cart_node_watches(self, dtime) 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 + new_watches[#new_watches+1] = node_pos end end @@ -141,7 +142,7 @@ end local function direction_away_from_players(self, staticdata) local objs = minetest.get_objects_inside_radius(self.object:get_pos(), 1.1) for n=1,#objs do - obj = objs[n] + local obj = objs[n] local player_name = obj:get_player_name() if player_name and player_name ~= "" and not ( self._driver and self._driver == player_name ) then local diff = obj:get_pos() - self.object:get_pos() @@ -314,7 +315,7 @@ local function do_movement_step(self, dtime) handle_cart_enter(self, pos, next_dir) -- Handle end of track - if next_dir == staticdata.dir * -1 and ( hopper_pulled or next_dir.y == 0 ) then + if next_dir == staticdata.dir * -1 and next_dir.y == 0 then if DEBUG then print("Stopping cart at end of track at "..tostring(pos)) end staticdata.velocity = 0 end @@ -593,6 +594,13 @@ end local function register_entity(entity_id, def) assert( def.drop, "drop is required parameter" ) + + -- Entity groups + local groups = { minecart = 1 } + for k,v in pairs(def.groups or {}) do + groups[k] = v + end + local cart = { initial_properties = { physical = true, @@ -603,8 +611,11 @@ local function register_entity(entity_id, def) textures = def.textures, }, + groups = groups, + on_rightclick = def.on_rightclick, 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, @@ -665,7 +676,7 @@ local function register_entity(entity_id, def) staticdata.connected_at = rounded_pos pos = rounded_pos else - print("TODO: handle detached cart behavior") + mineclone.log("warning","TODO: handle detached cart behavior") end end @@ -757,14 +768,19 @@ local function register_entity(entity_id, def) function cart:add_node_watch(pos) local staticdata = self._staticdata - local watches = staticdata.watches + local watches = staticdata.node_watches or {} + for _,watch in ipairs(watches) do if watch == pos then return end end watches[#watches+1] = pos + staticdata.node_watches = watches end function cart:remove_node_watch(pos) + local staticdata = self._staticdata + local watches = staticdata.node_watches or {} + local new_watches = {} for _,node_pos in ipairs(watches) do if node_pos ~= post then @@ -792,8 +808,6 @@ local function register_entity(entity_id, def) end local pos, rou_pos, node = self.object:get_pos() - --local update = {} - --local acceleration = 0 -- Controls local ctrl, player = nil, nil @@ -820,7 +834,7 @@ local function register_entity(entity_id, def) do_movement(self, dtime) - -- TODO: move this into do_movement_step + -- TODO: move this into mcl_core:cactus _mcl_minecarts_on_enter_side -- Drop minecart if it collides with a cactus node local r = 0.6 for _, node_pos in pairs({{r, 0}, {0, r}, {-r, 0}, {0, -r}}) do @@ -1156,6 +1170,7 @@ register_minecart({ }, icon = "mcl_minecarts_minecart_chest.png", drop = {"mcl_minecarts:minecart", "mcl_chests:chest"}, + groups = { container = 1 }, on_rightclick = nil, on_activate_by_rail = nil, creative = true @@ -1269,6 +1284,7 @@ register_minecart({ }, icon = "mcl_minecarts_minecart_hopper.png", drop = {"mcl_minecarts:minecart", "mcl_hoppers:hopper"}, + groups = { container = 1 }, on_rightclick = nil, on_activate_by_rail = nil, _mcl_minecarts_on_enter = function(self,pos) diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index a264c029b..113d3dbe2 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -34,6 +34,48 @@ local mcl_hoppers_formspec = table.concat({ "listring[current_player;main]", }) +local function hopper_push_to_mc(mc_ent, dest_pos, inv_size) + local dest_inv = mcl_entity_invs.load_inv(mc_ent, inv_size) + if not dest_inv then + mcl_log("No inv") + return false + end + + local meta = minetest.get_meta(dest_pos) + local inv = meta:get_inventory() + if not inv then + mcl_log("No dest inv") + return + 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 + return + else + mcl_log("no Room") + end + + else + mcl_log("nothing there") + end + end +end + + -- Downwards hopper (base definition) ---@type node_definition @@ -139,6 +181,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 + cart:add_node_watch(pos) + end + end, + _mcl_minecarts_on_leave_above = function(pos, cart, next_dir) + cart:remove_node_watch(pos) + end, + _mcl_minecarts_node_on_step = function(pos, cart, dtime) + local meta = minetest.get_meta(pos) + + local timer = meta:get_int("minecart_hopper_timer") + if timer < dtime then + hopper_push_to_mc(cart, pos, 5) + timer = timer + 1 + else + timer = timer - dtime + end + meta:set_int("minecart_hopper_timer", timer) + + return true + end, sounds = mcl_sounds.node_sound_metal_defaults(), _mcl_blast_resistance = 4.8, @@ -343,6 +408,44 @@ local def_hopper_side = { on_rotate = on_rotate, sounds = mcl_sounds.node_sound_metal_defaults(), + _mcl_minecarts_on_enter_side = function(pos, cart, next_dir, rail_pos) + -- 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 = {} + if face == 0 then + dst_pos = vector.offset(pos, -1, 0, 0) + elseif face == 1 then + dst_pos = vector.offset(pos, 0, 0, 1) + elseif face == 2 then + dst_pos = vector.offset(pos, 1, 0, 0) + elseif face == 3 then + dst_pos = vector.offset(pos, 0, 0, -1) + end + if dst_pos ~= rail_pos then return end + + -- Only push to containers + if cart.groups and (cart.groups.container or 0) ~= 0 then + cart:add_node_watch(pos) + end + end, + _mcl_minecarts_on_leave_side = function(pos, cart, next_dir) + cart:remove_node_watch(pos) + end, + _mcl_minecarts_node_on_step = function(pos, cart, dtime) + local meta = minetest.get_meta(pos) + + local timer = meta:get_int("minecart_hopper_timer") + if timer < dtime then + hopper_push_to_mc(cart, pos, 5) + timer = timer + 1 + else + timer = timer - dtime + end + meta:set_int("minecart_hopper_timer", timer) + + return true + end, + _mcl_blast_resistance = 4.8, _mcl_hardness = 3, } @@ -416,47 +519,6 @@ local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size) end mcl_hoppers.pull_from_minecart = hopper_pull_from_mc -local function hopper_push_to_mc(mc_ent, dest_pos, inv_size) - local dest_inv = mcl_entity_invs.load_inv(mc_ent, inv_size) - if not dest_inv then - mcl_log("No inv") - return false - end - - local meta = minetest.get_meta(dest_pos) - local inv = meta:get_inventory() - if not inv then - mcl_log("No dest inv") - return - 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 - return - else - mcl_log("no Room") - end - - else - mcl_log("nothing there") - end - end -end - --[[ BEGIN OF ABM DEFINITONS ]] minetest.register_abm({