Skip to content

Instantly share code, notes, and snippets.

@Death-123
Last active November 27, 2023 13:49
Show Gist options
  • Save Death-123/26922e7352580f31b566896b33534127 to your computer and use it in GitHub Desktop.
Save Death-123/26922e7352580f31b566896b33534127 to your computer and use it in GitHub Desktop.
opencomputer script
local component = require("component")
local sides = require("sides")
local thread = require("thread")
local term = require("term")
local robotLib = require("robotLib")
local Pos = require('Pos')
local File = require("File")
local Screen = require("Screen")
local Recipe = require("Recipe")
local robot = component.robot
local invc = component.inventory_controller
local DefaultPos = Pos(0,0,0)
local WIDTH , HEIGHT = Screen.getWH()
local idleTimeMax = 5
local inventoryItemList = {}
local inventorySide = 2 -- inventory side, 2 means right, 3 back, 4 left 箱子方向,2为右,3后,4左
local areaSize = 5 -- craft area size 3 or 5 normal 合成区域大小,一般是3或5
local areaStartPos = Pos(4 , 2) -- craft area start pos, 4 , 2 means the area start at forward 4 block , right 2 block and bottom 1 block
--合成区域起始位置,前方为x轴正向,右方为y轴正向,合成区域必须是右前方向
local recipeFile = '/home/recipe.txt'
local recipeArea = Pos()
local recipeUsed = {}
local recipeChanged = true
robotLib:init(DefaultPos)
local function processRecipe()
if recipeChanged then
recipeUsed = File.ReadFile(recipeFile)
if (recipeUsed == nil) then
recipeUsed = Recipe.setRecipe()
end
end
recipeArea = Pos()
local itemList = {}
for i,j in pairs(recipeUsed.recipe) do
for k,v in pairs(j) do
for l,m in pairs(v) do
if(m ~= nil) then
if(itemList[m] == nil) then
itemList[m] = 1
else
itemList[m] = itemList[m] + 1
end
recipeArea:large(Pos(l,k,i))
if (recipeArea > Pos(areaSize , areaSize , areaSize)) then
error('recipe required area larger than the area now')
end
end
end
end
end
if(recipeUsed.catalyzer ~= nil) then
if(itemList[recipeUsed.catalyzer] == nil) then
itemList[recipeUsed.catalyzer] = 1
else
itemList[recipeUsed.catalyzer] = itemList[recipeUsed.catalyzer] + 1
end
end
return itemList
end
local function placeBlock()
local pos = robotLib.getPos() - areaStartPos + Pos(1,1,1)
if(pos <= recipeArea) then
local block = recipeUsed.recipe[pos.z][pos.x][pos.y]
if(block ~= nil) then
local i = 1
while (inventoryItemList[block].slot[i] ~= nil) do
local slot = inventoryItemList[block].slot[i]
local item = invc.getStackInInternalSlot(slot)
if (item ~= nil and item.size > 0) then
robot.select(slot)
robot.place(sides.bottom)
return
end
i = i + 1
end
end
end
end
local function beforeBuild()
robotLib.turnTo(inventorySide)
local itemList = processRecipe()
local flag = robotLib.suckItem(sides.forward , itemList)
if(flag) then
inventoryItemList = robotLib.getItemList()
idleTimeMax = recipeUsed.craftTime
end
robotLib.turnTo(1)
return flag
end
local function moveToAreaStart()
for i = 1 , areaStartPos.x do
robotLib.forward(true)
end
robotLib.turn(true)
for i = 1, areaStartPos.y do
robotLib.forward(true)
end
robotLib.turn(false)
while (robotLib.getPos().z ~= areaStartPos.z) do
if (areaStartPos.z > 0) then
robotLib.moveUp(true)
else
robotLib.moveUp(false)
end
end
end
local function build()
local areaEndPos = areaStartPos + recipeArea - Pos(1,1,1)
local right = true
local total = recipeArea.x * recipeArea.y
for i = 1, areaSize do
local j = 1
while (j < total and i <= recipeArea.z) do
while(robotLib.getForwardPos():inArea(areaStartPos, areaEndPos)) do
placeBlock()
robotLib.forward(true)
j = j + 1
end
if (j < total) then
placeBlock()
robotLib.turn(right)
robotLib.forward()
j = j + 1
robotLib.turn(right)
right = not right
end
end
placeBlock()
robotLib.moveUp(true)
if (total ~= 1 and i < recipeArea.z) then
robotLib.turn()
robotLib.turn()
end
end
local catalyzer = recipeUsed.catalyzer
local i = 1
while (inventoryItemList[catalyzer].slot[i] ~= nil) do
local slot = inventoryItemList[catalyzer].slot[i]
local item = invc.getStackInInternalSlot(slot)
if (item ~= nil and item.size > 0) then
robot.select(slot)
robot.drop(sides.bottom)
break
end
i = i + 1
end
robotLib.turnTo(4)
while(robotLib.getPos().y ~= DefaultPos.y) do
robotLib.forward(true)
end
robotLib.turn(false)
while(robotLib.getPos().x ~= DefaultPos.x) do
robotLib.forward(true)
end
while(robotLib.getPos().z ~= DefaultPos.z) do
robotLib.moveUp(false)
end
robotLib.turn(true)
robotLib.turn(true)
end
local function afterBuild()
while (robotLib.getIdleTime() < idleTimeMax and robotLib.getIdleTime() ~= -1) do
robotLib.setIdleTime(robotLib.getIdleTime() + 1)
term.clear()
local signNumber = math.floor(robotLib.getIdleTime()*50/idleTimeMax)
print(robotLib.getStatus())
print(string.rep("*",signNumber)..string.rep("-" ,50 - signNumber))
print(robotLib.getIdleTime()..' / '..idleTimeMax)
if(robotLib.getIdleTime() == idleTimeMax - 1 and robotLib.energyLevel() <= 0.6) then
robotLib.setStatus('low energylevel idling')
robotLib.setIdleTime(0)
end
if (robotLib.key:iskey('q')) then
robotLib.ShouldRun = false
return
end
os.sleep(1)
end
while (robotLib.ShouldSleep) do
robotLib.Sleeping = true
os.sleep(1)
end
robotLib.Sleeping = false
if (robotLib.ShouldRun) then
term.clear()
print('running')
robotLib.setIdleTime(0)
end
end
local function run()
while true do
if(robotLib.getPos() == DefaultPos) then
robotLib.turnTo(1)
if (robotLib.ShouldRun) then
robotLib.setStatus('beforeBuild')
local flag = beforeBuild()
if(not flag) then
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'not enough items')
robotLib.setStatus('not enough item idling')
idleTimeMax = 600
afterBuild()
idleTimeMax = 5
else
robotLib.setStatus('moveToStart')
moveToAreaStart()
robotLib.setStatus('build')
build()
end
robotLib.setStatus('idling')
afterBuild()
else
return
end
else
local string = 'wrong start pos'
Screen.addInfo('posE', WIDTH - #string, HEIGHT, string)
end
os.sleep(0.5)
end
end
local function menu()
local key = robotLib.key
key.blocked = true
while (not key:iskey('q')) do
local space = string.rep(' ', math.floor(WIDTH / 6))
Screen.clear()
Screen.write('c', 1, 'build robot')
Screen.write('l', HEIGHT, 'press char to choice')
Screen.write('l', HEIGHT / 2 - 1, space..'S: set recipe')
Screen.write('l', HEIGHT / 2 , space..'R: run build robot')
Screen.write('l', HEIGHT / 2 + 1 , space..'Q: quit program')
if (key:iskey('s')) then
robotLib.turnTo(inventorySide)
Recipe.setRecipe()
key.key = nil
robotLib.turnTo(1)
elseif (key:iskey('r')) then
key.blocked = false
Screen.clear()
Screen.write('l', 1, 'start running')
robotLib.ShouldRun = true
run()
end
os.sleep(0.5)
end
Screen.clear()
os.exit()
end
if(not robotLib.debug()) then
Main_thread = thread.create(function()
while true do
menu()
os.sleep(1)
end
end)
else
print('debug mode')
os.sleep(1)
menu()
end
thread.waitForAny({robotLib.event_thread, Main_thread})
robotLib = nil
os.exit(0) -- closes all remaining threads
local filesystem = require('filesystem')
File = {}
local tab = 0
local function writeTab(file)
file:write(string.rep(' ', tab))
end
local function writeValue(file , value)
if (type(value) == 'string') then
file:write('"'..value..'"')
elseif (type(value) == 'nil') then
file:write('nil')
elseif (type(value) == 'number' or type(value) == 'boolean') then
local dot, _ = tostring(value):find('%.0+$')
if (dot) then
value = tostring(value):sub(1, dot - 1)
end
file:write(tostring(value))
elseif (type(value) == 'table') then
file:writeObj(value)
else
error('Invalid value to write')
end
end
local function detectArray(obj)
local isArray = true
local valueType = 'nil'
local valueTypeOld = 'nil'
for key , value in pairs(obj) do
valueTypeOld = valueType
valueType = type(value)
local flag = valueType ~= 'nil' and valueTypeOld ~= 'nil'
flag = flag and valueType ~= valueTypeOld
if (type(key) ~= 'number' or flag) then
isArray = false
break
end
end
return isArray , valueType == 'table'
end
local function writeArray(file , array , isTable)
file:write('{')
if isTable then
file:write('\n')
tab = tab + 1
end
local length = 0
for key , value in pairs(array) do
length = math.max(length, key)
end
for i = 1, length do
if isTable then
file:writeTab()
end
file:writeValue(array[i])
if i < length then
file:write(',')
if isTable then
file:write('\n')
else
file:write(' ')
end
end
end
if isTable then
tab = tab - 1
file:write('\n')
file:writeTab()
end
file:write('}')
end
local function writeObj(file , obj)
local length = 0
for key , value in pairs(obj) do
length = length + 1
end
local isArray , valueType = detectArray(obj)
if isArray then
file:writeArray(obj, valueType)
else
file:write('{\n')
tab = tab + 1
local j = 1
for key, value in pairs(obj) do
file:writeTab()
file:writeValue(key)
file:write(' = ')
file:writeValue(value)
if j < length then
file:write(',\n')
j = j + 1
end
end
tab = tab - 1
file:write('\n')
file:writeTab()
file:write('}')
end
end
function File.WriteFile(filepath , obj)
if (obj == nil) then
return
end
if (filesystem.exists(filepath)) then
local point = filepath:reverse():find('/')
local path = filepath:reverse():sub(point, -1):reverse()
local name = filepath:reverse():sub(1, point - 1):reverse()
local old = path..name:gsub('(%.%w+)$', '_old%1')
if filesystem.exists(old) then
filesystem.remove(old)
end
filesystem.rename(filepath, old)
end
local file = filesystem.open(filepath, 'w')
file.writeValue = writeValue
file.writeObj = writeObj
file.writeTab = writeTab
file.writeArray = writeArray
file:writeObj(obj)
file:close()
end
local function parse(tokenList)
local obj = {}
local i , k = 1 , 1
local nil_value = false
local key , value
while(i <= #tokenList) do
local token = tokenList[i]
if (token == '{') then
local atable = {}
local count = 0
for j = i + 1, #tokenList do
if (tokenList[j] == '{') then
count = count + 1
table.insert(atable, tokenList[j])
elseif (tokenList[j] ~= '}') then
table.insert(atable, tokenList[j])
elseif (tokenList[j] == '}' and count > 0) then
table.insert(atable, tokenList[j])
count = count - 1
elseif (tokenList[j] == '}' and count == 0) then
i = j
break
else
error('"{" missing "}" at '..tokenList[i - 2]..tokenList[i - 1]..' at '..i)
end
end
value = parse(atable)
elseif (token:match('[0-9-]') ~= nil) then
local number = ''
for j = i , #tokenList do
if (tokenList[j]:match('[0-9e.-]') ~= nil) then
number = number..tokenList[j]
elseif (tokenList[j]:match('[,=}]') ~= nil) then
i = j
break
else
error('Invalid number token: '..tokenList[j - 1]..tokenList[j]..' at '..j)
end
i = j
end
if (tokenList[i] == '=' and key == nil) then
key = tonumber(number)
else
value = tonumber(number)
end
elseif (token:match('[tfn]')) then
local three = token..tokenList[i+1]..tokenList[i+2]
local four = three .. (tokenList[i+3] or '')
local five = four .. (tokenList[i+4] or '')
if (three == 'nil') then
nil_value = true
i = i + 3
elseif (four == 'true') then
value = true
i = i + 4
elseif (five == 'false') then
value = false
i = i + 5
else
error('Invalid number token: '..tokenList[i - 1]..tokenList[i]..' at '..i)
end
elseif (token == '"') then
local string = ''
local count = 0
for j = i + 1, #tokenList do
if (tokenList[j] ~= '"') then
string = string..tokenList[j]
elseif (tokenList[j] == '"' and count > 0) then
string = string..tokenList[j]
count = count - 1
elseif (tokenList[j] == '"' and count == 0) then
i = j + 1
break
else
error([['"' missing '"' at ]]..tokenList[i - 2]..tokenList[i - 1]..' at '..i)
end
end
if (tokenList[i] == '=' and key == nil) then
key = string
else
value = string
end
elseif (token:match('[,}]') ~= nil) then
elseif (token == '=' and key ~= nil) then
else
error(string.format('parse token " %s " error at %s%s %d',token,tokenList[i - 2], tokenList[i - 1], i))
end
if (value ~= nil or nil_value) then
if (nil_value) then
nil_value = false
end
if (key ~= nil) then
obj[key] = value
key , value = nil , nil
else
obj[k] = value
k = k + 1
value = nil
end
end
i = i + 1
end
return obj
end
function File.ReadFile(filepath)
if (not filesystem.exists(filepath)) then
return nil
else
local tokenList = {}
for line in io.lines(filepath) do
for token in line:gmatch('%S') do
table.insert(tokenList, token)
end
end
return parse(tokenList)[1]
end
end
return File
local component = require("component")
local keyboard = require("keyboard")
local event = require("event")
local thread = require("thread")
local gpu = component.gpu
local factor = (1156 / 949 + 4430 / 3635) / 2
local STARTTIME = os.time()
local screenViewport = {gpu.getViewport()}
local WIDTH , HEIGHT = 64 , 16
local reactors = {address = {}, reactor = {}, reactors = {}, screens = {}}
Colors = {}
local symList = {'#', '@', '$', '%', '^', '&'}
local function getTemperature(reactor)
return reactor.getTemperature() / 1e6
end
local function numberToShow(number)
return tostring(number):sub(1 , tostring(number):find('%.') + 2)
end
local function showBar(x, y, width, height, color)
if (gpu.getDepth() > 1) then
gpu.setBackground(color)
gpu.fill(x ,y ,width ,height , ' ')
gpu.setBackground(0)
else
local sym
local i = 1
for color_set , sym_set in pairs(Colors) do
if (color_set == color) then
sym = sym_set
break
end
i = i + 1
end
if (sym == nil) then
Colors[color] = symList[i] or '*'
sym = Colors[color]
end
gpu.fill(x, y, width, height, sym)
end
end
local function screenLoop(reactor, i)
event.pull('screen set down')
local pos = 2 + 6 * (i - 1)
local reactorNumber = 'reactor '..i
gpu.fill(1 , pos , WIDTH , 1 , '-')
gpu.set((WIDTH - #reactorNumber) / 2, pos, reactorNumber)
gpu.set(1 , pos + 2 , 'Temperature :')
while true do
local statusShow = 'status : '..reactor.status
local problem = reactor.getProblem()
gpu.fill(1 , pos + 1 , WIDTH , 1 , ' ')
gpu.set(1 , pos + 1 , statusShow)
gpu.set(WIDTH - #problem + 1 , pos + 1 , problem)
local opti = reactor.optimumTemperature
local temp = getTemperature(reactor)
local maxtemp = reactor.MAXTEMPERATURE
local maxtemp_show = math.min(maxtemp , opti * 1.5)
local x1 = math.floor(temp / maxtemp_show * WIDTH)
local x2 = math.floor(opti / maxtemp_show * WIDTH)
local area_x1 = math.floor(opti * 0.99 / maxtemp_show * WIDTH)
local area_x2 = math.floor(opti * 1.01 / maxtemp_show * WIDTH)
local optiWidth = math.max(1, area_x2 - area_x1)
gpu.fill(1 , pos + 5 , WIDTH , 1 , ' ')
gpu.set(1 , pos + 5 , numberToShow(temp))
gpu.set(WIDTH - #numberToShow(maxtemp) + 1 , pos + 5 , numberToShow(maxtemp))
gpu.set(x2 - (#numberToShow(opti) / 2 - 1) , pos + 5 , numberToShow(opti))
showBar(1, pos + 4, WIDTH, 1, 0x00DBC0)
showBar(1, pos + 4, x1, 1, 0xCCB600)
showBar(x2, pos + 4, 1, 1, 0xFF7F50)
gpu.fill(1, pos + 3, WIDTH, 1, ' ')
gpu.set(area_x1 - #numberToShow(opti * 0.999) - 1 , pos + 3 , numberToShow(opti * 0.99))
gpu.set(area_x1 + optiWidth + 1 , pos + 3 , numberToShow(opti * 1.001))
showBar(area_x1, pos + 3, optiWidth , 1, 0xFF7F50)
os.sleep(0.05)
end
end
local function reactorLoop(reactor)
while true do
reactor.status = 'check temperature'
os.sleep(1)
local tem = getTemperature(reactor)
if(tem > reactor.optimumTemperature * 1.001) then
reactor.deactivate()
reactor.status = 'cooling'
os.sleep(1)
reactor.activate()
elseif(tem < reactor.optimumTemperature * 0.999) then
reactor.activate()
reactor.status = 'running'
os.sleep(1)
else
reactor.status = 'running'
os.sleep(1)
end
end
end
local function run()
local i = 1
for address, componentType in component.list() do
if (componentType == 'nc_fusion_reactor') then
local reactor = {}
reactor = component.proxy(address)
reactor.status = 'init'
reactor.optimumTemperature = reactor.getFusionComboHeatVariable() * factor
reactor.MAXTEMPERATURE = reactor.getMaxTemperature() / 1e6
reactors.address[i] = address
reactors.reactor[address] = reactor
reactors.reactors[address] = thread.create(reactorLoop, reactor)
reactors.screens[address] = thread.create(screenLoop, reactor, i)
i = i + 1
end
end
if (i == 1) then
local string = 'there is no reactor'
WIDTH , HEIGHT = screenViewport[1], screenViewport[2]
gpu.setViewport(WIDTH , HEIGHT)
gpu.fill(1, 1, WIDTH, HEIGHT, ' ')
gpu.set((WIDTH - #string) / 2 , HEIGHT / 2 , string)
os.sleep(5)
gpu.fill(1, 1, WIDTH, HEIGHT, ' ')
os.exit()
end
HEIGHT = 1
local width , height = gpu.getViewport()
WIDTH = math.min(width, WIDTH)
for j = 1, i - 1 do
HEIGHT = HEIGHT + 6
if (HEIGHT > height) then
HEIGHT = HEIGHT - 6
break
end
end
gpu.setViewport(WIDTH, HEIGHT)
gpu.fill(1, 1, WIDTH, HEIGHT,' ')
event.push('screen set down')
end
local time_thread = thread.create(function()
event.pull('screen set down')
while true do
local info = 'press Q to quit'
local time = 'running time : '..(os.time()-STARTTIME) / 100
gpu.fill(1, 1, WIDTH, 1, ' ')
gpu.set(1 , 1 , time)
gpu.set(WIDTH - #info , 1 , info)
os.sleep(0.1)
end
end)
local event_thread = thread.create(function()
while true do
local name,address,char,key,player = event.pull('key_down')
if(key == keyboard.keys.q) then
print('\nQ pressed, exit')
return
end
end
end)
run()
thread.waitForAll({event_thread})
gpu.fill(1, 1, WIDTH, HEIGHT, ' ')
gpu.setViewport(screenViewport[1], screenViewport[2])
os.exit(0) -- closes all remaining threads
Pos = {x = 0, y = 0, z = 0}
PosLib = {}
Pos.__index = Pos
function Pos:new(...)
local pos = {}
local x , y , z
setmetatable(pos, self)
local arg = {...}
if(#arg == 1 and type(arg[1]) == 'table') then
x = arg[1].x
y = arg[1].y
z = arg[1].z
elseif(#arg == 2 or #arg == 3) then
if (type(arg[1]) == 'number' and type(arg[2]) == 'number') then
x = arg[1]
y = arg[2]
if (type(arg[3]) == 'number' or type(arg[3]) == 'nil') then
z = arg[3]
else
error('Invalid Input To New Pos')
end
end
elseif(#arg ~= 0) then
error('Invalid Input To New Pos')
end
pos.x = x or 0
pos.y = y or 0
pos.z = z or 0
return pos
end
function Pos:set(...)
local x , y , z
local arg = {...}
if(#arg == 1 and type(arg[1]) == 'table') then
x = arg[1].x
y = arg[1].y
z = arg[1].z
elseif(#arg == 2 or #arg == 3) then
if (type(arg[1]) == 'number' and type(arg[2]) == 'number') then
x = arg[1]
y = arg[2]
if (type(arg[3]) == 'number' or type(arg[3]) == 'nil') then
z = arg[3]
else
error('Invalid Input To New Pos')
end
end
elseif(#arg ~= 0) then
error('Invalid Input To New Pos')
end
self.x = x or 0
self.y = y or 0
self.z = z or 0
return self
end
function Pos:__call(...)
return Pos:new(...)
end
function Pos:__tostring()
return string.format('x: %d , y: %d , z: %d', self.x, self.y, self.z)
end
function Pos:__add(pos)
local pos_out = Pos:new(self)
pos_out.x = pos_out.x + pos.x
pos_out.y = pos_out.y + pos.y
pos_out.z = pos_out.z + pos.z
return pos_out
end
function Pos:__sub(pos)
local pos_out = Pos:new(self)
pos_out.x = pos_out.x - pos.x
pos_out.y = pos_out.y - pos.y
pos_out.z = pos_out.z - pos.z
return pos_out
end
function Pos:__eq(pos)
local x_eq = self.x == pos.x
local y_eq = self.y == pos.y
local z_eq = self.z == pos.z
return x_eq and y_eq and z_eq
end
function Pos:__le(pos)
local x_le = self.x <= pos.x
local y_le = self.y <= pos.y
local z_le = self.z <= pos.z
return x_le and y_le and z_le
end
function Pos:__lt(pos)
return not (self >= pos)
end
function Pos:eqXY(x, y)
return self.x == x and self.y == y
end
function Pos:large(pos)
self.x = math.max(self.x , pos.x)
self.y = math.max(self.y , pos.y)
self.z = math.max(self.z , pos.z)
return self
end
function Pos:larger(pos)
local x = math.max(self.x , pos.x)
local y = math.max(self.y , pos.y)
local z = math.max(self.z , pos.z)
return Pos:new(x,y,z)
end
function Pos:small(pos)
self.x = math.min(self.x , pos.x)
self.y = math.min(self.y , pos.y)
self.z = math.min(self.z , pos.z)
return self
end
function Pos:smaller(pos)
local x = math.min(self.x , pos.x)
local y = math.min(self.y , pos.y)
local z = math.min(self.z , pos.z)
return Pos:new(x,y,z)
end
function Pos:rotate(right)
if right == nil then
right = true
end
local angle
if right then
angle = math.rad(90)
else
angle = math.rad(-90)
end
local sin = math.sin(angle)
local cos = math.cos(angle)
local x = self.x * cos - self.y * sin
local y = self.y * cos + self.x * sin
if math.abs(x) < 1e-8 then
x = 0
end
if math.abs(y) < 1e-8 then
y = 0
end
return Pos:new(x, y, self.z)
end
local function sym(x)
if (x == 0) then
return 0
else
return x / math.abs(x)
end
end
function Pos:mod()
local x = sym(self.x)
local y = sym(self.y)
local z = sym(self.z)
return Pos:new(x, y, z)
end
function Pos:inArea(posA , posB)
local larger = self <= posA:larger(posB)
local smaller = self >= posA:smaller(posB)
return larger and smaller
end
setmetatable(PosLib , Pos)
return PosLib
local Recipe = {}
local component = require("component")
local keyboard = require("keyboard")
local sides = require("sides")
local thread = require("thread")
local event = require("event")
local robotLib = require("robotLib")
local Screen = require("Screen")
local File = require("File")
local invc = component.inventory_controller
local recipeFile = '/home/recipe.txt'
local slotFilePath = '/home/slot.txt'
local WIDTH , HEIGHT = Screen.getWH()
local STICK = 'minecraft:stick'
local slotToRecipe
local key = {}
local function iskey(slef , ...)
for i , j in pairs({...}) do
if (slef.key == keyboard.keys[j]) then
slef.key = nil
return true
end
end
return false
end
local function locateRecipeSlot(key)
local size
local showinfo = false
while (not key:iskey('q')) do
while (not size and not key:iskey('q')) do
local string1 = 'please choice recipe size'
local string2 = 'press "A" means 3, press "B" means 5.'
Screen.clear()
Screen.write('c', HEIGHT / 2 , string1)
Screen.write('c', HEIGHT / 2 + 1 , string2)
if (key:iskey('a')) then
size = 3
elseif (key:iskey('b')) then
size = 5
end
if (size) then
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'size = '..tostring(size))
end
os.sleep(0.5)
end
if (not showinfo) then
local string1 = 'please place two stick at '
local string2 = string.format([[%d * %d area's]], size, size)
local string3 = 'top left and bottom right slot'
Screen.clear()
Screen.write('c', HEIGHT / 2 , string1..string2)
Screen.write('c', HEIGHT / 2 + 1 , string3)
showinfo = true
os.sleep(3)
end
Screen.clear(HEIGHT / 2 - 1)
Screen.write('c', HEIGHT / 2 - 1 , 'scaning all slot')
local stick = robotLib.getItemListOut(sides.forward)[STICK]
Screen.clear(HEIGHT / 2 - 1)
if (not stick) then
local string1 = 'please place two stick at '
local string2 = string.format([[%d * %d area's]], size, size)
local string3 = 'top left and bottom right slot'
Screen.clear()
Screen.write('c', HEIGHT / 2 , string1..string2)
Screen.write('c', HEIGHT / 2 + 1 , string3)
elseif (#(stick.slot) ~= 2) then
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'the number slot has stick is not two')
else
if (key:iskey('c')) then
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'calculating slot area')
local slotA = stick.slot[1]
local slotB = stick.slot[2]
local inventoryWidth = (slotB - slotA - size + 1) / (size - 1)
local _ , flag = math.modf(inventoryWidth)
if (flag < 1e-9) then
slotToRecipe = {}
local slotNumber = slotA
for i = 1, size do
slotToRecipe[i] = {}
for j = 1, size do
slotToRecipe[i][j] = slotNumber
slotNumber = slotNumber + 1
end
slotNumber = slotNumber + inventoryWidth - size
end
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'slot location saved')
File.WriteFile(slotFilePath, slotToRecipe)
os.sleep(0.5)
return
else
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'invalid stick location')
end
else
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'press "C" to save location')
end
end
os.sleep(1)
end
Screen.clear()
end
local function scanRecipeSlot(key)
local recipe = {}
local size = #slotToRecipe
local itemList = {}
local showList = {}
local itemNames = {}
local symList = {'#', '@', '$', '%', '^', '&'}
local zlevel = 1
local status = 1
local showinfo = {false, false}
while (not key:iskey('q')) do
if (status == 1) then
if (not showinfo[status]) then
local string1 = 'please place blocks that recipe need'
local string2 = 'at slots seted'
Screen.clear()
Screen.write('c', HEIGHT / 2 - 1 , string1)
Screen.write('c', HEIGHT / 2 , string2)
showinfo[status] = true
os.sleep(3)
end
Screen.clear(2)
Screen.write('c', 2 , 'scaning')
if (not itemList[zlevel]) then
itemList[zlevel] = {}
end
for i = 1, size do
if (not itemList[zlevel][i]) then
itemList[zlevel][i] = {}
end
showList[i] = ''
for j = 1, size do
local item = robotLib.getItemOut(sides.forward, slotToRecipe[i][j])
if (item.id == '') then
itemList[zlevel][i][j] = nil
showList[i] = showList[i]..'/'
else
itemList[zlevel][i][j] = item.id
for k, sym in pairs(symList) do
if (item.id == itemNames[k]) then
showList[i] = showList[i]..sym
break
elseif (itemNames[k] == nil and item.id ~= '') then
showList[i] = showList[i]..sym
itemNames[k] = item.id
break
end
end
if (showList[i] == '' or showList[i]:sub(-1, -1) == ' ') then
showList[i] = showList[i]..'*'
end
end
if (j < size) then
showList[i] = showList[i]..' '
end
end
end
local string1 = string.format('y level: %d / %d', zlevel, size)
Screen.clear()
Screen.write('c', 1 , string1)
for i = 1, size do
Screen.write('c', HEIGHT / 2 - size + i , showList[i])
end
Screen.write('l', HEIGHT - 2, 'press "Q" to back to up menu')
Screen.write('l', HEIGHT - 1, 'press "N" to next y level')
Screen.write('l', HEIGHT , 'press "C" to complete')
if (key:iskey('n')) then
if (zlevel < size) then
zlevel = zlevel + 1
else
status = 2
end
elseif (key:iskey('c')) then
status = 2
end
elseif (status == 2) then
if (not showinfo[status]) then
local string = 'please place the catalyzer in slot area'
Screen.clear()
Screen.write('c', HEIGHT / 2 , string)
showinfo[status] = true
os.sleep(3)
end
if (not recipe.recipe) then
recipe.recipe = itemList
end
itemList = {}
for i = 1, size do
for j = 1, size do
local item = robotLib.getItemOut(sides.forward, slotToRecipe[i][j])
if (item.id ~= '') then
table.insert(itemList, item.id)
end
end
end
if (#itemList == 0) then
Screen.clear()
Screen.write('c', HEIGHT / 2 - 1, 'please place the catalyzer in slot area')
elseif (#itemList ~= 1) then
Screen.clear()
Screen.write('c', HEIGHT / 2 - 1, 'there are more than one items in slot area')
Screen.write('c', HEIGHT / 2, 'catalyzer could only be one item')
elseif (#itemList == 1) then
if (key:iskey('c')) then
recipe.catalyzer = itemList[1]
status = 3
Screen.clear()
Screen.write('c', HEIGHT / 2, 'catalyzer set: '..itemList[1])
os.sleep(1)
else
Screen.clear()
Screen.write('c', HEIGHT / 2 - 1, 'please place the catalyzer in slot area')
Screen.write('c', HEIGHT / 2, 'press "C" to complete')
end
end
elseif (status == 3) then
local string = ''
while (not key:iskey('c', 'enter', 'numpadenter', 'q')) do
if (key.char >= string.byte('0') and key.char <= string.byte('9')) then
string = string..string.char(key.char)
key.char = 0
elseif (key:iskey('back', 'delete')) then
string = string:sub(1 , #string - 1)
end
Screen.clear()
Screen.write('c', HEIGHT / 2 - 2, 'please enter craftTime number')
Screen.write('c', HEIGHT / 2, string)
Screen.write('l', HEIGHT - 1, 'press "C" or "Enter" to complete')
os.sleep(0.05)
end
recipe.craftTime = tonumber(string) or 0
status = 4
Screen.clear()
Screen.write('c', HEIGHT / 2 - 1, 'recipe added')
else
return recipe
end
os.sleep(0.1)
end
end
function Recipe.setRecipe()
local recipeUsed
key.iskey = iskey
local key_thread = thread.create(function()
while true do
_,_,key.char,key.key,_ = event.pull('key_down')
end
end)
slotToRecipe = File.ReadFile(slotFilePath)
if (not slotToRecipe) then
locateRecipeSlot(key)
end
local space = string.rep(' ', math.floor(WIDTH / 6))
while (not key:iskey('q')) do
Screen.clear()
Screen.write('c', math.floor(HEIGHT / 3) , 'press keyboard to choice')
Screen.write('l', HEIGHT / 2 - 1, space..'R: reset slot location')
Screen.write('l', HEIGHT / 2 , space..'A: add recipe use saved slot location')
Screen.write('l', HEIGHT / 2 + 1, space..'Q: quit')
if (key:iskey('r')) then
locateRecipeSlot(key)
elseif (key:iskey('a')) then
Screen.clear()
Screen.write('c', HEIGHT / 2 , 'scaning slot')
recipeUsed = scanRecipeSlot(key)
if recipeUsed then
Screen.clear()
Screen.write('c', HEIGHT / 2, 'writing recipe into file')
File.WriteFile(recipeFile, recipeUsed)
end
end
os.sleep(0.5)
end
Screen.clear()
key_thread:kill()
return recipeUsed
end
return Recipe
local component = require("component")
local sides = require("sides")
local computer = require("computer")
local os = require("os")
local thread = require("thread")
local keyboard = require("keyboard")
local event = require("event")
local Pos = require('Pos')
local robot = component.robot
local invc = component.inventory_controller
local robotLib = {}
local STARTTIME = os.time()
local FILEPATH = '/home/robotStatus.txt'
local pos = Pos()
local face = Pos(1, 0)
local status
local idleTime
local idleTimeMax
local debug = false
local debugInfo = ''
robotLib.keyEvent = {}
robotLib.ShouldSleep = false
robotLib.Sleeping = false
robotLib.ShouldRun = true
robotLib.key = {blocked = false}
local maxEnergy = computer.maxEnergy()
local invSize = robot.inventorySize()
local function updateFile()
--File.WriteFile(FILEPATH, {pos = pos, face = face, debug = debug})
end
local function getCurrentTime()
return os.time() / 100
end
robotLib.debug = function()
return debug
end
robotLib.debugInfo = function(debugInfo_set)
debugInfo = debugInfo..'\n\t'..debugInfo_set
end
robotLib.getPos = function()
return pos
end
function robotLib.getForwardPos()
return pos + face
end
local faceToNumber = function (face_to)
if (face_to == Pos(1,0)) then
return 1
elseif (face_to == Pos(0,1)) then
return 2
elseif (face_to == Pos(-1,0)) then
return 3
elseif (face_to == Pos(0,-1)) then
return 4
end
end
local function numberToFace(face_to)
if (face_to == 1) then
return Pos(1,0)
elseif (face_to == 2) then
return Pos(0,1)
elseif (face_to == 3) then
return Pos(-1,0)
elseif (face_to == 4) then
return Pos(0,-1)
end
end
robotLib.isFace = function(face_to)
return faceToNumber(face) == face_to
end
robotLib.getFace = function()
return face
end
robotLib.getStatus = function()
return status
end
robotLib.setStatus = function(status_set)
status = status_set
if debug then
print(status)
end
end
robotLib.getIdleTime = function()
return idleTime
end
robotLib.setIdleTime = function(idleTime_set)
idleTime = idleTime_set
end
robotLib.STARTTIME = function()
return STARTTIME
end
robotLib.energyLevel = function()
return computer.energy() / maxEnergy
end
robotLib.forward = function(forward)
if (forward == nil) then
forward = true
end
local flag = false
while(not flag) do
if (forward) then
flag = robot.move(sides.forward)
else
flag = robot.move(sides.back)
end
end
if (forward) then
pos = pos + face
else
pos = pos - face
end
updateFile()
end
robotLib.moveUp = function(up)
if (up == nil) then
up = true
end
local flag = false
while(not flag) do
if (up) then
flag = robot.move(sides.top)
else
flag = robot.move(sides.bottom)
end
end
if(up) then
pos = pos + Pos(0, 0, 1)
else
pos = pos - Pos(0, 0, 1)
end
updateFile()
end
robotLib.turn = function(right)
if (right == nil) then
right = true
end
robot.turn(right)
face = face:rotate(right)
updateFile()
end
robotLib.turnTo = function(face_to)
face_to = numberToFace(face_to)
while (face ~= face_to) do
if (face:rotate(false) == face_to) then
robotLib.turn(false)
else
robotLib.turn(true)
end
end
end
-- TODO
robotLib.moveTo = function(pos_to)
local dpos = pos_to - pos
if (face == 1) then
if (dpos > 0) then
robotLib.forward()
end
elseif (face == 2) then
elseif (face == 3) then
elseif (face == 4) then
end
end
robotLib.getItem = function(slot)
local item = invc.getStackInInternalSlot(slot) or {}
if (item.name == nil) then
item.name = ''
item.damage = 0
item.size = 0
end
if (item.damage ~= 0) then
item.damage = math.modf(item.damage)
item.id = item.name..'@'..item.damage
else
item.id = item.name
end
return item
end
robotLib.getItemOut = function(side, slot)
local item = invc.getStackInSlot(side, slot) or {}
if (item.name == nil) then
item.name = ''
item.damage = 0
item.size = 0
end
if (item.damage ~= 0) then
item.damage = math.modf(item.damage)
item.id = item.name..'@'..item.damage
else
item.id = item.name
end
return item
end
robotLib.getItemList = function()
local itemList = {}
for i=1,16 do
local item = invc.getStackInInternalSlot(i)
if (item ~= nil) then
if (item.damage ~= 0) then
item.damage = math.modf(item.damage)
item.id = item.name..'@'..item.damage
else
item.id = item.name
end
if (itemList[item.id] == nil) then
itemList[item.id] = item
itemList[item.id].slot = {i}
else
itemList[item.id].size = itemList[item.id].size + item.size
table.insert(itemList[item.id].slot , i)
end
end
end
return itemList
end
robotLib.getItemListOut = function(side)
local slotNumber = invc.getInventorySize(side)
local itemList = {}
if(slotNumber ~= nil) then
local slot = 1
for item in invc.getAllStacks(side) do
if (item.name ~= nil) then
if (item.damage ~= 0) then
item.damage = math.modf(item.damage)
item.id = item.name..'@'..item.damage
else
item.id = item.name
end
if (itemList[item.id] == nil) then
itemList[item.id] = item
itemList[item.id].slot = {slot}
else
itemList[item.id].size = itemList[item.id].size + item.size
table.insert(itemList[item.id].slot , slot)
end
end
slot = slot + 1
end
return itemList
else
error('Not a Item Inventory')
end
end
robotLib.suckItem = function(side , itemList)
local itemsOut = robotLib.getItemListOut(side)
local flag = true
if(invc.getInventorySize(side) >= 1) then
for itemId , count in pairs(itemList) do
local item = itemsOut[itemId] or {size = 0}
flag = flag and (item.size >= count)
end
end
if(flag) then
robot.select(1)
for item , count in pairs(itemList) do
local i = 1
local itemsIn = robotLib.getItemList()
if (itemsIn[item] == nil) then
itemsIn[item] = {size = 0}
end
while (itemsIn[item].size < count) do
local countNeed = count - itemsIn[item].size
invc.suckFromSlot(side , itemsOut[item].slot[i] , countNeed)
itemsIn = robotLib.getItemList()
if (invc.getStackInSlot(side, itemsOut[item].slot[i]) == nil) then
i = i + 1
end
end
end
end
return flag
end
--TODO
robotLib.sort = function()
local k = 1
for i = 1 , invSize - 1 do
local itemA = invc.getStackInInternalSlot(i)
local itemB = invc.getStackInInternalSlot(i + 1)
end
robot.select(1)
end
robotLib.printStatus = function()
end
function robotLib:addKeyEvent(key_set , func)
key_set = string.lower(key_set)
self.keyEvent[key_set] = func
end
local function iskey(slef , ...)
for i , j in pairs({...}) do
if (slef.key == keyboard.keys[j]) then
slef.key = nil
return true
end
end
return false
end
robotLib.key.iskey = iskey
function robotLib:init(pos_set)
pos = pos_set
status = 'init'
idleTime = 0
local fileRead = File.ReadFile(FILEPATH)
if (fileRead ~= nil) then
pos = Pos(fileRead.pos)
face = Pos(fileRead.face)
debug = fileRead.debug
print('read from file:')
print('pos:\n'..tostring(pos))
print('face:\n'..tostring(face))
print('debug:\n'..tostring(debug))
end
self.event_thread = thread.create(function()
while true do
local name,address,char,key,player = event.pull('key_down')
robotLib.key.name = name
robotLib.key.address = address
robotLib.key.char = char
robotLib.key.key = key
robotLib.key.player = player
if (not robotLib.key.blocked) then
if(key == keyboard.keys.e) then
print('\nE pressed, waiting for finsh task then exit')
robotLib.shouldRun = false
elseif(key == keyboard.keys.r) then
robotLib.shouldRun = true
robotLib.setIdleTime(-1)
elseif(key == keyboard.keys.d) then
debug = not debug
end
for key_set , func in pairs(robotLib.keyEvent) do
if(key == keyboard.keys[key_set]) then
func()
end
end
end
end
end)
end
return robotLib
Screen = {}
local component = require("component")
local gpu = component.gpu
local WIDTH , HEIGHT = gpu.getViewport()
local info = {}
function Screen.getWH()
return WIDTH, HEIGHT
end
function Screen.write(location, y, string_to)
location = string.lower(location)
if (location == 'c') then
gpu.set((WIDTH - #string_to) / 2 , y, string_to)
elseif (location == 'l') then
gpu.set(1, y, string_to)
elseif (location == 'r') then
gpu.set(WIDTH - #string_to, y, string_to)
else
error('Invalid location')
end
end
function Screen.addInfo(id,x,y,string)
local info_add = {
x = x,
y = y,
string = string
}
info[id] = info_add
Screen.showInfo()
end
function Screen.removeInfo(id)
local x = info[id].x
local y = info[id].y
local string = info[id].string
gpu.fill(x,y,#string,1,' ')
info[id] = nil
end
function Screen.showInfo()
for i, info_show in pairs(info) do
local x = info_show.x
local y = info_show.y
local string = info_show.string
gpu.set(x, y, string)
end
end
function Screen.clear(...)
local arg = {...}
if (#arg == 0) then
gpu.fill(1,1,WIDTH,HEIGHT,' ')
elseif (#arg == 1) then
gpu.fill(1,arg[1],WIDTH,1,' ')
elseif (#arg == 4) then
gpu.fill(arg[1],arg[2],arg[3],arg[4],' ')
else
error('Invalid input to clear screen')
end
end
return Screen
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment