-- manager/config.lua — Configuration constants, data tables, and lookup structures -- Usage: local cfg = dofile(_path("manager/config.lua"))(log, _path) return function(log, _path) -- Fall back to CWD-relative if _path not provided (standalone use) if not _path then _path = function(p) return p end end -- Persistent config path: survives Opus package updates local _PERSIST_DIR = "usr/config/inventory-manager" local function _configPath(rel) if fs.isDir(_PERSIST_DIR) or fs.isDir("packages/inventory-manager") then if not fs.isDir(_PERSIST_DIR) then fs.makeDir(_PERSIST_DIR) end return fs.combine(_PERSIST_DIR, rel) end return _path(rel) end local C = {} ------------------------------------------------- -- Default configuration (overridden by .manager_config) ------------------------------------------------- C.DROPPER_NAME = "minecraft:dropper_9" C.BARREL_NAME = "minecraft:barrel_0" C.POLL_INTERVAL = 2 C.MONITOR_SIDE = "left" C.SCAN_INTERVAL = 120 C.SMELT_INTERVAL = 3 C.SMELT_RESERVE = 128 C.DEFRAG_INTERVAL = 600 C.COMPOST_INTERVAL = 3 C.ALERT_INTERVAL = 15 C.CACHE_FILE = _configPath(".inventory_cache") C.SMELTER_MONITOR_SIDE = "top" C.DISABLED_RECIPES_FILE = _configPath(".disabled_recipes") -- Network C.BROADCAST_CHANNEL = 4200 C.ORDER_CHANNEL = 4201 C.BROADCAST_INTERVAL = 1 C.CRAFT_CHANNEL = 4203 C.CRAFT_REPLY_CHANNEL = 4204 C.SYSTEM_CHANNEL = 4205 -- Crafting C.CRAFT_TIMEOUT = 15 C.GRID_TO_SLOT = {1, 2, 3, 5, 6, 7, 9, 10, 11} -- Compost (overridable via config file) C.COMPOST_RESERVE = 128 C.COMPOST_DROPPER = "minecraft:dropper_10" C.COMPOST_HOPPER = "minecraft:hopper_0" -- Peripheral C.PERIPHERAL_CACHE_TTL = 5 -- Parallel scanning C.PARALLEL_SCAN_CHUNKS = 8 -- Storage priority (higher = preferred; keyed by chest peripheral name) C.CHEST_PRIORITY = {} -- Builder / supply manifest C.SUPPLY_CHEST = "" -- peripheral name of supply chest (empty = disabled) C.SUPPLY_INTERVAL = 10 -- seconds between supply checks C.SUPPLY_MANIFEST = {} -- { { name = "mod:item", count = N }, ... } -- Furnace types C.FURNACE_TYPES = { "minecraft:furnace", "minecraft:smoker", "minecraft:blast_furnace", } C.SLOT_INPUT = 1 C.SLOT_FUEL = 2 C.SLOT_OUTPUT = 3 ------------------------------------------------- -- Config file loader ------------------------------------------------- local CONFIG_FILE = _configPath(".manager_config") function C.loadConfig() if not fs.exists(CONFIG_FILE) then return end local f = fs.open(CONFIG_FILE, "r") local data = f.readAll() f.close() local ok, cfg = pcall(textutils.unserialiseJSON, data) if not ok or not cfg then log.warn("CONFIG", "Failed to parse %s", CONFIG_FILE) return end C._raw = cfg if cfg.dropperName then C.DROPPER_NAME = cfg.dropperName end if cfg.barrelName then C.BARREL_NAME = cfg.barrelName end if cfg.monitorSide then C.MONITOR_SIDE = cfg.monitorSide end if cfg.smelterMonitorSide then C.SMELTER_MONITOR_SIDE = cfg.smelterMonitorSide end if cfg.pollInterval then C.POLL_INTERVAL = cfg.pollInterval end if cfg.scanInterval then C.SCAN_INTERVAL = cfg.scanInterval end if cfg.smeltInterval then C.SMELT_INTERVAL = cfg.smeltInterval end if cfg.defragInterval then C.DEFRAG_INTERVAL = cfg.defragInterval end if cfg.compostInterval then C.COMPOST_INTERVAL = cfg.compostInterval end if cfg.alertInterval then C.ALERT_INTERVAL = cfg.alertInterval end if cfg.broadcastInterval then C.BROADCAST_INTERVAL = cfg.broadcastInterval end if cfg.smeltReserve then C.SMELT_RESERVE = cfg.smeltReserve end if cfg.broadcastChannel then C.BROADCAST_CHANNEL = cfg.broadcastChannel end if cfg.orderChannel then C.ORDER_CHANNEL = cfg.orderChannel end if cfg.craftChannel then C.CRAFT_CHANNEL = cfg.craftChannel end if cfg.craftReplyChannel then C.CRAFT_REPLY_CHANNEL = cfg.craftReplyChannel end if cfg.compostReserve then C.COMPOST_RESERVE = cfg.compostReserve end if cfg.compostDropper then C.COMPOST_DROPPER = cfg.compostDropper end if cfg.compostHopper then C.COMPOST_HOPPER = cfg.compostHopper end if cfg.parallelScanChunks then C.PARALLEL_SCAN_CHUNKS = cfg.parallelScanChunks end if cfg.chestPriority then C.CHEST_PRIORITY = cfg.chestPriority end if cfg.supplyChest then C.SUPPLY_CHEST = cfg.supplyChest end if cfg.supplyInterval then C.SUPPLY_INTERVAL = cfg.supplyInterval end if cfg.supplyManifest then C.SUPPLY_MANIFEST = cfg.supplyManifest end if cfg.logLevel then log.setLevel(cfg.logLevel) end log.info("CONFIG", "Loaded from %s", CONFIG_FILE) end ------------------------------------------------- -- Data tables ------------------------------------------------- C.FUEL_LIST = dofile(_path("data/fuel.lua")) local _compostData = dofile(_path("data/compostable.lua")) C.COMPOSTABLE = _compostData.items C.COMPOST_TRASH = _compostData.trash C.LOW_STOCK_ALERTS = dofile(_path("data/alerts.lua")) -- Recipe book: merges built-in recipes + user-learned recipes local recipeBook = dofile(_path("lib/recipeBook.lua")) recipeBook.init(_configPath(".recipes.db")) recipeBook.loadLegacyCrafting(dofile(_path("data/craftable.lua"))) recipeBook.loadLegacySmelting(dofile(_path("data/smeltable.lua"))) C.recipeBook = recipeBook C.SMELTABLE = recipeBook.getSmeltingTable() C.CRAFTABLE = recipeBook.getCraftingList() -- Rebuild furnace/smelt indices from current recipe data function C.rebuildIndices() for _, recipe in pairs(C.SMELTABLE) do recipe.furnaceSet = {} for _, ft in ipairs(recipe.furnaces) do recipe.furnaceSet[ft] = true end end C.smeltCandidatesByType = {} for _, ftype in ipairs(C.FURNACE_TYPES) do C.smeltCandidatesByType[ftype] = {} end for itemName, recipe in pairs(C.SMELTABLE) do local isFood = recipe.furnaceSet["minecraft:smoker"] or false for ft in pairs(recipe.furnaceSet) do table.insert(C.smeltCandidatesByType[ft], { name = itemName, recipe = recipe, food = isFood }) end end for _, list in pairs(C.smeltCandidatesByType) do table.sort(list, function(a, b) if a.food ~= b.food then return a.food end return a.name < b.name end) end end -- Refresh recipes from recipeBook and rebuild all indices function C.refreshRecipes() C.SMELTABLE = C.recipeBook.getSmeltingTable() C.CRAFTABLE = C.recipeBook.getCraftingList() C.rebuildIndices() end C.rebuildIndices() -- Build fuel set for quick lookup C.FUEL_SET = {} for _, f in ipairs(C.FUEL_LIST) do C.FUEL_SET[f.name] = true end -- Build compostable set for quick lookup C.COMPOSTABLE_SET = {} for _, name in ipairs(C.COMPOSTABLE) do C.COMPOSTABLE_SET[name] = true end return C end