distribution algorithm reviced

This commit is contained in:
Joachim Stolberg 2018-08-19 21:30:04 +02:00
parent b72b703dfc
commit 37ab82b371

@ -20,34 +20,6 @@ local CYCLE_TIME = 2
local STOP_STATE = 0 local STOP_STATE = 0
local STANDBY_STATE = -1 local STANDBY_STATE = -1
-- Get one item-stack from the given ItemList, specified by stack number (1..n).
-- Returns nil if ItemList is empty.
local function get_this_stack(meta, listname, number)
if meta == nil or meta.get_inventory == nil then return nil end
local inv = meta:get_inventory()
if inv:is_empty(listname) then
return nil
end
local items = inv:get_stack(listname, number)
if items:get_count() > 0 then
return inv:remove_item(listname, items)
end
return nil
end
-- Return a key/value table with all items and the corresponding stack numbers
local function invlist_content_as_kvlist(list)
local res = {}
for idx,items in ipairs(list) do
local name = items:get_name()
if name ~= "" then
res[name] = idx
end
end
return res
end
-- Return the total number of list entries -- Return the total number of list entries
local function invlist_num_entries(list) local function invlist_num_entries(list)
local res = 0 local res = 0
@ -75,10 +47,9 @@ local function invlist_entries_as_list(list)
return res return res
end end
local function AddToTbl(kvTbl, new_items, val)
local function AddToTbl(kvTbl, new_items)
for _, l in ipairs(new_items) do for _, l in ipairs(new_items) do
kvTbl[l] = true kvTbl[l] = val
end end
return kvTbl return kvTbl
end end
@ -139,6 +110,7 @@ local function allow_metadata_inventory_move(pos, from_list, from_index, to_list
return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
end end
local Side2Color = {B="red", L="green", F="blue", R="yellow"}
local SlotColors = {"red", "green", "blue", "yellow"} local SlotColors = {"red", "green", "blue", "yellow"}
local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation local Num2Ascii = {"B", "L", "F", "R"} -- color to side translation
local FilterCache = {} -- local cache for filter settings local FilterCache = {} -- local cache for filter settings
@ -148,8 +120,8 @@ local function filter_settings(pos)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false} local filter = minetest.deserialize(meta:get_string("filter")) or {false,false,false,false}
local kvFilterItemNames = {} -- {<item:name> = true,...} local kvFilterItemNames = {} -- {<item:name> = side,...}
local kvSide2ItemNames = {} -- {"F" = {<item:name>,...},...} local kvOpenPorts = {} -- {side = true, ...}
-- collect all filter settings -- collect all filter settings
for idx,slot in ipairs(SlotColors) do for idx,slot in ipairs(SlotColors) do
@ -157,14 +129,16 @@ local function filter_settings(pos)
if filter[idx] == true then if filter[idx] == true then
local list = inv:get_list(slot) local list = inv:get_list(slot)
local filter = invlist_entries_as_list(list) local filter = invlist_entries_as_list(list)
AddToTbl(kvFilterItemNames, filter) AddToTbl(kvFilterItemNames, filter, side)
kvSide2ItemNames[side] = filter if not next(filter) then
kvOpenPorts[side] = true
end
end end
end end
FilterCache[hash] = { FilterCache[hash] = {
kvFilterItemNames = kvFilterItemNames, kvFilterItemNames = kvFilterItemNames,
kvSide2ItemNames = kvSide2ItemNames kvOpenPorts = kvOpenPorts,
} }
end end
@ -215,14 +189,6 @@ local function keep_running(pos, elapsed)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local running = meta:get_int("running") - 1 local running = meta:get_int("running") - 1
local player_name = meta:get_string("player_name") local player_name = meta:get_string("player_name")
--print("running", running)
local slot_idx = meta:get_int("slot_idx") or 1
meta:set_int("slot_idx", (slot_idx + 1) % NUM_FILTER_SLOTS)
local side = Num2Ascii[slot_idx+1]
local listname = SlotColors[slot_idx+1]
local inv = meta:get_inventory()
local list = inv:get_list("src")
local kvSrc = invlist_content_as_kvlist(list)
local counter = minetest.deserialize(meta:get_string("item_counter")) or local counter = minetest.deserialize(meta:get_string("item_counter")) or
{red=0, green=0, blue=0, yellow=0} {red=0, green=0, blue=0, yellow=0}
@ -233,50 +199,58 @@ local function keep_running(pos, elapsed)
end end
-- read data from Cache -- read data from Cache
-- all filter items as key/value {<item:name> = true,...}
local kvFilterItemNames = FilterCache[hash].kvFilterItemNames local kvFilterItemNames = FilterCache[hash].kvFilterItemNames
-- filter items of one slot as list {<item:name>,...} local open_ports = table.copy(FilterCache[hash].kvOpenPorts)
local names = FilterCache[hash].kvSide2ItemNames[side]
if names == nil then -- no filter configured?
-- this slot is empty if next(kvFilterItemNames) == nil then
return true return true
end end
local busy = false local busy = false
-- move items from configured filters to the output local unused_outputs = {B=true, L=true, F=true, R=true}
if next(names) then
for _,name in ipairs(names) do local inv = meta:get_inventory()
if kvSrc[name] then local list = inv:get_list("src")
local item = get_this_stack(meta, "src", kvSrc[name]) for _,stack in ipairs(list) do
if item then if stack:get_count() > 0 then
if not tubelib.push_items(pos, side, item, player_name) then local name = stack:get_name()
tubelib.put_item(meta, "src", item) local second_try = false
else
counter[listname] = counter[listname] + 1 -- try configured output ports
local side = kvFilterItemNames[name]
if side then -- configured
if unused_outputs[side] then
if tubelib.push_items(pos, side, stack, player_name) then
stack:set_count(0)
unused_outputs[side] = false
local color = Side2Color[side]
counter[color] = counter[color] + 1
busy = true busy = true
else
second_try = true -- port blocked
end end
end end
end else
end second_try = true -- not configured
end end
-- move additional items from unconfigured filters to the output -- try unconfigured open output ports
if next(names) == nil then if second_try then
for name,_ in pairs(kvSrc) do side,_ = next(open_ports)
if kvFilterItemNames[name] == nil then -- not in the filter so far? if side then
local item = get_this_stack(meta, "src", kvSrc[name]) if tubelib.push_items(pos, side, stack, player_name) then
if item then stack:set_count(0)
if not tubelib.push_items(pos, side, item, player_name) then open_ports[side] = nil
tubelib.put_item(meta, "src", item) local color = Side2Color[side]
else counter[color] = counter[color] + 1
counter[listname] = counter[listname] + 1
busy = true busy = true
end end
end end
end end
end end
end end
inv:set_list("src", list)
if busy == true then if busy == true then
if running <= 0 then if running <= 0 then