diff --git a/api/access_point.lua b/api/access_point.lua
index e775618..4b2941f 100644
--- a/api/access_point.lua
+++ b/api/access_point.lua
@@ -43,6 +43,11 @@ local function on_access_point_rightclick(pos, node, clicker, itemstack, pointed
logistica.access_point_on_rightclick(pos, node, clicker, itemstack, pointed_thing)
end
+local function after_dig_access_point(pos, oldnode, oldmeta, digger)
+ logistica.on_access_point_change(pos, oldnode, oldmeta)
+ logistica.access_point_on_dug(pos)
+end
+
local function can_dig_access_point(pos, player)
return true
end
@@ -83,7 +88,7 @@ function logistica.register_access_point(desc, name, tiles)
can_dig = can_dig_access_point,
connect_sides = {"top", "bottom", "left", "back", "right" },
after_place_node = after_place_access_point,
- after_dig_node = logistica.on_access_point_change,
+ after_dig_node = after_dig_access_point,
on_rightclick = on_access_point_rightclick,
-- on_metadata_inventory_move = on_access_point_inv_move,
-- on_metadata_inventory_put = on_access_point_inv_put,
diff --git a/api/reservoir.lua b/api/reservoir.lua
index d090518..cfb30fc 100644
--- a/api/reservoir.lua
+++ b/api/reservoir.lua
@@ -66,13 +66,14 @@ local function after_place_node(pos, placer, itemstack, pointed_thing)
if not nodeDef or not nodeDef.logistica then return end
local liquidLevel = stackMeta:get_int(META_LIQUID_LEVEL)
- local liquidDesc = nodeDef.logistica.liquidDesc
+ local liquidDesc = logistica.reservoir_get_description_of_liquid(nodeDef.logistica.liquidName)
local maxBuckets = nodeDef.logistica.maxBuckets
nodeMeta:set_int(META_LIQUID_LEVEL, liquidLevel)
node.param2 = logistica.reservoir_make_param2(liquidLevel, maxBuckets)
minetest.swap_node(pos, node)
nodeMeta:set_string("infotext", logistica.reservoir_get_description(liquidLevel, maxBuckets, liquidDesc))
+ logistica.on_reservoir_change(pos)
end
@@ -84,7 +85,7 @@ local function preserve_metadata(pos, oldnode, oldmeta, drops)
local meta = minetest.get_meta(pos)
local drop = drops[1]
local dropMeta = drop:get_meta()
- local liquidDesc = nodeDef.logistica.liquidDesc
+ local liquidDesc = logistica.reservoir_get_description_of_liquid(nodeDef.logistica.liquidName)
local maxBuckets = nodeDef.logistica.maxBuckets
local liquidLevel = meta:get_int(META_LIQUID_LEVEL)
@@ -118,9 +119,10 @@ local commonDef = {
paramtype2 = "glasslikeliquidlevel",
is_ground_content = false,
sunlight_propagates = false,
- groups = {cracky = 3, level = 1},
+ groups = {cracky = 3, level = 1, [logistica.TIER_ALL] = 1},
preserve_metadata = preserve_metadata,
after_place_node = after_place_node,
+ after_dig_node = logistica.on_reservoir_change,
on_rightclick = on_rightclick,
stack_max = 1,
backface_culling = false,
@@ -144,8 +146,8 @@ for _, variantName in ipairs(variants) do
local nodeName = L("reservoir_"..variantName..EMPTY_SUFFIX)
def.drops = nodeName
def.logistica.liquidName = LIQUID_NONE
- def.logistica.liquidDesc = LIQUID_NONE
minetest.register_node(nodeName, def)
+ logistica.reservoirs[nodeName] = true
end
--[[
@@ -165,12 +167,12 @@ function logistica.register_reservoir(liquidName, liquidDesc, bucketItemName, li
def.drops = nodeName
def.special_tiles = {liquidTexture}
def.logistica.liquidName = lname
- def.logistica.liquidDesc = liquidDesc
def.groups.not_in_creative_inventory = 1
def.light_source = optLight
minetest.register_node(nodeName, def)
+ logistica.reservoirs[nodeName] = true
- logistica.reservoir_register_names(lname, bucketItemName, optEmptyBucketName)
+ logistica.reservoir_register_names(lname, bucketItemName, optEmptyBucketName, liquidDesc, liquidTexture)
end
end
diff --git a/logic/access_point.lua b/logic/access_point.lua
index ec932d9..47158bd 100644
--- a/logic/access_point.lua
+++ b/logic/access_point.lua
@@ -1,10 +1,19 @@
+local S = logistica.TRANSLATOR
+
local META_CURR_PAGE = "ap_curr_p"
local META_SORT_TYPE = "ap_sort"
local META_FILTER_TYPE = "ap_fltr"
local META_CURR_SEARCH = "ap_curr_s"
local META_IGNORE_METADATA = "ap_usemd"
+local META_CURR_LIQUID_INDEX = "ap_curr_l"
+
+local STR_NO_LIQUID = S("No Liquid Storage")
+local STR_EMPTY_RESERVOIRS = S("Free Capacity:")
local fakeInvMap = {}
+local liquidsMap = {}
+
+local LIQUID_NONE = -1
local SORT_NAME = 1
local SORT_MOD = 2
@@ -126,6 +135,26 @@ local function build_stack_list(pos)
}
end
+-- { description = "description here", capacity = "3/32", texture = "texture_name.png"}
+local function make_display_info(name, currBuckets, maxBuckets)
+ if not currBuckets or not maxBuckets then return { description = name, capacity = "", texture = ""} end
+
+ local desc, cap
+ if name == "" then
+ desc = STR_EMPTY_RESERVOIRS
+ cap = tostring(maxBuckets)
+ else
+ desc = logistica.reservoir_get_description_of_liquid(name)
+ cap = tostring(currBuckets).." / "..tostring(maxBuckets)
+ end
+
+ local texture = logistica.reservoir_get_texture_of_liquid(name)
+ return {
+ description = desc,
+ capacity = cap,
+ texture = texture,
+ }
+end
--------------------------------
-- public functions
@@ -133,6 +162,7 @@ end
function logistica.access_point_on_player_close(playerName)
fakeInvMap[playerName] = nil
+ liquidsMap[playerName] = nil
end
function logistica.update_fake_inv(pos, invName, listName, listSize, playerName)
@@ -242,4 +272,62 @@ end
function logistica.access_point_get_current_search_term(meta)
return meta:get_string(META_CURR_SEARCH)
-end
\ No newline at end of file
+end
+
+function logistica.access_point_change_liquid(meta, dir, playerName)
+ local liquidsInfo = liquidsMap[playerName]
+ if not liquidsInfo then return end
+ local currLiquidIndex = meta:get_int(META_CURR_LIQUID_INDEX)
+ if currLiquidIndex == LIQUID_NONE then return end
+ local numLiquids = #liquidsInfo
+ if numLiquids <= 0 then return end
+ local next = currLiquidIndex + dir
+
+ if next > numLiquids then next = 1 end
+ if next < 1 then next = numLiquids end
+
+ meta:set_int(META_CURR_LIQUID_INDEX, next)
+ return true
+end
+
+function logistica.access_point_refresh_liquids(pos, playerName)
+ local liquidsInfo = logistica.get_available_liquids_in_network(pos)
+ liquidsMap[playerName] = liquidsInfo
+
+ local meta = minetest.get_meta(pos)
+ if #liquidsInfo <= 0 then
+ meta:set_int(META_CURR_LIQUID_INDEX, LIQUID_NONE)
+ return
+ end
+
+ local currLiquid = meta:get_int(META_CURR_LIQUID_INDEX)
+ local validSelected = currLiquid >= 1 and currLiquid <= #liquidsInfo
+ if not validSelected then
+ meta:set_int(META_CURR_LIQUID_INDEX, 1)
+ end
+end
+
+-- returns a table: { description = "description here", capacity = "3/32", texture = "texture_name.png"}
+function logistica.access_point_get_current_liquid_display_info(meta, playerName)
+ local liquidsInfo = liquidsMap[playerName]
+ if not liquidsInfo then return make_display_info(STR_NO_LIQUID, nil, nil) end
+ local currLiquid = meta:get_int(META_CURR_LIQUID_INDEX)
+ local liquidInfo = liquidsInfo[currLiquid]
+
+ if currLiquid == LIQUID_NONE or not liquidInfo then return make_display_info(STR_NO_LIQUID, nil, nil) end
+
+ return make_display_info(liquidInfo.name, liquidInfo.curr, liquidInfo.max)
+end
+
+-- returns the current liquid name (which may be "" for the empty reservoirs) or nil if invalid/no reservoirs
+function logistica.access_point_get_current_liquid_name(meta, playerName)
+ local liquidsInfo = liquidsMap[playerName]
+ if not liquidsInfo then return nil end
+
+ local currLiquid = meta:get_int(META_CURR_LIQUID_INDEX)
+ if currLiquid == LIQUID_NONE then return "" end
+
+ local liquidInfo = liquidsInfo[currLiquid]
+ if not liquidInfo then return nil
+ else return liquidInfo.name end
+end
diff --git a/logic/access_point_formspec.lua b/logic/access_point_formspec.lua
index 5fc3968..6be2004 100644
--- a/logic/access_point_formspec.lua
+++ b/logic/access_point_formspec.lua
@@ -19,9 +19,12 @@ local SORT_COUNT_BTN = "sort_cnt"
local SORT_WEAR_BTN = "sort_wer"
local SEARCH_FIELD = "srch_fld"
local USE_META_BTN = "tgl_meta"
+local LIQUID_NEXT_BTN = "liq_nxt"
+local LIQUID_PREV_BTN = "liq_prv"
local INV_FAKE = "fake"
local INV_INSERT = "isert"
+local INV_LIQUID = "liqd"
local FAKE_INV_W = 12
local FAKE_INV_H = 4
local FAKE_INV_SIZE = FAKE_INV_W * FAKE_INV_H
@@ -49,15 +52,16 @@ local STR_LIGHT_DESC = S("Show Light sources only")
local STR_SERCH_DESC = S("Search by text\nUse group:some_group to find items belongong to some_group")
local STR_CLEAR_DESC = S("Clear search")
-
+local detachedInventories = {}
local accessPointForms = {}
-- creates the inv and returns the inv name
local function get_or_create_detached_inventory(pos, playerName)
- if accessPointForms[playerName] and accessPointForms[playerName].invName then
- return accessPointForms[playerName].invName
+ local hash = minetest.hash_node_position(pos)
+ if detachedInventories[hash] then
+ return detachedInventories[hash]
end
- local invName = playerName.."_LAP_"..logistica.get_rand_string_for(pos)
+ local invName = "Logistica_AP_"..logistica.get_rand_string_for(pos)
local inv = minetest.create_detached_inventory(invName, {
allow_move = logistica.access_point_allow_move,
allow_put = logistica.access_point_allow_put,
@@ -68,6 +72,8 @@ local function get_or_create_detached_inventory(pos, playerName)
}, playerName)
inv:set_size(INV_FAKE, FAKE_INV_SIZE)
inv:set_size(INV_INSERT, 1)
+ inv:set_size(INV_LIQUID, 1)
+ detachedInventories[hash] = invName
return invName
end
@@ -144,6 +150,17 @@ local function get_search_and_page_section(searchTerm, pageInfo) return
"image_button[13.9,6.5;0.8,0.8;logistica_icon_last.png;"..LAST_BTN..";;false;false;]"
end
+local function get_liquid_section(invName, meta, playerName)
+ local currInfo = logistica.access_point_get_current_liquid_display_info(meta, playerName)
+
+ return
+ "list[detached:"..invName..";"..INV_LIQUID..";1.2,7.3;1,1;0]"..
+ "image[1.3,6;0.8,0.8;"..currInfo.texture.."]"..
+ "label[1.0,7.1;"..currInfo.description.." "..currInfo.capacity.."]"..
+ "image_button[0.7,6;0.6,0.8;logistica_icon_prev.png;"..LIQUID_PREV_BTN..";;false;false]"..
+ "image_button[2.1,6;0.6,0.8;logistica_icon_next.png;"..LIQUID_NEXT_BTN..";;false;false]"
+end
+
local function get_access_point_formspec(pos, invName, optMeta, playerName)
--local posForm = "nodemeta:"..pos.x..","..pos.y..","..pos.z
local meta = optMeta or minetest.get_meta(pos)
@@ -158,12 +175,13 @@ local function get_access_point_formspec(pos, invName, optMeta, playerName)
"size[15.2,12.5]"..
logistica.ui.background..
"list[detached:"..invName..";"..INV_FAKE..";0.2,0.2;"..FAKE_INV_W..","..FAKE_INV_H..";0]"..
- "image[2.8,6.4;1,1;logistica_icon_input.png]"..
- "list[detached:"..invName..";"..INV_INSERT..";3.8,6.4;1,1;0]"..
+ "image[3.2,6.5;0.8,0.8;logistica_icon_input.png]"..
+ "list[detached:"..invName..";"..INV_INSERT..";4.0,6.4;1,1;0]"..
"list[current_player;main;5.2,7.5;8.0,4.0;0]"..
"label[1.4,12.2;"..S("Crafting").."]"..
"list[current_player;craft;0.2,8.4;3,3;]"..
"list[current_player;craftpreview;3.9,8.4;1,1;]"..
+ get_liquid_section(invName, meta, playerName)..
get_listrings(invName)..
get_filter_section(usesMetaStr, filterHighImg)..
get_tooltips()..
@@ -180,6 +198,7 @@ local function show_access_point_formspec(pos, playerName, optMeta)
invName = invName,
}
logistica.access_point_refresh_fake_inv(pos, invName, INV_FAKE, FAKE_INV_SIZE, playerName)
+ logistica.access_point_refresh_liquids(pos, playerName)
minetest.show_formspec(
playerName,
FORMSPEC_NAME,
@@ -207,7 +226,6 @@ function logistica.on_receive_access_point_formspec(player, formname, fields)
if minetest.is_protected(pos, playerName) or not pos then return true end
if fields.quit and not fields.key_enter_field then
- logistica.access_point_on_player_leave(playerName)
return true
elseif fields[FRST_BTN] then
if not logistica.access_point_change_page(pos, -2, playerName, FAKE_INV_SIZE) then return true end
@@ -241,6 +259,10 @@ function logistica.on_receive_access_point_formspec(player, formname, fields)
logistica.access_point_on_search_clear(pos)
elseif fields[SEARCH_BTN] or fields.key_enter_field then
logistica.access_point_on_search_change(pos, fields[SEARCH_FIELD])
+ elseif fields[LIQUID_PREV_BTN] then
+ if not logistica.access_point_change_liquid(minetest.get_meta(pos),-1, playerName) then return true end
+ elseif fields[LIQUID_NEXT_BTN] then
+ if not logistica.access_point_change_liquid(minetest.get_meta(pos), 1, playerName) then return true end
end
show_access_point_formspec(pos, playerName)
return true
@@ -252,9 +274,18 @@ end
function logistica.access_point_allow_put(inv, listname, index, stack, player)
if listname == INV_FAKE then return 0 end
+
local pos = get_curr_pos(player)
if not pos then return 0 end
if not logistica.get_network_or_nil(pos) then return 0 end
+
+ if listname == INV_LIQUID then
+ if logistica.reservoir_is_known_bucket(stack:get_name()) then
+ local currStack = inv:get_stack(listname, index)
+ if currStack:is_empty() then return 1 else return 0 end
+ else return 0 end
+ end
+
return stack:get_count()
end
@@ -298,6 +329,7 @@ end
function logistica.access_point_allow_move(inv, from_list, from_index, to_list, to_index, count, player)
if from_list == INV_FAKE or to_list == INV_FAKE then return 0 end
+ if to_list == INV_LIQUID then return 0 end
return count
end
@@ -319,6 +351,13 @@ function logistica.access_point_on_put(inv, listname, index, stack, player)
end
inv:set_stack(listname, index, ItemStack(""))
show_access_point_formspec(pos, player:get_player_name())
+ elseif listname == INV_LIQUID then
+ local currLiquid = logistica.access_point_get_current_liquid_name(minetest.get_meta(pos), player:get_player_name())
+ local newStack = logistica.use_bucket_for_liquid_in_network(pos, stack, currLiquid)
+ if newStack then
+ inv:set_stack(listname, index, newStack)
+ show_access_point_formspec(pos, player:get_player_name())
+ end
end
end
@@ -342,8 +381,28 @@ end
function logistica.access_point_on_player_leave(playerName)
local info = accessPointForms[playerName]
if info and info.invName then
- minetest.remove_detached_inventory(info.invName)
+ local onlyRef = true
+ for _, otherInfo in pairs(accessPointForms) do
+ if otherInfo.invName == info.invName then onlyRef = false end
+ end
+ if onlyRef then
+ minetest.remove_detached_inventory(info.invName)
+ end
end
accessPointForms[playerName] = nil
logistica.access_point_on_player_close(playerName)
end
+
+function logistica.access_point_on_dug(pos)
+ local removeForPlayers = {}
+ local i =0
+ for playerName, info in pairs(accessPointForms) do
+ if info.position and vector.equals(pos, info.position) then
+ i = i + 1
+ removeForPlayers[i] = playerName
+ end
+ end
+ for _, playerName in ipairs(removeForPlayers) do
+ logistica.access_point_on_player_leave(playerName)
+ end
+end
diff --git a/logic/groups.lua b/logic/groups.lua
index ef3ff4e..6038fa3 100644
--- a/logic/groups.lua
+++ b/logic/groups.lua
@@ -9,6 +9,7 @@ logistica.item_storage = {}
logistica.misc_machines = {}
logistica.trashcans = {}
logistica.vaccuum_suppliers = {}
+logistica.reservoirs = {}
logistica.TIER_ALL = "logistica_all_tiers"
logistica.GROUP_ALL = "group:" .. logistica.TIER_ALL
logistica.TIER_CONTROLLER = "logistica_controller"
@@ -20,7 +21,7 @@ function logistica.is_machine(name)
return logistica.is_requester(name) or logistica.is_supplier(name) or logistica.is_mass_storage(name)
or logistica.is_item_storage(name) or logistica.is_controller(name) or logistica.is_injector(name)
or logistica.is_crafting_supplier(name) or logistica.is_trashcan(name) or logistica.is_vaccuum_supplier(name)
- or logistica.is_misc(name)
+ or logistica.is_misc(name) or logistica.is_reservoir(name)
end
function logistica.is_cable(name)
@@ -66,3 +67,7 @@ end
function logistica.is_vaccuum_supplier(name)
return logistica.vaccuum_suppliers[name] ~= nil
end
+
+function logistica.is_reservoir(name)
+ return logistica.reservoirs[name] ~= nil
+end
diff --git a/logic/network_logic.lua b/logic/network_logic.lua
index bce5a8f..1c26fa4 100644
--- a/logic/network_logic.lua
+++ b/logic/network_logic.lua
@@ -23,6 +23,7 @@ local function has_machine(network, id)
or network.injectors[id]
or network.misc[id]
or network.trashcans[id]
+ or network.reservoirs[id]
then
return true
else
@@ -204,6 +205,10 @@ local function recursive_scan_for_nodes_for_controller(network, positionHashes,
network.trashcans[otherHash] = true
valid = true
end
+ if logistica.is_reservoir(otherName) then
+ network.reservoirs[otherHash] = true
+ valid = true
+ end
if valid then
newToScan = newToScan + 1
set_cache_network_id(minetest.get_meta(otherPos), network.controller)
@@ -242,6 +247,7 @@ local function create_network(controllerPosition, oldNetworkName)
network.storage_cache = {}
network.supplier_cache = {}
network.requester_cache = {}
+ network.reservoirs = {}
local startPos = {}
startPos[controllerHash] = true
local status = recursive_scan_for_nodes_for_controller(network, startPos)
@@ -369,6 +375,12 @@ local TRASHCAN_OPS = {
update_cache_node_removed = function(_) end,
}
+local RESERVOIR_OPS = {
+ get_list = function(network) return network.reservoirs end,
+ update_cache_node_added = function(_) end,
+ update_cache_node_removed = function(_) end,
+}
+
local function cable_can_extend_network_from(pos)
local node = minetest.get_node_or_nil(pos)
if not node then return false end
@@ -494,3 +506,7 @@ end
function logistica.on_trashcan_change(pos, oldNode, oldMeta)
on_node_change(pos, oldNode, oldMeta, TRASHCAN_OPS)
end
+
+function logistica.on_reservoir_change(pos, oldNode, oldMeta)
+ on_node_change(pos, oldNode, oldMeta, RESERVOIR_OPS)
+end
diff --git a/logic/network_storage.lua b/logic/network_storage.lua
index b8e0449..3959ee6 100644
--- a/logic/network_storage.lua
+++ b/logic/network_storage.lua
@@ -3,11 +3,75 @@ local MASS_STORAGE_LIST_NAME = "storage"
local ITEM_STORAGE_LIST_NAME = "main"
local MAX_NETWORK_DEPTH_SEARCH = 16 -- somewhat arbitrary but prevents stackoverflows
+local h2p = minetest.get_position_from_hash
+
local function get_meta(pos)
logistica.load_position(pos)
return minetest.get_meta(pos)
end
+local function fill_bucket_from_network(network, bucketItemStack, liquidName)
+ local lowestReservoirPos = nil
+ local lowestReservoirLvl = 999999
+ for hash, _ in pairs(network.reservoirs or {}) do
+ local pos = h2p(hash)
+ logistica.load_position(pos)
+ if logistica.reservoir_get_liquid_name(pos) == liquidName then
+ local levels = logistica.reservoir_get_liquid_level(pos)
+ if levels and levels[1] < lowestReservoirLvl then
+ lowestReservoirPos = pos
+ lowestReservoirLvl = levels[1]
+ end
+ end
+ end
+
+ if lowestReservoirPos then
+ return logistica.reservoir_use_item_on(lowestReservoirPos, bucketItemStack)
+ else
+ return nil
+ end
+end
+
+local function empty_bucket_into_network(network, bucketItemStack)
+ local bucketName = bucketItemStack:get_name()
+ local liquidName = logistica.reservoir_get_liquid_name_for_bucket(bucketName)
+
+ local highestReservoirPos = nil
+ local emptyReservoirPos = nil
+ local emptyResrvoirMinCap = 999999
+ local highestReservoirLvl = 0
+ for hash, _ in pairs(network.reservoirs or {}) do
+ local pos = h2p(hash)
+ logistica.load_position(pos)
+ local liquidInReservoir = logistica.reservoir_get_liquid_name(pos)
+ if liquidInReservoir == liquidName then
+ local levels = logistica.reservoir_get_liquid_level(pos)
+ if levels and levels[1] < levels[2] and levels[1] > highestReservoirLvl then
+ highestReservoirPos = pos
+ highestReservoirLvl = levels[1]
+ end
+ elseif liquidInReservoir == "" then
+ local levels = logistica.reservoir_get_liquid_level(pos)
+ if levels and levels[2] < emptyResrvoirMinCap then
+ emptyResrvoirMinCap = levels[2]
+ emptyReservoirPos = pos
+ end
+ end
+ end
+
+ if highestReservoirPos then
+ return logistica.reservoir_use_item_on(highestReservoirPos, bucketItemStack)
+ elseif emptyReservoirPos then
+ return logistica.reservoir_use_item_on(emptyReservoirPos, bucketItemStack)
+ else
+ return nil
+ end
+end
+
+--------------------------------
+-- public functions
+--------------------------------
+
-- tries to take a stack from the network locations
-- calls the collectorFunc with the stack - collectorFunc needs to return how many were left-over
-- `collectorFunc = function(stackToInsert)`
@@ -40,7 +104,7 @@ function logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc
local stackName = stackToTake:get_name()
local validSupplers = network.supplier_cache[stackName] or {}
for hash, _ in pairs(validSupplers) do
- local pos = minetest.get_position_from_hash(hash)
+ local pos = h2p(hash)
logistica.load_position(pos)
local nodeName = minetest.get_node(pos).name
if logistica.is_supplier(nodeName) or logistica.is_vaccuum_supplier(nodeName) then
@@ -64,7 +128,7 @@ function logistica.take_stack_from_item_storage(stack, network, collectorFunc, i
if useMetadata then eq = function(s1, s2) return s1:equals(s2) end end
for storageHash, _ in pairs(network.item_storage) do
- local storagePos = minetest.get_position_from_hash(storageHash)
+ local storagePos = h2p(storageHash)
local storageInv = get_meta(storagePos):get_inventory()
local storageList = storageInv:get_list(ITEM_STORAGE_LIST_NAME) or {}
for i, storedStack in ipairs(storageList) do
@@ -97,7 +161,7 @@ function logistica.take_stack_from_mass_storage(stackToTake, network, collectorF
if stackToTake:get_count() == 0 then return end
if massLocations == nil then return end
for storageHash, _ in pairs(massLocations) do
- local storagePos = minetest.get_position_from_hash(storageHash)
+ local storagePos = h2p(storageHash)
local meta = get_meta(storagePos)
local storageInv = meta:get_inventory()
local storageList = storageInv:get_list(MASS_STORAGE_LIST_NAME) or {}
@@ -155,7 +219,7 @@ function logistica.insert_item_in_network(itemstack, networkId, dryRun)
-- check requesters first
local listOfRequestersInNeedOfItem = network.requester_cache[itemstack:get_name()] or {}
for hash, _ in pairs(listOfRequestersInNeedOfItem) do
- local pos = minetest.get_position_from_hash(hash)
+ local pos = h2p(hash)
logistica.load_position(pos)
local leftover = logistica.insert_itemstack_for_requester(pos, workingStack, true)
if leftover <= 0 then return 0 end -- we took all items
@@ -173,7 +237,7 @@ function logistica.insert_item_in_network(itemstack, networkId, dryRun)
addFunc = logistica.insert_item_into_mass_storage
end
for hash, _ in pairs(storages) do
- local pos = minetest.get_position_from_hash(hash)
+ local pos = h2p(hash)
local inv = get_meta(pos):get_inventory()
local remainingStack = addFunc(pos, inv, workingStack, dryRun)
if remainingStack:is_empty() then return 0 end -- we took all items
@@ -183,7 +247,7 @@ function logistica.insert_item_in_network(itemstack, networkId, dryRun)
-- try to add to passive suppliers that accept this
local suppliers = network.suppliers
for hash, _ in pairs(suppliers) do
- local pos = minetest.get_position_from_hash(hash)
+ local pos = h2p(hash)
logistica.load_position(pos)
local leftover = logistica.put_item_in_supplier(pos, workingStack)
if leftover:is_empty() then return 0 end
@@ -193,11 +257,67 @@ function logistica.insert_item_in_network(itemstack, networkId, dryRun)
-- [Keep this last] delete the item if any trashcan accepts it
local trashcans = network.trashcans or {}
for hash, _ in pairs(trashcans) do
- local pos = minetest.get_position_from_hash(hash)
+ local pos = h2p(hash)
logistica.load_position(pos)
workingStack = logistica.trashcan_trash_item(pos, workingStack)
if workingStack:is_empty() then return 0 end
end
return workingStack:get_count()
-end
\ No newline at end of file
+end
+
+--[[ returns a natural-indexed list of tables - or empty table if there's no network or no liquids:
+ ```
+ [1] = {
+ name = "liquid_name", -- name of the liquid or "" if for empty reservoirs
+ curr = 0 -- amount of liquid stored in network
+ max = 32 -- combined max capacity of the reservoirs occupied by liquid
+ },
+ [2] = {...}
+ ```
+]]
+function logistica.get_available_liquids_in_network(pos)
+ local network = logistica.get_network_or_nil(pos)
+ if not network then return {} end
+ local liquidInfo = {}
+ for hash, _ in pairs(network.reservoirs or {}) do
+ local resPos = h2p(hash)
+ local liquidName = logistica.reservoir_get_liquid_name(resPos)
+ local liquidLevels = logistica.reservoir_get_liquid_level(resPos)
+ if liquidName and liquidLevels then
+ local info = liquidInfo[liquidName] or {curr = 0, max = 0}
+ info.curr = info.curr + liquidLevels[1]
+ info.max = info.max + liquidLevels[2]
+ liquidInfo[liquidName] = info
+ end
+ end
+ return
+ logistica.table_to_list_indexed(liquidInfo, function(lName, lInfo)
+ return {
+ name = lName,
+ curr = lInfo.curr,
+ max = lInfo.max,
+ }
+ end)
+end
+
+-- attempts to use, either fill or empty, the given bucket in/from liquid storage on
+-- the network.
+-- `liquidName` is only used if the bucketItem is a type of empty bucket
+-- Otherwise a full bucket will attempt to fill any applicable reservoir on the network.
+-- This function attempts to take from the lowest filled reservoir, and insert into the highest filled reservoir first.
+-- returns new itemstack to replace the old one, or `nil` if it wasn't changed
+function logistica.use_bucket_for_liquid_in_network(pos, bucketItemStack, liquidName)
+ local network = logistica.get_network_or_nil(pos)
+ if not network then return nil end
+
+ local bucketName = bucketItemStack:get_name()
+ local isEmptyBucket = logistica.reservoir_is_empty_bucket(bucketName)
+ local isFullBucket = logistica.reservoir_is_full_bucket(bucketName)
+ if isEmptyBucket then
+ if not liquidName then return nil end
+ return fill_bucket_from_network(network, bucketItemStack, liquidName)
+ elseif isFullBucket then
+ return empty_bucket_into_network(network, bucketItemStack)
+ end
+end
diff --git a/logic/reservoir.lua b/logic/reservoir.lua
index 15e65c7..8ec404a 100644
--- a/logic/reservoir.lua
+++ b/logic/reservoir.lua
@@ -3,6 +3,9 @@ local S = logistica.TRANSLATOR
local BUCKET_TO_NAME = {}
local NAME_TO_BUCKET = {}
local NAME_TO_EMPTY_BUCKET = {}
+local NAME_TO_DESC = {}
+local NAME_TO_TEXTURE = {}
+
local EMPTY_BUCKET = "bucket:bucket_empty"
local EMPTY_SUFFIX = "_empty"
@@ -54,6 +57,14 @@ end
-- public functions
--------------------------------
+function logistica.reservoir_get_description_of_liquid(liquidName)
+ return NAME_TO_DESC[liquidName] or LIQUID_NONE
+end
+
+function logistica.reservoir_get_texture_of_liquid(liquidName)
+ return NAME_TO_TEXTURE[liquidName] or ""
+end
+
function logistica.reservoir_make_param2(val, max)
local ret = math.floor(63*(val/max))
if val > 0 and ret == 0 then
@@ -66,12 +77,14 @@ function logistica.reservoir_get_description(currBuckets, maxBuckets, liquidName
return strDescription.."\n"..getStrContains(currBuckets, maxBuckets, liquidName)
end
-function logistica.reservoir_register_names(liquidName, bucketName, emptyBucketName)
+function logistica.reservoir_register_names(liquidName, bucketName, emptyBucketName, liquidDesc, liquidTexture)
BUCKET_TO_NAME[bucketName] = liquidName
NAME_TO_BUCKET[liquidName] = bucketName
if emptyBucketName then
NAME_TO_EMPTY_BUCKET[liquidName] = emptyBucketName
end
+ NAME_TO_DESC[liquidName] = liquidDesc
+ NAME_TO_TEXTURE[liquidName] = liquidTexture
end
-- returns nil if item had no effect
@@ -86,7 +99,7 @@ function logistica.reservoir_use_item_on(pos, itemstack, optNode)
local nodeLiquidLevel = meta:get_int(META_LIQUID_LEVEL)
local liquidName = nodeDef.logistica.liquidName
local maxBuckets = nodeDef.logistica.maxBuckets
- local liquidDesc = nodeDef.logistica.liquidDesc
+ local liquidDesc = logistica.reservoir_get_description_of_liquid(liquidName)
local emptyBucket = get_empty_bucket_needed_for(liquidName)
local fullBucket = get_full_bucket_needed_for(liquidName)
@@ -127,14 +140,57 @@ function logistica.reservoir_use_item_on(pos, itemstack, optNode)
minetest.swap_node(pos, node)
local newNodeName = get_liquid_reservoir_name_for(node.name, newLiquidName)
- if not minetest.registered_nodes[newNodeName] then return nil end
+ local nodeDef = minetest.registered_nodes[newNodeName]
+ if not nodeDef or not nodeDef.logistica then return nil end
if nodeLiquidLevel == 1 then -- first bucket we added, swap to that reservoir type
logistica.swap_node(pos, newNodeName)
end
- local newLiquidDesc = minetest.registered_nodes[newNodeName].logistica.liquidDesc
+ local newLiquidDesc = logistica.reservoir_get_description_of_liquid(nodeDef.logistica.liquidName)
meta:set_string("infotext", logistica.reservoir_get_description(nodeLiquidLevel, maxBuckets, newLiquidDesc))
meta:set_int(META_LIQUID_LEVEL, nodeLiquidLevel)
return ItemStack(newEmptyBucket)
end
return nil
end
+
+-- returns the liquid name for the reservoir; or "" if there's no liquid stored, or nil if its not a reservoir
+function logistica.reservoir_get_liquid_name(pos)
+ local node = minetest.get_node(pos)
+ if not logistica.is_reservoir(node.name) then return nil end
+ local def = minetest.registered_nodes[node.name]
+ if not def or not def.logistica or not def.logistica.liquidName then return nil end
+ return def.logistica.liquidName
+end
+
+-- return {currentLevel, maxLevel} measured in buckets; or nil if its not a reservoir
+function logistica.reservoir_get_liquid_level(pos)
+ local node = minetest.get_node(pos)
+ if not logistica.is_reservoir(node.name) then return nil end
+ local def = minetest.registered_nodes[node.name]
+ if not def or not def.logistica or not def.logistica.maxBuckets then return nil end
+ local meta = minetest.get_meta(pos)
+ return { meta:get_int(META_LIQUID_LEVEL), def.logistica.maxBuckets }
+end
+
+function logistica.reservoir_is_empty_bucket(bucketName)
+ if bucketName == EMPTY_BUCKET then return true end
+ for _, bucket in pairs(NAME_TO_EMPTY_BUCKET) do
+ if bucket == bucketName then return true end
+ end
+ return false
+end
+
+function logistica.reservoir_is_full_bucket(bucketName)
+ if BUCKET_TO_NAME[bucketName] ~= nil then return true end
+ return false
+end
+
+-- returns true if the itemname is a known empty or filled bucket that can be used in a reservoir
+function logistica.reservoir_is_known_bucket(bucketName)
+ return logistica.reservoir_is_empty_bucket(bucketName) or logistica.reservoir_is_full_bucket(bucketName)
+end
+
+-- return the liquid name for the given bucket name, or nil if there's none registered
+function logistica.reservoir_get_liquid_name_for_bucket(bucketName)
+ return BUCKET_TO_NAME[bucketName]
+end
\ No newline at end of file
diff --git a/textures/logistica_reservoir_obsidian.png b/textures/logistica_reservoir_obsidian.png
index acf7520..5c8f688 100644
Binary files a/textures/logistica_reservoir_obsidian.png and b/textures/logistica_reservoir_obsidian.png differ
diff --git a/textures/logistica_reservoir_silverin.png b/textures/logistica_reservoir_silverin.png
index c6b5b37..d78b406 100644
Binary files a/textures/logistica_reservoir_silverin.png and b/textures/logistica_reservoir_silverin.png differ