Merge pull request 'Who doesn't love hopper minecarts?' (#2941) from feature/hopper_minecarts into master

Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/2941
Reviewed-by: cora <cora@noreply.git.minetest.land>
This commit is contained in:
cora 2022-11-14 03:25:47 +00:00
commit b7f766e7cc
6 changed files with 291 additions and 35 deletions

View File

@ -2,6 +2,10 @@ mcl_entity_invs = {}
local open_invs = {} local open_invs = {}
local function mcl_log (message)
mcl_util.mcl_log (message, "[Entity Invs]")
end
local function check_distance(inv,player,count) local function check_distance(inv,player,count)
for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do for _,o in pairs(minetest.get_objects_inside_radius(player:get_pos(),5)) do
local l = o:get_luaentity() local l = o:get_luaentity()
@ -22,20 +26,25 @@ local inv_callbacks = {
end, end,
} }
local function load_inv(ent,size) function mcl_entity_invs.load_inv(ent,size)
mcl_log("load_inv")
if not ent._inv_id then return end if not ent._inv_id then return end
mcl_log("load_inv 2")
local inv = minetest.get_inventory({type="detached", name=ent._inv_id}) local inv = minetest.get_inventory({type="detached", name=ent._inv_id})
if not inv then if not inv then
mcl_log("load_inv 3")
inv = minetest.create_detached_inventory(ent._inv_id, inv_callbacks) inv = minetest.create_detached_inventory(ent._inv_id, inv_callbacks)
inv:set_size("main", size) inv:set_size("main", size)
if ent._items then if ent._items then
inv:set_list("main",ent._items) inv:set_list("main",ent._items)
end end
else
mcl_log("load_inv 4")
end end
return inv return inv
end end
local function save_inv(ent) function mcl_entity_invs.save_inv(ent)
if ent._inv then if ent._inv then
ent._items = {} ent._items = {}
for i,it in ipairs(ent._inv:get_list("main")) do for i,it in ipairs(ent._inv:get_list("main")) do
@ -46,32 +55,60 @@ local function save_inv(ent)
end end
end end
local function load_default_formspec (ent, text)
text = text or ""
local invent_size = ent._inv_size
local div_by_two = invent_size % 2 == 0
local div_by_three = invent_size % 3 == 0
--mcl_log("Div by 3: ".. tostring(div_by_three))
--mcl_log("Div by 2: ".. tostring(div_by_two))
--mcl_log("invent_size: ".. tostring(invent_size))
local rows = 3
if invent_size > 18 or (div_by_three == true and invent_size > 8) then
--mcl_log("Div by 3")
rows = 3
elseif (div_by_two == true and invent_size > 3) or invent_size > 9 then
--mcl_log("Div by 2")
rows = 2
else
--mcl_log("Not div by 2 or 3")
rows = 1
end
--local rows = 3
local cols = (math.ceil(ent._inv_size/rows))
local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape(
minetest.colorize("#313131", ent._inv_title .. " ".. text)) .. "]"
.. "list[detached:"..ent._inv_id..";main;"..spacing..",0.5;"..cols..","..rows..";]"
.. mcl_formspec.get_itemslot_bg(spacing,0.5,cols,rows)
.. "label[0,4.0;" .. minetest.formspec_escape(
minetest.colorize("#313131", "Inventory")) .. "]"
.. "list[current_player;main;0,4.5;9,3;9]"
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
.. "list[current_player;main;0,7.74;9,1;]"
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
.. "listring[detached:"..ent._inv_id..";main]"
.. "listring[current_player;main]"
return formspec
end
function mcl_entity_invs.show_inv_form(ent,player,text) function mcl_entity_invs.show_inv_form(ent,player,text)
if not ent._inv_id then return end if not ent._inv_id then return end
if not open_invs[ent] then if not open_invs[ent] then
open_invs[ent] = 0 open_invs[ent] = 0
end end
text = text or "" ent._inv = mcl_entity_invs.load_inv(ent,ent._inv_size)
ent._inv = load_inv(ent,ent._inv_size)
open_invs[ent] = open_invs[ent] + 1 open_invs[ent] = open_invs[ent] + 1
local playername = player:get_player_name() local playername = player:get_player_name()
local rows = 3
local cols = (math.ceil(ent._inv_size/rows)) minetest.show_formspec(playername, ent._inv_id, load_default_formspec (ent, text))
local spacing = (9 - cols) / 2
local formspec = "size[9,8.75]"
.. "label[0,0;" .. minetest.formspec_escape(
minetest.colorize("#313131", ent._inv_title .. " ".. text)) .. "]"
.. "list[detached:"..ent._inv_id..";main;"..spacing..",0.5;"..cols..","..rows..";]"
.. mcl_formspec.get_itemslot_bg(spacing,0.5,cols,rows)
.. "label[0,4.0;" .. minetest.formspec_escape(
minetest.colorize("#313131", "Inventory")) .. "]"
.. "list[current_player;main;0,4.5;9,3;9]"
.. mcl_formspec.get_itemslot_bg(0,4.5,9,3)
.. "list[current_player;main;0,7.74;9,1;]"
.. mcl_formspec.get_itemslot_bg(0,7.74,9,1)
.. "listring[detached:"..ent._inv_id..";main]"
.. "listring[current_player;main]"
minetest.show_formspec(playername,ent._inv_id,formspec)
end end
local function drop_inv(ent) local function drop_inv(ent)
@ -85,9 +122,9 @@ local function drop_inv(ent)
end end
local function on_remove(self,killer,oldf) local function on_remove(self,killer,oldf)
save_inv(self) mcl_entity_invs.save_inv(self)
drop_inv(self) drop_inv(self)
if oldf then return oldf(self,killer) end if oldf then return oldf(self,killer) end
end end
minetest.register_on_player_receive_fields(function(player, formname, fields) minetest.register_on_player_receive_fields(function(player, formname, fields)
@ -95,7 +132,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == k._inv_id then if formname == k._inv_id then
open_invs[k] = open_invs[k] - 1 open_invs[k] = open_invs[k] - 1
if open_invs[k] < 1 then if open_invs[k] < 1 then
save_inv(k) mcl_entity_invs.save_inv(k)
open_invs[k] = nil open_invs[k] = nil
end end
end end
@ -151,7 +188,7 @@ function mcl_entity_invs.register_inv(entity_name,show_name,size,no_on_righclick
local old_ode = minetest.registered_entities[entity_name].on_deactivate local old_ode = minetest.registered_entities[entity_name].on_deactivate
minetest.registered_entities[entity_name].on_deactivate = function(self,removal) minetest.registered_entities[entity_name].on_deactivate = function(self,removal)
save_inv(self) mcl_entity_invs.save_inv(self)
if removal then if removal then
on_remove(self) on_remove(self)
end end

View File

@ -25,4 +25,10 @@ http://minetest.net/
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO. 0. You just DO WHAT THE FUCK YOU WANT TO.
---------
Alterations and contributions are released under GNU GPLv3 after 11/11/2022 and for contributors:
AncientMariner/ancientmarinerdev

View File

@ -6,6 +6,16 @@ local pool = {}
local tick = false local tick = false
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_item_entities",false)
local function mcl_log (message)
if LOGGING_ON then
mcl_util.mcl_log (message, "[Item Entities]", true)
end
end
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local name local name
name = player:get_player_name() name = player:get_player_name()
@ -375,6 +385,116 @@ local function cxcz(o, cw, one, zero)
return o return o
end end
local function hopper_take_item (self, pos)
--mcl_log("self.itemstring: ".. self.itemstring)
--mcl_log("self.itemstring: ".. minetest.pos_to_string(pos))
local objs = minetest.get_objects_inside_radius(pos, 2)
if objs and self.itemstring then
--mcl_log("there is an itemstring. Number of objs: ".. #objs)
for k,v in pairs(objs) do
local ent = v:get_luaentity()
-- Don't forget actual hoppers
if ent and ent.name == "mcl_minecarts:hopper_minecart" then
local taken_items = false
mcl_log("ent.name: ".. tostring(ent.name))
mcl_log("ent pos: ".. tostring(ent.object:get_pos()))
local inv = mcl_entity_invs.load_inv(ent,5)
if not inv then
mcl_log("No inv")
return false
end
local current_itemstack = ItemStack(self.itemstring)
mcl_log("inv. size: " .. ent._inv_size)
if inv:room_for_item("main", current_itemstack) then
mcl_log("Room")
inv:add_item("main", current_itemstack)
self.object:get_luaentity().itemstring = ""
self.object:remove()
taken_items = true
else
mcl_log("no Room")
end
if not taken_items then
local items_remaining = current_itemstack:get_count()
-- This will take part of a floating item stack if no slot can hold the full amount
for i = 1, ent._inv_size,1 do
local stack = inv:get_stack("main", i)
mcl_log("i: " .. tostring(i))
mcl_log("Items remaining: " .. items_remaining)
mcl_log("Name: " .. tostring(stack:get_name()))
if current_itemstack:get_name() == stack:get_name() then
mcl_log("We have a match. Name: " .. tostring(stack:get_name()))
local room_for = stack:get_stack_max() - stack:get_count()
mcl_log("Room for: " .. tostring(room_for))
if room_for == 0 then
-- Do nothing
mcl_log("No room")
elseif room_for < items_remaining then
mcl_log("We have more items remaining than space")
items_remaining = items_remaining - room_for
stack:set_count(stack:get_stack_max())
inv:set_stack("main", i, stack)
taken_items = true
else
local new_stack_size = stack:get_count() + items_remaining
stack:set_count(new_stack_size)
mcl_log("We have more than enough space. Now holds: " .. new_stack_size)
inv:set_stack("main", i, stack)
items_remaining = 0
self.object:get_luaentity().itemstring = ""
self.object:remove()
taken_items = true
break
end
mcl_log("Count: " .. tostring(stack:get_count()))
mcl_log("stack max: " .. tostring(stack:get_stack_max()))
--mcl_log("Is it empty: " .. stack:to_string())
end
if i == ent._inv_size and taken_items then
mcl_log("We are on last item and still have items left. Set final stack size: " .. items_remaining)
current_itemstack:set_count(items_remaining)
--mcl_log("Itemstack2: " .. current_itemstack:to_string())
self.itemstring = current_itemstack:to_string()
end
end
end
--Add in, and delete
if taken_items then
mcl_log("Saving")
mcl_entity_invs.save_inv(ent)
return taken_items
else
mcl_log("No need to save")
end
end
end
end
return false
end
minetest.register_entity(":__builtin:item", { minetest.register_entity(":__builtin:item", {
initial_properties = { initial_properties = {
hp_max = 1, hp_max = 1,
@ -648,6 +768,12 @@ minetest.register_entity(":__builtin:item", {
end end
local p = self.object:get_pos() local p = self.object:get_pos()
-- If hopper has taken item, it has gone, and no operations should be conducted on this item
if hopper_take_item(self, p) then
return
end
local node = minetest.get_node_or_nil(p) local node = minetest.get_node_or_nil(p)
local in_unloaded = (node == nil) local in_unloaded = (node == nil)

View File

@ -770,8 +770,9 @@ register_minecart(
}, },
"mcl_minecarts_minecart_hopper.png", "mcl_minecarts_minecart_hopper.png",
{"mcl_minecarts:minecart", "mcl_hoppers:hopper"}, {"mcl_minecarts:minecart", "mcl_hoppers:hopper"},
nil, nil, false nil, nil, true
) )
mcl_entity_invs.register_inv("mcl_minecarts:hopper_minecart", "Hopper Minecart", 5, false, true)
-- Minecart with TNT -- Minecart with TNT
register_minecart( register_minecart(
@ -839,16 +840,14 @@ minetest.register_craft({
}, },
}) })
-- TODO: Re-enable crafting of special minecarts when they have been implemented minetest.register_craft({
--[[minetest.register_craft({
output = "mcl_minecarts:hopper_minecart", output = "mcl_minecarts:hopper_minecart",
recipe = { recipe = {
{"mcl_hoppers:hopper"}, {"mcl_hoppers:hopper"},
{"mcl_minecarts:minecart"}, {"mcl_minecarts:minecart"},
}, },
}) })
--]]
minetest.register_craft({ minetest.register_craft({
output = "mcl_minecarts:chest_minecart", output = "mcl_minecarts:chest_minecart",
@ -863,5 +862,4 @@ if has_mcl_wip then
mcl_wip.register_wip_item("mcl_minecarts:chest_minecart") mcl_wip.register_wip_item("mcl_minecarts:chest_minecart")
mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart") mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart")
mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart") mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart")
mcl_wip.register_wip_item("mcl_minecarts:hopper_minecart")
end end

View File

@ -311,9 +311,9 @@ function mcl_beds.get_bed_top (pos)
local bed_top = minetest.get_node(bed_top_pos) local bed_top = minetest.get_node(bed_top_pos)
if bed_top then if bed_top then
mcl_log("Has a bed top") --mcl_log("Has a bed top")
else else
mcl_log("No bed top") --mcl_log("No bed top")
end end
return bed_top_pos return bed_top_pos
end end

View File

@ -1,5 +1,12 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local LOGGING_ON = minetest.settings:get_bool("mcl_logging_hoppers",false)
local function mcl_log (message)
if LOGGING_ON then
mcl_util.mcl_log (message, "[Hoppers]", true)
end
end
--[[ BEGIN OF NODE DEFINITIONS ]] --[[ BEGIN OF NODE DEFINITIONS ]]
local mcl_hoppers_formspec = local mcl_hoppers_formspec =
@ -331,8 +338,90 @@ minetest.register_node("mcl_hoppers:hopper_side_disabled", def_hopper_side_disab
--[[ END OF NODE DEFINITIONS ]] --[[ END OF NODE DEFINITIONS ]]
local function hopper_pull_from_mc (mc_ent, dest_pos)
local inv = mcl_entity_invs.load_inv(mc_ent,5)
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
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 ]] --[[ BEGIN OF ABM DEFINITONS ]]
minetest.register_abm({
label = "Hoppers pull from minecart hoppers",
nodenames = {"mcl_hoppers:hopper","mcl_hoppers:hopper_side"},
interval = 0.5,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
mcl_log("ABM for: " .. minetest.pos_to_string(pos))
local objs = minetest.get_objects_inside_radius(pos, 3)
if objs and #objs > 0 then
for k,v in pairs(objs) do
local entity = v:get_luaentity()
if entity and entity.name then
--mcl_log("Name of object near: " .. tostring(entity.name))
if entity.name == "mcl_minecarts:hopper_minecart" then
local hm_pos = entity.object:get_pos()
mcl_log("We have a hopper minecart close: ".. minetest.pos_to_string(hm_pos))
--if hm_pos.y == pos.y + 1 then mcl_log("y is correct") end
--if (hm_pos.x >= pos.x - DIST_FROM_MC and hm_pos.x <= pos.x + DIST_FROM_MC) then mcl_log("x is within range") end
--if (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then mcl_log("z is within range") end
local DIST_FROM_MC = 1.5
if (hm_pos.y == pos.y + 1)
and (hm_pos.x >= pos.x - DIST_FROM_MC and hm_pos.x <= pos.x + DIST_FROM_MC)
and (hm_pos.z >= pos.z - DIST_FROM_MC and hm_pos.z <= pos.z + DIST_FROM_MC) then
mcl_log("Minecart close enough")
hopper_pull_from_mc (entity, pos)
end
end
else
mcl_log("no entity")
end
end
else
mcl_log("objs missing")
end
end,
})
-- Make hoppers suck in dropped items -- Make hoppers suck in dropped items
minetest.register_abm({ minetest.register_abm({
label = "Hoppers suck in dropped items", label = "Hoppers suck in dropped items",