Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- VillageBot v1.7
- --#region STRICT TOP-LEVEL CONFIGURATION AND LOGGER GLOBALS
- local LOG_LEVELS = { DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4, FATAL = 5 }
- local DEBUG_LOGGING_ENABLED = true
- local LOG_FILE_NAME_CONST = "villagebot.log"
- local current_log_level_val
- if DEBUG_LOGGING_ENABLED then
- current_log_level_val = (LOG_LEVELS and LOG_LEVELS.DEBUG) or 1
- else
- current_log_level_val = (LOG_LEVELS and LOG_LEVELS.INFO) or 2
- end
- local BOT_DATA_FILE = "villagebot_data.json"
- local ME_BRIDGE_NAME = "advancedperipherals:me_bridge"
- local REDSTONE_BLOCK_NAME = "minecraft:redstone_block"
- local AUTOMATA_PERIPHERAL_NAME = "endAutomata"
- local ME_BRIDGE_PERIPHERAL_NAME = "meBridge"
- local COLONY_INTEGRATOR_PERIPHERAL_NAME = "colonyIntegrator"
- local FUEL_SLOT = 16
- local COAL_BLOCK_NAME = "minecraft:coal_block"
- local REFUEL_BELOW_PERCENTAGE = 0.90
- local MAX_REDSTONE_BLOCK_RETRIES = 10
- local REDSTONE_BLOCK_RETRY_WAIT = 5
- local REFUEL_BARREL_ACCESS_POS = { x = -114, y = 65, z = 221, dir = 3 }
- --#endregion
- --#region Global State
- local current_pos = { x = nil, y = nil, z = nil }; local current_dir = nil
- local roboSlot = nil; local home_pos = { x = nil, y = nil, z = nil, dir = nil }
- local pAutomata = nil; local pMeBridge = nil; local pColonyIntegrator = nil
- local DIR_VECTORS = { [0]={x=0,z=1},[1]={x=1,z=0},[2]={x=0,z=-1},[3]={x=-1,z=0} }
- local DIR_NAMES = {[0]="North",[1]="East",[2]="South",[3]="West"}
- local mounted_peripherals = {}; local undeliveredItemsBuffer = {}
- --#endregion
- --#region Logger Function
- local function botLog(level, message)
- local message_str = message
- if type(message) ~= "string" and type(message) ~= "number" then
- message_str = textutils.serialize(message, {compact=true})
- if message == nil then message_str = "nil_message_passed_to_botLog" end
- else message_str = tostring(message) end
- local level_display_name = "LVL?"
- if LOG_LEVELS and type(LOG_LEVELS) == "table" then
- for name_key, lVal_val in pairs(LOG_LEVELS) do if lVal_val == level then level_display_name = name_key; break end end
- else print("Console: botLog - LOG_LEVELS is nil or not a table! Cannot determine level name.") end
- print(string.format("[%s] [%s] %s", os.date("%Y-%m-%d %H:%M:%S"), level_display_name, message_str))
- local can_write_to_file = false
- if LOG_LEVELS and type(LOG_LEVELS) == "table" and current_log_level_val and LOG_FILE_NAME_CONST and type(LOG_FILE_NAME_CONST) == "string" then
- if DEBUG_LOGGING_ENABLED or level >= (LOG_LEVELS.WARN or 3) then
- if level >= current_log_level_val then
- can_write_to_file = true
- end
- end
- end
- if can_write_to_file then
- local levelNameInFile = "UNK_LVL"
- if LOG_LEVELS then for name, lVal in pairs(LOG_LEVELS) do if lVal == level then levelNameInFile = name; break end end end
- local logMessageToFile = string.format("[%s] [%s] %s", os.date("%Y-%m-%d %H:%M:%S"), levelNameInFile, message_str)
- local f, err = fs.open(LOG_FILE_NAME_CONST, "a")
- if f then
- f.write(logMessageToFile .. "\n"); f.close()
- else
- print("CONSOLE: LOG FILE OPEN ERROR for '"..LOG_FILE_NAME_CONST.."' (in botLog): " .. tostring(err))
- end
- elseif DEBUG_LOGGING_ENABLED then
- if not LOG_LEVELS or type(LOG_LEVELS) ~= "table" then print("Console: botLog - Cannot write to file, LOG_LEVELS invalid.") end
- if not current_log_level_val then print("Console: botLog - Cannot write to file, current_log_level_val invalid.") end
- if not LOG_FILE_NAME_CONST or type(LOG_FILE_NAME_CONST) ~= "string" then print("Console: botLog - Cannot write to file, LOG_FILE_NAME_CONST invalid.") end
- end
- end
- --#endregion
- --#region Peripheral Management
- function findPeripheral(name,type_arg,required)
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"FindP: "..name.." type '"..tostring(type_arg).."'")end
- if type(type_arg) ~= "string" then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "FindP: Invalid type arg. Expected string, got " .. type(type_arg)) end
- return nil
- end
- local p=peripheral.find(type_arg)
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"FindP: peripheral.find Result for '"..type_arg.."': "..tostring(p))end
- if p then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Found peripheral: "..name) end
- mounted_peripherals[name]=p
- return p
- else
- local m="Peripheral NOT FOUND: "..name.." (type: " .. type_arg .. ")"
- if required then
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,m.." - REQUIRED!") end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,m) end
- end
- return nil
- end
- end
- function initCorePeripherals()
- print("Console: CHKPT - Enter initCorePeripherals")
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initCoreP: Start") end
- pAutomata=findPeripheral("Automata",AUTOMATA_PERIPHERAL_NAME,true)
- if not pAutomata then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initCoreP: Automata peripheral missing. Cannot proceed.") end
- print("Console: CHKPT - initCorePeripherals FAIL (Automata missing)")
- return false
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initCoreP: Core peripherals OK.") end
- print("Console: CHKPT - initCorePeripherals OK")
- return true
- end
- function findHomeLocationPeripherals()
- print("Console: CHKPT - Enter findHomeLocationPeripherals")
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"findHomeLocP: Start (should be at home and oriented)") end
- if not (home_pos and home_pos.x and current_pos and current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z) then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"findHomeLocP: Called when not at stored home coordinates.") end
- end
- if not (home_pos and home_pos.dir ~= nil and current_dir == home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"findHomeLocP: Not facing home direction (".. (home_pos and DIR_NAMES[home_pos.dir] or "N/A")..").") end
- if home_pos and home_pos.dir ~= nil then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "findHomeLocP: Attempting re-orientation to home dir: " .. DIR_NAMES[home_pos.dir]) end
- if not ml.turnToDir(home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "findHomeLocP: Re-orientation failed.") end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "findHomeLocP: home_pos.dir is nil, cannot re-orient.") end
- end
- end
- if not pMeBridge then
- pMeBridge=findPeripheral("ME Bridge",ME_BRIDGE_PERIPHERAL_NAME,true)
- elseif DEBUG_LOGGING_ENABLED and LOG_LEVELS then
- botLog(LOG_LEVELS.DEBUG, "findHomeLocP: pMeBridge already attached.")
- end
- if not pColonyIntegrator then
- pColonyIntegrator=findPeripheral("Colony Integrator",COLONY_INTEGRATOR_PERIPHERAL_NAME,true)
- elseif DEBUG_LOGGING_ENABLED and LOG_LEVELS then
- botLog(LOG_LEVELS.DEBUG, "findHomeLocP: pColonyIntegrator already attached.")
- end
- if not (pMeBridge and pColonyIntegrator)then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"findHomeLocP: ME Bridge or Colony Integrator missing after checks.") end
- print("Console: CHKPT - findHomeLocationPeripherals FAIL")
- return false
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"findHomeLocP: Home location peripherals OK.") end
- print("Console: CHKPT - findHomeLocationPeripherals OK")
- return true
- end
- --#endregion
- --#region JSON Data Handling
- function saveData() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"saveData: Attempt")end; if roboSlot==nil or not home_pos or home_pos.x==nil or not current_pos or current_pos.x==nil or current_dir==nil then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"saveData: Skip, incomplete data.")end; return false end; local d={roboSlot=roboSlot,home_pos=home_pos,current_pos=current_pos,current_dir=current_dir}; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"saveData: Data: "..textutils.serialize(d))end; local s,e=textutils.serialiseJSON(d); if not s then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"saveData: Serialize fail: "..tostring(e))end; return false end; local f,fe=fs.open(BOT_DATA_FILE,"w"); if not f then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"saveData: Open file fail: "..tostring(fe))end; return false end; f.write(s);f.close(); if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Bot data saved.")end; return true end
- function loadData() print("Console: CHKPT - Enter loadData"); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: Attempt from '"..BOT_DATA_FILE.."'")end; if not fs.exists(BOT_DATA_FILE)then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"loadData: File not found.")end; print("Console: CHKPT - loadData: No file"); return false end; local f,fe=fs.open(BOT_DATA_FILE,"r"); if not f then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"loadData: Open file fail: "..tostring(fe))end; print("Console: CHKPT - loadData: Open fail"); return false end; local s=f.readAll();f.close(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: File content: "..s)end; local sc,d=pcall(textutils.unserialiseJSON,s); if not sc or type(d)~="table"then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"loadData: Parse fail. SC:"..tostring(sc)..",D:"..tostring(d))end; print("Console: CHKPT - loadData: Parse JSON fail"); return false end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"loadData: Parsed: "..textutils.serialize(d))end; if d.roboSlot and d.home_pos and d.home_pos.x~=nil and d.home_pos.y~=nil and d.home_pos.z~=nil and d.home_pos.dir~=nil and d.current_pos and d.current_pos.x~=nil and d.current_pos.y~=nil and d.current_pos.z~=nil and d.current_dir~=nil then roboSlot=d.roboSlot;home_pos=d.home_pos;current_pos=d.current_pos;current_dir=d.current_dir; if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"Bot data loaded.")end; print("Console: CHKPT - loadData: OK"); return true else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"loadData: Incomplete/malformed data in JSON.")end; print("Console: CHKPT - loadData: Malformed data"); return false end end
- --#endregion
- --#region Movement Library (ml)
- ml = {}
- function ml.setPos(x,y,z,dirNum) current_pos={x=x,y=y,z=z}; current_dir=dirNum; if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("ml.setPos: X%sY%sZ%sD%s (%s)",x,y,z,dirNum,DIR_NAMES[dirNum])) end; saveData() end
- function ml.inspect() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspect: Called") end; local s,d=turtle.inspect(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspect: OK, Block: "..d.name) end; return d elseif s and not d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspect: OK, Empty.")end; return nil else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.inspect: Fail: " .. tostring(d))end; return nil end end
- function ml.inspectUp() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspectUp: Called") end; local s,d=turtle.inspectUp(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectUp: OK, Block: "..d.name)end; return d else if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectUp: OK, Empty/fail.")end; return nil end end
- function ml.inspectDown() if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "ml.inspectDown: Called") end; local s,d=turtle.inspectDown(); if s and d then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectDown: OK, Block: "..d.name)end; return d else if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.inspectDown: OK, Empty/fail.")end; return nil end end
- local function genericMove(moveFunc,actionName,updatesPos,updatesDir) local s,e=pcall(moveFunc); if s then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,actionName.." OK. Fuel:"..turtle.getFuelLevel())end; if updatesPos and current_pos and current_pos.x~=nil and current_dir~=nil then local oX,oY,oZ=current_pos.x,current_pos.y,current_pos.z; if actionName=="forward"then current_pos.x=current_pos.x+DIR_VECTORS[current_dir].x;current_pos.z=current_pos.z+DIR_VECTORS[current_dir].z elseif actionName=="back"then current_pos.x=current_pos.x-DIR_VECTORS[current_dir].x;current_pos.z=current_pos.z-DIR_VECTORS[current_dir].z elseif actionName=="up"then current_pos.y=current_pos.y+1 elseif actionName=="down"then current_pos.y=current_pos.y-1 end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"gMove Pos "..oX..","..oY..","..oZ.." -> "..current_pos.x..","..current_pos.y..","..current_pos.z)end; end; if updatesDir and current_dir~=nil then local oD=current_dir; if actionName=="turnLeft"then current_dir=(current_dir-1+4)%4 elseif actionName=="turnRight"then current_dir=(current_dir+1)%4 end; if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"gMove Dir "..(oD and DIR_NAMES[oD] or "nil").." -> "..(current_dir and DIR_NAMES[current_dir] or "nil"))end; end; if updatesPos or updatesDir then saveData() end; return true else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,actionName.." FAIL: "..tostring(e))end; return false end end
- function ml.forward() return genericMove(turtle.forward,"forward",true,false) end
- function ml.back() return genericMove(turtle.back,"back",true,false) end
- function ml.up() return genericMove(turtle.up,"up",true,false) end
- function ml.down() return genericMove(turtle.down,"down",true,false) end
- function ml.turnLeft() return genericMove(turtle.turnLeft,"turnLeft",false,true) end
- function ml.turnRight() return genericMove(turtle.turnRight,"turnRight",false,true) end
- function ml.select(slot) if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.select: Slot "..slot) end; turtle.select(slot); return true end
- function ml.getItemCount(slot) local c=turtle.getItemCount(slot); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getItemCount: Slt "..slot.." has "..c)end; return c end
- function ml.getItemDetail(slot) local d=turtle.getItemDetail(slot); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getItemDetail: Slt "..slot.." detail: "..(d and textutils.serialize(d, {compact=true}) or "nil"))end; return d end
- function ml.getFuelLevel() local l=turtle.getFuelLevel(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getFuelLevel: "..l)end; return l end
- function ml.getFuelLimit() local l=turtle.getFuelLimit(); if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.getFuelLimit: "..l)end; return l end
- function ml.drop(count) local sl=turtle.getSelectedSlot();local dt=ml.getItemDetail(sl);local iN=(dt and dt.name or "unk item");local aC=count or ml.getItemCount(sl);if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.drop: Try drop "..aC.." "..iN.." from slt "..sl)end;if aC==0 then return true end;local sc;if count then sc=turtle.drop(count)else sc=turtle.drop()end;if sc then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.drop: OK from slt "..sl)end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.drop: FAIL from slt "..sl)end end;return sc end
- function ml.suck(count) local sl=turtle.getSelectedSlot();local aC=count or 1;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.suck: Try suck "..aC.." into slt "..sl)end;local sc;if count then sc=turtle.suck(count)else sc=turtle.suck()end;if sc then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.suck: OK into slt "..sl .. " (req: "..aC..")")end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.suck: FAIL into slt "..sl)end end;return sc end
- function ml.refuel() ml.select(FUEL_SLOT);local it=ml.getItemDetail(FUEL_SLOT);if not it or it.name ~= COAL_BLOCK_NAME then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.refuel: Fail: No/wrong fuel. Need '"..COAL_BLOCK_NAME.."', Has: "..(it and it.name or "nil"))end;return false end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.refuel: Attempt from slt "..FUEL_SLOT.." with "..it.name)end;local iF=ml.getFuelLevel();local s=turtle.refuel();if s then if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.refuel: OK. Fuel: "..ml.getFuelLevel().." (was "..iF..")")end else if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.refuel: turtle.refuel() fail.")end end;return s end
- function ml.turnToDir(targetDirNum) if current_dir==nil then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"ml.turnToDir: current_dir is nil.")end; return false end;if targetDirNum<0 or targetDirNum>3 then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"ml.turnToDir: Invalid targetDir: "..targetDirNum)end; return false end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.turnToDir: From "..(DIR_NAMES[current_dir] or "nil").."("..current_dir..") to "..DIR_NAMES[targetDirNum].."("..targetDirNum..")")end;if current_dir==targetDirNum then return true end;local df=(targetDirNum-current_dir+4)%4;if df==1 then return ml.turnRight()elseif df==2 then return ml.turnRight() and ml.turnRight()elseif df==3 then return ml.turnLeft()end;return false end
- function ml.moveTo(tx,ty,tz,tdir_opt) print(string.format("Console: ml.moveTo Start - Tgt X%sY%sZ%sD%s", tx, ty, tz, (tdir_opt and DIR_NAMES[tdir_opt] or "any"))); if LOG_LEVELS then botLog(LOG_LEVELS.INFO, string.format("ml.moveTo: Tgt X%sY%sZ%sD%s | Cur X%sY%sZ%sD%s",tx,ty,tz,(tdir_opt and DIR_NAMES[tdir_opt] or "any"), current_pos.x,current_pos.y,current_pos.z,(current_dir and DIR_NAMES[current_dir] or "nil")))end; local function att(aF,cnt,axisName)for i=1,cnt do if not aF()then return false end;if ml.getFuelLevel()<5 and ml.getFuelLimit()>0 then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Low fuel ("..ml.getFuelLevel()..")!")end end;sleep(0.05)end;return true end; if current_pos.y~=ty then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj Y "..current_pos.y.."->"..ty)end; while current_pos.y<ty do if not ml.up()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked UP at Y="..current_pos.y.." to Y="..ty)end;return false end end;while current_pos.y>ty do if not ml.down()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked DOWN at Y="..current_pos.y.." to Y="..ty)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Y OK at "..current_pos.y)end end; if current_pos.x~=tx then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj X "..current_pos.x.."->"..tx)end; if current_pos.x<tx then if not ml.turnToDir(1)then return false end;if not att(ml.forward,tx-current_pos.x,"East")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked EAST at X="..current_pos.x)end;return false end elseif current_pos.x>tx then if not ml.turnToDir(3)then return false end;if not att(ml.forward,current_pos.x-tx,"West")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked WEST at X="..current_pos.x)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: X OK at "..current_pos.x)end end; if current_pos.z~=tz then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj Z "..current_pos.z.."->"..tz)end; if current_pos.z<tz then if not ml.turnToDir(0)then return false end;if not att(ml.forward,tz-current_pos.z,"North")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked NORTH at Z="..current_pos.z)end;return false end elseif current_pos.z>tz then if not ml.turnToDir(2)then return false end;if not att(ml.forward,current_pos.z-tz,"South")then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"ml.moveTo: Blocked SOUTH at Z="..current_pos.z)end;return false end end;if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Z OK at "..current_pos.z)end end; if tdir_opt~=nil and current_dir~=tdir_opt then if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"ml.moveTo: Adj final dir to "..DIR_NAMES[tdir_opt])end; if not ml.turnToDir(tdir_opt)then return false end end; if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"ml.moveTo: Target vicinity. Final Pos: X:"..current_pos.x.." Y:"..current_pos.y.." Z:"..current_pos.z.." Dir:"..(current_dir and DIR_NAMES[current_dir] or "nil"))end; print(string.format("Console: ml.moveTo End - Cur X%sY%sZ%sD%s", current_pos.x, current_pos.y, current_pos.z, (current_dir and DIR_NAMES[current_dir] or "nil"))); return current_pos.x==tx and current_pos.y==ty and current_pos.z==tz and (tdir_opt == nil or current_dir == tdir_opt) end
- --#endregion
- --#region Core Logic Functions
- function initializeBot()
- print("Console: CHKPT - Enter initializeBot");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Start")end;
- if not pAutomata then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"initializeBot: pAutomata nil!")end; print("Console: initializeBot - pAutomata nil, FAIL"); return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Warp 'home'")end;
- local ws,we=pcall(function()return pAutomata.warpToPoint("home")end);
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Warp pcall: SC="..tostring(ws)..", RES="..tostring(we))end;
- if not ws or not we then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Warp fail: SC="..tostring(ws)..", RES="..tostring(we))end; print("Console: initializeBot - Warp FAIL"); return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Warp OK. At physical home.")end;
- current_pos={x=nil,y=nil,z=nil};current_dir=nil;
- local me_bridge_peripheral_found = false
- for i=1,4 do
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Try " .. i .. "/4 find ME Bridge ("..ME_BRIDGE_PERIPHERAL_NAME..").") end
- pMeBridge = peripheral.find(ME_BRIDGE_PERIPHERAL_NAME)
- if pMeBridge then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "initializeBot: ME Bridge peripheral (type '"..ME_BRIDGE_PERIPHERAL_NAME.."') found on try " .. i .. ".") end
- mounted_peripherals["ME Bridge"] = pMeBridge
- me_bridge_peripheral_found = true
- break
- end
- if i < 4 then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: ME Bridge not found. Turning right.") end
- if not turtle.turnRight() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: turtle.turnRight() failed during ME Bridge search.") end
- return false
- end
- sleep(0.2)
- end
- end
- if not me_bridge_peripheral_found then
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "initializeBot: ME Bridge peripheral (type '"..ME_BRIDGE_PERIPHERAL_NAME.."') NOT found after 4 tries. REQUIRED.") end
- return false
- end
- pColonyIntegrator = findPeripheral("Colony Integrator", COLONY_INTEGRATOR_PERIPHERAL_NAME, true)
- if not pColonyIntegrator then
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "initializeBot: Colony Integrator NOT found (REQUIRED).") end
- return false
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Home location peripherals (ME Bridge, Colony Integrator) found.") end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Confirming visual to ME Bridge block ('"..ME_BRIDGE_NAME.."')...") end
- local visually_oriented_to_me_block = false
- for visual_orient_attempt = 1, 4 do
- local success_inspect, block_in_front = turtle.inspect()
- if success_inspect and block_in_front and block_in_front.name == ME_BRIDGE_NAME then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "initializeBot: Visually confirmed ME_BRIDGE_NAME block in front (try " .. visual_orient_attempt .. ").") end
- visually_oriented_to_me_block = true
- break
- end
- if visual_orient_attempt < 4 then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "initializeBot: Not visually facing ME_BRIDGE_NAME. Turning right.") end
- if not turtle.turnRight() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: turtle.turnRight() failed during visual ME Bridge confirm.") end
- return false
- end
- sleep(0.2)
- end
- end
- if not visually_oriented_to_me_block then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "initializeBot: Could not visually confirm ME_BRIDGE_NAME block in front after 4 tries.") end
- return false
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Backing up from ME Bridge.")end;
- if not turtle.back()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Raw turtle.back() failed.")end; print("Console: initializeBot - Back ME FAIL"); return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Turning right (to face Redstone path).")end;
- if not turtle.turnRight()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Raw turtle.turnRight() failed.")end; print("Console: initializeBot - TR after back FAIL"); return false end;
- local forward_count_to_redstone=0;
- local redstone_retries=0;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"initializeBot: Searching for Redstone Block ("..REDSTONE_BLOCK_NAME..")...")end;
- while true do
- local pcall_success, inspect_success_val, block_data_val_or_errmsg = pcall(turtle.inspect);
- if pcall_success and inspect_success_val and block_data_val_or_errmsg and type(block_data_val_or_errmsg) == "table" and block_data_val_or_errmsg.name==REDSTONE_BLOCK_NAME then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Redstone Block found after " .. forward_count_to_redstone .. " forward moves.")end;
- break
- end;
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then
- local block_ahead_log_str = "pcall_fail"
- if pcall_success then
- if inspect_success_val then block_ahead_log_str = (block_data_val_or_errmsg and type(block_data_val_or_errmsg)=="table" and block_data_val_or_errmsg.name or "empty")
- else block_ahead_log_str = "inspect_fail:" .. tostring(block_data_val_or_errmsg) end
- else block_ahead_log_str = "pcall_fail:" .. tostring(inspect_success_val) end
- botLog(LOG_LEVELS.DEBUG,"initializeBot: Redstone not found. Fwd. Count:"..forward_count_to_redstone.." Ahead: " .. block_ahead_log_str)
- end;
- if turtle.forward()then
- forward_count_to_redstone=forward_count_to_redstone+1;
- redstone_retries=0
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"initializeBot: Path to Redstone obstructed. Retry "..(redstone_retries+1).."/"..MAX_REDSTONE_BLOCK_RETRIES)end;
- redstone_retries=redstone_retries+1;
- if redstone_retries>=MAX_REDSTONE_BLOCK_RETRIES then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"initializeBot: Failed to reach Redstone Block.")end; print("Console: initializeBot - Redstone search FAIL (obstructed)"); return false
- end;
- sleep(REDSTONE_BLOCK_RETRY_WAIT)
- end
- end;
- roboSlot = forward_count_to_redstone + 1;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Determined roboSlot: "..roboSlot)end;
- local redstone_block_abs_x = -110
- local redstone_block_abs_y = 65
- local redstone_block_abs_z = 220
- local redstone_block_abs_dir = 1
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("initializeBot: Setting pos at Redstone: X%dY%dZ%dD%s(1)", redstone_block_abs_x, redstone_block_abs_y, redstone_block_abs_z, DIR_NAMES[redstone_block_abs_dir]))end;
- ml.setPos(redstone_block_abs_x, redstone_block_abs_y, redstone_block_abs_z, redstone_block_abs_dir);
- home_pos.x = redstone_block_abs_x - (roboSlot - 1);
- home_pos.y = redstone_block_abs_y;
- home_pos.z = redstone_block_abs_z + 1;
- home_pos.dir = 0;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("initializeBot: Calc home_pos: X%sY%sZ%sD%s (%s)",home_pos.x,home_pos.y,home_pos.z,home_pos.dir, DIR_NAMES[home_pos.dir]))end;
- if not saveData()then if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"initializeBot: Save data failed post-init.")end end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"initializeBot: Initialization complete.")end;
- print("Console: CHKPT - initializeBot OK");
- return true
- end
- function maneuverToBarrelsFromHome()
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverToBarrels: Start")end;
- if not(current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"maneuverToBarrels: Not at home! Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..current_dir..". Home: X"..home_pos.x.."Y"..home_pos.y.."Z"..home_pos.z.."D"..home_pos.dir..". Abort.")end;
- return false
- end;
- if not ml.moveTo(REFUEL_BARREL_ACCESS_POS.x,REFUEL_BARREL_ACCESS_POS.y,REFUEL_BARREL_ACCESS_POS.z,REFUEL_BARREL_ACCESS_POS.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverToBarrels: Failed ml.moveTo barrel access.")end;
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverToBarrels: OK, at barrel access.")end;
- return true
- end
- function maneuverHomeFromBarrels()
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverHome: Start")end
- if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"maneuverHome: Not at barrel access! Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..current_dir..". Expect: X"..REFUEL_BARREL_ACCESS_POS.x.."Y"..REFUEL_BARREL_ACCESS_POS.y.."Z"..REFUEL_BARREL_ACCESS_POS.z.."D"..REFUEL_BARREL_ACCESS_POS.dir..". Abort.")end; return false
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Cur pos at barrel access: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir])end
- local deltaX = home_pos.x - current_pos.x
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: DeltaX to home: " .. deltaX .. " (home.x: "..home_pos.x..", cur.x: "..current_pos.x..")") end
- if deltaX ~= 0 then
- local target_x_dir = (deltaX > 0) and 1 or 3
- if not ml.turnToDir(target_x_dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn for X align.")end; return false
- end
- for _=1, math.abs(deltaX) do
- if not ml.forward() then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed move during X align.")end; return false end
- end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: X coord aligned. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir]) end
- if current_pos.z ~= home_pos.z then
- local deltaZ_to_home = home_pos.z - current_pos.z
- local target_z_dir = (deltaZ_to_home > 0) and 0 or 2
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Adj Z from "..current_pos.z.." to "..home_pos.z) end
- if not ml.turnToDir(target_z_dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn for Z align.")end; return false
- end
- for _=1, math.abs(deltaZ_to_home) do
- if not ml.forward() then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed move during Z align.")end; return false end
- end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"maneuverHome: Z coord aligned. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..DIR_NAMES[current_dir]) end
- if not ml.turnToDir(home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"maneuverHome: Failed turn to final home dir ("..DIR_NAMES[home_pos.dir]..").")end; return false
- end
- if current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"maneuverHome: OK, at home.")end; return true
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,string.format("maneuverHome: Homing FAILED. Pos Mismatch. Expect X%sY%sZ%sD%s, Got X%sY%sZ%sD%s", home_pos.x,home_pos.y,home_pos.z,DIR_NAMES[home_pos.dir], current_pos.x,current_pos.y,current_pos.z,DIR_NAMES[current_dir]))end;
- return false
- end
- end
- function goHomeProcedure()
- print("Console: CHKPT - Enter goHomeProcedure");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Start")end;
- if current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Already at home.")end; print("Console: goHomeProcedure - Already home");
- return true
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Nav to nest entry x-113 y100 z221...")end;
- if not ml.moveTo(-113,100,221,nil)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"goHomeProc: Failed to nav to nest entry.")end; print("Console: goHomeProcedure - moveTo nest entry FAIL");
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: At nest entry. Descending to Y65.")end;
- while current_pos.y > 65 do
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Descending. Cur Y:"..current_pos.y)end;
- if not ml.down()then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: Descend failed at Y:"..current_pos.y)end; print("Console: goHomeProcedure - descend FAIL");
- return false
- end
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Descended to Y65.")end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Moving to barrel access pos REFUEL_BARREL_ACCESS_POS")end;
- if not ml.moveTo(REFUEL_BARREL_ACCESS_POS.x,REFUEL_BARREL_ACCESS_POS.y,REFUEL_BARREL_ACCESS_POS.z,REFUEL_BARREL_ACCESS_POS.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: Failed to move to barrel access pos.")end;
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"goHomeProc: Positioned at refuel barrel access.")end;
- if not maneuverHomeFromBarrels()then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"goHomeProc: maneuverHomeFromBarrels failed.")end;
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"goHomeProc: Successfully returned home.")end;
- print("Console: CHKPT - goHomeProcedure OK");
- return true
- end
- function handleFuel()
- print("Console: CHKPT - Enter handleFuel");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Start")end;
- if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Not at barrel access. Skipping fuel.")end;
- return true
- end;
- local fuel_level, fuel_limit = ml.getFuelLevel(), ml.getFuelLimit();
- if fuel_limit == 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Infinite fuel.")end;
- return true
- end;
- local fuel_percentage = (fuel_level / fuel_limit);
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,string.format("handleFuel: Fuel: %d/%d (%.2f%%)",fuel_level,fuel_limit,fuel_percentage*100))end;
- local needs_refuel = fuel_percentage < REFUEL_BELOW_PERCENTAGE;
- local coal_detail = ml.getItemDetail(FUEL_SLOT);
- local coal_count = ml.getItemCount(FUEL_SLOT);
- local needs_restock = not coal_detail or coal_detail.name ~= COAL_BLOCK_NAME or coal_count < (coal_detail and coal_detail.maxCount or 64);
- if needs_refuel or needs_restock then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Action. Refuel="..tostring(needs_refuel)..", Restock="..tostring(needs_restock))end;
- if needs_restock then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Restocking slt "..FUEL_SLOT.." with "..COAL_BLOCK_NAME)end;
- ml.select(FUEL_SLOT);
- if coal_detail and coal_detail.name ~= COAL_BLOCK_NAME and coal_count > 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Non-"..COAL_BLOCK_NAME.." in fuel slt! Can't restock.")end
- else
- local amount_to_suck = (coal_detail and coal_detail.maxCount or 64) - coal_count;
- if amount_to_suck > 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleFuel: Try suck "..amount_to_suck.." "..COAL_BLOCK_NAME..".")end;
- if ml.suck(amount_to_suck)then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Sucked "..COAL_BLOCK_NAME..". New count: "..ml.getItemCount(FUEL_SLOT))end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Failed to suck "..COAL_BLOCK_NAME..".")end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleFuel: Fuel slt full of "..COAL_BLOCK_NAME.." or needs 0.")end
- end
- end
- end;
- coal_detail = ml.getItemDetail(FUEL_SLOT)
- if fuel_percentage < REFUEL_BELOW_PERCENTAGE and coal_detail and coal_detail.name == COAL_BLOCK_NAME then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Refueling...")end;
- if not ml.refuel()then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: ml.refuel() attempt failed.")end
- end
- elseif fuel_percentage < REFUEL_BELOW_PERCENTAGE then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleFuel: Needs refuel, but fuel slt no "..COAL_BLOCK_NAME)end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleFuel: Fuel level and stock OK.")end
- end;
- print("Console: CHKPT - Exit handleFuel");
- return true
- end
- function handleItemReturn()
- print("Console: CHKPT - Enter handleItemReturn");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Start")end;
- if not(current_pos.x==REFUEL_BARREL_ACCESS_POS.x and current_pos.y==REFUEL_BARREL_ACCESS_POS.y and current_pos.z==REFUEL_BARREL_ACCESS_POS.z and current_dir==REFUEL_BARREL_ACCESS_POS.dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleItemReturn: Not at barrel access. Skipping.")end;
- return true
- end;
- local items_found_to_return=false;
- for slot_idx=1,15 do
- if ml.getItemCount(slot_idx)>0 then
- items_found_to_return=true;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Found items in slt "..slot_idx.." to return.")end;
- break
- end
- end;
- if not items_found_to_return then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: No items in cargo slts 1-15.")end; print("Console: handleItemReturn - No items");
- return true
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Items found. Moving up to Return Barrel.")end;
- if not ml.up()then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"handleItemReturn: Failed move up to Return Barrel.")end; print("Console: handleItemReturn - up FAIL");
- return false
- end;
- for slot_idx=1,15 do
- ml.select(slot_idx);
- local item_count_in_slot=ml.getItemCount(slot_idx);
- if item_count_in_slot > 0 then
- local item_detail=ml.getItemDetail(slot_idx);
- local item_name = item_detail and item_detail.name or "Unknown Item";
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Try return "..item_count_in_slot.."x "..item_name.." from slt "..slot_idx)end;
- if not ml.drop()then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"handleItemReturn: Failed drop items from slt "..slot_idx)end
- end
- end
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"handleItemReturn: Finished returns. Moving down from Return Barrel.")end;
- if not ml.down()then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"handleItemReturn: Failed move down from Return Barrel.")end; print("Console: handleItemReturn - down FAIL");
- return false
- end;
- undeliveredItemsBuffer = {}
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"handleItemReturn: Item return complete.")end;
- print("Console: CHKPT - Exit handleItemReturn");
- return true
- end
- function getItemsFromME(itemsToGetTable)
- print("Console: CHKPT - Enter getItemsFromME")
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Start") end
- if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: Not at home. Aborting.") end
- return {}
- end
- if not pMeBridge then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: pMeBridge is nil. Aborting.") end
- return {}
- end
- if type(pMeBridge.exportItem) ~= "function" then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: pMeBridge NO 'exportItem' method. Peripheral/mod issue? Abort ME.") end
- return {}
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Moving up to ME xfer chest.") end
- if not ml.up() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: Failed move up to ME xfer chest.") end
- return {}
- end
- local fetched_item_details = {}
- for _, requested_item_spec in ipairs(itemsToGetTable) do
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Request " .. requested_item_spec.count .. "x " .. requested_item_spec.name .. " from ME.") end
- local export_pcall_success, export_result_or_err = pcall(function() return pMeBridge.exportItem({ name = requested_item_spec.name, count = requested_item_spec.count }, "up") end)
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: exportItem pcall SC=" .. tostring(export_pcall_success) .. ", Res/Err=" .. textutils.serialize(export_result_or_err)) end
- if not export_pcall_success then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: CRITICAL - pcall pMeBridge.exportItem failed for " .. requested_item_spec.name .. ". Err: " .. tostring(export_result_or_err)) end
- goto continue_me_item_request
- end
- if type(export_result_or_err) ~= "number" or export_result_or_err == 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: ME export 0/non-numeric for " .. requested_item_spec.name .. ". Actual ME resp: " .. textutils.serialize(export_result_or_err)) end
- goto continue_me_item_request
- end
- local actual_exported_count = export_result_or_err
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: ME Bridge exported " .. actual_exported_count .. "x " .. requested_item_spec.name .. " to chest.") end
- local amount_remaining_to_suck_from_chest = actual_exported_count
- while amount_remaining_to_suck_from_chest > 0 do
- local target_slot = -1
- for s = 1, 15 do
- local item_in_slot = ml.getItemDetail(s)
- if item_in_slot and item_in_slot.name == requested_item_spec.name and item_in_slot.count < item_in_slot.maxCount then
- target_slot = s
- break
- end
- end
- if target_slot == -1 then
- for s = 1, 15 do
- if not ml.getItemDetail(s) then
- target_slot = s
- break
- end
- end
- end
- if target_slot == -1 then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: No inv space for '" .. requested_item_spec.name .. "' (need " .. amount_remaining_to_suck_from_chest .. "). Items may remain in chest.") end
- break
- end
- ml.select(target_slot)
- local space_in_this_slot = turtle.getItemSpace(target_slot)
- local attempt_suck_amount = math.min(amount_remaining_to_suck_from_chest, space_in_this_slot)
- if attempt_suck_amount == 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Slt " .. target_slot .. " full or no more items for " .. requested_item_spec.name .. ". Skip suck.") end
- break
- end
- local count_in_slot_before_suck = ml.getItemCount(target_slot)
- if ml.suck(attempt_suck_amount) then
- local count_in_slot_after_suck = ml.getItemCount(target_slot)
- local num_actually_sucked_this_op = count_in_slot_after_suck - count_in_slot_before_suck
- if num_actually_sucked_this_op > 0 then
- amount_remaining_to_suck_from_chest = amount_remaining_to_suck_from_chest - num_actually_sucked_this_op
- local existing_entry_idx = -1
- for i, entry in ipairs(fetched_item_details) do
- if entry.slot == target_slot then
- existing_entry_idx = i; break
- end
- end
- if existing_entry_idx ~= -1 then
- fetched_item_details[existing_entry_idx].count = count_in_slot_after_suck
- else
- table.insert(fetched_item_details, { name = requested_item_spec.name, slot = target_slot, count = count_in_slot_after_suck })
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Sucked " .. num_actually_sucked_this_op .. "x " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Total: " .. count_in_slot_after_suck .. ". Left in chest: " .. amount_remaining_to_suck_from_chest) end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: ml.suck() 0 items for " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Chest empty?") end
- break
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "getItemsFromME: ml.suck() failed for " .. requested_item_spec.name .. " to slt " .. target_slot .. ". Chest obstructed/empty?") end
- break
- end
- end
- ::continue_me_item_request::
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "getItemsFromME: Finished all requests. Moving down from ME chest.") end
- if not ml.down() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "getItemsFromME: Failed to move down from ME xfer chest.") end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "getItemsFromME: Process complete. Fetched " .. #fetched_item_details .. " item stacks/details.") end
- print("Console: CHKPT - Exit getItemsFromME")
- return fetched_item_details
- end
- function leaveNest()
- print("Console: CHKPT - Enter leaveNest");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"leaveNest: Start")end;
- local start_exit_pos_x = home_pos.x
- local start_exit_pos_y = home_pos.y
- local start_exit_pos_z = home_pos.z - 1
- local start_exit_dir = 1
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("leaveNest: Moving to redstone block pos (X%sY%sZ%sD%s) for exit.", start_exit_pos_x, start_exit_pos_y, start_exit_pos_z, DIR_NAMES[start_exit_dir]))end;
- if not ml.moveTo(start_exit_pos_x, start_exit_pos_y, start_exit_pos_z, start_exit_dir)then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Failed to move to redstone block for exit.")end;
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Turning South (TR from East).")end;
- if not ml.turnRight()then return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Moving Forward (South).")end;
- if not ml.forward()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed moving South.")end;return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Turning West (TR from South).")end;
- if not ml.turnRight()then return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Moving Forward (West).")end;
- if not ml.forward()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed moving West.")end;return false end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Ascending to Y=100...")end;
- while current_pos.y < 100 do
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Ascending. Cur Y:"..current_pos.y)end;
- if not ml.up()then if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Obstructed ascent at Y:"..current_pos.y)end;return false end
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"leaveNest: Reached Y=100.")end;
- local target_exit_x = -111
- local target_exit_y = 100
- local target_exit_z = 221
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, string.format("leaveNest: Moving to final exit (X%sY%sZ%s).",target_exit_x, target_exit_y, target_exit_z))end;
- if not ml.moveTo(target_exit_x, target_exit_y, target_exit_z, nil)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, string.format("leaveNest: Can't reach precise final exit. Cur Y:%s. Tgt X%sY%sZ%s.", current_pos.y, target_exit_x, target_exit_y, target_exit_z))end;
- if current_pos.y ~= target_exit_y then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"leaveNest: Critical - Y incorrect after ascent. Expected Y"..target_exit_y)end;
- return false
- end
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("leaveNest: OK. Cur Pos: X%sY%sZ%sD%s (%s)",current_pos.x,current_pos.y,current_pos.z,current_dir, DIR_NAMES[current_dir]))end;
- print("Console: CHKPT - Exit leaveNest");
- return true
- end
- function deliverItems(target_pos,items_in_slots_details)
- print("Console: CHKPT - Enter deliverItems");
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,string.format("deliverItems: Target X%sY%sZ%s",target_pos.x,target_pos.y,target_pos.z))end;
- if not ml.moveTo(target_pos.x,target_pos.y,target_pos.z,nil)then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"deliverItems: Failed move to delivery loc ("..target_pos.x..","..target_pos.y..","..target_pos.z.."). Buffering items.")end;
- for _,item_detail_entry in ipairs(items_in_slots_details)do
- table.insert(undeliveredItemsBuffer,{name=item_detail_entry.name,count=item_detail_entry.count,original_slot=item_detail_entry.slot})
- end;
- if DEBUG_LOGGING_ENABLED and LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: All items for this delivery buffered. Buffer size:"..#undeliveredItemsBuffer)end;
- return false
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: Arrived at delivery loc. Dropping items.")end;
- for _,item_detail_entry in ipairs(items_in_slots_details)do
- ml.select(item_detail_entry.slot);
- local count_to_drop = ml.getItemCount(item_detail_entry.slot);
- if count_to_drop > 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: Try drop "..count_to_drop.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot)end;
- if not ml.drop(count_to_drop)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"deliverItems: Failed drop all ("..item_detail_entry.name..") from slt "..item_detail_entry.slot)end;
- local remaining_count = ml.getItemCount(item_detail_entry.slot);
- if remaining_count > 0 then
- table.insert(undeliveredItemsBuffer,{name=item_detail_entry.name,count=remaining_count,original_slot=item_detail_entry.slot});
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"deliverItems: "..remaining_count.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot.." added to buffer.")end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"deliverItems: OK dropped "..count_to_drop.."x "..item_detail_entry.name.." from slt "..item_detail_entry.slot)end
- end
- end
- end;
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"deliverItems: Delivery attempt complete.")end;
- print("Console: CHKPT - Exit deliverItems");
- return true
- end
- --#endregion
- --#region Main Loop
- local function run()
- print("Console: CHKPT - run() CALLED")
- do
- local fileNameToOpen = LOG_FILE_NAME_CONST
- if type(fileNameToOpen) ~= "string" then
- print("Console: CRITICAL - LOG_FILE_NAME_CONST nil. Forcing default.")
- fileNameToOpen = "villagebot_forced_CRITICAL.log"
- end
- local f,ferr=fs.open(fileNameToOpen,"w")
- if f then
- f.write(string.format("[%s] VillageBot Log Initialized.\n",os.date("%Y-%m-%d %H:%M:%S")))
- f.close()
- print("Console: Log file reset: " .. fileNameToOpen)
- else
- print("Console: CRITICAL - Log init FAIL for '" .. tostring(fileNameToOpen) .. "': "..tostring(ferr))
- if LOG_LEVELS and pcall then
- pcall(botLog,LOG_LEVELS.FATAL,"CRITICAL - Log init FAIL: "..tostring(ferr))
- end
- return
- end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"VillageBot v1.7 Starting...") else print("Console: VillageBot v1.7 Starting... (LOG_LEVELS nil)") end
- sleep(0.1)
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"RUN: Init core peripherals...") end; sleep(0.1)
- local corePOK=initCorePeripherals();
- if not corePOK then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: initCoreP FAILED. Terminating.")end; print("Console: Error - Core P init FAILED. Terminate."); return end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Core Peripherals OK.")end; sleep(0.1)
- local data_setup_successful=false
- if loadData() and roboSlot~=nil and home_pos and home_pos.x~=nil and current_pos and current_pos.x~=nil and current_dir~=nil then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Bot data loaded. RoboSlot:"..roboSlot)end
- data_setup_successful=true
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: No valid data file/incomplete. Full initialization.")end
- if fs.exists(BOT_DATA_FILE) then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"RUN: Existing data file invalid. Deleting.")end
- pcall(fs.delete, BOT_DATA_FILE)
- end
- if initializeBot()then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Bot full initialization OK.")end
- data_setup_successful=true
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Bot full initialization FAILED. Terminating.")end;print("Console: Error - Bot core init FAILED. Terminate.");return
- end
- end
- if not data_setup_successful then if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Failed load/init bot data. Terminating.")end;print("Console: FATAL - Data setup FAILED. Terminate.");return end
- if not pMeBridge or not pColonyIntegrator then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "RUN: Home location P (ME, ColonyIntegrator) not confirmed. Ensure home & find.") end
- if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "RUN: Bot not home. Running goHomeProcedure.") end
- if not goHomeProcedure() then
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "RUN: goHomeProcedure failed during setup. Cannot find home P. Terminating.") end
- return
- end
- end
- if not findHomeLocationPeripherals() then
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL, "RUN: Failed to find/attach home P after ensuring home. Terminating.") end
- return
- end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Data load/init phase complete. Required P should be found."); end; sleep(0.1)
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"RUN: Entering main operational loop...")end;
- while true do
- -- Declare ALL loop-specific locals at the top to avoid goto scope issues
- local work_order_data = nil
- local items_to_fetch = nil
- local fetched_items_summary = nil
- local get_work_pcall_success = false -- For getBuilderResources pcall
- local work_order_result_from_api = nil -- Result from getBuilderResources
- local all_wo_pcall_success = false -- For getWorkOrders pcall
- local all_wo_result = nil -- Result from getWorkOrders
- local all_work_orders = nil
- local my_assigned_work_order_details = nil
- local builder_hut_pos_for_api_call = nil
- local needs_dedicated_barrel_trip_flag = false
- local fuel_check_still_needed_flag = true
- local item_return_check_still_needed_flag = true
- local was_at_barrels_this_cycle_leg = false
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "===== Cycle Start =====")end; sleep(0.1)
- if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Not home. Cur: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..(current_dir and DIR_NAMES[current_dir] or "nil")..". Running goHomeProcedure.")end
- if not goHomeProcedure() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: goHomeProcedure failed. Retry cycle after delay.")end
- sleep(60); goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: goHomeProcedure OK. Bot should be home (passed barrels).")end
- was_at_barrels_this_cycle_leg = true
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Started cycle at home.")end
- end
- if was_at_barrels_this_cycle_leg then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Bot was at barrels during goHome transit. Performing checks.")end
- else
- local current_fuel_level = ml.getFuelLevel(); local current_fuel_limit = ml.getFuelLimit()
- if current_fuel_limit == 0 or (current_fuel_limit > 0 and (current_fuel_level / current_fuel_limit >= REFUEL_BELOW_PERCENTAGE)) then
- fuel_check_still_needed_flag = false
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel OK/infinite, no trip *just* for low fuel %.")end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel low. Trip for fuel may be needed.")end
- end
- local items_in_cargo_slots = false
- for slot_idx=1,15 do if ml.getItemCount(slot_idx) > 0 then items_in_cargo_slots = true; break; end end
- if not items_in_cargo_slots then
- item_return_check_still_needed_flag = false
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: No items in cargo, no trip *just* for item return.")end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Items in cargo. Trip for item return may be needed.")end
- end
- local coal_detail_check = ml.getItemDetail(FUEL_SLOT)
- local needs_fuel_slot_restock = not coal_detail_check or coal_detail_check.name ~= COAL_BLOCK_NAME or ml.getItemCount(FUEL_SLOT) < (coal_detail_check and coal_detail_check.maxCount or 64)
- if needs_fuel_slot_restock then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel slt needs restock. Trip for fuel may be needed.")end
- fuel_check_still_needed_flag = true
- end
- needs_dedicated_barrel_trip_flag = fuel_check_still_needed_flag or item_return_check_still_needed_flag
- if needs_dedicated_barrel_trip_flag then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Home, but needs fuel/return. Maneuvering to barrels. FuelNeeded="..tostring(fuel_check_still_needed_flag).." ItemReturnNeeded="..tostring(item_return_check_still_needed_flag))end
- if not maneuverToBarrelsFromHome() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed maneuver to barrels from home. Retry cycle after delay.")end
- sleep(60); goto continue_main_loop_cycle
- end
- was_at_barrels_this_cycle_leg = true
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Home, no dedicated fuel/return ops needed from here.")end
- end
- end
- if was_at_barrels_this_cycle_leg then
- if item_return_check_still_needed_flag then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Item return at barrels.")end
- if not handleItemReturn() then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN, "LOOP: Issue during item return at barrels. Continuing.")end
- end
- end
- if fuel_check_still_needed_flag then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Fuel handling at barrels.")end
- if not handleFuel() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed fuel handling at barrels. Retry cycle after delay.")end;
- sleep(60); goto continue_main_loop_cycle
- end
- end
- if not (current_pos.x == home_pos.x and current_pos.y == home_pos.y and current_pos.z == home_pos.z and current_dir == home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Not home after barrel ops. Maneuvering home.")end
- if not maneuverHomeFromBarrels() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Failed maneuver home from barrels. Retry cycle after delay.")end
- sleep(60); goto continue_main_loop_cycle
- end
- end
- end
- if not(current_pos.x==home_pos.x and current_pos.y==home_pos.y and current_pos.z==home_pos.z and current_dir==home_pos.dir) then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: CRITICAL - NOT HOME before get work! Pos: X"..current_pos.x.."Y"..current_pos.y.."Z"..current_pos.z.."D"..(current_dir and DIR_NAMES[current_dir] or "nil")..". Forcing goHomeProcedure.")end
- if not goHomeProcedure() then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: Critical Fail on forced goHomeProcedure. Retry cycle after delay.")end
- sleep(60); goto continue_main_loop_cycle
- end
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Pos confirmed home before work tasks.")end
- if not pColonyIntegrator then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pColonyIntegrator nil. Cannot get work. Retry cycle.") end
- sleep(30); goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: Fetching all work orders.")end
- all_wo_pcall_success, all_wo_result = pcall(function() return pColonyIntegrator.getWorkOrders() end)
- if not all_wo_pcall_success or not all_wo_result or type(all_wo_result) ~= "table" then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pcall getWorkOrders() failed or invalid data. Res/Err: " .. textutils.serialize(all_wo_result) .. ". Retry cycle.") end
- sleep(30); goto continue_main_loop_cycle
- end
- all_work_orders = all_wo_result
- if #all_work_orders == 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: No active work orders from getWorkOrders(). Wait & retry.") end
- sleep(30); goto continue_main_loop_cycle
- end
- if roboSlot < 1 or roboSlot > #all_work_orders then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: roboSlot (" .. roboSlot .. ") out of bounds for work orders (size: " .. #all_work_orders .. "). Wait & retry.") end
- sleep(30); goto continue_main_loop_cycle
- end
- my_assigned_work_order_details = all_work_orders[roboSlot]
- if not my_assigned_work_order_details or
- not my_assigned_work_order_details.builder or
- type(my_assigned_work_order_details.builder) ~= "table" or
- not my_assigned_work_order_details.builder.x or
- not my_assigned_work_order_details.builder.y or
- not my_assigned_work_order_details.builder.z then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: Assigned WO at index " .. roboSlot .. " invalid or missing builder pos. Details: " .. textutils.serialize(my_assigned_work_order_details) .. ". Retry cycle.") end
- sleep(30); goto continue_main_loop_cycle
- end
- builder_hut_pos_for_api_call = my_assigned_work_order_details.builder
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Fetching resources via getBuilderResources for builder hut at X:" .. builder_hut_pos_for_api_call.x .. "Y:" .. builder_hut_pos_for_api_call.y .. "Z:" .. builder_hut_pos_for_api_call.z .. " (roboSlot " .. roboSlot .. ")") end
- get_work_pcall_success, work_order_result_from_api = pcall(function() return pColonyIntegrator.getBuilderResources(builder_hut_pos_for_api_call) end)
- if not get_work_pcall_success then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR, "LOOP: pcall pColonyIntegrator.getBuilderResources() failed. Err: "..tostring(work_order_result_from_api)..". Retry cycle.") end
- sleep(30); goto continue_main_loop_cycle
- end
- work_order_data = work_order_result_from_api
- if not work_order_data or type(work_order_data) ~= "table" then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: No work data or invalid from getBuilderResources. Data: "..textutils.serialize(work_order_data) ..". Wait & retry.") end
- sleep(30); goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG, "LOOP: Received work data from getBuilderResources: " .. textutils.serialize(work_order_data)) end
- if work_order_data.resources and type(work_order_data.resources) == "table" and
- work_order_data.hutLocation and type(work_order_data.hutLocation) == "table" and
- work_order_data.hutLocation.x and work_order_data.hutLocation.y and work_order_data.hutLocation.z then
- if #work_order_data.resources == 0 then
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: WO for roboSlot "..roboSlot.." has no resources in getBuilderResources response. Task complete for now. Waiting.") end
- sleep(30); goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO, "LOOP: Valid work data. Resources: "..#work_order_data.resources..", Hut: X"..work_order_data.hutLocation.x .. "Y"..work_order_data.hutLocation.y .. "Z"..work_order_data.hutLocation.z) end
- items_to_fetch = work_order_data.resources
- fetched_items_summary = getItemsFromME(items_to_fetch)
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: getItemsFromME returned "..#fetched_items_summary.." item slot details.")end
- local has_items_to_deliver = false
- if fetched_items_summary and #fetched_items_summary > 0 then
- for _, item_entry in ipairs(fetched_items_summary) do
- if item_entry.count > 0 then has_items_to_deliver = true; break; end
- end
- end
- if has_items_to_deliver then
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Items fetched. Leaving nest.")end
- if not leaveNest()then
- if LOG_LEVELS then botLog(LOG_LEVELS.ERROR,"LOOP: Failed to leave nest. Items returned next cycle. Retry cycle after delay.")end
- sleep(30);goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: leaveNest OK.")end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: Delivering items to hut X:"..work_order_data.hutLocation.x.."Y:"..work_order_data.hutLocation.y.."Z:"..work_order_data.hutLocation.z)end
- if not deliverItems(work_order_data.hutLocation, fetched_items_summary)then
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"LOOP: Delivery issues. Undelivered items buffered.")end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: deliverItems process completed for this WO.")end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"LOOP: No items fetched from ME for WO, or ME bridge issue.")end
- end
- else
- if LOG_LEVELS then botLog(LOG_LEVELS.WARN,"LOOP: Work data from getBuilderResources incomplete/malformed. Structure: "..textutils.serialize(work_order_data)..". Wait & retry.")end
- sleep(30); goto continue_main_loop_cycle
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.INFO,"===== Cycle End OK =====")end
- ::continue_main_loop_cycle::
- if LOG_LEVELS then botLog(LOG_LEVELS.DEBUG,"LOOP: Sleeping 30s before next cycle.")end
- print("Console: LOOP - Cycle End. Sleep 30s.")
- sleep(30)
- end
- if LOG_LEVELS then botLog(LOG_LEVELS.FATAL,"RUN: Main loop EXITED UNEXPECTEDLY!")end; print("Console: FATAL - Main loop EXITED!")
- end
- --#endregion
- -- Start the bot
- print("Console: DEBUG - Script exec start. Calling run().")
- run()
- print("Console: DEBUG - Script exec finished. run() completed/exited.")
- if LOG_LEVELS and LOG_FILE_NAME_CONST and type(LOG_FILE_NAME_CONST) == "string" then
- pcall(botLog,LOG_LEVELS.FATAL, "SCRIPT ENDED ABNORMALLY: Reached end of file after run() call.")
- else
- print("Console: SCRIPT ENDED ABNORMALLY (LOG_LEVELS or LOG_FILE_NAME_CONST invalid).")
- end
Add Comment
Please, Sign In to add comment