Skip to content

Instantly share code, notes, and snippets.

@nguyen-vh
Forked from adkinss/RSWarehouse.lua
Last active April 29, 2025 23:36
Show Gist options
  • Save nguyen-vh/56ce79dc58a6c5b3136c46230eb4f052 to your computer and use it in GitHub Desktop.
Save nguyen-vh/56ce79dc58a6c5b3136c46230eb4f052 to your computer and use it in GitHub Desktop.
Minecolonies x ComputerCraft (CC:Tweaked) x Advanced Peripherals x ME/RS script to automatically fulfill open work requests
---@diagnostic disable: undefined-global
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
--** ULTIMATE CC X MINECOLONIES PROGRAM **--
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
----------------------------------------------------------------------------
----------------------------------------------------------------------------
--* VARIABLES
----------------------------------------------------------------------------
-- Displays Ticker in the first row right-side. Default: 15
local refreshInterval = 10
-- If true, Advanced Computer will show all Log information. Default: false
local bShowInGameLog = false
-- Name of the log file e.g. "logFileName"_log.txt
local logFileName = "CCxM"
----------------------------------------------------------------------------
--* LOG (FATAL ERROR WARN_ INFO_ DEBUG TRACE)
----------------------------------------------------------------------------
-- Log a message to a file and optionally print it to the console
function logToFile(message, level, bPrint)
level = level or "INFO_"
bPrint = bPrint or bShowInGameLog
local logFolder = logFileName .. "_logs"
local logFilePath = logFolder .. "/" .. logFileName .. "_log_latest.txt"
if not fs.exists(logFolder) then
local success, err = pcall(function() fs.makeDir(logFolder) end)
if not success then
print(string.format("Failed to create log folder: %s", err))
return
end
end
local success, err = pcall(function()
local logFile = fs.open(logFilePath, "a")
if logFile then
-- Write the log entry with a timestamp and level
logFile.writeLine(string.format("[%s] [%s] %s", os.date("%Y-%m-%d %H:%M:%S"), level, message))
logFile.close()
else
error("Unable to open log file.")
end
end)
if not success then
print(string.format("Error writing to log file: %s", err))
return
end
-- Optionally print the message to the console
if bPrint then
if level == "ERROR" or level == "FATAL" then
print("")
end
print(string.format("[%s] %s", level, message))
if level == "ERROR" or level == "FATAL" then
print("")
end
end
logCounter = (logCounter or 0) + 1
if logCounter >= 250 then
rotateLogs(logFolder, logFilePath)
logCounter = 0
end
end
-- Rotates logs and limits the number of old logs stored
function rotateLogs(logFolder, logFilePath)
local maxLogs = 5 -- Maximum number of log files to keep
local timestamp = os.date("%Y-%m-%d_%H-%M-%S")
local archivedLog = string.format("%s/log_%s.txt", logFolder, timestamp)
local success, err = pcall(function()
if fs.exists(logFilePath) then
fs.move(logFilePath, archivedLog)
end
end)
if not success then
print(string.format("Failed to rotate log file: %s", err))
return
end
local logs = fs.list(logFolder)
table.sort(logs)
local logCount = #logs
while logCount > maxLogs do
local oldestLog = logFolder .. "/" .. logs[1]
local deleteSuccess, deleteErr = pcall(function() fs.delete(oldestLog) end)
if not deleteSuccess then
print(string.format("Failed to delete old log file: %s", deleteErr))
break
end
table.remove(logs, 1)
logCount = logCount - 1
end
end
----------------------------------------------------------------------------
--* ERROR-HANDLING FUNCTION
----------------------------------------------------------------------------
function safeCall(func, ...)
local success, result = pcall(func, ...)
if not success then
logToFile((result or "Unknown error"), "ERROR")
return false
end
return true
end
----------------------------------------------------------------------------
--* GENERIC HELPER FUNCTIONS
----------------------------------------------------------------------------
local function trimLeadingWhitespace(str)
return str:match("^%s*(.*)$")
end
function getLastWord(str)
return string.match(str, "%S+$")
end
function tableToString(tbl, indent)
indent = indent or 0
local toString = string.rep(" ", indent) .. "{\n"
for key, value in pairs(tbl) do
local formattedKey = type(key) == "string" and string.format("%q", key) or tostring(key)
if type(value) == "table" then
toString = toString ..
string.rep(" ", indent + 1) ..
"[" .. formattedKey .. "] = " .. tableToString(value, indent + 1) .. ",\n"
else
local formattedValue = type(value) == "string" and string.format("%q", value) or tostring(value)
toString = toString ..
string.rep(" ", indent + 1) .. "[" .. formattedKey .. "] = " .. formattedValue .. ",\n"
end
end
return toString .. string.rep(" ", indent) .. "}"
end
function writeToLogFile(fileName, equipment_list, builder_list, others_list)
local file = io.open(fileName, "w") -- Open file in write mode
if not file then
error("Could not open file for writing: " .. fileName)
end
-- Write the contents of each list
file:write("Equipment List:\n")
file:write(tableToString(equipment_list) .. "\n\n")
file:write("Builder List:\n")
file:write(tableToString(builder_list) .. "\n\n")
file:write("Others List:\n")
file:write(tableToString(others_list) .. "\n\n")
file:close() -- Close the file
end
local function ensure_width(line, width)
width = width or term.getSize()
line = line:sub(1, width)
if #line < width then
line = line .. (" "):rep(width - #line)
end
return line
end
----------------------------------------------------------------------------
--* CHECK REQUIREMENTS
----------------------------------------------------------------------------
local monitor = peripheral.find("monitor")
local colony
local bridge
local storage
function getPeripheral(type)
local peripheral = peripheral.find(type)
if not peripheral then
logToFile(type .. " peripheral not found.", "WARN_")
return nil
end
logToFile(type .. " peripheral found.")
return peripheral
end
function updatePeripheralMonitor()
monitor = getPeripheral("monitor")
if monitor then
return true
else
return false
end
end
function checkMonitorSize()
monitor.setTextScale(0.5)
local width, height = monitor.getSize()
if width < 79 or height < 38 then
logToFile("Use more Monitors! (min 4x3)", "WARN_")
return false
end
return true
end
function updatePeripheralColonyIntegrator()
colony = getPeripheral("colonyIntegrator")
if colony then
return true
else
return false
end
end
function getStorageBridge()
local meBridge = getPeripheral("meBridge")
local rsBridge = getPeripheral("rsBridge")
if meBridge then
return meBridge
elseif rsBridge then
return rsBridge
else
logToFile("Neither ME Storage Bridge nor RS Storage Bridge found.", "WARN_")
return nil
end
end
function updatePeripheralStorageBridge()
bridge = getStorageBridge()
if bridge then
return true
else
return false
end
end
function autodetectStorage()
for _, side in pairs(peripheral.getNames()) do
if peripheral.hasType(side, "inventory") then
logToFile("Storage detected on " .. side)
return side
end
end
logToFile("No storage container detected!", "WARN_")
return nil
end
function updatePeripheralStorage()
storage = autodetectStorage()
if storage then
return true
else
return false
end
end
----------------------------------------------------------------------------
-- MONITOR DASHBOARD NAME
----------------------------------------------------------------------------
-- 1st line on dashboard with color changing depending on the refreshInterval
-- Reset through a rainbow
local dashboardName = "MineColonies DASHBOARD"
local rainbowColors = {
colors.red, colors.orange, colors.yellow,
colors.green, colors.cyan, colors.blue,
colors.purple, colors.magenta, colors.pink
}
function monitorDisplayDashboardName(monitor, y, text, colorsTable)
local w, h = monitor.getSize()
local x = math.floor((w - #text) / 2) + 1
for i = 1, #text do
local char = text:sub(i, i)
local color = colorsTable[i]
monitor.setTextColor(color)
monitor.setCursorPos(x + i - 1, y)
monitor.write(char)
sleep(0.01)
end
end
function dashboardGenerateTransitionColors(progress, length)
local colorsTable = {}
local threshold = math.floor((progress) * length)
for i = 1, length do
if i <= threshold then
table.insert(colorsTable, colors.orange)
else
table.insert(colorsTable, colors.white)
end
end
return colorsTable
end
function dashboardGenerateRainbowColors(baseColors, length)
local result = {}
local totalColors = #baseColors
for i = 1, length do
result[i] = baseColors[((i - 1) % totalColors) + 1]
end
return result
end
function monitorDashboardName()
local startTime = os.clock()
local y = 1
while true do
local elapsedTime = os.clock() - startTime
local progress = math.min(elapsedTime / (refreshInterval - 1), 1)
if elapsedTime >= refreshInterval then
sleep(0.5)
local rainbowColorsTable = dashboardGenerateRainbowColors(rainbowColors, #dashboardName)
monitorDisplayDashboardName(monitor, y, dashboardName, rainbowColorsTable)
sleep(0.1)
else
local colorsTable = dashboardGenerateTransitionColors(progress, #dashboardName)
monitorDisplayDashboardName(monitor, y, dashboardName, colorsTable)
sleep(0.1)
end
if elapsedTime >= refreshInterval then
break
end
end
end
----------------------------------------------------------------------------
--* ART
----------------------------------------------------------------------------
local artUltimateCCxM_Logo = [[
_ _ _ _ _ _
| | | | | |_(_)_ __ ___ __ _| |_ ___
| | | | | __| | '_ ` _ \ / _` | __/ _ \
| |_| | | |_| | | | | | | (_| | || __/
\____|_____|_|_| |_|___|_____|\__\___|
/ ___/ ___|__ __| \/ (_)_ __ ___
| | | | \ \/ /| |\/| | | '_ \ / _ \
| |__| |___ > < | | | | | | | | __/
\____\____|/_/\_\|_| |_|_|_| |_|\___|
/ ___|___ | | ___ _ __ (_) ___ ___
| | / _ \| |/ _ \| '_ \| |/ _ \/ __|
| |__| (_) | | (_) | | | | | __/\__ \
\____\___/|_|\___/|_| |_|_|\___||___/
]]
----------------------------------------------------------------------------
--* MONITOR OR TERMINAL OUTPUT
----------------------------------------------------------------------------
function resetDefault(screen)
screen.setTextColor(colors.white)
screen.setBackgroundColor(colors.black)
screen.setCursorPos(1, 1)
screen.clear()
end
function drawLoadingBar(screen, x, y, width, progress, bgColor, barColor)
screen.setBackgroundColor(bgColor or colors.gray)
screen.setTextColor(colors.white)
screen.setCursorPos(x, y)
-- Draw the empty bar
screen.write(string.rep(" ", width))
-- Draw the filled part
local filledWidth = math.floor(progress * width)
screen.setCursorPos(x, y)
screen.setBackgroundColor(barColor or colors.green)
screen.write(string.rep(" ", filledWidth))
end
----------------------------------------------------------------------------
--* MONITOR OUTPUT
----------------------------------------------------------------------------
local x, y = 1, 1
function monitorDisplayArt(asciiArt, monitor_)
monitor_.clear()
local x, y = 1, 2
for line in asciiArt:gmatch("[^\n]+") do
monitor_.setCursorPos(x, y)
monitor_.write(line)
y = y + 1
end
end
function monitorLoadingAnimation()
resetDefault(monitor)
monitor.setTextScale(1)
local width, height = monitor.getSize()
local barWidth = math.floor(width * 0.9)
local barX = math.floor((width - barWidth) / 2 + 1)
local barHeight = 17
monitor.setTextColor(colors.orange)
monitor.setCursorPos(1, 1)
monitorDisplayArt(artUltimateCCxM_Logo, monitor)
local barSpeed = 30
for i = 0, barSpeed do
local progress = i / barSpeed
drawLoadingBar(monitor, barX, barHeight, barWidth, progress, colors.gray, colors.orange)
sleep(0.1)
end
resetDefault(monitor)
monitor.setTextScale(0.5)
end
function monitorPrintText(y, pos, text, ...)
local w, h = monitor.getSize()
local fg = monitor.getTextColor()
local bg = monitor.getBackgroundColor()
local x = 1
if pos == "left" then
x = 4
text = ensure_width(text, math.floor(w / 2) - 2)
elseif pos == "center" then
x = math.floor((w - #text) / 2)
elseif pos == "right" then
x = w - #text - 2
elseif pos == "middle" then
x = math.floor((w - #text) / 2)
y = math.floor(h / 2) - 2
end
if select("#", ...) > 0 then
monitor.setTextColor(select(1, ...))
end
if select("#", ...) > 1 then
monitor.setBackgroundColor(select(2, ...))
end
monitor.setCursorPos(x, y)
monitor.write(text)
monitor.setTextColor(fg)
monitor.setBackgroundColor(bg)
end
function drawBox(xMin, xMax, yMin, yMax, title, bcolor, tcolor)
monitor.setBackgroundColor(bcolor)
for xPos = xMin, xMax, 1 do
monitor.setCursorPos(xPos, yMin)
monitor.write(" ")
end
for yPos = yMin, yMax, 1 do
monitor.setCursorPos(xMin, yPos)
monitor.write(" ")
monitor.setCursorPos(xMax, yPos)
monitor.write(" ")
end
for xPos = xMin, xMax, 1 do
monitor.setCursorPos(xPos, yMax)
monitor.write(" ")
end
monitor.setCursorPos(xMin + 2, yMin)
monitor.setBackgroundColor(colors.black)
monitor.setTextColor(tcolor)
monitor.write(" ")
monitor.write(title)
monitor.write(" ")
monitor.setTextColor(colors.white)
end
function monitorDashboardRequests(equipment_list, builder_list, others_list)
local x, y = monitor.getSize()
local equipment_count = #equipment_list
local builder_count = #builder_list
local others_count = #others_list
drawBox(2, x - 1, 3, (equipment_count + math.ceil(builder_count / 2) + others_count) + 11, "REQUESTS", colors.gray,
colors.purple)
--Builder
monitorPrintText(5, "center", "Builder", colors.orange)
local half = math.ceil(builder_count / 2)
for i = 1, half do
local item = builder_list[i]
if item then
monitorPrintText(i + 5, "left", (item.provided .. "/" .. item.name), item.displayColor)
end
end
for i = half + 1, builder_count do
local item = builder_list[i]
if item then
monitorPrintText(i - half + 5, "right", (item.provided .. "/" .. item.name),
item.displayColor)
end
end
--Equipment
monitorPrintText(math.ceil(builder_count / 2) + 7, "center", "Equipment", colors.orange)
for i, item in pairs(equipment_list) do
monitorPrintText(math.ceil(builder_count / 2) + i + 7, "left", item.name, item.displayColor)
monitorPrintText(math.ceil(builder_count / 2) + i + 7, "right", item.target, colors.lightGray)
end
--Others
monitorPrintText(equipment_count + math.ceil(builder_count / 2) + 9, "center", "Other", colors.orange)
for i, item in pairs(others_list) do
monitorPrintText(i + equipment_count + math.ceil(builder_count / 2) + 9, "left",
(item.provided .. "/" .. item.name),
item.displayColor)
monitorPrintText(i + equipment_count + math.ceil(builder_count / 2) + 9, "right", item.target, colors.lightGray)
end
end
----------------------------------------------------------------------------
--* TERMINAL OUTPUT
----------------------------------------------------------------------------
local termWidth, termHeight = term.getSize()
local needTermDrawRequirements = true
local needTermDrawRequirements_executed = false
function termDisplayArt(asciiArt)
term.clear()
local x, y = 6, 2
for line in asciiArt:gmatch("[^\n]+") do
term.setCursorPos(x, y)
term.write(line)
y = y + 1
end
end
-- Function to simulate the loading process
function termLoadingAnimation()
resetDefault(term)
local width, height = term.getSize()
local barWidth = math.floor(width * 0.8)
local barX = math.floor((width - barWidth) / 2 + 1)
local barHeight = math.floor(height * 0.9)
term.setTextColor(colors.orange)
term.setCursorPos(1, 1)
termDisplayArt(artUltimateCCxM_Logo)
local barSpeed = 25
for i = 0, barSpeed do
local progress = i / barSpeed
drawLoadingBar(term, barX, barHeight, barWidth, progress, colors.gray, colors.orange)
sleep(0.1)
end
resetDefault(term)
end
function termDrawProgramReq_helper(y, isRequirementMet)
if isRequirementMet then
term.setTextColor(colors.green)
term.setCursorPos(49, y)
term.write("[O]")
else
term.setTextColor(colors.red)
term.setCursorPos(49, y)
term.write("[X]")
end
term.setTextColor(colors.white)
end
function termDrawProgramReq_Header()
local text_Divider = "-------------------------------------------------------"
term.setCursorPos(math.floor((termWidth - #text_Divider) / 2) + 1, 4)
term.write(text_Divider)
local text_Requirements = "\187 Program Requirements \171"
term.setCursorPos(math.floor((termWidth - #text_Requirements) / 2) + 1, 2)
textutils.slowWrite(text_Requirements, 16)
end
function termDrawCheckRequirements()
if not needTermDrawRequirements_executed then
term.clear()
end
local text_Monitor_1 = "\16 Monitor attached"
term.setCursorPos(2, 6)
term.write(text_Monitor_1)
local text_Monitor_2 = "\16 Monitor size (min 4x3)"
term.setCursorPos(2, 8)
term.write(text_Monitor_2)
local text_Colony_1 = "\16 Colony Integrator attached"
term.setCursorPos(2, 10)
term.write(text_Colony_1)
local text_Colony_2 = "\16 Colony Integrator in a colony"
term.setCursorPos(2, 12)
term.write(text_Colony_2)
local text_StoargeBridge = "\16 ME or RS Bridge attached"
term.setCursorPos(2, 14)
term.write(text_StoargeBridge)
local text_Stoarge = "\16 Storage/Warehouse attached"
term.setCursorPos(2, 16)
term.write(text_Stoarge)
if updatePeripheralMonitor() then
termDrawProgramReq_helper(6, true)
if checkMonitorSize() then
termDrawProgramReq_helper(8, true)
else
termDrawProgramReq_helper(8, false)
end
else
termDrawProgramReq_helper(6, false)
termDrawProgramReq_helper(8, false)
end
if updatePeripheralColonyIntegrator() then
termDrawProgramReq_helper(10, true)
if colony.isInColony() then
termDrawProgramReq_helper(12, true)
else
termDrawProgramReq_helper(12, false)
end
else
termDrawProgramReq_helper(10, false)
termDrawProgramReq_helper(12, false)
end
if updatePeripheralStorageBridge() then
termDrawProgramReq_helper(14, true)
else
termDrawProgramReq_helper(14, false)
end
if updatePeripheralStorage() then
termDrawProgramReq_helper(16, true)
else
termDrawProgramReq_helper(16, false)
end
if not needTermDrawRequirements_executed then
termDrawProgramReq_Header()
needTermDrawRequirements_executed = true
end
if updatePeripheralMonitor() and updatePeripheralColonyIntegrator() and updatePeripheralStorageBridge() and updatePeripheralStorage() then
if checkMonitorSize() and colony.isInColony() then
termDrawProgramReq_helper(6, true)
termDrawProgramReq_helper(8, true)
termDrawProgramReq_helper(10, true)
termDrawProgramReq_helper(12, true)
termDrawProgramReq_helper(14, true)
termDrawProgramReq_helper(16, true)
needTermDrawRequirements = false
needTermDrawRequirements_executed = false
local text_RequirementsFullfilled = "Requirements fullfilled"
term.setCursorPos(math.floor((termWidth - #text_RequirementsFullfilled) / 2), 19)
term.setTextColor(colors.green)
sleep(0.5)
textutils.slowWrite(text_RequirementsFullfilled, 16)
textutils.slowWrite(" . . .", 5)
sleep(1)
-- Cleanup
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1, 1)
return true
end
end
return true
end
function termShowLog()
term.setCursorPos(1, 1)
term.clearLine()
term.setCursorPos(1, 2)
term.clearLine()
term.setCursorPos(1, 3)
term.clearLine()
local text_Divider = "-------------------------------------------------------"
term.setCursorPos(math.floor((termWidth - #text_Divider) / 2) + 1, 4)
term.write(text_Divider)
local text_Requirements = "\187 MineColonies Logs \171"
term.setCursorPos(math.floor((termWidth - #text_Requirements) / 2) + 1, 2)
textutils.slowWrite(text_Requirements, 16)
end
----------------------------------------------------------------------------
--* MINECOLONIES
----------------------------------------------------------------------------
local function isEquipment(desc)
local equipmentKeywords = { "Sword ", "Bow ", "Pickaxe ", "Axe ", "Shovel ", "Hoe ", "Shears ", "Helmet ",
"Chestplate ", "Leggings ", "Boots " }
for _, keyword in ipairs(equipmentKeywords) do
if string.find(desc, keyword) then
return true
end
end
return false
end
function colonyCategorizeRequests()
local equipment_list = {}
local builder_list = {}
local others_list = {}
for _, req in ipairs(colony.getRequests()) do
local name = req.name
local target = req.target or ""
local desc = req.desc or ""
local count = req.count
local item_displayName = trimLeadingWhitespace(req.items[1].displayName)
local item_name = req.items[1].name
local itemIsEquipment = isEquipment(desc)
-- Equipment Categorization
if itemIsEquipment then
local levelTable = {
["and with maximal level: Leather"] = "Leather",
["and with maximal level: Stone"] = "Stone",
["and with maximal level: Chain"] = "Chain",
["and with maximal level: Gold"] = "Gold",
["and with maximal level: Iron"] = "Iron",
["and with maximal level: Diamond"] = "Diamond",
["with maximal level: Wood or Gold"] = "Wood or Gold"
}
local level = "Any Level"
for pattern, mappedLevel in pairs(levelTable) do
if string.find(desc, pattern) then
level = mappedLevel
break
end
end
local new_name = level .. " " .. name
table.insert(equipment_list, {
name = new_name,
target = target,
count = count,
item_displayName = item_displayName,
item_name = item_name,
desc = desc,
provided = 0,
isCraftable = false,
equipment = itemIsEquipment,
displayColor = colors.white,
level = level
})
-- Builder Categorization
elseif string.find(target, "Builder") then
table.insert(builder_list, {
name = name,
target = target,
count = count,
item_displayName = item_displayName,
item_name = item_name,
desc = desc,
provided = 0,
isCraftable = false,
equipment = itemIsEquipment,
displayColor = colors.white,
level = ""
})
-- Non-Builder Categorization
else
table.insert(others_list, {
name = name,
target = target,
count = count,
item_displayName = item_displayName,
item_name = item_name,
desc = desc,
provided = 0,
isCraftable = false,
equipment = itemIsEquipment,
displayColor = colors.white,
level = ""
})
end
end
return equipment_list, builder_list, others_list
end
----------------------------------------------------------------------------
--* STORAGE SYSTEM REQUEST AND SEND
----------------------------------------------------------------------------
-- Color code: red = not available
-- yellow = stuck
-- blue = crafting
-- green = fully exported
-- Try or skip equipment craft
local b_craftEquipment = true
-- Choose "Iron" or "Diamond" or "Iron and Diamond"
local craftEquipmentOfLevel = "Iron"
function equipmentCraft(name, level, item_name)
if (item_name == "minecraft:bow") then
return item_name, true
end
if (level == "Iron" or level == "Iron and Diamond" or level == "Any Level") and (craftEquipmentOfLevel == "Iron" or craftEquipmentOfLevel == "Iron and Diamond") then
if level == "Any Level" then
level = "Iron"
end
item_name = string.lower("minecraft:" .. level .. "_" .. getLastWord(name))
return item_name, true
elseif (level == "Diamond" or level == "Iron and Diamond" or level == "Any Level") and craftEquipmentOfLevel == "Diamond" then
if level == "Any Level" then
level = "Diamond"
end
item_name = string.lower("minecraft:" .. level .. "_" .. getLastWord(name))
return item_name, true
end
return item_name, false
end
function storageSystemHandleRequests(request_list)
for _, item in ipairs(request_list) do
local itemStored = 0
local b_CurrentlyCrafting = false
local b_equipmentCraft = true
if item.equipment then
item.item_name, b_equipmentCraft = equipmentCraft(item.name, item.level, item.item_name)
end
--getItem() to see if item in system (if not, error), count and if craftable
b_functionGetItem = safeCall(function()
itemStored = (bridge.getItem({ name = item.item_name })).count or 0
item.isCraftable = (bridge.getItem({ name = item.item_name })).isCraftable
end)
if not b_functionGetItem then
logToFile(item.item_displayName .. " isn't in system and isn't craftable.", "WARN_", true)
item.displayColor = colors.red
goto continue
end
if not (itemStored == 0) then
b_functionExportItemToPeripheral = safeCall(function()
item.provided = bridge.exportItemToPeripheral({ name = item.item_name, count = item.count }, storage)
end)
if not b_functionExportItemToPeripheral then
logToFile("Failed to export item.", "WARN_", true)
item.displayColor = colors.yellow
end
if (item.provided == item.count) then
item.displayColor = colors.green
else
item.displayColor = colors.yellow
end
end
if not b_craftEquipment and item.equipment then
goto continue
end
if (item.provided < item.count) and item.isCraftable and b_equipmentCraft then
b_functionIsItemCrafting = safeCall(function()
b_CurrentlyCrafting = bridge.isItemCrafting({ name = item.item_name })
end)
if not b_functionIsItemCrafting then
logToFile("Asking for crafting job failed.", "WARN_")
end
if b_CurrentlyCrafting then
item.displayColor = colors.blue
goto continue
end
end
local b_craftItem = not b_CurrentlyCrafting and item.isCraftable and (item.provided < item.count)
if b_craftItem then
-- Skip Equipments if set to false
if not b_craftEquipment and item.equipment then
goto continue
end
b_functionCraftItem = safeCall(function()
local craftedItem = { name = item.item_name, count = item.count - item.provided }
return bridge.craftItem(craftedItem)
end)
if not b_functionCraftItem then
logToFile("Crafting request failed. (Items missing)", "WARN_", true)
item.displayColor = colors.yellow
goto continue
end
item.displayColor = colors.blue
end
::continue::
end
end
----------------------------------------------------------------------------
--* MAIN LOGIC FUNCTIONS
----------------------------------------------------------------------------
function updatePeripheralAll()
if not updatePeripheralMonitor() or not checkMonitorSize() then
needTermDrawRequirements = true
end
if not updatePeripheralColonyIntegrator() or not colony.isInColony() then
needTermDrawRequirements = true
end
if not updatePeripheralStorageBridge() then
needTermDrawRequirements = true
end
if not updatePeripheralStorage() then
needTermDrawRequirements = true
end
while needTermDrawRequirements do
termDrawCheckRequirements()
sleep(1)
end
end
function requestAndFulfill()
local equipment_list, builder_list, others_list = colonyCategorizeRequests()
writeToLogFile("log1.txt", equipment_list, builder_list, others_list)
storageSystemHandleRequests(equipment_list)
storageSystemHandleRequests(builder_list)
storageSystemHandleRequests(others_list)
writeToLogFile("log2.txt", equipment_list, builder_list, others_list)
return equipment_list, builder_list, others_list
end
--TODO
function monitorShowDashboard(equipment_list, builder_list, others_list)
monitor.clear()
monitorDashboardRequests(equipment_list, builder_list, others_list)
-- monitorDashboardResearch()
-- monitorDashboardStats()
monitorDashboardName()
end
----------------------------------------------------------------------------
--* MAIN
----------------------------------------------------------------------------
function main()
termLoadingAnimation()
updatePeripheralAll()
monitorLoadingAnimation()
while true do
updatePeripheralAll()
termShowLog()
term.setCursorPos(1, 5)
local equipment_list, builder_list, others_list = requestAndFulfill()
monitorShowDashboard(equipment_list, builder_list, others_list)
end
end
main()
@sergejsaenko
Copy link

@nguyen-vh Makes sense. But it was just an idea. Most of the stuff can be already done with the jobs sooo...

@TheIOzikI
Copy link

TheIOzikI commented Apr 6, 2025

@nguyen-vh Hello, Autocrafting feature is not working with AE2 on ATM10 2.42. Could you do an update meaby? (for EQ and builder items)

Edit1. It doesn't work when TPS is low. I had time-wand clicker automation for smelting and when that is running, the autocrafting feature does not work.

@coldino
Copy link

coldino commented Apr 7, 2025

This does seem to work well for me in ATM10 2.42.

One suggestion: with all the Domum Ornamentum Architect's Cutter recipes, would it be possible to extract the tooltip info from those request and display it somehow for each item? Type, style, main and secondary ingredient I think is what's needed, where relevant.

@nguyen-vh
Copy link
Author

@TheIOzikI Can you provide more information, such as specific items that stopped the program or events that triggered it?

@nguyen-vh
Copy link
Author

@coldino Great suggestion! When I have time, I'll try it out and hope that it doesn't fail due to the space available. But it's definitely something that's been missing.

@coldino
Copy link

coldino commented Apr 7, 2025

If it helps I discovered the raw data is available on the item:

if req.items[1].components then
    domum = {
        name=req.items[1].name,
        type=(req.items[1].components['minecraft:block_state'] or {})['type'],
        components=req.items[1].components["domum_ornamentum:texture_data"],
    }
end

...but this isn't very presentable (components is just item IDs) and updating the UI to include it is rather outside of my expertise. Hmmm, perhaps the name could be discovered from the ME/RS system if the item is in there, or fall back to displaying the ID if not.

@Fennsy
Copy link

Fennsy commented Apr 20, 2025

Hello @nguyen-vh, realy good job for your script ! It work fine but it do not export anything ... i found in log this line
"[ERROR] /MCI2:963: attempt to index a nil value"
and nothing else, but if it have to craft an item it craft it but no export ...
I'm in 1.20.1 with advanced peripherals 0.7.41r if can help

EDIT : I have found i think, i've replace ".count" to ".amount" at the end of line 963 :
"itemStored = (bridge.getItem({ name = item.item_name })).amount or 0"
now it's work !

@nguyen-vh
Copy link
Author

@Fennsy Nice to hear that you have already found a solution. When I have time again, I will continue to improve the script.

@Butter41
Copy link

Butter41 commented Apr 22, 2025

Hi I was wondering how to get the computer running because i have tryed pasting the code into it and it didnt work

@TheIOzikI
Copy link

2025-04-22_08 35 12
2025-04-22_08 34 44
Hi, What about armor crafting/exporting? It's not doing it.

@Butter41
Copy link

Hi I was wondering how to get the computer running because i have tryed pasting the code into it and it didnt work

I got that running now but how do you attach the colony intergrader in the colony?

Bild_2025-04-22_151346314

@nguyen-vh
Copy link
Author

@TheIOzikI You can find the function for this in line 925. I have set it to make iron and diamond armor. If you want armor lower than iron, you have to add it manually.

function equipmentCraft(name, level, item_name)
   if (item_name == "minecraft:bow") then
       return item_name, true
   end

   if (level == "Iron" or level == "Iron and Diamond" or level == "Any Level") and (craftEquipmentOfLevel == "Iron" or craftEquipmentOfLevel == "Iron and Diamond") then
       if level == "Any Level" then
           level = "Iron"
       end

       item_name = string.lower("minecraft:" .. level .. "_" .. getLastWord(name))

       return item_name, true
   elseif (level == "Diamond" or level == "Iron and Diamond" or level == "Any Level") and craftEquipmentOfLevel == "Diamond" then
       if level == "Any Level" then
           level = "Diamond"
       end

       item_name = string.lower("minecraft:" .. level .. "_" .. getLastWord(name))
       return item_name, true
   end

   return item_name, false
end

@nguyen-vh
Copy link
Author

@Butter41 I think the colony integrator only needs to be within the boundaries of your colony.

@Butter41
Copy link

@Butter41 I think the colony integrator only needs to be within the boundaries of your colony.

how do i connect it with the computer tho cause it wont change anything?

@nguyen-vh
Copy link
Author

@Butter41 It is connected if the colony integrator touches any side of the CC advanced computer.

@sergejsaenko
Copy link

sergejsaenko commented Apr 22, 2025

@Butter41 I think the colony integrator only needs to be within the boundaries of your colony.

@nguyen-vh Do you maybe know a way to have it outside the boundaries of the colony? I was aiming to build a few colonies and have for each an integrator and everything running at my base/a central place.

@nguyen-vh
Copy link
Author

@sergejsaenko I haven't tried it, but maybe entangle the colony integrator sitting in your colony and place the entangled block next to the computer.

@sergejsaenko
Copy link

@nguyen-vh That's smart and it actually worked. I was using the same method for the warehouse block but somehow didn't think to try it with the integrator.

@nguyen-vh
Copy link
Author

@sergejsaenko It's like standing too close to the blackboard with the solution, you may not see it, but it's obvious to someone else sitting far away with a bigger picture. It happens even to the best of us.

@TheIOzikI
Copy link

TheIOzikI commented Apr 23, 2025

@nguyen-vh
This will work? some GPT action :P

-- Auto-select from all armor tiers, strongest → weakest
local craftEquipmentOfLevel = "Any"  -- no longer used, kept for compatibility

-- Define all vanilla armor materials in descending power
local tiers = {
  "Netherite",
  "Diamond",
  "Iron",
  "Chainmail",
  "Gold",
  "Leather"
}

function equipmentCraft(name, level, item_name)
    -- Extract the armor piece name (helmet, chestplate, leggings, boots)
    local piece = getLastWord(name)

    -- Try each material in order until one can be crafted
    for _, tier in ipairs(tiers) do
        -- Build the Minecraft item ID, e.g. "minecraft:diamond_leggings"
        local candidate = string.lower("minecraft:" .. tier .. "_" .. piece)
        return candidate, true
    end

    -- Fallback: leave the original request unchanged
    return item_name, false
end

@nguyen-vh
Copy link
Author

@TheIOzikI It's been a long time since I last tested the equipment output strings, but I remember that the request can be “Any level” if the colonists are high enough. But you can definitely change the existing function with your function.

@Butter41
Copy link

Bild_2025-04-25_001404766
ATM 9 Server Version 1.20.1 Bug

@coldino
Copy link

coldino commented Apr 25, 2025

There's also a problem with requests for dyed leather armour. I ended up with a warehouse full of 2000 leather pieces before I realised the script would continually fulfil the request with a freshly crafted piece, but the request stayed open forever as it needed the dyed one :D

Turns out this was decoration for one of the residence models.

@nguyen-vh
Copy link
Author

@coldino I see. Since the leather cap is not requested as part of the equipment requirement, the string filter is not applied in the program and the request is sent to the ME/RS system. But why are normal leather caps requested and not colored ones, that is the real question.

@coldino
Copy link

coldino commented Apr 28, 2025

Possibly the dye component is included in the request, but that's not being sent to either getItem or craftItem so the ME system just sends/crafts anything with the same ID. Needs experimentation.

I'm also seeing massive delays (20-150 seconds or more) on some ME bridge calls, in particular isItemCrafting but sometimes also getItem. I can mitigate it by keeping reguarly requested items in stock, but there are so many different items that there's no way to cover everything. Perhaps it's related to the quantum crafting setup on my system and its huge number of crafting CPUs.

@katsuo
Copy link

katsuo commented Apr 28, 2025

Hello, Im on ATM9 MC 1.20.1,IN the AE2 sytem i see the item being crafted but it never go in the warehouse of minecolonie so it Craft in loop the items any clue ? thanks
image

@nguyen-vh
Copy link
Author

@katsuo Just some general questions. I see you use an entangled chest as output and not your warehouse block. Do the items at least end up in that chest? If yes, do you send them from the chest to the warehouse? If not, then thats the problem.

@katsuo
Copy link

katsuo commented Apr 29, 2025 via email

@nguyen-vh
Copy link
Author

@katsuo So you used a normal chest or barrel (not entangled) and it didn’t transfer into it? Can you check if only one storage is touching the advanced computer because it can’t differentiate between many.

@katsuo
Copy link

katsuo commented Apr 29, 2025

i try whit entangled linked to the warehouse and linked to the chest,i try only a chest connected to the Computer and i have the same result,item is crafted but not transfered,
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment