diff --git a/README.md b/README.md index fce9630..d15b48e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Logistica +# WORK IN PROGRESS - PRE-ALPHA STATE Logistica is a item transport, distribution and storage mod. diff --git a/api/api.lua b/api/api.lua index debf5e8..f0c8bb1 100644 --- a/api/api.lua +++ b/api/api.lua @@ -3,4 +3,5 @@ local path = logistica.MODPATH.."/api" dofile(path.."/cables.lua") dofile(path.."/controller.lua") dofile(path.."/mass_storage.lua") +dofile(path.."/supplier.lua") dofile(path.."/demander.lua") diff --git a/api/controller.lua b/api/controller.lua index 1e31030..2326450 100644 --- a/api/controller.lua +++ b/api/controller.lua @@ -66,7 +66,7 @@ logistica.register_controller("Simple Controller", { description = "Simple Controller", tiles = { "logistica_silver_cable.png" }, groups = { - oddly_breakable_by_hand = 2, + oddly_breakable_by_hand = 1, }, sounds = default.node_sound_metal_defaults(), paramtype = "light", diff --git a/api/mass_storage.lua b/api/mass_storage.lua index 3e29992..fed98b2 100644 --- a/api/mass_storage.lua +++ b/api/mass_storage.lua @@ -1,4 +1,7 @@ +local META_SERIALIZED_INV = "logistica:ser_inv" +local META_ITEM_NAME = "logistica:item_name" + local function get_mass_storage_upgrade_inv(posForm, numUpgradeSlots) if numUpgradeSlots <= 0 then return "" end local upIconX = 1.5 + 1.25 * (7 - numUpgradeSlots) -- sort of hardcoded @@ -34,9 +37,11 @@ end -- callbacks -local function after_place_mass_storage(pos, placer, numSlots, numUpgradeSlots) +local function after_place_mass_storage(pos, placer, itemstack, numSlots, numUpgradeSlots) local meta = minetest.get_meta(pos) - meta:set_string("owner", placer:get_player_name()) + if placer and placer:is_player() then + meta:set_string("owner", placer:get_player_name()) + end local inv = meta:get_inventory() inv:set_size("main", 1) inv:set_size("filter", numSlots) @@ -44,12 +49,55 @@ local function after_place_mass_storage(pos, placer, numSlots, numUpgradeSlots) inv:set_size("upgrade", numUpgradeSlots) -- and connect to network logistica.on_storage_change(pos) + -- restore inventory, if any + local itemstackMetaInv = itemstack:get_meta():get_string(META_SERIALIZED_INV) + if itemstackMetaInv then + local listsTable = logistica.deserialize_inv(itemstackMetaInv) + for name, listTable in pairs(listsTable) do + inv:set_list(name, listTable) + end + end +end + +local function on_mass_storage_preserve_metadata(pos, oldnode, oldmeta, drops) + local drop = drops[1] + local meta = minetest.get_meta(pos) + if not drop or not meta then return end + local inv = meta:get_inventory() + local serialized = logistica.serialize_inv(inv) + drop:get_meta():set_string(META_SERIALIZED_INV, serialized) + -- update description + local name = minetest.registered_nodes[oldnode.name].logistica.baseName + if inv:is_empty("storage") then + name = name.."\n(Empty)" + else + name = name.."\n(Contains items)" -- TODO set a node name or use a stackname + end + drop:get_meta():set_string("description", name) +end + +local function allow_mass_storage_inv_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player) then return 0 end + if listname == "storage" then + return logistica.clamp(stack:get_count(), 0, stack:get_stack_max()) + end + if listname == "main" then return stack:get_count() end + if listname == "filter" then + local inv = minetest.get_meta(pos):get_inventory() + if not inv:get_stack("storage", index):is_empty() then return 0 end + local storageStack = inv:get_stack("filter", index) + storageStack:clear() + inv:set_stack("filter", index, storageStack) + logistica.updateStorageCacheFromPosition(pos) + return 0 + end + return stack:get_count() end local function allow_mass_storage_inv_move(pos, from_list, from_index, to_list, to_index, count, player) if minetest.is_protected(pos, player) then return 0 end if from_list == "main" and to_list == "main" then return count end - if from_list == "filter" and to_list == "filter" then return count end + if from_list == "upgrade" and to_list == "upgrade" then return count end return 0 end @@ -65,27 +113,12 @@ local function allow_mass_storage_inv_put(pos, listname, index, stack, player) copyStack:set_count(1) local inv = minetest.get_meta(pos):get_inventory() inv:set_stack("filter", index, copyStack) + logistica.updateStorageCacheFromPosition(pos) return 0 end return stack:get_count() end -local function allow_mass_storage_inv_take(pos, listname, index, stack, player) - if minetest.is_protected(pos, player) then return 0 end - if listname == "storage" then - return logistica.clamp(stack:get_count(), 0, stack:get_stack_max()) - end - if listname == "main" then return stack:get_count() end - if listname == "filter" then - local inv = minetest.get_meta(pos):get_inventory() - if not inv:get_stack("storage", index):is_empty() then return 0 end - local stack = inv:get_stack("filter", index) - stack:clear() - inv:set_stack("filter", index, stack) - return 0 - end - return stack:get_count() -end local function on_mass_storage_inv_move(pos, from_list, from_index, to_list, to_index, count, player) if minetest.is_protected(pos, player) then return 0 end @@ -123,12 +156,6 @@ local function on_mass_storage_right_click(pos, node, clicker, itemstack, pointe ) end -local function on_mass_storage_preserve_metadata(pos, oldnode, oldmeta, drops) - local drop = drops[1] - if not drop then return end - -end - ---------------------------------------------------------------- -- Public Registration API ---------------------------------------------------------------- @@ -136,21 +163,23 @@ end function logistica.register_mass_storage(simpleName, numSlots, numItemsPerSlot, numUpgradeSlots) local lname = string.lower(string.gsub(simpleName, " ", "_")) local storageName = "logistica:mass_storage_"..lname - local grps = {cracky = 3, choppy = 3, oddly_breakable_by_hand = 2} + local grps = {cracky = 1, choppy = 1, oddly_breakable_by_hand = 1} numUpgradeSlots = logistica.clamp(numUpgradeSlots, 0, 4) grps[logistica.TIER_ALL] = 1 logistica.mass_storage[storageName] = true local def = { - description = simpleName.." Mass Storage", + description = simpleName.." Mass Storage\n(Empty)", tiles = { "logistica_"..lname.."_mass_storage.png" }, groups = grps, + sounds = default.node_sound_metal_defaults(), after_place_node = function(pos, placer, itemstack) - after_place_mass_storage(pos, placer, numSlots, numUpgradeSlots) + after_place_mass_storage(pos, placer, itemstack, numSlots, numUpgradeSlots) end, after_destruct = logistica.on_storage_change, drop = storageName, logistica = { + baseName = simpleName.." Mass Storage", maxItems = numItemsPerSlot, numSlots = numSlots, numUpgradeSlots = numUpgradeSlots, diff --git a/api/supplier.lua b/api/supplier.lua new file mode 100644 index 0000000..e69de29 diff --git a/logic/demander.lua b/logic/demander.lua new file mode 100644 index 0000000..5dee749 --- /dev/null +++ b/logic/demander.lua @@ -0,0 +1,24 @@ + +-- Returns a list of ItemStacks from the demandList that are missing in the storageList +function logistica.get_demand_based_on_list(demandList, storageList) + local missing = {} + local storageSize = #storageList + for _, demanded in ipairs(demandList) do + local remaining = demanded:get_count() + local i = 1 + local checkNext = true + while checkNext and i <= storageSize do + local stored = storageList[i] + if demanded:get_name() == stored:get_name() then + remaining = remaining - stored:get_count() + end + if remaining <= 0 then checkNext = false end + end + if remaining > 0 then + local missingStack = ItemStack(demanded) + missingStack:set_count(remaining) + table.insert(missing, missingStack) + end + end + return missing +end diff --git a/logic/groups.lua b/logic/groups.lua index 6845ec5..8583943 100644 --- a/logic/groups.lua +++ b/logic/groups.lua @@ -73,4 +73,4 @@ function logistica.do_tiers_match(tiers1, tiers2) end end return false -end \ No newline at end of file +end diff --git a/logic/logic.lua b/logic/logic.lua index 773630d..7fc4207 100644 --- a/logic/logic.lua +++ b/logic/logic.lua @@ -5,3 +5,5 @@ dofile(path .. "/push_pull.lua") dofile(path .. "/network_logic.lua") dofile(path .. "/controller.lua") dofile(path .. "/storage.lua") +dofile(path .. "/supplier.lua") +dofile(path .. "/demander.lua") diff --git a/logic/network_logic.lua b/logic/network_logic.lua index 8760e10..ca23a2d 100644 --- a/logic/network_logic.lua +++ b/logic/network_logic.lua @@ -5,6 +5,11 @@ local CREATE_NETWORK_STATUS_FAIL_OTHER_NETWORK = -1 local CREATE_NETWORK_STATUS_TOO_MANY_NODES = -2 local ADD_STORAGE_MULTIPLE_NETWORKS = -1 +logistica.networks = networks + +local p2h = minetest.hash_node_position +local h2p = minetest.get_position_from_hash + local adjecent = { vector.new( 1, 0, 0), vector.new( 0, 1, 0), @@ -13,6 +18,7 @@ local adjecent = { vector.new( 0, -1, 0), vector.new( 0, 0, -1), } + local function has_machine(network, id) if not network then return false end if network.demanders and network.demanders[id] then @@ -27,7 +33,7 @@ local function has_machine(network, id) end function logistica.get_network_name_or_nil(pos) - local hash = minetest.hash_node_position(pos) + local hash = p2h(pos) for nHash, network in pairs(networks) do if hash == nHash then return network.name end if network.cables[hash] then return network.name end @@ -37,7 +43,7 @@ function logistica.get_network_name_or_nil(pos) end function logistica.get_network_or_nil(pos) - local hash = minetest.hash_node_position(pos) + local hash = p2h(pos) for nHash, network in pairs(networks) do if hash == nHash then return network end if network.cables[hash] then return network end @@ -59,7 +65,7 @@ end local function dumb_remove_from_network(networkName, pos) local network = networks[networkName] if not network then return false end - local hashedPos = minetest.hash_node_position(pos) + local hashedPos = p2h(pos) if network.cables[hashedPos] then network.cables[hashedPos] = nil return true @@ -94,6 +100,14 @@ local function break_logistica_node(pos) logistica.swap_node(pos, node.name .. "_disabled") end +-- calls updateStorageCache(network) if the current position belongs to a network +function logistica.updateStorageCacheFromPosition(pos) + local network = logistica.get_network_or_nil(pos) + if network then + logistica.updateStorageCache(network) + end +end + --[[ updates the storage cach which holds where items may be found The cache is in the followiing format: network.storage_cache = { @@ -108,11 +122,10 @@ function logistica.updateStorageCache(network) -- for now, do full rescan network.storage_cache = {} for storageHash, _ in pairs(network.mass_storage) do - local storagePos = minetest.get_position_from_hash(storageHash) + local storagePos = h2p(storageHash) logistica.load_position(storagePos) - local meta = minetest.get_meta(storagePos) - local inv = meta:get_inventory():get_list("filter") - for _, itemStack in pairs(inv) do + local filterList = minetest.get_meta(storagePos):get_inventory():get_list("filter") or {} + for _, itemStack in pairs(filterList) do local name = itemStack:get_name() if not network.storage_cache[name] then network.storage_cache[name] = {} end network.storage_cache[name][storageHash] = true @@ -124,7 +137,7 @@ local function dumb_add_storage_to_network(networkId, pos) local network = networks[networkId] if not network then return false end local node = minetest.get_node(pos) - local hashedPos = minetest.hash_node_position(pos) + local hashedPos = p2h(pos) if logistica.is_mass_storage(node.name) then network.mass_storage[hashedPos] = true return true @@ -139,7 +152,7 @@ local function dumb_add_cable_to_network(networkName, pos) local network = networks[networkName] if not network then return false end local node = minetest.get_node(pos) - local hashedPos = minetest.hash_node_position(pos) + local hashedPos = p2h(pos) if logistica.is_cable(node.name) then network.cables[hashedPos] = true return true @@ -165,7 +178,7 @@ local function recursive_scan_for_nodes_for_controller(network, positions, numSc for _, offset in pairs(adjecent) do local otherPos = vector.add(pos, offset) logistica.load_position(otherPos) - local otherHash = minetest.hash_node_position(otherPos) + local otherHash = p2h(otherPos) local tiersMatch = isAllTier if tiersMatch ~= true then local otherTiers = logistica.get_item_tiers(minetest.get_node(otherPos).name) @@ -203,7 +216,7 @@ local function create_network(controllerPosition) local node = minetest.get_node(controllerPosition) if not node.name:find("_controller") or not node.name:find("logistica:") then return false end local meta = minetest.get_meta(controllerPosition) - local controllerHash = minetest.hash_node_position(controllerPosition) + local controllerHash = p2h(controllerPosition) local network = {} local networkName = logistica.get_network_name_for(controllerPosition) networks[controllerHash] = network @@ -242,7 +255,7 @@ local function rescan_network(networkName) if not network then return false end if not network.controller then return false end local conHash = network.controller - local controllerPosition = minetest.get_position_from_hash(conHash) + local controllerPosition = h2p(conHash) clear_network(networkName) create_network(controllerPosition) end @@ -301,7 +314,7 @@ local function try_to_add_mass_storage_to_network(pos) end local function remove_mass_storage_from_network(pos) - local hash = minetest.hash_node_position(pos) + local hash = p2h(pos) local network = logistica.get_network_or_nil(pos) if not network then return end if not network.mass_storage[hash] then return end @@ -361,7 +374,7 @@ function logistica.on_cable_change(pos, oldNode) end function logistica.on_controller_change(pos, oldNode) - local hashPos = minetest.hash_node_position(pos) + local hashPos = p2h(pos) local placed = (oldNode == nil) -- if oldNode is nil, we placed a new one if placed == true then try_to_add_network(pos) @@ -377,4 +390,4 @@ function logistica.on_storage_change(pos, oldNode) else remove_mass_storage_from_network(pos) end -end \ No newline at end of file +end diff --git a/logic/processing_queue.lua b/logic/processing_queue.lua index 91a5c59..b36dabc 100644 --- a/logic/processing_queue.lua +++ b/logic/processing_queue.lua @@ -55,4 +55,3 @@ function logistica.proq.get_all(pos) end return positions end - diff --git a/logic/storage.lua b/logic/storage.lua index 934892c..2b360cc 100644 --- a/logic/storage.lua +++ b/logic/storage.lua @@ -66,24 +66,43 @@ function logistica.try_to_add_item_to_storage(pos, inputStack, dryRun) end -- takes a list of ItemStacks and returns a single string representation -function logistica.inv_to_table(list) - local itemStackStrings = {} - for _,v in pairs(list) do - itemStackStrings:insert(v:to_string()) +function logistica.inv_list_to_table(list) + local itemstackTable = {} + for k,v in ipairs(list) do + itemstackTable[k] = v and v:to_string() or "" end + return itemstackTable end -function logistica.table_to_inv(string) - +function logistica.table_to_inv_list(table) + local list = {} + for k,v in ipairs(table) do + if v == nil or v == "" then + list[k] = "" + else + list[k] = ItemStack(v) + end + end + return list end -local LIST_SEPARATOR = "L|L" --- takes a inventory and returns a single string represetation -function logistica.serliaze_inventory(list) - +-- returns a serialized string of the inventory +function logistica.serialize_inv(inv) + local lists = inv:get_lists() + local invTable = {} + for name, list in pairs(lists) do + invTable[name] = logistica.inv_list_to_table(list) + end + return minetest.serialize(invTable) end --- takes a inventory and returns a single string represetation -function logistica.deserliaze_inventory(list) - +-- takes a inventory serialized string and returns a table +function logistica.deserialize_inv(serializedInv) + local strTable = minetest.deserialize(serializedInv) + if not strTable then return {} end + local liveTable = {} + for name, listStrTable in pairs(strTable) do + liveTable[name] = logistica.table_to_inv_list(listStrTable) + end + return liveTable end diff --git a/logic/supplier.lua b/logic/supplier.lua new file mode 100644 index 0000000..d05a6d1 --- /dev/null +++ b/logic/supplier.lua @@ -0,0 +1,38 @@ + +local p2h = minetest.hash_node_position +local h2p = minetest.get_position_from_hash + +-- attempts to insert the given itemstack in the network, returns how many items were inserted +function logistica.insert_item_in_network(itemstack, networkId) + local network = logistica.networks[networkId] + if not itemstack or not network then return 0 end + + local workingStack = ItemStack(itemstack) + -- check demanders first + for hash, _ in pairs(network.demanders) do + local pos = h2p(hash) + logistica.load_position(pos) + local taken = 0 -- logistica.try_to_give_item_to_demander(pos, workingStack) + local leftover = workingStack:get_count() - taken + if leftover <= 0 then return itemstack:get_count() end -- we took all items + workingStack:set_count(leftover) + end + + -- check storages + local storages = {} + if itemstack:get_stack_max() <= 1 then + storages = network.item_storage + else + storages = network.mass_storage + end + for hash, _ in pairs(storages) do + local pos = h2p(hash) + logistica.load_position(pos) + local taken = logistica.try_to_add_item_to_storage(pos, workingStack) + local leftover = workingStack:get_count() - taken + if leftover <= 0 then return itemstack:get_count() end -- we took all items + workingStack:set_count(leftover) + end + + return itemstack:get_count() - workingStack:get_count() +end diff --git a/textures/logistica_formspec_background.png b/textures/logistica_formspec_background.png index 3c339f6..c7a31a3 100644 Binary files a/textures/logistica_formspec_background.png and b/textures/logistica_formspec_background.png differ diff --git a/util/ui.lua b/util/ui.lua index 2f8ff8f..9c763be 100644 --- a/util/ui.lua +++ b/util/ui.lua @@ -1,3 +1,3 @@ logistica.ui = {} -logistica.ui.background = "bgcolor[#0000]background9[0,0;1,1;logistica_formspec_background.png;true;4]" \ No newline at end of file +logistica.ui.background = "no_prepend[]bgcolor[#0000]background9[0,0;1,1;logistica_formspec_background.png;true;8]" \ No newline at end of file