Minerchest mod added to modpack.

New mod is added in this commit and it contains one element:
minerchest. The idea behind this self-organizing storage node
is to eliminate burden of manual combination of ingots and other
items mined and produced in large quantities. Putting such items
in this chest will automatically compact them into blocks.

Version changed to 2.8.

Signed-off-by: Michal Cieslakiewicz <michal.cieslakiewicz@wp.pl>
This commit is contained in:
Michal Cieslakiewicz 2019-05-24 21:45:57 +02:00
parent be846a7bc4
commit 3a2e07f620
11 changed files with 578 additions and 3 deletions

View File

@ -1,10 +1,10 @@
# MicuPack v2.7
# MicuPack v2.8
**Minetest modpack by (real)micu.**
**Tested with following Minetest versions running Minetest Game:**
* **0.4.17.1 (*stable-0.4* branch) - all modpack versions up to v2.62**
* **5.0.0 (*stable-5* branch) - from modpack v2.62**
* **0.4.17.1 (*stable-0.4* branch) - all modpack versions up to v2.61**
* **5.0.0+ (*stable-5* branch) - from modpack v2.62**
### Installation:
@ -322,5 +322,49 @@ git clone https://github.com/realmicu/minetest-micupack.git micupack
- $get_status(...)
* **Miner Chest** (minerchest)
Miner Chest is a high capacity storage chest that automatically combines selected resources
into respective blocks. Chest is compatible with Techpack (Tubelib2 framework). It has
capacity of 60 items and supports stack pulling (can be paired with HighPerf Pusher).
It automatically combines following items in its inventory:
- all ingots types into respective blocks
- all sand units into respective sandstones
- coal lump -> coal block
- mese crystal -> mese block
- diamond crystal -> diamond block
- wheat -> straw
- clay lump -> clay block
More allowed item combinations can be registered via API function.
Chest supports only reversible combinations (example: metal blocks can be converted back to
ingots) of popular minerals and resources (hence name Miner's Chest). Some free space is
required to perform item reorganization as node may process only things that are already in
its inventory. To increase efficiency, chest automatically piles up items into stacks, trying
to free up as many slots as possible.
When used as a source for Tubelib network, chest prioritizes items it sends out into tubes -
so ingots and all other items that can be later combined into blocks are scheduled to be
sent last. This approach increases chance that incoming elements will be successfully combined
and passed further in compacted form.
Features:
- automatic crafting of configured items into blocks
- automatic stack merging
- Tubelib I/O compatibility
- support for Tubelib stack pulling (can be paired with HighPerf Pusher)
- item prioritization for Tubelib pulling (stackable items go last)
- no defects (not a machine)
- support for standard SaferLua storage status (empty/loaded/full)
- storage status - visual indicator and infotext
- infobar in inventory window
- no node timer (working only when inventory is updated)
Supported SaferLua functions:
- $get_status(...)
Future plans - see TODO file.

2
TODO
View File

@ -1,5 +1,7 @@
Future plans:
* add SaferLua command to query device and return its type and, optionally,
custom text field (helps to locate defects in complex machinery)
* introduce enhanced machine statictics including:
+ counters for items in and items out
+ biogas used counter

7
minerchest/depends.txt Normal file
View File

@ -0,0 +1,7 @@
default
farming
tubelib
tubelib_addons1
tubelib2
moreores?
basic_materials?

View File

@ -0,0 +1 @@
High capacity chest that can automatically combine certain materials into blocks.

517
minerchest/init.lua Normal file
View File

@ -0,0 +1,517 @@
--[[
========================================================================
Miner's Chest
by Micu (c) 2019
Copyright (C) 2019 Michal Cieslakiewicz
This is source file for Miner's Chest - a high capacity storage chest
that automatically combines selected resources into respective blocks.
Chest is compatible with Techpack (Tubelib2 framework). It has capacity
of 60 items and supports stack pulling (can be paired with HighPerf
Pusher).
It automatically combines following items into blocks:
* steel ingot -> steel block
* copper ingot -> copper block
* bronze ingot -> bronze block
* tin ingot -> tin block
* gold ingot -> gold block
* silver ingot (moreores mod) -> silver block
* mithril ingot (moreores mod) -> mithril block
* brass ingot (basic_materials mod) -> brass block
* coal lump -> coal block
* mese crystal -> mese block
* diamond crystal -> diamond block
* wheat -> straw
* sand -> sandstone
* desert sand -> desert sandstone
* silver sand -> silver sandstone
* clay lump -> clay block
More allowed item combinations can be registered via API function.
Chest supports only reversible combinations (example: metal blocks can
be converted back to ingots) of popular minerals and resources (hence
name Miner's Chest). Due to game internal design, chest requires some
spare slots to perform item reorganization as it may process only
things that are already in its inventory.
Features:
* automatic crafting of configured items into blocks
* automatic stack merging
* Tubelib I/O compatibility
* support for Tubelib stack pulling (can be paired with HighPerf Pusher)
* item prioritization for Tubelib pulling (stackable items go last)
* no defects (not a machine)
* support for standard SaferLua storage status (empty/loaded/full)
* storage status visual indicator and infotext
* infobar in inventory window
* no node timer
License: LGPLv2.1+
========================================================================
]]--
--[[
---------
Variables
---------
]]--
minerchest = {}
local INV_X = 12
local INV_Y = 5
local INV_SIZE = INV_X * INV_Y
--[[
----------------------
Public functions (API)
----------------------
]]--
local combdata = {}
-- Allow chest to combine items into respective blocks
-- source_item - source item name
-- block_item - destination block item name
-- Note: do not put any quantities here - function automatically
-- picks up recipe based on supplied parameters; it returns true
-- if completed successfully, false if error or already defined.
function minerchest.allow_item_combine(source_item, block_item)
if not source_item or not block_item then
return false
end
local source_stack = ItemStack(source_item)
local block_stack = ItemStack(block_item)
if not source_stack:is_known() or not block_stack:is_known() then
return false
end
local sn = source_stack:get_name()
local bn = block_stack:get_name()
if combdata[sn] then
return false
end
local fis = nil
local fib = nil
-- find recipe for block that uses source item only
local rt = minetest.get_all_craft_recipes(bn)
for _, r in ipairs(rt) do
if r.type == "normal" and r.method == "normal" then
local o = ItemStack(r.output)
if bn == o:get_name() then
local icnt = 0
local iok = true
for _, i in ipairs(r.items) do
local s = ItemStack(i)
if s:get_name() ~= sn then
iok = false
break
end
icnt = icnt + s:get_count()
end
if iok then
fis = sn .. " " .. icnt
fib = o:to_string()
break
end
end
end
end
if not fis or not fib then
return false
end
-- verify if recipe is reversible
local isrev = false
rt = minetest.get_all_craft_recipes(sn)
for _, r in ipairs(rt) do
if r.type == "normal" and r.method == "normal" then
local o = ItemStack(r.output)
if sn == o:get_name() then
local iok = true
for _, i in ipairs(r.items) do
local s = ItemStack(i)
if s:get_name() ~= bn then
iok = false
break
end
end
if iok then
isrev = true
break
end
end
end
end
if not isrev then
return false
end
combdata[sn] = { items = fis, output = fib }
return true
end
--[[
--------
Formspec
--------
]]--
-- get node/item/tool description for tooltip
local function formspec_tooltip(name)
local def = minetest.registered_nodes[name] or
minetest.registered_craftitems[name] or
minetest.registered_items[name] or
minetest.registered_tools[name] or nil
return def and def.description or ""
end
-- display info bar between chest and player repositories
local function formspec_item_bar(width, y)
local cblen = 0
for i, _ in pairs(combdata) do
cblen = cblen + 1
end
local arrowup = "tubelib_gui_arrow.png^[transformR90"
local mx = math.max((width - cblen * 0.5 - 1) / 2, 0)
local itembar = "image[" .. tostring(mx) .. "," ..
tostring(y + 0.25) .. ";0.5,0.5;" .. arrowup .. "]"
local x = mx + 0.5
for i, c in pairs(combdata) do
local b = ItemStack(c.output)
b = b:get_name()
itembar = itembar ..
"item_image[" .. tostring(x) .. "," .. tostring(y) .. ";0.5,0.5;" .. b .. "]" ..
"tooltip[" .. tostring(x) .. "," .. tostring(y) .. ";0.5,0.5;" .. formspec_tooltip(b) .. "]" ..
"item_image[" .. tostring(x) .. "," .. tostring(y + 0.5) .. ";0.5,0.5;" .. i .. "]" ..
"tooltip[" .. tostring(x) .. "," .. tostring(y + 0.5) .. ";0.5,0.5;" .. formspec_tooltip(i) .. "]"
x = x + 0.5
if x >= width - mx - 0.5 then
break
end
end
local itembar = itembar .. "image[" .. tostring(x) .. "," ..
tostring(y + 0.25) .. ";0.5,0.5;" .. arrowup .. "]"
return itembar
end
-- formspec (with autoformatting)
local function formspec()
local sizex = math.max(INV_X, 8)
local invby = math.max(INV_Y, 2)
local plrx = tostring((sizex - 8) / 2)
return "size[" .. tostring(sizex) .. "," ..
tostring(invby + 5.75) .. "]" ..
default.gui_bg ..
default.gui_bg_img ..
default.gui_slots ..
"list[context;main;" .. tostring((sizex - INV_X) / 2).. "," ..
tostring((invby - INV_Y) / 2) .. ";" ..
tostring(INV_X) .. "," ..
tostring(INV_Y) .. ";]" ..
formspec_item_bar(sizex, invby + 0.25) ..
"list[current_player;main;" .. plrx .. "," ..
tostring(invby + 1.5) .. "4;8,1;]" ..
"list[current_player;main;" .. plrx .. "," ..
tostring(invby + 2.75) .. ";8,3;8]" ..
"listring[context;main]" ..
"listring[current_player;main]" ..
default.get_hotbar_bg(plrx, invby + 1.5)
end
--[[
-------
Helpers
-------
]]--
-- swap chest node at pos to reflect current fill state
local function update_chest_node(pos)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
local state = tubelib.get_inv_state(meta, "main")
meta:set_string("infotext", "Miner Chest " .. number ..
" (" .. state .. ")")
local newname
if state == "full" then
newname = "minerchest:chest_full"
else
newname = "minerchest:chest"
end
if newname ~= node.name then
node.name = newname
minetest.swap_node(pos, node)
end
end
-- pile up all items to maximize free space
local function pile_up_items(inv, list)
local invsz = inv:get_size(list)
local itbl = {}
for i = 1, invsz do
local s = inv:get_stack(list, i)
if not s:is_empty() then
itbl[#itbl + 1] = s:to_string() -- otherwise you get reference!
s:clear()
inv:set_stack(list, i, s)
end
end
for i = 1, #itbl do
inv:add_item(list, itbl[i])
end
end
-- reorganize and combine items
local function combine_chest_items(pos)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("main") then
return
end
-- pile up before
pile_up_items(inv, "main")
-- combine items when applicable
for i, c in pairs(combdata) do
local is = ItemStack(c.items)
local bs = ItemStack(c.output)
local iscnt = is:get_count()
while true do
local taken = inv:remove_item("main", is)
if taken:is_empty() then
break
elseif taken:get_count() < iscnt or
not inv:room_for_item("main", bs) then
inv:add_item("main", taken) -- put back
break
end
inv:add_item("main", bs)
end
end
-- pile up after
pile_up_items(inv, "main")
end
-- tubelib takes items in a round-robin fashion - this function
-- modifies this method a little by skipping items that can be
-- combined into blocks - until only these remain
local function set_next_tubelib_item(meta, list)
local inv = meta:get_inventory()
if inv:is_empty(list) then
return
end
local invsz = inv:get_size(list)
local i = meta:get_int("tubelib_startpos") or 0
local c = 0
while c < invsz do
local ni = (i % invsz) + 1
local s = inv:get_stack(list, ni)
if not s:is_empty() and not combdata[s:get_name()] then
break
end
i = ni
c = c + 1
end
meta:set_int("tubelib_startpos", i)
end
--[[
---------
Callbacks
---------
]]--
-- do not allow to dig protected or non-empty chest
local function can_dig(pos, player)
if minetest.is_protected(pos, player:get_player_name()) then
return false
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("main")
end
-- cleanup after digging
local function after_dig_node(pos, oldnode, oldmetadata, digger)
tubelib.remove_node(pos)
end
-- init after placement
local function after_place_node(pos, placer, itemstack, pointed_thing)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("main", INV_SIZE)
meta:set_string("owner", placer:get_player_name())
local number = tubelib.add_node(pos, "minerchest:chest")
meta:set_string("number", number)
meta:set_string("formspec", formspec())
update_chest_node(pos)
end
-- common function for on_metadata_inventory_* callbacks
local function on_metadata_inventory_change(pos)
combine_chest_items(pos)
update_chest_node(pos)
end
--[[
-----------------
Node registration
-----------------
]]--
minetest.register_node("minerchest:chest", {
description = "Miner Chest",
tiles = {
-- up, down, right, left, back, front
"minerchest_plate.png",
"minerchest_plate.png",
"minerchest_side.png",
"minerchest_side.png",
"minerchest_side.png",
"minerchest_front.png",
},
drawtype = "nodebox",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = { choppy = 2, cracky = 2, crumbly = 2 },
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = after_dig_node,
on_rotate = screwdriver.disallow,
on_metadata_inventory_move = on_metadata_inventory_change,
on_metadata_inventory_put = on_metadata_inventory_change,
on_metadata_inventory_take = on_metadata_inventory_change,
})
minetest.register_node("minerchest:chest_full", {
description = "Miner Chest",
tiles = {
-- up, down, right, left, back, front
"minerchest_plate.png",
"minerchest_plate.png",
"minerchest_side.png",
"minerchest_side.png",
"minerchest_side.png",
"minerchest_front_full.png",
},
drawtype = "nodebox",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = { choppy = 2, cracky = 2, crumbly = 2,
not_in_creative_inventory = 1 },
is_ground_content = false,
sounds = default.node_sound_metal_defaults(),
drop = "minerchest:chest",
after_place_node = after_place_node,
can_dig = can_dig,
after_dig_node = after_dig_node,
on_rotate = screwdriver.disallow,
on_metadata_inventory_move = on_metadata_inventory_change,
on_metadata_inventory_put = on_metadata_inventory_change,
on_metadata_inventory_take = on_metadata_inventory_change,
})
tubelib.register_node("minerchest:chest", { "minerchest:chest_full" }, {
on_push_item = function(pos, side, item)
local meta = minetest.get_meta(pos)
local ret = tubelib.put_item(meta, "main", item)
combine_chest_items(pos)
update_chest_node(pos)
return ret
end,
on_pull_item = function(pos, side)
local meta = minetest.get_meta(pos)
set_next_tubelib_item(meta, "main")
local ret = tubelib.get_item(meta, "main")
combine_chest_items(pos)
update_chest_node(pos)
return ret
end,
on_pull_stack = function(pos, side)
local meta = minetest.get_meta(pos)
set_next_tubelib_item(meta, "main")
local ret = tubelib.get_stack(meta, "main")
combine_chest_items(pos)
update_chest_node(pos)
return ret
end,
on_unpull_item = function(pos, side, item)
local meta = minetest.get_meta(pos)
local ret = tubelib.put_item(meta, "main", item)
combine_chest_items(pos)
update_chest_node(pos)
return ret
end,
on_recv_message = function(pos, topic, payload)
if topic == "state" then
local meta = minetest.get_meta(pos)
return tubelib.get_inv_state(meta, "main")
else
return "unsupported"
end
end,
})
--[[
--------
Crafting
--------
]]--
minetest.register_craft({
output = "minerchest:chest",
recipe = {
{ "default:steelblock", "tubelib:tubeS", "default:goldblock" },
{ "group:wood", "", "group:wood" },
{ "default:copperblock", "group:wood", "default:tinblock" },
},
})
--[[
------------
Combinations
------------
]]--
minerchest.allow_item_combine("default:steel_ingot", "default:steelblock")
minerchest.allow_item_combine("default:copper_ingot", "default:copperblock")
minerchest.allow_item_combine("default:bronze_ingot", "default:bronzeblock")
minerchest.allow_item_combine("default:tin_ingot", "default:tinblock")
minerchest.allow_item_combine("default:gold_ingot", "default:goldblock")
minerchest.allow_item_combine("default:coal_lump", "default:coalblock")
minerchest.allow_item_combine("default:diamond", "default:diamondblock")
minerchest.allow_item_combine("default:mese_crystal", "default:mese")
minerchest.allow_item_combine("default:sand", "default:sandstone")
minerchest.allow_item_combine("default:desert_sand", "default:desert_sandstone")
minerchest.allow_item_combine("default:silver_sand", "default:silver_sandstone")
minerchest.allow_item_combine("default:clay_lump", "default:clay")
minerchest.allow_item_combine("farming:wheat", "farming:straw")
if minetest.global_exists("moreores") then
minerchest.allow_item_combine("moreores:silver_ingot", "moreores:silver_block")
minerchest.allow_item_combine("moreores:mithril_ingot", "moreores:mithril_block")
end
if minetest.global_exists("basic_materials") then
minerchest.allow_item_combine("basic_materials:brass_ingot", "basic_materials:brass_block")
end

4
minerchest/mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = minerchest
description = High capacity chest that can automatically combine certain materials into blocks.
depends = default,farming,tubelib,tubelib_addons1,tubelib2
optional_depends = moreores,basic_materials

BIN
minerchest/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B