diff --git a/oregen-manager.lua b/oregen-manager.lua new file mode 100644 index 0000000..55fda20 --- /dev/null +++ b/oregen-manager.lua @@ -0,0 +1,390 @@ +-- Manages an oregen facility + +local STOCK_TICKER = "" +local EXPORT_STORAGE = "" +local SPEEDOMETER = "" + +local CRUSHER_ADDR = "Crusher" +local MELTER_ADDR = "Melter" +local MIXER_ADDR = "Mixer" +local WASHER_ADDR = "Washer" +local SMELTER_ADDR = "Smelter" +local HAUNTER_ADDR = "Haunter" +local PRESS_ADDR = "Press" +local EXPORT_ADDR = "Output" +-- Packages sent here leave the oregen system and go to main storage. +-- Helps keep slots freed up in oregen storage +local MAIN_STORAGE_ADDR = "Main Storage" + +-- amount to keep in EXPORT_STORAGE +local KEEP_STOCKED = { + ["minecraft:iron_nugget"] = 4 * 64, + ["minecraft:gold_nugget"] = 4 * 64, + ["create:zinc_nugget"] = 4 * 64, + ["create:copper_nugget"] = 4 * 64, + ["minecraft:netherrack"] = 4 * 64, + ["create:cinder_flour"] = 0, + ["minecraft:gravel"] = 0, + ["minecraft:netherite_scrap"] = 4, + ["minecraft:nether_bricks"] = 0, + ["oreganized:silver_nugget"] = 4 * 64, + ["tfmg:nickel_nugget"] = 4 * 64, + ["tfmg:bauxite_powder"] = 4 * 64, + ["minecraft:flint"] = 0, + ["minecraft:andesite"] = 4 * 64, + ["minecraft:clay_ball"] = 4 * 64, + ["minecraft:wither_skeleton_skull"] = 4, +} + +local GLOBAL_LIMS = { + lower = 6 * 64, + upper = 10 * 64, +} + +local LIMIT_EXCEPTIONS = { + ["create:cinder_flour"] = { + lower = 64, + upper = 2 * 64, + }, + ["minecraft:gravel"] = { + lower = 10 * 64, + upper = 20 * 64, + }, + ["minecraft:netherite_scrap"] = { + lower = 0, + upper = 4, + }, + ["minecraft:flint"] = { + lower = 64, + upper = 2 * 64, + }, + ["minecraft:andesite"] = { + lower = 0, + upper = 2 * 64, + }, + ["minecraft:clay_ball"] = { + lower = 0, + upper = 4 * 64, + }, + ["minecraft:wither_skeleton_skull"] = { + lower = 0, + upper = 4, + }, +} + +-- if these exist, they will be used up +-- "limit" is the limit on the amt sent at a time (default is 64) +-- "keep" is the amount not to use up (default is 0) +local PRODUCTS = { + {"create:crimsite", CRUSHER_ADDR}, + {"create:crushed_raw_iron", MELTER_ADDR}, + {"create:crushed_raw_zinc", MELTER_ADDR}, + {"create:asurine", CRUSHER_ADDR}, + {"create:crushed_raw_copper", MELTER_ADDR}, + {"create:veridium", CRUSHER_ADDR, limit = 32}, + {"create:ochrum", CRUSHER_ADDR}, + {"create:crushed_raw_gold", MELTER_ADDR}, + {"minecraft:sand", WASHER_ADDR}, + {"minecraft:clay_ball", SMELTER_ADDR, keep = 4 * 64}, + {"minecraft:brick", HAUNTER_ADDR}, + {"minecraft:flint", CRUSHER_ADDR, keep = 4 * 64}, + {"minecraft:nether_bricks", CRUSHER_ADDR}, + {"minecraft:basalt", CRUSHER_ADDR}, + {"create:crushed_raw_silver", WASHER_ADDR, limit = 16}, + {"minecraft:calcite", CRUSHER_ADDR}, + {"create:crushed_raw_nickel", WASHER_ADDR, limit = 32}, + {"tfmg:bauxite", CRUSHER_ADDR}, + {"tfmg:lithium_nugget", MAIN_STORAGE_ADDR}, + {"minecraft:iron_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"minecraft:gold_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"create:copper_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"create:zinc_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"tfmg:nickel_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"oreganized:silver_nugget", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"minecraft:netherrack", MAIN_STORAGE_ADDR, keep = 16 * 64, limit = 4 * 64}, + {"minecraft:blackstone", CRUSHER_ADDR}, +} + +-- these will be crafted when needed +local RECIPES = { + ["minecraft:gravel"] = { + ingredients = { + {"minecraft:cobblestone", 2 * 64}, + }, + addr = CRUSHER_ADDR, + limit = 6, + }, + ["minecraft:iron_nugget"] = { + ingredients = { + {"minecraft:iron_nugget", 60}, + {"minecraft:gravel", 24}, + }, + addr = PRESS_ADDR, + }, + ["minecraft:gold_nugget"] = { + ingredients = { + {"minecraft:gold_nugget", 64}, + {"minecraft:gravel", 64}, + }, + addr = PRESS_ADDR, + }, + ["create:zinc_nugget"] = { + ingredients = { + {"create:zinc_nugget", 64}, + {"minecraft:gravel", 32}, + }, + addr = PRESS_ADDR, + }, + ["create:copper_nugget"] = { + ingredients = { + {"create:copper_nugget", 63}, + {"minecraft:gravel", 18}, + }, + addr = PRESS_ADDR, + }, + ["minecraft:netherrack"] = { + ingredients = { + {"create:cinder_flour", 64}, + {"minecraft:cobblestone", 64}, + }, + addr = MIXER_ADDR, + }, + ["create:cinder_flour"] = { + ingredients = { + {"minecraft:netherrack", 64} + }, + addr = CRUSHER_ADDR, + }, + ["minecraft:netherite_scrap"] = { + ingredients = { + {"minecraft:gravel", 2 * 64}, + }, + addr = CRUSHER_ADDR, + limit = 6, + }, + ["minecraft:nether_bricks"] = { + ingredients = { + {"minecraft:nether_brick", 64}, + }, + addr = PRESS_ADDR, + }, + ["oreganized:silver_nugget"] = { + ingredients = { + {"oreganized:silver_nugget", 60}, + {"minecraft:gravel", 24}, + }, + addr = PRESS_ADDR, + }, + ["tfmg:nickel_nugget"] = { + ingredients = { + {"tfmg:nickel_nugget", 64}, + {"minecraft:gravel", 64}, + }, + addr = PRESS_ADDR, + }, + ["tfmg:bauxite_powder"] = { + ingredients = { + {"tfmg:bauxite_powder", 64}, + {"minecraft:gravel", 64}, + }, + addr = PRESS_ADDR, + limit = 6, + }, + ["minecraft:flint"] = { + ingredients = { + {"minecraft:gravel", 64}, + }, + addr = WASHER_ADDR, + limit = 8, + }, + ["minecraft:andesite"] = { + ingredients = { + {"minecraft:flint", 64}, + {"minecraft:gravel", 32}, + }, + addr = PRESS_ADDR, + limit = 6, + }, + ["minecraft:clay_ball"] = { + ingredients = { + {"minecraft:gravel", 2 * 64}, + }, + addr = CRUSHER_ADDR, + limit = 6, + }, + ["minecraft:wither_skeleton_skull"] = { + ingredients = { + {"minecraft:cobblestone", 2 * 64}, + }, + addr = HAUNTER_ADDR, + limit = 6, + }, +} + +local SLEEP_T = 20 + +function createModes (items) + local result = {} + for item, _ in pairs(items) do + result[item] = {"export", 0} + end + return result +end + +function updateModes (current_modes, current_stock, first_run) + local lower_lim, upper_lim + local limits = {} + for item, _ in pairs(current_modes) do + if LIMIT_EXCEPTIONS[item] ~= nil then + lower_lim = LIMIT_EXCEPTIONS[item].lower + upper_lim = LIMIT_EXCEPTIONS[item].upper + else + lower_lim = GLOBAL_LIMS.lower + upper_lim = GLOBAL_LIMS.upper + end + limits[item] = { + lower = lower_lim, + upper = upper_lim, + } + end + for item, limits in pairs(limits) do + local count = current_stock[item] + if count == nil then count = 0 end + if count <= limits.lower then + current_modes[item] = {"recipe"} + elseif count >= limits.upper or first_run then + current_modes[item] = { + "export", + count - limits.lower, + } + end + end +end + +function cycleItems (ticker, items) + local makeRequest + makeRequest = function (item, amt, addr, limit_override) + local limit = 64 + if addr == MELTER_ADDR then limit = 9 end + if limit_override ~= nil then limit = limit_override end + if amt < limit then return end + local request = { + name = item, + _requestCount = limit + } + ticker.requestFiltered(addr, request) + os.sleep(1) + return makeRequest(item, amt - limit, addr, limit_override) + end + for _, pair in pairs(PRODUCTS) do + local name, addr, limit, keep = pair[1], pair[2], pair.limit, pair.keep + if items[name] ~= nil then + local amt = items[name] + if keep ~= nil then amt = amt - keep end + if amt < 0 then amt = 0 end + makeRequest(name, amt, addr, limit) + end + end +end + +function getAmounts (storage_f) + local result = {} + for _, item in pairs(storage_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 getNumCraftable (ingredients, current_stock) + local result = nil + local item, count + for _, ingredient in ipairs(ingredients) do + item, count = ingredient[1], ingredient[2] + if current_stock[item] == nil then return 0 end + local num = math.floor(current_stock[item] / count) + if result == nil then + result = num + else + result = math.min(result, num) + end + end + if result == nil then result = 0 end + return result +end + +function adjustStock (current_stock, ingredients, count) + if count == 0 then return end + local item, i_count + for _, ingredient in ipairs(ingredients) do + item, i_count = ingredient[1], ingredient[2] + current_stock[item] = current_stock[item] - (i_count * count) + end +end + +function craftRecipe (ticker, recipe, current_stock) + local count = getNumCraftable(recipe.ingredients, current_stock) + if recipe.limit ~= nil then + count = math.min(count, recipe.limit) + end + adjustStock(current_stock, recipe.ingredients, count) + local createRequest + createRequest = function (recipe, i) + if i == nil then i = 1 end + local ingredient = recipe.ingredients[i] + if ingredient == nil then return end + local item = { + name = ingredient[1], + _requestCount = ingredient[2], + } + return item, createRequest(recipe, i + 1) + end + while count > 0 do + ticker.requestFiltered(recipe.addr, createRequest(recipe)) + os.sleep(1) + count = count - 1 + end +end + +function export (ticker, item, amt) + if amt <= 0 then return end + local request = { + name = item, + _requestCount = amt + } + ticker.requestFiltered(EXPORT_ADDR, request) +end + +function run (ticker, export_storage, current_modes, first_run) + if SPEEDOMETER ~= "" and peripheral.call(SPEEDOMETER, "getSpeed") == 0 then + os.sleep(SLEEP_T) + return run (ticker, export_storage, current_modes, first_run) + end + local export_amounts = getAmounts(export_storage.list) + local stock_amounts = getAmounts(ticker.stock) + updateModes(current_modes, stock_amounts, first_run) + for item, mode in pairs(current_modes) do + -- mode[1] is mode, mode[2] is amt_extra when exporting + if mode[1] == "recipe" then + -- make as many recipes as you can with current stock + local recipe = RECIPES[item] + craftRecipe(ticker, recipe, stock_amounts) + elseif mode[1] == "export" then + local export_amt = export_amounts[item] + if export_amt == nil then export_amt = 0 end + local amt_needed = KEEP_STOCKED[item] - export_amt + local amt = math.min(amt_needed, mode[2]) + export(ticker, item, amt) + end + end + cycleItems(ticker, stock_amounts) + os.sleep(SLEEP_T) + return run (ticker, export_storage, current_modes) +end + +if arg ~= nil and arg[1] == "run" then + local ticker = peripheral.wrap(STOCK_TICKER) + local export_storage = peripheral.wrap(EXPORT_STORAGE) + local current_modes = createModes(KEEP_STOCKED) + run(ticker, export_storage, current_modes, true) +end