-- Program to control a compacting storage made with create. -- NOTE: set block -> ingot refresh amount higher than the level desired in -- this program to prioritize using available resources before generating -- new ones -- constants local MAIN_TICKER = "" local REQUEST_TICKER = "" local CRAFTING_REQUESTER = "" local STORAGE_ADDR = "" local COMPACTING_ADDR = "" local UNPACKING_ADDR = "" local SLEEP_TIME = 30 local NUGGET_RATIO = 63 -- amount of nuggets per craft local BLOCK_RATIO = 7 -- amount of blocks per craft local ITEM_TYPES = { iron = { nugget = "minecraft", ingot = "minecraft", block = "minecraft", }, copper = { nugget = "create", ingot = "minecraft", block = "minecraft", }, zinc = { nugget = "create", ingot = "create", block = "create", }, gold = { nugget = "minecraft", ingot = "minecraft", block = "minecraft", }, electrum = { nugget = "createaddition", ingot = "createaddition", block = "createaddition", }, } local STACKS = 64 local NUGGETS = 1 local INGOTS = 9 local BLOCKS = 81 -- Levels local MIN_NUM = (4 * STACKS * NUGGETS) + (4 * STACKS * INGOTS) local MAX_NUM = (8 * STACKS * NUGGETS) + (8 * STACKS * INGOTS) local getName = { nugget = function (item_type) return ("%s:%s_nugget"):format( ITEM_TYPES[item_type].nugget, item_type ) end, ingot = function (item_type) return ("%s:%s_ingot"):format( ITEM_TYPES[item_type].ingot, item_type ) end, block = function (item_type) return ("%s:%s_block"):format( ITEM_TYPES[item_type].block, item_type ) end, } -- basic actions function craft (requester, item_type, conversion_type) -- conversion_type key: 1, nuggets to ingots; 2, ingots to blocks; -- 3, blocks to ingots; 4, ingots to nuggets local convert = { getName.nugget, getName.ingot, getName.block, getName.ingot, } local name = convert[conversion_type](item_type) local compacting = conversion_type <= 2 local count, address if compacting then count = NUGGET_RATIO address = COMPACTING_ADDR else count = BLOCK_RATIO address = UNPACKING_ADDR end requester.setAddress(address) requester.setRequest({ name = name, count = count }) requester.request() end function craft_multiple (requester, item_type, conversion_type, count) if count < 1 then return else craft(requester, item_type, conversion_type) os.sleep(1) return craft_multiple(requester, item_type, conversion_type, count - 1) end end function execute_crafts (requester, item_type, crafts) local num_crafts = crafts.nugget if num_crafts > 0 then print(("Crafting %s nuggets"):format(item_type)) craft_multiple(requester, item_type, 4, num_crafts) elseif num_crafts < 0 then print(("Crafting %s ingots"):format(item_type)) craft_multiple(requester, item_type, 1, -num_crafts) end num_crafts = crafts.block if num_crafts > 0 then print(("Crafting %s blocks"):format(item_type)) craft_multiple(requester, item_type, 2, num_crafts) elseif num_crafts < 0 then print(("Crafting %s ingots"):format(item_type)) craft_multiple(requester, item_type, 3, -num_crafts) end end function request_more (ticker, item_type) ticker.requestFiltered(STORAGE_ADDR, { name = getName.nugget(item_type) }) end -- logic function sum_items (inv_f) local result = {} for _, item in pairs(inv_f()) do if result[item.name] == nil then result[item.name] = 0 end result[item.name] = result[item.name] + item.count end return result end function dist_to_num (dist) return dist.nugget + (dist.ingot * INGOTS) + (dist.block * BLOCKS) end function get_dist (item_type, items) local dist = { nugget = 0, ingot = 0, block = 0 } for item, count in pairs(items) do local type, form = item:match":(%l-)_(%l*)" if type == item_type and dist[form] ~= nil then dist[form] = dist[form] + count end end return dist end function decide_dist (num) local dist = { nugget = 0, ingot = 0, block = 0 } if num > MAX_NUM then local excess = num - MAX_NUM dist.block = math.floor(excess / BLOCKS) num = num - (dist.block * BLOCKS) end local balance = math.floor(num / 10) dist.nugget, dist.ingot = balance, balance num = num - (balance * 10) dist.nugget = dist.nugget + num return dist end function get_diff (dist1, dist2) return { nugget = dist1.nugget - dist2.nugget, ingot = dist1.ingot - dist2.ingot, block = dist1.block - dist2.block } end function filter_clamp (diff, current_dist) -- reduce diff numbers to what can be crafted using current resources if diff.block > 0 then diff.block = math.min( diff.block - (diff.block % BLOCK_RATIO), math.floor(current_dist.ingot / 9) ) end if diff.nugget > 0 then diff.nugget = math.min( diff.nugget - (diff.nugget % NUGGET_RATIO), current_dist.ingot * 9 ) end diff.ingot = (-diff.nugget / 9) + (-diff.block * 9) return diff end function diff_to_crafts (diff) -- go from one end e.g. nuggets to the other e.g. blocks, removing -- from the diff to create crafts until the diff is empty local crafts = {} crafts.nugget = math.floor(diff.nugget / NUGGET_RATIO) crafts.block = math.floor(diff.block / BLOCK_RATIO) return crafts end function print_counts (items) for item, amount in pairs(items) do local type, form = string.match(item, ":(%l+)_(%l+)") if type ~= nil and form ~= nil then print(("%s %s: %d"):format(type, form, amount)) end end end local main_t = peripheral.wrap(MAIN_TICKER) local request_t = peripheral.wrap(REQUEST_TICKER) local craft_requester = peripheral.wrap(CRAFTING_REQUESTER) craft_requester.setConfiguration("strict") local requesting = {} while true do -- 1. Sum items in inventory and organize by item type local items = sum_items(main_t.stock) -- print_counts(items) -- 2. either work towards a desired distribution or create more resources for item_type, _ in pairs(ITEM_TYPES) do local current_dist = get_dist(item_type, items) local num = dist_to_num(current_dist) if num > MIN_NUM then local desired_dist = decide_dist(num) local diff = get_diff(desired_dist, current_dist) diff = filter_clamp(diff, current_dist) local crafts = diff_to_crafts(diff) execute_crafts(craft_requester, item_type, crafts) else requesting[item_type] = true end if num > MAX_NUM then -- keep requesting until above MAX_NUM requesting[item_type] = false end if requesting[item_type] then request_more(request_t, item_type) end end -- sleep until next cycle os.sleep(SLEEP_TIME) end