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

This commit is contained in:
teknomunk 2024-03-23 06:13:53 +00:00
parent 232769e5fb
commit 9b0e387ffa
2 changed files with 129 additions and 51 deletions

View File

@ -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)

View File

@ -96,6 +96,48 @@ local function bent_hopper_act(pos, node, active_object_count, active_object_cou
mcl_util.hopper_pull(pos, src_pos)
end
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
@ -201,6 +243,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,
@ -406,6 +471,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,
}
@ -480,47 +583,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({