151 lines
5.3 KiB
Lua
151 lines
5.3 KiB
Lua
local ui = unified_inventory
|
|
local uip = unified_inventory_plus
|
|
local has = uip.has
|
|
local settings = uip.settings
|
|
local S = uip.S
|
|
local F = minetest.formspec_escape
|
|
|
|
-- Backup to inject code
|
|
uip.craft_all = ui.pages["craft"].get_formspec
|
|
|
|
ui.pages["craft"] = {
|
|
get_formspec = function(player, perplayer_formspec)
|
|
local formspec = uip.craft_all(player, perplayer_formspec).formspec
|
|
formspec = formspec ..
|
|
("image[%f,%f;%f,%f;ui_crafting_long_arrow.png]"):format(
|
|
perplayer_formspec.craft_arrow_x,
|
|
perplayer_formspec.craft_y,
|
|
ui.imgscale,
|
|
ui.imgscale * 3) ..
|
|
("button[%f,%f;%f,%f;craft_craftall;%s]"):format(
|
|
perplayer_formspec.craft_arrow_x + 0.23,
|
|
perplayer_formspec.craft_y + 1.50,
|
|
perplayer_formspec.btn_size,
|
|
perplayer_formspec.btn_size,
|
|
F(S("All"))
|
|
)
|
|
return { formspec = formspec }
|
|
end,
|
|
}
|
|
|
|
-- make sure the width is right
|
|
local function infer_width(list, expected)
|
|
if not expected or expected:is_empty() then
|
|
return
|
|
end
|
|
local width
|
|
for i = 1, 3 do
|
|
local output, _ = minetest.get_craft_result({ method = "normal", width = i, items = list })
|
|
if output.item:to_string() == expected:to_string() then
|
|
width = i
|
|
break
|
|
end
|
|
end
|
|
if not width then
|
|
uip.log("warning", "Can't infer recipe width for %s", expected:to_string())
|
|
end
|
|
return width
|
|
end
|
|
|
|
-- Craft max possible items and put the result in the main inventory
|
|
local function craft_craftall(player)
|
|
local player_name = player:get_player_name()
|
|
local player_inv = player:get_inventory()
|
|
local craft_list = player_inv:get_list("craft")
|
|
local expected_result = player_inv:get_stack("craftpreview", 1)
|
|
local craft_width = infer_width(craft_list, expected_result)
|
|
if not craft_width then
|
|
return
|
|
end
|
|
|
|
local num_crafted = 0
|
|
-- don't modify player's inventory until we're done, in case something goes wrong (e.g. crash)
|
|
-- use a fake inventory instead of a detached inventory, because detached inventory actions all result in packets
|
|
-- sent to the player.
|
|
local tmp_inv = fakelib.create_inventory()
|
|
tmp_inv:set_list("main", player_inv:get_list("main"))
|
|
tmp_inv:set_list("craft", craft_list)
|
|
|
|
while true do
|
|
if (
|
|
has.stamina and
|
|
stamina.get_saturation and
|
|
stamina.get_saturation(player) <= settings.craft_all_min_saturation
|
|
) then
|
|
minetest.chat_send_player(player_name, S("You are too hungry to use Craft All at this time."))
|
|
break
|
|
end
|
|
|
|
-- note that get_craft_result can be *very* slow, until minetest 5.7.0 is released.
|
|
-- see https://github.com/minetest/minetest/issues/13231
|
|
local output, decremented_input = minetest.get_craft_result({
|
|
method = "normal",
|
|
width = craft_width,
|
|
items = craft_list,
|
|
})
|
|
|
|
if output.item:get_name() ~= expected_result:get_name() then
|
|
-- the recipe changed, so we've run out of something. stop processing.
|
|
break
|
|
end
|
|
|
|
-- minetest.on_craft expects to see the decremented input list.
|
|
tmp_inv:set_list("craft", decremented_input.items)
|
|
|
|
-- invoke callbacks, for compatibility w/ stamina, skyblock, moretrees, etc.
|
|
-- note that this is an *undocumented* handler of the minetest lua API, and possibly is subject to change
|
|
-- in the future.
|
|
output.item = minetest.on_craft(output.item, player, craft_list, tmp_inv)
|
|
|
|
-- track items added to the inventory, in case we need to remove them later
|
|
local added = {}
|
|
|
|
if tmp_inv:room_for_item("main", output.item) then
|
|
tmp_inv:add_item("main", output.item) -- should be no remainder, ignore it
|
|
table.insert(added, output.item)
|
|
else
|
|
-- no room for the output item, stop
|
|
break
|
|
end
|
|
|
|
-- we now try to add all replacements.
|
|
local all_added = true
|
|
for _, replacement_stk in ipairs(output.replacements) do
|
|
if tmp_inv:room_for_item("main", replacement_stk) then
|
|
tmp_inv:add_item("main", replacement_stk) -- should be no remainder, ignore it
|
|
table.insert(added, replacement_stk)
|
|
else
|
|
all_added = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if not all_added then
|
|
-- if we failed to add all the replacements, remove what we've added, and abort
|
|
for _, stk in ipairs(added) do
|
|
tmp_inv:remove_item("main", stk) -- should be no remainder, ignore it
|
|
end
|
|
break
|
|
end
|
|
|
|
-- the craft list can be modified by the callbacks, so re-load it
|
|
craft_list = tmp_inv:get_list("craft")
|
|
|
|
num_crafted = num_crafted + 1
|
|
end
|
|
|
|
player_inv:set_list("craft", craft_list)
|
|
player_inv:set_list("main", tmp_inv:get_list("main"))
|
|
|
|
uip.log("action", "player %s crafts %s %i", player_name, expected_result:to_string(), num_crafted)
|
|
end
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
for k, _ in pairs(fields) do
|
|
if k:match("craft_craftall") then
|
|
craft_craftall(player)
|
|
return
|
|
end
|
|
end
|
|
end)
|