diff --git a/api/controller.lua b/api/controller.lua index 4e9ef54..de9de65 100644 --- a/api/controller.lua +++ b/api/controller.lua @@ -12,8 +12,6 @@ local function get_controller_formspec(pos) "button[5.6,0.6;3,0.8;"..SET_BUTTON..";Set]" end - - local function show_controller_formspec(pos, playerName) local pInfo = {} pInfo.position = pos @@ -37,7 +35,12 @@ local function on_controller_receive_fields(player, formname, fields) return true end +local function after_controller_place(pos) + logistica.start_controller_timer(pos) +end + -- registration stuff + minetest.register_on_player_receive_fields(on_controller_receive_fields) --[[ @@ -52,7 +55,7 @@ minetest.register_on_player_receive_fields(on_controller_receive_fields) tier may be `nil` which will result in the controller connecting to everything ]] -function logistica.register_controller(simpleName, def, tier) +function logistica.register_controller(name, def, tier) local controller_group = nil if not tier then tier = logistica.TIER_ALL @@ -62,7 +65,7 @@ function logistica.register_controller(simpleName, def, tier) logistica.tiers[ltier] = true controller_group = logistica.get_machine_group(ltier) end - local controller_name = "logistica:" .. string.lower(simpleName:gsub(" ", "_")) .. "_controller" + local controller_name = "logistica:" .. string.lower(name:gsub(" ", "_")) logistica.controllers[controller_name] = tier local on_construct = function(pos) @@ -70,15 +73,16 @@ function logistica.register_controller(simpleName, def, tier) logistica.on_controller_change(pos, nil) end local after_destruct = logistica.on_controller_change - local on_timer = logistica.on_controller_timer if not def.groups then def.groups = {} end def.groups[controller_group] = 1 + def.groups[logistica.TIER_CONTROLLER] = 1 + def.on_timer = logistica.on_controller_timer def.on_construct = on_construct def.after_destruct = after_destruct - def.on_timer = logistica.on_timer_powered(on_timer) + def.after_place_node = after_controller_place def.drop = controller_name def.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) if clicker and clicker:is_player() then @@ -101,7 +105,7 @@ function logistica.register_controller(simpleName, def, tier) minetest.register_node(controller_name.."_disabled", def_disabled) end -logistica.register_controller("Simple Controller", { +logistica.register_controller("simple_controller", { description = "Simple Controller", tiles = { "logistica_silver_cable.png" }, groups = { diff --git a/api/supplier.lua b/api/supplier.lua index cf7b126..b41c21c 100644 --- a/api/supplier.lua +++ b/api/supplier.lua @@ -1,24 +1,21 @@ -local NUM_SUPPLY_SLOTS = 8 -local PULL_LIST_PICKER = "pull_pick" -local ON_OFF_BUTTON = "on_off_btn" local FORMSPEC_NAME = "logistica_supplier" +local ON_OFF_BUTTON = "on_off_btn" local supplierForms = {} local function get_supplier_formspec(pos) local posForm = "nodemeta:"..pos.x..","..pos.y..","..pos.z - local pushPos = logistica.get_supplier_target(pos) - local selectedList = logistica.get_supplier_target_list(pos) local isOn = logistica.is_machine_on(pos) + return "formspec_version[4]" .. - "size[10.6,8]" .. + "size[10.5,12]" .. logistica.ui.background.. - logistica.ui.pull_list_picker(PULL_LIST_PICKER, 6.7, 0.7, pushPos, selectedList, "Supply from:").. - logistica.ui.on_off_btn(isOn, 9.3, 0.5, ON_OFF_BUTTON, "Enable").. - "label[0.6,1.2;Items to make available as Supply. If left empty, nothing is supplied]".. - "list["..posForm..";filter;0.5,1.5;"..NUM_SUPPLY_SLOTS..",1;0]".. - "list[current_player;main;0.5,3;8,4;0]" + logistica.ui.on_off_btn(isOn, 9.0, 0.3, ON_OFF_BUTTON, "Enable").. + "label[0.6,1.0;Passive Supplier: Items become available to network requests.]".. + "list["..posForm..";main;0.4,1.4;8,4;0]".. + "list[current_player;main;0.4,7.0;8,4;0]".. + "listring[]" end local function show_supplier_formspec(playerName, pos) @@ -40,13 +37,6 @@ local function on_player_receive_fields(player, formname, fields) if not pos then return false end logistica.toggle_machine_on_off(pos) show_supplier_formspec(player:get_player_name(), pos) - elseif fields[PULL_LIST_PICKER] then - local selected = fields[PULL_LIST_PICKER] - if logistica.is_allowed_pull_list(selected) then - local pos = supplierForms[playerName].position - if not pos then return false end - logistica.set_supplier_target_list(pos, selected) - end end return true end @@ -56,40 +46,32 @@ local function on_supplier_rightclick(pos, node, clicker, itemstack, pointed_thi show_supplier_formspec(clicker:get_player_name(), pos) end -local function after_place_supplier(pos, placer, itemstack, numRequestSlots) +local function after_place_supplier(pos, placer, itemstack) local meta = minetest.get_meta(pos) - if placer and placer:is_player() then - meta:set_string("owner", placer:get_player_name()) - end - logistica.toggle_machine_on_off(pos) - logistica.set_supplier_target_list(pos, "dst") local inv = meta:get_inventory() - inv:set_size("filter", numRequestSlots) + inv:set_size("main", logistica.get_supplier_inv_size(pos)) + logistica.set_node_tooltip_from_state(pos) logistica.on_supplier_change(pos) end local function allow_supplier_storage_inv_put(pos, listname, index, stack, player) - if listname ~= "filter" then return 0 end - local inv = minetest.get_meta(pos):get_inventory() - local newStack = ItemStack(stack) - newStack:set_count(1) - inv:set_stack(listname, index, newStack) - logistica.update_cache_at_pos(pos, LOG_CACHE_SUPPLIER) - return 0 + return stack:get_count() end local function allow_supplier_inv_take(pos, listname, index, stack, player) - if listname ~= "filter" then return 0 end - local inv = minetest.get_meta(pos):get_inventory() - local slotStack = inv:get_stack(listname, index) - slotStack:take_item(stack:get_count()) - inv:set_stack(listname, index, slotStack) - logistica.update_cache_at_pos(pos, LOG_CACHE_SUPPLIER) - return 0 + return stack:get_count() end local function allow_supplier_inv_move(pos, from_list, from_index, to_list, to_index, count, player) - return 0 + return count +end + +local function on_suppler_inventory_put(pos, listname, index, stack, player) + logistica.update_cache_at_pos(pos, LOG_CACHE_SUPPLIER) +end + +local function on_suppler_inventory_take(pos, listname, index, stack, player) + logistica.update_cache_at_pos(pos, LOG_CACHE_SUPPLIER) end ---------------------------------------------------------------- @@ -102,41 +84,34 @@ minetest.register_on_player_receive_fields(on_player_receive_fields) -- Public Registration API ---------------------------------------------------------------- -- `simpleName` is used for the description and for the name (can contain spaces) --- `maxTransferRate` indicates how many nodes at a time this supplier can take when asked -function logistica.register_supplier(simpleName, maxTransferRate) - local lname = string.lower(simpleName:gsub(" ", "_")) - local supplier_name = "logistica:supplier_"..lname +-- `inventorySize` should be 32 at max (aka regular chest) +function logistica.register_supplier(desc, name, inventorySize, tiles) + local lname = string.lower(name:gsub(" ", "_")) + local supplier_name = "logistica:passive_supplier_"..lname logistica.suppliers[supplier_name] = true local grps = {oddly_breakable_by_hand = 3, cracky = 3 } grps[logistica.TIER_ALL] = 1 local def = { - description = simpleName.." Supplier", + description = desc, drawtype = "normal", - tiles = { - "logistica_"..lname.."_supplier_side.png^[transformR270", - "logistica_"..lname.."_supplier_side.png^[transformR90", - "logistica_"..lname.."_supplier_side.png^[transformR180", - "logistica_"..lname.."_supplier_side.png", - "logistica_"..lname.."_supplier_back.png", - "logistica_"..lname.."_supplier_front.png", - }, + tiles = tiles, paramtype = "light", paramtype2 = "facedir", is_ground_content = false, groups = grps, drop = supplier_name, sounds = logistica.node_sound_metallic(), - after_place_node = function (pos, placer, itemstack) - after_place_supplier(pos, placer, itemstack, NUM_SUPPLY_SLOTS) - end, + after_place_node = after_place_supplier, after_destruct = logistica.on_supplier_change, on_rightclick = on_supplier_rightclick, allow_metadata_inventory_put = allow_supplier_storage_inv_put, allow_metadata_inventory_take = allow_supplier_inv_take, allow_metadata_inventory_move = allow_supplier_inv_move, + on_metadata_inventory_put = on_suppler_inventory_put, + on_metadata_inventory_take = on_suppler_inventory_take, logistica = { - supplier_transfer_rate = maxTransferRate, - on_power = function() end, -- necessary for power toggle to work + inventory_size = inventorySize, + on_power = function(pos, power) logistica.set_node_tooltip_from_state(pos, nil, power) end } } @@ -159,5 +134,11 @@ function logistica.register_supplier(simpleName, maxTransferRate) end -logistica.register_supplier("Item", 1) -logistica.register_supplier("Stack", 99) +logistica.register_supplier("Passive Supplier", "simple", 32, { + "logistica_passive_supplier_top.png", + "logistica_passive_supplier_bottom.png", + "logistica_passive_supplier_side.png^[transformFX", + "logistica_passive_supplier_side.png", + "logistica_passive_supplier_side.png", + "logistica_passive_supplier_front.png", +}) -- default supplier diff --git a/logic/controller.lua b/logic/controller.lua index 7790e05..ce1dbaf 100644 --- a/logic/controller.lua +++ b/logic/controller.lua @@ -1,42 +1,19 @@ ---[[ -Outline of controller tick/s: -1. Gather request from each requester, add them to queue - - smart queue needed, unify request per requester -2. For the first N requests, check each supplier and if applicable fulfil request -3. Gather all storage slots - - cached, hopefully -4. For each storage slot, check each supplier, and pull up to S items per slot into storage -]] -local TIMER_DURATION_SHORT = 0.5 -local TIMER_DURATION_LONG = 2.0 +local TIMER_DURATION_LONG = 5 function logistica.start_controller_timer(pos, duration) if duration == nil then duration = TIMER_DURATION_LONG end - local timer = minetest.get_node_timer(pos) - timer:start(duration) + logistica.start_node_timer(pos, duration) end function logistica.on_controller_timer(pos, elapsed) - if pos then return false end -- - local node = minetest.get_node(pos) - if not node then return false end -- what? - if node.name:find("_disabled") then return false end -- disabled controllers don't do anything - - local had_demand = false + local node = minetest.get_node_or_nil(pos) + if not node then return true end -- what? + if not logistica.is_controller(node.name) then return false end local network = logistica.get_network_or_nil(pos) if not network then - logistica.on_controller_change(pos, nil) -- this should re-scan the network + logistica.on_controller_change(pos) -- this should re-scan the network end - network = logistica.get_network_or_nil(pos) - if not network then return true end -- something went wrong, retry again - - if had_demand then - logistica.start_controller_timer(pos, TIMER_DURATION_SHORT) - else - logistica.start_controller_timer(pos, TIMER_DURATION_LONG) - end - - return false + return true end diff --git a/logic/groups.lua b/logic/groups.lua index 78076d2..039f0bd 100644 --- a/logic/groups.lua +++ b/logic/groups.lua @@ -10,6 +10,7 @@ logistica.item_storage = {} logistica.tiers = {} logistica.TIER_ALL = "logistica_all_tiers" logistica.GROUP_ALL = "group:" .. logistica.TIER_ALL +logistica.TIER_CONTROLLER = "controller" function logistica.get_cable_group(tier) return "logistica_" .. tier .. "_cable" diff --git a/logic/injector.lua b/logic/injector.lua index be7de2e..c241371 100644 --- a/logic/injector.lua +++ b/logic/injector.lua @@ -38,12 +38,9 @@ function logistica.start_injector_timer(pos) end function logistica.on_injector_timer(pos, elapsed) + if not logistica.is_machine_on(pos) then return false end local networkId = logistica.get_network_id_or_nil(pos) - if not networkId then - logistica.toggle_machine_on_off(pos) - logistica.set_node_tooltip_from_state(pos) - return false - end + if not networkId then return false end logistica.set_node_tooltip_from_state(pos) local node = minetest.get_node_or_nil(pos) diff --git a/logic/network_cache.lua b/logic/network_cache.lua index b694b09..131a4ee 100644 --- a/logic/network_cache.lua +++ b/logic/network_cache.lua @@ -10,7 +10,7 @@ LOG_CACHE_MASS_STORAGE = { nodes = function (network) return network.mass_storage end, } LOG_CACHE_SUPPLIER = { - listName = "filter", + listName = "main", clear = function (network) network.supplier_cache = {} end, cache = function (network) return network.supplier_cache end, nodes = function (network) return network.suppliers end, @@ -38,7 +38,11 @@ end local function list_to_cache_nameset(list) local ret = {} - for i, item in ipairs(list) do ret[item:get_name()] = true end + for i, item in ipairs(list) do + if item:get_name() ~= "" then + ret[item:get_name()] = true + end + end return ret end @@ -90,10 +94,12 @@ local function update_network_cache(network, cacheOps) logistica.load_position(storagePos) local nodeMeta = get_meta(storagePos) local list = nodeMeta:get_inventory():get_list(listName) or {} - for _, itemStack in pairs(list) do + for _, itemStack in ipairs(list) do local name = itemStack:get_name() - if not cache[name] then cache[name] = {} end - cache[name][hash] = true + if name ~= "" then + if not cache[name] then cache[name] = {} end + cache[name][hash] = true + end end save_prev_cache(nodeMeta, listName, list_to_cache_nameset(list)) end @@ -112,12 +118,12 @@ local function update_network_cache_for_pos(pos, cacheOps) local cache = cacheOps.cache(network) local remAndAdd = diff(prevCacheItems, currCacheItems) for name, _ in pairs(remAndAdd[1]) do - local posCache = cache[name] - if posCache then posCache[hash] = nil end + if cache[name] then cache[name][hash] = nil end + if logistica.table_is_empty(cache[name]) then cache[name] = nil end end for name, _ in pairs(remAndAdd[2]) do - local posCache = cache[name] - if posCache then posCache[hash] = true end + if not cache[name] then cache[name] = {} end + if cache[name] then cache[name][hash] = true end end save_prev_cache(meta, listName, currCacheItems) end diff --git a/logic/network_storage.lua b/logic/network_storage.lua index b22156c..a5d3347 100644 --- a/logic/network_storage.lua +++ b/logic/network_storage.lua @@ -1,17 +1,30 @@ local MASS_STORAGE_LIST_NAME = "storage" local ITEM_STORAGE_LIST_NAME = "main" +local SUPPLIER_LIST_NAME = "main" local function get_meta(pos) logistica.load_position(pos) return minetest.get_meta(pos) end +local function updateSupplierCacheFor(supplierPosList) + for _, pos in ipairs(supplierPosList) do + logistica.update_cache_at_pos(pos, LOG_CACHE_SUPPLIER) + end +end + -- 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)`
-- note that it may be called multiple times as the itemstack is gathered from mass storage function logistica.take_stack_from_network(stackToTake, network, collectorFunc, isAutomatedRequest) + if not network then return false end + -- first check suppliers + if logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc, isAutomatedRequest) then + return + end + -- then check storages if stackToTake:get_stack_max() <= 1 then logistica.take_stack_from_item_storage(stackToTake, network, collectorFunc, isAutomatedRequest) else @@ -19,6 +32,52 @@ function logistica.take_stack_from_network(stackToTake, network, collectorFunc, end end +-- tries to take the given stack from the passive suppliers on the network +-- calls the collectorFunc with the stack when necessary +-- note that it may be called multiple times as the itemstack is gathered from mass storage +function logistica.take_stack_from_suppliers(stackToTake, network, collectorFunc, isAutomatedRequest) + local requestedAmount = stackToTake:get_count() + local remaining = requestedAmount + local stackName = stackToTake:get_name() + local validSupplers = network.supplier_cache[stackName] or {} + local modifiedPos = {} + for hash, _ in pairs(validSupplers) do + local supplierPos = minetest.get_position_from_hash(hash) + local supplierInv = get_meta(supplierPos):get_inventory() + local machineIsOn = logistica.is_machine_on(supplierPos) + local supplyList = (machineIsOn and supplierInv:get_list(SUPPLIER_LIST_NAME)) or {} + for i, supplyStack in ipairs(supplyList) do + if supplyStack:get_name() == stackName then + table.insert(modifiedPos, supplierPos) + local supplyCount = supplyStack:get_count() + if supplyCount >= remaining then -- enough to fulfil requested + local toSend = ItemStack(supplyStack) ; toSend:set_count(remaining) + local leftover = collectorFunc(toSend) + supplyStack:set_count(supplyCount - remaining + leftover) + supplierInv:set_stack(SUPPLIER_LIST_NAME, i, supplyStack) + updateSupplierCacheFor(modifiedPos) + return true + else -- not enough to fulfil requested + local toSend = ItemStack(supplyStack) + local leftover = collectorFunc(toSend) + remaining = remaining - (supplyCount - leftover) + supplyStack:set_count(leftover) + if leftover > 0 then -- for some reason we could not insert all - exit early + supplierInv:set_stack(SUPPLIER_LIST_NAME, i, supplyStack) + updateSupplierCacheFor(modifiedPos) + return true + end + end + end + end + -- if we get there, we did not fulfil the request from this supplier + -- but some items still may have been inserted + if machineIsOn then supplierInv:set_list(SUPPLIER_LIST_NAME, supplyList) end + end + updateSupplierCacheFor(modifiedPos) + return false +end + -- calls the collectorFunc with the stack - collectorFunc needs to return how many were left-over
-- `collectorFunc = function(stackToInsert)`
-- returns true if item successfully found and given to collector, false otherwise diff --git a/logic/requester.lua b/logic/requester.lua index 48ca804..69ec66c 100644 --- a/logic/requester.lua +++ b/logic/requester.lua @@ -139,12 +139,9 @@ function logistica.start_requester_timer(pos, duration) end function logistica.on_requester_timer(pos, elapsed) + if not logistica.is_machine_on(pos) then return false end local network = logistica.get_network_or_nil(pos) - if not network then - logistica.toggle_machine_on_off(pos) - logistica.set_node_tooltip_from_state(pos) - return false - end + if not network then return false end logistica.set_node_tooltip_from_state(pos) update_requester_actual_request(pos) if take_requested_items_from_network(pos, network) then diff --git a/logic/supplier.lua b/logic/supplier.lua index 8d1c7fe..459e30d 100644 --- a/logic/supplier.lua +++ b/logic/supplier.lua @@ -1,34 +1,12 @@ -local META_SUPPLIER_LISTNAME = "suptarlist" +local META_SUPPLIER_LIST = "main" -function logistica.get_supplier_target(pos) - local node = minetest.get_node_or_nil(pos) - if not node then return nil end - local shift = logistica.get_rot_directions(node.param2).backward - if not shift then return nil end - return {x = (pos.x + shift.x), - y = (pos.y + shift.y), - z = (pos.z + shift.z)} -end - -function logistica.get_supplier_target_list(pos) - logistica.load_position(pos) - local meta = minetest.get_meta(pos) - return meta:get_string(META_SUPPLIER_LISTNAME) -end - -function logistica.set_supplier_target_list(pos, listName) - logistica.load_position(pos) - local meta = minetest.get_meta(pos) - meta:set_string(META_SUPPLIER_LISTNAME, listName) -end - -function logistica.get_supplier_max_item_transfer(pos) +function logistica.get_supplier_inv_size(pos) local node = minetest.get_node_or_nil(pos) if not node then return 0 end local def = minetest.registered_nodes[node.name] - if def and def.logistica and def.logistica.supplier_transfer_rate then - return def.logistica.supplier_transfer_rate + if def and def.logistica and def.logistica.inventory_size then + return def.logistica.inventory_size else return 0 end @@ -39,15 +17,6 @@ function logistica.take_item_from_supplier(pos, stack) logistica.load_position(pos) if not logistica.is_machine_on(pos) then return ItemStack("") end local meta = minetest.get_meta(pos) - local canTake = math.min(stack:get_count(), logistica.get_supplier_max_item_transfer(pos)) - local copyStack = ItemStack(stack) - copyStack:set_count(canTake) - - local targetListName = meta:get_string(META_SUPPLIER_LISTNAME) - local targetPos = logistica.get_supplier_target(pos) - logistica.load_position(targetPos) - local targetInv = minetest.get_meta(targetPos):get_inventory() - local targetList = targetInv:get_list(targetListName) - if not targetList then copyStack:set_count(0); return copyStack end - return targetInv:remove_item(targetListName, copyStack) + local inv = meta:get_inventory() + return inv:remove_item(META_SUPPLIER_LIST, stack) end diff --git a/textures/logistica_item_supplier_back.png b/textures/logistica_item_supplier_back.png deleted file mode 100644 index 676c703..0000000 Binary files a/textures/logistica_item_supplier_back.png and /dev/null differ diff --git a/textures/logistica_item_supplier_front.png b/textures/logistica_item_supplier_front.png deleted file mode 100644 index 1c22f47..0000000 Binary files a/textures/logistica_item_supplier_front.png and /dev/null differ diff --git a/textures/logistica_item_supplier_side.png b/textures/logistica_item_supplier_side.png deleted file mode 100644 index 2a8a05b..0000000 Binary files a/textures/logistica_item_supplier_side.png and /dev/null differ diff --git a/textures/logistica_passive_supplier_bottom.png b/textures/logistica_passive_supplier_bottom.png new file mode 100644 index 0000000..4b07b22 Binary files /dev/null and b/textures/logistica_passive_supplier_bottom.png differ diff --git a/textures/logistica_passive_supplier_front.png b/textures/logistica_passive_supplier_front.png new file mode 100644 index 0000000..20d9974 Binary files /dev/null and b/textures/logistica_passive_supplier_front.png differ diff --git a/textures/logistica_passive_supplier_side.png b/textures/logistica_passive_supplier_side.png new file mode 100644 index 0000000..13e470d Binary files /dev/null and b/textures/logistica_passive_supplier_side.png differ diff --git a/textures/logistica_passive_supplier_top.png b/textures/logistica_passive_supplier_top.png new file mode 100644 index 0000000..e49d650 Binary files /dev/null and b/textures/logistica_passive_supplier_top.png differ diff --git a/util/common.lua b/util/common.lua index 7c5845d..2b41c99 100644 --- a/util/common.lua +++ b/util/common.lua @@ -99,11 +99,13 @@ function logistica.toggle_machine_on_off(pos) return nil end --- isOn is optional --- extraText is optional -function logistica.set_node_tooltip_from_state(pos, extraText) +-- `isOn` is optional +-- `extraText` is optional +-- `overrideState` is optional +function logistica.set_node_tooltip_from_state(pos, extraText, overrideState) if extraText == nil then extraText = "" else extraText = "\n"..extraText end - local isOn = logistica.is_machine_on(pos) + local isOn = overrideState + if isOn == nil then isOn = logistica.is_machine_on(pos) end logistica.load_position(pos) local meta = minetest.get_meta(pos) local node = minetest.get_node(pos) @@ -178,4 +180,8 @@ function logistica.on_timer_powered(func) return function(pos, elapsed) if logistica.is_machine_on(pos) then func(pos, elapsed) end end +end + +function logistica.table_is_empty(table) + return table == nil or (next(table) == nil) end \ No newline at end of file diff --git a/util/util.lua b/util/util.lua index fc2cf04..e267ea4 100644 --- a/util/util.lua +++ b/util/util.lua @@ -10,7 +10,7 @@ dofile(path.."/sound.lua") -- bad debug d = {} d.ttos = logistica.ttos -d.print = minetest.chat_send_all +d.log = minetest.chat_send_all function table.map(self, f) local t = {} for k,v in pairs(self) do