38 Commits

Author SHA1 Message Date
kepler155c
d4cf76b8e8 cleanup 2018-01-06 22:31:54 -05:00
kepler155c
44932ac515 peripheral overhaul + 1.7 fixes 2018-01-06 22:26:21 -05:00
kepler155c
f2b9efc80f peripheral overhaul 2018-01-06 06:08:39 -05:00
kepler155c
c48243eae5 item db naming fix for items with diff names-nbt combinations 2018-01-04 03:33:09 -05:00
kepler155c
45bbc72fc3 autocrafting improvements 2018-01-03 02:41:56 -05:00
kepler155c
aa50b55ab1 storage manager improvements 2017-12-27 23:56:14 -05:00
kepler155c
85c5f542a8 Autocrafting improvements 2017-12-23 01:48:36 -05:00
kepler155c
863b7ff600 Autocrafting improvements 2017-12-16 00:09:28 -05:00
kepler155c
0ce537d4ce autocrafting improvements 2017-12-13 01:38:59 -05:00
kepler155c
73dc16703a crafting improvements 2017-12-11 11:30:56 -05:00
kepler155c
f6fb6a4433 api cleanup 2017-11-15 00:09:29 -05:00
kepler155c
2526308eb6 turtle api 2017-10-31 02:01:14 -04:00
kepler155c
d97a9d7468 refactor + cleanup 2017-10-27 20:25:16 -04:00
kepler155c
9939c75fc3 proxy apis over wireless 2017-10-24 23:01:59 -04:00
kepler155c
77107e1d57 refactor builder 2017-10-23 21:36:47 -04:00
kepler155c
a2f452dc90 builder starting point 2017-10-22 19:11:06 -04:00
kepler155c
e0cac06c2a builder starting point 2017-10-22 01:29:42 -04:00
kepler155c
5e80591160 input redo 2017-10-20 13:56:35 -04:00
kepler155c
c057f98830 fix Script bug + crafter 2017-10-20 04:23:54 -04:00
kepler155c
11a005969c crafter 2017-10-19 03:23:05 -04:00
kepler155c
6a1f72f957 crafter 2017-10-19 02:57:17 -04:00
kepler155c
3622518b20 crafter 2017-10-18 19:54:28 -04:00
kepler155c
1eb47cf3c8 crafter 2017-10-17 22:51:13 -04:00
kepler155c
7892c0dbb7 crafter 2017-10-17 22:30:50 -04:00
kepler155c
fe79e582cd crafter 2017-10-17 12:53:55 -04:00
kepler155c
a5c7fde530 crafter 2017-10-16 16:55:37 -04:00
kepler155c
c04ec356e5 redo input translation -round 2 2017-10-16 00:04:16 -04:00
kepler155c
194e6f0a91 redo input translation + shift-paste 2017-10-15 19:55:43 -04:00
kepler155c
d0c8d2dc4f better detection for adapters 2017-10-15 02:35:40 -04:00
kepler155c
728cda2215 non-global clipboard 2017-10-14 13:40:16 -04:00
kepler155c
1f31f7ef40 non-global clipboard, ad hoc crafting 2017-10-14 03:39:47 -04:00
kepler155c
3734afed92 compatibility improvements 2017-10-12 17:56:14 -04:00
kepler155c
5232b5a115 wrong box 2017-10-11 16:27:51 -04:00
kepler155c
f5dede540e cleanup 2017-10-11 15:07:32 -04:00
kepler155c
980c635037 simplify ui 2017-10-11 11:36:56 -04:00
kepler155c
ed2d6eeef1 lint 2017-10-08 17:45:37 -04:00
kepler155c
bba7841c43 UI improvements 2017-10-07 23:02:38 -04:00
kepler155c
8ef97df223 inactive elements 2017-10-07 00:28:18 -04:00
62 changed files with 8330 additions and 5317 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/etc/fstab /etc/fstab
/etc/recipes2.db

View File

@@ -6,42 +6,10 @@ local JSON = require('json')
-- see https://github.com/Khroki/MCEdit-Unified/blob/master/pymclevel/minecraft.yaml -- see https://github.com/Khroki/MCEdit-Unified/blob/master/pymclevel/minecraft.yaml
-- see https://github.com/Khroki/MCEdit-Unified/blob/master/Items/minecraft/blocks.json -- see https://github.com/Khroki/MCEdit-Unified/blob/master/Items/minecraft/blocks.json
--[[-- nameDB --]]--
local nameDB = TableDB({
fileName = 'blocknames.db'
})
function nameDB:load(dir, blockDB)
self.fileName = fs.combine(dir, self.fileName)
if fs.exists(self.fileName) then
TableDB.load(self)
end
self.blockDB = blockDB
end
function nameDB:getName(id, dmg)
return self:lookupName(id, dmg) or id .. ':' .. dmg
end
function nameDB:lookupName(id, dmg)
-- is it in the name db ?
local name = self:get({ id, dmg })
if name then
return name
end
-- is it in the block db ?
for _,v in pairs(self.blockDB.data) do
if v.strId == id and v.dmg == dmg then
return v.name
end
end
end
--[[-- blockDB --]]-- --[[-- blockDB --]]--
local blockDB = TableDB() local blockDB = TableDB()
function blockDB:load() function blockDB:load()
local blocks = JSON.decodeFromFile('usr/etc/blocks.json') local blocks = JSON.decodeFromFile('usr/etc/blocks.json')
if not blocks then if not blocks then
@@ -64,7 +32,7 @@ function blockDB:lookup(id, dmg)
if not id then if not id then
return return
end end
return self.data[id .. ':' .. dmg] return self.data[id .. ':' .. dmg]
end end
@@ -85,19 +53,6 @@ end
local placementDB = TableDB() local placementDB = TableDB()
function placementDB:load(sbDB, btDB) function placementDB:load(sbDB, btDB)
for k,blockType in pairs(sbDB.data) do
local bt = btDB.data[blockType]
if not bt then
error('missing block type: ' .. blockType)
end
local id, dmg = string.match(k, '(%d+):*(%d+)')
self:addSubsForBlockType(tonumber(id), tonumber(dmg), bt)
end
end
function placementDB:load2(sbDB, btDB)
for k,v in pairs(sbDB.data) do for k,v in pairs(sbDB.data) do
if v.place then if v.place then
local bt = btDB.data[v.place] local bt = btDB.data[v.place]
@@ -113,7 +68,6 @@ function placementDB:load2(sbDB, btDB)
self:addSubsForBlockType(155, 2, btDB.data['quartz-pillar']) self:addSubsForBlockType(155, 2, btDB.data['quartz-pillar'])
end end
function placementDB:addSubsForBlockType(id, dmg, bt) function placementDB:addSubsForBlockType(id, dmg, bt)
for _,sub in pairs(bt) do for _,sub in pairs(bt) do
local odmg = sub.odmg local odmg = sub.odmg
@@ -136,12 +90,12 @@ function placementDB:addSubsForBlockType(id, dmg, bt)
sub.extra) sub.extra)
end end
end end
function placementDB:add(id, dmg, sid, sdmg, direction, extra) function placementDB:add(id, dmg, sid, sdmg, direction, extra)
if direction and #direction == 0 then if direction and #direction == 0 then
direction = nil direction = nil
end end
local entry = { local entry = {
oid = id, -- numeric ID oid = id, -- numeric ID
odmg = dmg, -- dmg with placement info odmg = dmg, -- dmg with placement info
@@ -176,9 +130,8 @@ function blockTypeDB:addTemp(blockType, subs)
end end
self.dirty = true self.dirty = true
end end
function blockTypeDB:load() function blockTypeDB:load()
blockTypeDB:addTemp('stairs', { blockTypeDB:addTemp('stairs', {
{ 0, nil, 0, 'east-up' }, { 0, nil, 0, 'east-up' },
{ 1, nil, 0, 'west-up' }, { 1, nil, 0, 'west-up' },
@@ -564,20 +517,17 @@ end
local Blocks = class() local Blocks = class()
function Blocks:init(args) function Blocks:init(args)
Util.merge(self, args) Util.merge(self, args)
self.blockDB = blockDB self.blockDB = blockDB
self.nameDB = nameDB
blockDB:load() blockDB:load()
blockTypeDB:load() blockTypeDB:load()
nameDB:load(self.dir, blockDB) placementDB:load(blockDB, blockTypeDB)
placementDB:load2(blockDB, blockTypeDB)
end end
-- for an ID / dmg (with placement info) - return the correct block (without the placment info embedded in the dmg) -- for an ID / dmg (with placement info)
-- return the correct block (without the placment info embedded in the dmg)
function Blocks:getPlaceableBlock(id, dmg) function Blocks:getPlaceableBlock(id, dmg)
local p = placementDB:get({id, dmg}) local p = placementDB:get({id, dmg})
if p then if p then
return Util.shallowCopy(p) return Util.shallowCopy(p)

101
apis/builder/builder.lua Normal file
View File

@@ -0,0 +1,101 @@
local Blocks = require('builder.blocks')
local class = require('class')
local Message = require('message')
local Util = require('util')
local device = _G.device
local fs = _G.fs
local turtle = _G.turtle
local Builder = class()
Util.merge(Builder, {
isCommandComputer = not turtle,
loc = { },
index = 1,
mode = 'build',
})
local BUILDER_DIR = 'usr/builder'
local blockInfo = Blocks()
function Builder:getBlockCounts()
local blocks = { }
for k = self.index, #self.schematic.blocks do
local b = self.schematic.blocks[k]
local key = tostring(b.id) .. ':' .. b.dmg
local block = blocks[key]
if not block then
block = Util.shallowCopy(b)
block.qty = 0
block.need = 0
blocks[key] = block
end
block.need = block.need + 1
end
return blocks
end
function Builder:substituteBlocks(throttle)
for _,b in pairs(self.schematic.blocks) do
-- replace schematic block type with substitution
local pb = blockInfo:getPlaceableBlock(b.id, b.dmg)
Util.merge(b, pb)
b.odmg = pb.odmg or pb.dmg
local sub = self.subDB:get({ b.id, b.dmg })
if sub then
b.id, b.dmg = self.subDB:extract(sub)
end
throttle()
end
end
function Builder:reloadSchematic(throttle)
self.schematic:reload(throttle)
self:substituteBlocks(throttle)
end
function Builder:log(...)
Util.print(...)
end
function Builder:dumpInventory()
end
function Builder:logBlock(index, b)
local bdir = b.direction or ''
local logText = string.format('%d %s:%d (x:%d,z:%d:y:%d) %s',
index, b.id, b.dmg, b.x, b.z, b.y, bdir)
self:log(logText)
-- self:log(b.index) -- unique identifier of block
if device.wireless_modem then
Message.broadcast('builder', { x = b.x, y = b.y, z = b.z, heading = b.heading })
end
end
function Builder:saveProgress(index)
Util.writeTable(
fs.combine(BUILDER_DIR, self.schematic.filename .. '.progress'),
{ index = index, loc = self.loc }
)
end
function Builder:loadProgress(filename)
local progress = Util.readTable(fs.combine(BUILDER_DIR, filename))
if progress then
self.index = progress.index
if self.index > #self.schematic.blocks then
self.index = 1
end
self.loc = progress.loc or { }
end
end
return Builder

84
apis/builder/commands.lua Normal file
View File

@@ -0,0 +1,84 @@
local Builder = require('builder.builder')
local Event = require('event')
local Util = require('util')
local commands = _G.commands
local fs = _G.fs
local os = _G.os
local read = _G.read
function Builder:begin()
local direction = 1
local last = #self.schematic.blocks
local throttle = Util.throttle()
local cx, cy, cz = commands.getBlockPosition()
if self.loc.x then
cx, cy, cz = self.loc.rx, self.loc.ry, self.loc.rz
end
if self.mode == 'destroy' then
direction = -1
last = 1
end
for i = self.index, last, direction do
self.index = i
local b = self.schematic:getComputedBlock(i)
if b.id ~= 'minecraft:air' then
self:logBlock(self.index, b)
local id = b.id
if self.mode == 'destroy' then
id = 'minecraft:air'
end
local function placeBlock(bid, dmg, x, y, z)
local command = table.concat({
"setblock",
cx + x + 1,
cy + y,
cz + z + 1,
bid,
dmg,
}, ' ')
commands.execAsync(command)
local result = { os.pullEvent("task_complete") }
if not result[4] then
Util.print(result[5])
if self.mode ~= 'destroy' then
read()
end
end
end
placeBlock(id, b.odmg, b.x, b.y, b.z)
if b.twoHigh then
local _, topBlock = self.schematic:findIndexAt(b.x, b.z, b.y + 1, true)
if topBlock then
placeBlock(id, topBlock.odmg, b.x, b.y + 1, b.z)
end
end
if self.mode == 'destroy' then
self:saveProgress(math.max(self.index, 1))
else
self:saveProgress(self.index + 1)
end
else
throttle() -- sleep in case there are a large # of skipped blocks
end
end
fs.delete(self.schematic.filename .. '.progress')
print('Finished')
Event.exitPullEvents()
end
return Builder

View File

@@ -1,9 +1,17 @@
local class = require('class') local class = require('class')
local Util = require('util') local Util = require('util')
local DEFLATE = require('deflatelua') local DEFLATE = require('deflatelua')
local UI = require('ui')
local Point = require('point') local Point = require('point')
local bit = _G.bit
local fs = _G.fs
local os = _G.os
local term = _G.term
local function getHeadingInfo(heading)
return Point.headings[heading]
end
--[[ --[[
Loading and manipulating a schematic Loading and manipulating a schematic
--]] --]]
@@ -11,8 +19,54 @@ local Point = require('point')
local schematicMagic = 0x0a00 local schematicMagic = 0x0a00
local gzipMagic = 0x1f8b local gzipMagic = 0x1f8b
--[[-- Spinner --]]--
local Spinner = class()
function Spinner:init(args)
local defaults = {
timeout = .095,
c = os.clock(),
spinIndex = 0,
spinSymbols = { '-', '/', '|', '\\' }
}
defaults.x, defaults.y = term.getCursorPos()
defaults.startX = defaults.x
defaults.startY = defaults.y
Util.merge(self, defaults)
Util.merge(self, args)
end
function Spinner:spin(text)
local cc = os.clock()
if text then
self.text = text
end
if cc > self.c + self.timeout then
term.setCursorPos(self.x, self.y)
local str = self.spinSymbols[self.spinIndex % #self.spinSymbols + 1]
if self.text then
str = str .. ' ' .. self.text
self.text = nil
end
term.write(str)
self.spinIndex = self.spinIndex + 1
os.sleep(0)
self.c = os.clock()
end
end
function Spinner:stop(text)
term.setCursorPos(self.x, self.y)
local str = string.rep(' ', #self.spinSymbols)
if text then
str = str .. ' ' .. text
end
term.write(str)
term.setCursorPos(self.startX, self.startY)
end
local Schematic = class() local Schematic = class()
function Schematic:init(args) function Schematic:init()
self.blocks = { } self.blocks = { }
self.damages = { } self.damages = { }
self.originalBlocks = { } self.originalBlocks = { }
@@ -24,7 +78,7 @@ end
--[[ --[[
Credit to Orwell for the schematic file reader code Credit to Orwell for the schematic file reader code
http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/ http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/
Some parts of the file reader code was modified from the original Some parts of the file reader code was modified from the original
--]] --]]
@@ -48,11 +102,11 @@ function Schematic:readname(h)
local n = n1*256 + n2 local n = n1*256 + n2
local str = "" local str = ""
for i=1,n do for _=1,n do
local c = h:readbyte(h) local c = h:readbyte(h)
if c == nil then if c == nil then
return return
end end
str = str .. string.char(c) str = str .. string.char(c)
end end
return str return str
@@ -218,11 +272,11 @@ function DiskFile:close()
end end
local MemoryFile = class() local MemoryFile = class()
function MemoryFile:init(args) function MemoryFile:init()
self.s = { } self.s = { }
self.i = 1 self.i = 1
end end
function MemoryFile:open(filename) function MemoryFile:open()
self.i = 1 self.i = 1
end end
function MemoryFile:close() end function MemoryFile:close() end
@@ -247,7 +301,7 @@ function Schematic:decompress(ifname, spinner)
local mh = MemoryFile() local mh = MemoryFile()
DEFLATE.gunzip({ DEFLATE.gunzip({
input=function(...) spinner:spin() return ifh.read() end, input=function() spinner:spin() return ifh.read() end,
output=function(b) mh:write(b) end, output=function(b) mh:write(b) end,
disable_crc=true disable_crc=true
}) })
@@ -276,7 +330,7 @@ function Schematic:loadpass(fh, spinner)
fh:close() fh:close()
print('Assigning coords ') spinner.text = 'Assigning coords '
local index = 1 local index = 1
for _, b in ipairs(self.blocks) do for _, b in ipairs(self.blocks) do
while index < b.index do while index < b.index do
@@ -309,11 +363,10 @@ function Schematic:loadpass(fh, spinner)
end end
function Schematic:load(filename) function Schematic:load(filename)
local _, cy = term.getCursorPos()
local cursorX, cursorY = term.getCursorPos() local spinner = Spinner({
local spinner = UI.Spinner({ x = 1,
x = UI.term.width, y = cy,
y = cursorY - 1
}) })
local f local f
@@ -322,7 +375,7 @@ function Schematic:load(filename)
filename = originalFile .. '.uncompressed' filename = originalFile .. '.uncompressed'
if not fs.exists(filename) then if not fs.exists(filename) then
print('Decompressing') spinner.text = 'Decompressing'
f = self:decompress(originalFile, spinner) f = self:decompress(originalFile, spinner)
end end
end end
@@ -335,7 +388,7 @@ function Schematic:load(filename)
self:checkFileType(f) self:checkFileType(f)
print('Loading blocks ') spinner.text = 'Loading blocks '
self:loadpass(f, spinner) self:loadpass(f, spinner)
self.rowIndex = { } self.rowIndex = { }
@@ -352,7 +405,7 @@ function Schematic:load(filename)
end end
function Schematic:assignDamages(spinner) function Schematic:assignDamages(spinner)
print('Assigning damages') spinner.text = 'Assigning damages'
for _,b in pairs(self.blocks) do for _,b in pairs(self.blocks) do
b.dmg = self.damages[b.index] or 0 b.dmg = self.damages[b.index] or 0
@@ -382,7 +435,7 @@ function Schematic:findIndexAt(x, z, y, allBlocks)
end end
function Schematic:findBlockAtSide(b, side) function Schematic:findBlockAtSide(b, side)
local hi = turtle.getHeadingInfo(side) local hi = getHeadingInfo(side)
local index = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y + hi.yd) local index = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y + hi.yd)
if index then if index then
return self.blocks[index] -- could be better return self.blocks[index] -- could be better
@@ -416,10 +469,10 @@ function Schematic:bestSide(b, chains, ...)
local blocks = { } local blocks = { }
for k,d in pairs(directions) do for k,d in pairs(directions) do
local hi = turtle.getHeadingInfo(d) local hi = getHeadingInfo(d)
local sb = self:findIndexAt(b.x - hi.xd, b.z - hi.zd, b.y) local sb = self:findIndexAt(b.x - hi.xd, b.z - hi.zd, b.y)
if not sb then if not sb then
b.heading = turtle.getHeadingInfo(d).heading b.heading = getHeadingInfo(d).heading
b.direction = d .. '-block' b.direction = d .. '-block'
return return
end end
@@ -476,7 +529,7 @@ function Schematic:bestFlipSide(b, chains)
} }
local d = directions[b.direction] local d = directions[b.direction]
local hi = turtle.getHeadingInfo(d) local hi = getHeadingInfo(d)
local _, fb = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y) local _, fb = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y)
if fb then if fb then
@@ -492,7 +545,7 @@ function Schematic:bestFlipSide(b, chains)
{ x = b.x - hi.xd, z = b.z - hi.zd, y = b.y }, -- room for the turtle { x = b.x - hi.xd, z = b.z - hi.zd, y = b.y }, -- room for the turtle
{ x = b.x + hi.xd, z = b.z + hi.zd, y = b.y }, -- block we are placing against { x = b.x + hi.xd, z = b.z + hi.zd, y = b.y }, -- block we are placing against
}) })
b.direction = turtle.getHeadingInfo((hi.heading + 2) % 4).direction .. '-block' b.direction = getHeadingInfo((hi.heading + 2) % 4).direction .. '-block'
end end
end end
@@ -532,7 +585,7 @@ function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
table.insert(pc, { x = b.x, z = b.z, y = b.y }) table.insert(pc, { x = b.x, z = b.z, y = b.y })
b.direction = side1 .. '-block' b.direction = side1 .. '-block'
b.heading = turtle.getHeadingInfo(side1).heading b.heading = getHeadingInfo(side1).heading
if b == lb then if b == lb then
break break
@@ -550,7 +603,7 @@ function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
local ub = self:findBlockAtSide(fb, 'down') local ub = self:findBlockAtSide(fb, 'down')
if not ub then if not ub then
fb.direction = side1 .. '-block' fb.direction = side1 .. '-block'
fb.heading = turtle.getHeadingInfo(side1).heading fb.heading = getHeadingInfo(side1).heading
else else
fb.direction = od fb.direction = od
end end
@@ -564,7 +617,7 @@ function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
local ub = self:findBlockAtSide(lb, 'down') local ub = self:findBlockAtSide(lb, 'down')
if not ub then if not ub then
lb.direction = side1 .. '-block' lb.direction = side1 .. '-block'
lb.heading = turtle.getHeadingInfo(side1).heading lb.heading = getHeadingInfo(side1).heading
else else
fb.direction = od fb.direction = od
end end
@@ -581,7 +634,7 @@ function Schematic:determineBlockPlacement(y)
print('Processing level ' .. y) print('Processing level ' .. y)
local spinner = UI.Spinner({ local spinner = Spinner({
x = 1, x = 1,
spinSymbols = { 'o.....', '.o....', '..o...', '...o..', '....o.', '.....o' } spinSymbols = { 'o.....', '.o....', '..o...', '...o..', '....o.', '.....o' }
}) })
@@ -709,12 +762,12 @@ function Schematic:determineBlockPlacement(y)
spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ') spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ')
if directions[d] then if directions[d] then
b.heading = turtle.getHeadingInfo(directions[d]).heading b.heading = getHeadingInfo(directions[d]).heading
end end
if doorDirections[d] then if doorDirections[d] then
local hi = turtle.getHeadingInfo(doorDirections[d]) local hi = getHeadingInfo(doorDirections[d])
b.heading = hi.heading b.heading = hi.heading
self:addPlacementChain(chains, { self:addPlacementChain(chains, {
@@ -726,9 +779,9 @@ function Schematic:determineBlockPlacement(y)
if stairDownDirections[d] then if stairDownDirections[d] then
if not self:findIndexAt(b.x, b.z, b.y-1) then if not self:findIndexAt(b.x, b.z, b.y-1) then
b.direction = stairDownDirections[b.direction] b.direction = stairDownDirections[b.direction]
b.heading = turtle.getHeadingInfo(b.direction).heading b.heading = getHeadingInfo(b.direction).heading
else else
b.heading = turtle.getHeadingInfo(stairDownDirections[b.direction]).heading b.heading = getHeadingInfo(stairDownDirections[b.direction]).heading
end end
end end
@@ -757,7 +810,7 @@ function Schematic:determineBlockPlacement(y)
-- otherwise, the turtle must place the block from the same plane -- otherwise, the turtle must place the block from the same plane
-- against another block -- against another block
-- if no block to place against (from side) then the turtle must place from -- if no block to place against (from side) then the turtle must place from
-- the other side -- the other side
-- --
-- Stair bug in 1.7 - placing a stair southward doesn't respect the turtle's direction -- Stair bug in 1.7 - placing a stair southward doesn't respect the turtle's direction
-- all other directions are fine -- all other directions are fine
@@ -767,7 +820,7 @@ function Schematic:determineBlockPlacement(y)
if self:findIndexAt(b.x, b.z, b.y-1) then if self:findIndexAt(b.x, b.z, b.y-1) then
-- there's a block below -- there's a block below
b.direction = sd[1] b.direction = sd[1]
b.heading = turtle.getHeadingInfo(b.direction).heading b.heading = getHeadingInfo(b.direction).heading
else else
local _,pb = self:findIndexAt(b.x + sd[3], b.z + sd[4], b.y) local _,pb = self:findIndexAt(b.x + sd[3], b.z + sd[4], b.y)
if pb and pb.direction ~= sd[5] then if pb and pb.direction ~= sd[5] then
@@ -775,7 +828,7 @@ function Schematic:determineBlockPlacement(y)
d = sd[2] -- fall through to the blockDirections code below d = sd[2] -- fall through to the blockDirections code below
b.direction = sd[2] b.direction = sd[2]
else else
b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4 b.heading = (getHeadingInfo(sd[1]).heading + 2) % 4
end end
end end
elseif flipDirections[d] then elseif flipDirections[d] then
@@ -784,7 +837,7 @@ function Schematic:determineBlockPlacement(y)
if blockDirections[d] then if blockDirections[d] then
-- placing a block from the side -- placing a block from the side
local hi = turtle.getHeadingInfo(blockDirections[d]) local hi = getHeadingInfo(blockDirections[d])
b.heading = hi.heading b.heading = hi.heading
self:addPlacementChain(chains, { self:addPlacementChain(chains, {
{ x = b.x + hi.xd, z = b.z + hi.zd, y = b.y }, -- block we are placing against { x = b.x + hi.xd, z = b.z + hi.zd, y = b.y }, -- block we are placing against
@@ -843,8 +896,6 @@ end
-- set the order for block dependencies -- set the order for block dependencies
function Schematic:setPlacementOrder(spinner, placementChains) function Schematic:setPlacementOrder(spinner, placementChains)
local cursorX, cursorY = term.getCursorPos()
-- optimize for overlapping check -- optimize for overlapping check
for _,chain in pairs(placementChains) do for _,chain in pairs(placementChains) do
for index,_ in pairs(chain.keys) do for index,_ in pairs(chain.keys) do
@@ -917,9 +968,9 @@ function Schematic:setPlacementOrder(spinner, placementChains)
]]-- ]]--
local masterChain = table.remove(chains) local masterChain = table.remove(chains)
--[[ it's something like this: --[[ it's something like this:
A chain B chain result A chain B chain result
1 1 1 1
2 -------- 2 2 2 -------- 2 2
@@ -1040,12 +1091,10 @@ v.info = 'Unplaceable'
end end
term.clearLine() term.clearLine()
return t
end end
function Schematic:optimizeRoute(spinner, y) function Schematic:optimizeRoute(spinner, y)
local function getNearestNeighbor(p, pt, maxDistance) local function getNearestNeighbor(p, pt, maxDistance)
local key, block, heading local key, block, heading
local moves = maxDistance local moves = maxDistance
@@ -1115,8 +1164,8 @@ function Schematic:optimizeRoute(spinner, y)
return block return block
end end
local pt = Util.shallowCopy(self.cache[y - 1] or turtle.point) local pt = Util.shallowCopy(self.cache[y - 1] or { x = -1, y = 0, z = -1, heading = 0 })
local t = {} local t = { }
local ri = self.rowIndex[y] local ri = self.rowIndex[y]
local blockCount = ri.e - ri.s + 1 local blockCount = ri.e - ri.s + 1
@@ -1146,7 +1195,6 @@ function Schematic:optimizeRoute(spinner, y)
local maxDistance = self.width*self.length local maxDistance = self.width*self.length
local plane, doors = extractPlane(y) local plane, doors = extractPlane(y)
spinner:spin(percent)
pt.index = 0 pt.index = 0
for i = 1, #plane do for i = 1, #plane do
local b = getNearestNeighbor(plane, pt, maxDistance) local b = getNearestNeighbor(plane, pt, maxDistance)

1248
apis/builder/turtle.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@ local convertNames = {
displayName = 'display_name', displayName = 'display_name',
maxDamage = 'max_dmg', maxDamage = 'max_dmg',
} }
local keys = { local keys = {
'damage', 'damage',
'displayName', 'displayName',
'maxCount', 'maxCount',
@@ -31,7 +31,7 @@ local function safeString(text)
local newText = {} local newText = {}
for i = 4, #text do for i = 4, #text do
local val = text:byte(i) val = text:byte(i)
newText[i - 3] = (val > 31 and val < 127) and val or 63 newText[i - 3] = (val > 31 and val < 127) and val or 63
end end
return string.char(unpack(newText)) return string.char(unpack(newText))
@@ -65,11 +65,11 @@ function ChestAdapter:init(args)
Util.merge(self, chest) Util.merge(self, chest)
end end
end end
function ChestAdapter:isValid() function ChestAdapter:isValid()
return not not self.getAllStacks return not not self.getAllStacks
end end
function ChestAdapter:refresh(throttle) function ChestAdapter:refresh(throttle)
return self:listItems(throttle) return self:listItems(throttle)
end end
@@ -86,13 +86,12 @@ function ChestAdapter:listItems(throttle)
if not entry then if not entry then
self.cache[key] = v self.cache[key] = v
local ikey = { v.name, v.damage, v.nbtHash } if not itemDB:get(v) then
if not itemDB:get(ikey) then
local t = { } local t = { }
for _,k in pairs(keys) do for _,k in pairs(keys) do
t[k] = v[k] t[k] = v[k]
end end
itemDB:add(ikey, t) itemDB:add(t)
end end
else else
entry.count = entry.count + v.count entry.count = entry.count + v.count
@@ -109,12 +108,11 @@ function ChestAdapter:getItemInfo(item)
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':') local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
return self.cache[key] return self.cache[key]
end end
function ChestAdapter:craft(id, dmg, qty) function ChestAdapter:craft()
return false
end end
function ChestAdapter:craftItems(items) function ChestAdapter:craftItems()
end end
function ChestAdapter:provide(item, qty, slot, direction) function ChestAdapter:provide(item, qty, slot, direction)
@@ -144,7 +142,7 @@ end
function ChestAdapter:insert(slot, qty) function ChestAdapter:insert(slot, qty)
local s, m = pcall(function() self.pullItem(self.direction, slot, qty) end) local s, m = pcall(function() self.pullItem(self.direction, slot, qty) end)
if not s and m then if not s and m then
sleep(1) os.sleep(1)
pcall(function() self.pullItem(self.direction, slot, qty) end) pcall(function() self.pullItem(self.direction, slot, qty) end)
end end
end end

View File

@@ -5,28 +5,23 @@ local Peripheral = require('peripheral')
local ChestAdapter = class() local ChestAdapter = class()
local keys = Util.transpose({
'damage',
'displayName',
'maxCount',
'maxDamage',
'name',
'nbtHash',
})
function ChestAdapter:init(args) function ChestAdapter:init(args)
local defaults = { local defaults = {
name = 'chest', name = 'chest',
direction = 'up',
wrapSide = 'bottom',
} }
Util.merge(self, defaults) Util.merge(self, defaults)
Util.merge(self, args) Util.merge(self, args)
local chest = Peripheral.getBySide(self.wrapSide) local chest
if not chest then if not self.side then
chest = Peripheral.getByMethod('list') chest = Peripheral.getByMethod('list')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.list then
chest = nil
end
end end
if chest then if chest then
Util.merge(self, chest) Util.merge(self, chest)
end end
@@ -37,30 +32,19 @@ function ChestAdapter:isValid()
end end
function ChestAdapter:getCachedItemDetails(item, k) function ChestAdapter:getCachedItemDetails(item, k)
local key = { item.name, item.damage, item.nbtHash } local cached = itemDB:get(item)
if cached then
local detail = itemDB:get(key) return cached
if not detail then
pcall(function() detail = self.getItemMeta(k) end)
if not detail then
return
end
-- NOT SUFFICIENT
if detail.name ~= item.name then
return
end
for _,k in ipairs(Util.keys(detail)) do
if not keys[k] then
detail[k] = nil
end
end
itemDB:add(key, detail)
end end
if detail then
return Util.shallowCopy(detail) local s, detail = pcall(self.getItemMeta, k)
if not s or not detail or detail.name ~= item.name then
-- debug({ s, detail })
-- error('Inventory has changed')
return
end end
return itemDB:add(detail)
end end
function ChestAdapter:refresh(throttle) function ChestAdapter:refresh(throttle)
@@ -69,33 +53,38 @@ end
-- provide a consolidated list of items -- provide a consolidated list of items
function ChestAdapter:listItems(throttle) function ChestAdapter:listItems(throttle)
self.cache = { } local cache = { }
local items = { } local items = { }
throttle = throttle or Util.throttle() throttle = throttle or Util.throttle()
for k,v in pairs(self.list()) do for k,v in pairs(self.list()) do
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':') if v.count > 0 then
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':')
local entry = self.cache[key] local entry = cache[key]
if not entry then if not entry then
entry = self:getCachedItemDetails(v, k) entry = self:getCachedItemDetails(v, k)
if entry then if not entry then
return -- Inventory has changed
end
entry = Util.shallowCopy(entry)
entry.count = 0 entry.count = 0
self.cache[key] = entry cache[key] = entry
table.insert(items, entry) table.insert(items, entry)
end end
end
if entry then if entry then
entry.count = entry.count + v.count entry.count = entry.count + v.count
end
throttle()
end end
throttle()
end end
itemDB:flush() itemDB:flush()
return items if not Util.empty(items) then
self.cache = cache
return items
end
end end
function ChestAdapter:getItemInfo(item) function ChestAdapter:getItemInfo(item)
@@ -106,34 +95,68 @@ function ChestAdapter:getItemInfo(item)
return self.cache[key] return self.cache[key]
end end
function ChestAdapter:craft(name, damage, qty) function ChestAdapter:craft()
end end
function ChestAdapter:craftItems(items) function ChestAdapter:craftItems()
end
function ChestAdapter:getPercentUsed()
if self.cache and self.getDrawerCount then
return math.floor(Util.size(self.cache) / self.getDrawerCount() * 100)
end
return 0
end end
function ChestAdapter:provide(item, qty, slot, direction) function ChestAdapter:provide(item, qty, slot, direction)
local stacks = self.list() local s, m = pcall(function()
for key,stack in pairs(stacks) do local stacks = self.list()
if stack.name == item.name and stack.damage == item.damage then for key,stack in Util.rpairs(stacks) do
local amount = math.min(qty, stack.count) if stack.name == item.name and
if amount > 0 then (not item.damage or stack.damage == item.damage) and
self.pushItems(direction or self.direction, key, amount, slot) (not item.nbtHash or stack.nbtHash == item.nbtHash) then
end local amount = math.min(qty, stack.count)
qty = qty - amount if amount > 0 then
if qty <= 0 then self.pushItems(direction or self.direction, key, amount, slot)
break end
qty = qty - amount
if qty <= 0 then
break
end
end end
end end
end end)
return s, m
end
function ChestAdapter:eject(item, qty, direction)
local s, m = pcall(function()
local stacks = self.list()
local maxStack = itemDB:getMaxCount(item)
for key,stack in Util.rpairs(stacks) do
if stack.name == item.name and
(not item.damage or stack.damage == item.damage) and
(not item.nbtHash or stack.nbtHash == item.nbtHash) then
local amount = math.min(maxStack, math.min(qty, stack.count))
if amount > 0 then
self.drop(key, amount, direction)
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
return s, m
end end
function ChestAdapter:extract(slot, qty, toSlot) function ChestAdapter:extract(slot, qty, toSlot)
self.pushItems(self.direction, slot, qty, toSlot) self.pushItems(self.direction, slot, qty, toSlot)
end end
function ChestAdapter:insert(slot, qty) function ChestAdapter:insert(slot, qty, toSlot)
self.pullItems(self.direction, slot, qty) self.pullItems(self.direction, slot, qty, toSlot)
end end
return ChestAdapter return ChestAdapter

View File

@@ -0,0 +1,18 @@
local Adapter = { }
function Adapter.wrap(args)
local adapters = {
'refinedAdapter',
'meAdapter',
}
for _,adapterType in ipairs(adapters) do
local adapter = require(adapterType)(args)
if adapter:isValid() then
return adapter
end
end
end
return Adapter

52
apis/inventoryAdapter.lua Normal file
View File

@@ -0,0 +1,52 @@
local Util = require('util')
local Adapter = { }
function Adapter.wrap(args)
local adapters = {
--'refinedAdapter',
'chestAdapter18',
'meAdapter',
'chestAdapter',
}
if args and args.side and args.facing and not args.direction then
args = Util.shallowCopy(args)
local horz = { top = 'down', bottom = 'up' }
args.direction = horz[args.side]
if not args.direction then
local sides = {
front = 0,
back = 2,
right = 1,
left = 3,
}
-- pretty sure computer/turtle have sides reversed
local cards = {
east = 0,
south = 1,
west = 2,
north = 3,
}
local icards = {
[ 0 ] = 'west',
[ 1 ] = 'north',
[ 2 ] = 'east',
[ 3 ] = 'south',
}
args.direction = icards[(cards[args.facing] + sides[args.side]) % 4]
end
end
for _,adapterType in ipairs(adapters) do
local adapter = require(adapterType)(args)
if adapter:isValid() then
return adapter
end
end
end
return Adapter

View File

@@ -4,73 +4,165 @@ local Util = require('util')
local itemDB = TableDB({ fileName = 'usr/config/items.db' }) local itemDB = TableDB({ fileName = 'usr/config/items.db' })
local function splitKey(key, item) local function safeString(text)
local val = text:byte(1)
if val < 32 or val > 128 then
local newText = { }
local skip = 0
for i = 1, #text do
val = text:byte(i)
if val == 167 then
skip = 2
end
if skip > 0 then
skip = skip - 1
else
if val >= 32 and val <= 128 then
newText[#newText + 1] = val
end
end
end
return string.char(unpack(newText))
end
return text
end
local function makeKey(item)
return table.concat({ item.name, item.damage or '*', item.nbtHash }, ':')
end
function itemDB:splitKey(key, item)
item = item or { } item = item or { }
local t = Util.split(key, '(.-):') local t = Util.split(key, '(.-):')
if #t[#t] > 8 then if #t[#t] > 8 then
item.nbtHash = table.remove(t) item.nbtHash = table.remove(t)
end end
item.damage = tonumber(table.remove(t)) local damage = table.remove(t)
if damage ~= '*' then
item.damage = tonumber(damage)
end
item.name = table.concat(t, ':') item.name = table.concat(t, ':')
return item return item
end end
function itemDB:get(key) function itemDB:get(key)
if type(key) == 'string' then
key = self:splitKey(key)
end
local item = TableDB.get(self, key) local item = TableDB.get(self, makeKey(key))
if item then if item then
return item return item
end end
if key[2] ~= 0 then -- try finding an item that has damage values
item = TableDB.get(self, { key[1], 0, key[3] }) if type(key.damage) == 'number' then
if item and item.maxDamage > 0 then item = TableDB.get(self, makeKey({ name = key.name, nbtHash = key.nbtHash }))
if item and item.maxDamage then
item = Util.shallowCopy(item) item = Util.shallowCopy(item)
item.damage = key[2] item.damage = key.damage
item.displayName = string.format('%s (damage: %d)', item.displayName, item.damage) if item.maxDamage > 0 and type(item.damage) == 'number' and item.damage > 0 then
item.displayName = string.format('%s (damage: %s)', item.displayName, item.damage)
end
return item
end
end
if key.nbtHash then
item = self:get({ name = key.name, damage = key.damage })
if item and item.ignoreNBT then
item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash
item.damage = key.damage
return item return item
end end
end end
end end
function itemDB:add(key, item) --[[
If the base item contains an NBT hash, then the NBT hash uniquely
identifies this item.
]]--
function itemDB:add(baseItem)
local nItem = {
name = baseItem.name,
damage = baseItem.damage,
nbtHash = baseItem.nbtHash,
}
-- if detail.maxDamage > 0 then
-- nItem.damage = '*'
-- end
if item.maxDamage > 0 then nItem.displayName = safeString(baseItem.displayName)
key = { key[1], 0, key[3] } nItem.maxCount = baseItem.maxCount
nItem.maxDamage = baseItem.maxDamage
for k,item in pairs(self.data) do
if nItem.name == item.name and
nItem.displayName == item.displayName then
if nItem.nbtHash ~= item.nbtHash and nItem.damage ~= item.damage then
nItem.damage = '*'
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
elseif nItem.damage ~= item.damage then
nItem.damage = '*'
self.data[k] = nil
break
elseif nItem.nbtHash ~= item.nbtHash then
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
end
end
end end
TableDB.add(self, key, item)
end
function itemDB:makeKey(item) TableDB.add(self, makeKey(nItem), nItem)
return { item.name, item.damage, item.nbtHash } nItem = Util.shallowCopy(nItem)
nItem.damage = baseItem.damage
nItem.nbtHash = baseItem.nbtHash
return nItem
end end
-- Accepts: "minecraft:stick:0" or { name = 'minecraft:stick', damage = 0 } -- Accepts: "minecraft:stick:0" or { name = 'minecraft:stick', damage = 0 }
function itemDB:getName(item) function itemDB:getName(item)
if type(item) == 'string' then if type(item) == 'string' then
item = splitKey(item) item = self:splitKey(item)
end end
local detail = self:get(self:makeKey(item)) local detail = self:get(item)
if detail then if detail then
return detail.displayName return detail.displayName
end end
-- fallback to nameDB -- fallback to nameDB
return nameDB:getName(item.name .. ':' .. item.damage) return nameDB:getName(item.name .. ':' .. (item.damage or '*'))
end
function itemDB:getMaxCount(item)
local detail = self:get(item)
if detail then
return detail.maxCount
end
return 64
end end
function itemDB:load() function itemDB:load()
TableDB.load(self) TableDB.load(self)
for key,item in pairs(self.data) do for key,item in pairs(self.data) do
splitKey(key, item) self:splitKey(key, item)
item.maxDamage = item.maxDamage or 0 item.maxDamage = item.maxDamage or 0
item.maxCount = item.maxCount or 64 item.maxCount = item.maxCount or 64
end end
@@ -85,6 +177,7 @@ function itemDB:flush()
v.name = nil v.name = nil
v.damage = nil v.damage = nil
v.nbtHash = nil v.nbtHash = nil
v.count = nil -- wipe out previously saved counts - temporary
if v.maxDamage == 0 then if v.maxDamage == 0 then
v.maxDamage = nil v.maxDamage = nil
end end

View File

@@ -3,7 +3,8 @@ local itemDB = require('itemDB')
local Peripheral = require('peripheral') local Peripheral = require('peripheral')
local Util = require('util') local Util = require('util')
local MEAdapter = class() local os = _G.os
local peripheral = _G.peripheral
local convertNames = { local convertNames = {
name = 'id', name = 'id',
@@ -13,7 +14,7 @@ local convertNames = {
displayName = 'display_name', displayName = 'display_name',
maxDamage = 'max_dmg', maxDamage = 'max_dmg',
} }
local keys = { local keys = {
'damage', 'damage',
'displayName', 'displayName',
'maxCount', 'maxCount',
@@ -31,7 +32,7 @@ local function safeString(text)
local newText = {} local newText = {}
for i = 4, #text do for i = 4, #text do
local val = text:byte(i) val = text:byte(i)
newText[i - 3] = (val > 31 and val < 127) and val or 63 newText[i - 3] = (val > 31 and val < 127) and val or 63
end end
return string.char(unpack(newText)) return string.char(unpack(newText))
@@ -48,31 +49,33 @@ local function convertItem(item)
item.displayName = safeString(item.displayName) item.displayName = safeString(item.displayName)
end end
local MEAdapter = class()
function MEAdapter:init(args) function MEAdapter:init(args)
local defaults = { local defaults = {
items = { }, items = { },
name = 'ME', name = 'ME',
jobList = { }, jobList = { },
direction = 'up',
wrapSide = 'bottom',
auto = false,
} }
Util.merge(self, defaults) Util.merge(self, defaults)
Util.merge(self, args) Util.merge(self, args)
if self.auto then local chest
local mep = Peripheral.getByMethod('getAvailableItems')
if mep then if not self.side then
Util.merge(self, mep) chest = Peripheral.getByMethod('getAvailableItems')
end
else else
local mep = peripheral.wrap(self.wrapSide) chest = Peripheral.getBySide(self.side)
if mep then if chest and not chest.getAvailableItems then
Util.merge(self, mep) chest = nil
end end
end end
if chest then
Util.merge(self, chest)
end
end end
function MEAdapter:isValid() function MEAdapter:isValid()
return self.getAvailableItems and self.getAvailableItems() return self.getAvailableItems and self.getAvailableItems()
end end
@@ -84,13 +87,8 @@ function MEAdapter:refresh()
Util.merge(v, v.item) Util.merge(v, v.item)
convertItem(v) convertItem(v)
local key = { v.name, v.damage, v.nbtHash } if not itemDB:get(v) then
if not itemDB:get(key) then itemDB:add(v, v)
local t = { }
for _,k in pairs(keys) do
t[k] = v[k]
end
itemDB:add(key, t)
end end
end end
itemDB:flush() itemDB:flush()
@@ -102,9 +100,9 @@ function MEAdapter:listItems()
self:refresh() self:refresh()
return self.items return self.items
end end
function MEAdapter:getItemInfo(item) function MEAdapter:getItemInfo(item)
for key,i in pairs(self.items) do for _,i in pairs(self.items) do
if item.name == i.name and item.damage == i.damage and item.nbtHash == i.nbtHash then if item.name == i.name and item.damage == i.damage and item.nbtHash == i.nbtHash then
return i return i
end end
@@ -123,7 +121,7 @@ function MEAdapter:isCPUAvailable()
end end
end end
return available return available
end end
function MEAdapter:craft(item, count) function MEAdapter:craft(item, count)
@@ -133,7 +131,7 @@ function MEAdapter:craft(item, count)
self:refresh() self:refresh()
local item = self:getItemInfo(item) item = self:getItemInfo(item)
if item and item.is_craftable then if item and item.is_craftable then
local cpus = self.getCraftingCPUs() or { } local cpus = self.getCraftingCPUs() or { }
@@ -186,8 +184,8 @@ end
function MEAdapter:isCrafting(item) function MEAdapter:isCrafting(item)
for _,v in pairs(self:getJobList()) do for _,v in pairs(self:getJobList()) do
if v.name == item.name and if v.name == item.name and
v.damage == item.damage and v.damage == item.damage and
v.nbtHash == item.nbtHash then v.nbtHash == item.nbtHash then
return true return true
end end
@@ -220,7 +218,7 @@ function MEAdapter:provide(item, count, slot, direction)
return pcall(function() return pcall(function()
while count > 0 do while count > 0 do
local qty = math.min(count, 64) local qty = math.min(count, 64)
local s, m = self.exportItem({ local s = self.exportItem({
id = item.name, id = item.name,
dmg = item.damage dmg = item.damage
}, direction or self.direction, qty, slot) }, direction or self.direction, qty, slot)
@@ -232,18 +230,14 @@ function MEAdapter:provide(item, count, slot, direction)
end end
end) end)
end end
function MEAdapter:insert(slot, count) function MEAdapter:insert(slot, count)
local s, m = pcall(function() self.pullItem(self.direction, slot, count) end) local s, m = pcall(function() self.pullItem(self.direction, slot, count) end)
if not s and m then if not s and m then
print('MEAdapter:pullItem') os.sleep(1)
print(m)
sleep(1)
s, m = pcall(function() self.pullItem(self.direction, slot, count) end) s, m = pcall(function() self.pullItem(self.direction, slot, count) end)
if not s and m then if not s and m then
print('MEAdapter:pullItem') error(m)
print(m)
read()
end end
end end
end end

View File

@@ -12,7 +12,7 @@ function nameDB:load()
end end
for strId, block in pairs(blocks) do for strId, block in pairs(blocks) do
local strId = 'minecraft:' .. strId strId = 'minecraft:' .. strId
if type(block.name) == 'string' then if type(block.name) == 'string' then
self.data[strId .. ':0'] = block.name self.data[strId .. ':0'] = block.name
else else

View File

@@ -5,7 +5,7 @@ local itemDB = require('itemDB')
local RefinedAdapter = class() local RefinedAdapter = class()
local keys = { local keys = {
'damage', 'damage',
'displayName', 'displayName',
'maxCount', 'maxCount',
@@ -18,11 +18,22 @@ function RefinedAdapter:init(args)
local defaults = { local defaults = {
items = { }, items = { },
name = 'refinedStorage', name = 'refinedStorage',
direction = 'up',
wrapSide = 'bottom',
} }
Util.merge(self, defaults) Util.merge(self, defaults)
Util.merge(self, args) Util.merge(self, args)
local controller = Peripheral.getByType('refinedstorage:controller') local controller
if self.autoDetect then
controller = Peripheral.getByType('refinedstorage:controller')
else
controller = Peripheral.getBySide(self.wrapSide)
if controller and not controller.listAvailableItems then
controller = nil
end
end
if controller then if controller then
Util.merge(self, controller) Util.merge(self, controller)
end end
@@ -37,9 +48,7 @@ function RefinedAdapter:isOnline()
end end
function RefinedAdapter:getCachedItemDetails(item) function RefinedAdapter:getCachedItemDetails(item)
local key = { item.name, item.damage, item.nbtHash } local detail = itemDB:get(item)
local detail = itemDB:get(key)
if not detail then if not detail then
detail = self.findItem(item) detail = self.findItem(item)
if detail then if detail then
@@ -56,7 +65,7 @@ function RefinedAdapter:getCachedItemDetails(item)
end end
detail = t detail = t
itemDB:add(key, detail) itemDB:add(detail)
end end
end end
if detail then if detail then
@@ -91,10 +100,7 @@ function RefinedAdapter:listItems()
end end
function RefinedAdapter:getItemInfo(fingerprint) function RefinedAdapter:getItemInfo(fingerprint)
local item = itemDB:get(fingerprint)
local key = { fingerprint.name, fingerprint.damage, fingerprint.nbtHash }
local item = itemDB:get(key)
if not item then if not item then
return self:getCachedItemDetails(fingerprint) return self:getCachedItemDetails(fingerprint)
end end
@@ -109,8 +115,8 @@ end
function RefinedAdapter:isCrafting(item) function RefinedAdapter:isCrafting(item)
for _,task in pairs(self.getCraftingTasks()) do for _,task in pairs(self.getCraftingTasks()) do
local output = task.getPattern().outputs[1] local output = task.getPattern().outputs[1]
if output.name == item.name and if output.name == item.name and
output.damage == item.damage and output.damage == item.damage and
output.nbtHash == item.nbtHash then output.nbtHash == item.nbtHash then
return true return true
end end
@@ -125,18 +131,18 @@ function RefinedAdapter:craft(item, qty)
end end
end end
function RefinedAdapter:craftItems(items) function RefinedAdapter:craftItems()
return false return false
end end
function RefinedAdapter:provide(item, qty, slot) function RefinedAdapter:provide()
end end
function RefinedAdapter:extract(slot, qty) function RefinedAdapter:extract()
-- self.pushItems(self.direction, slot, qty) -- self.pushItems(self.direction, slot, qty)
end end
function RefinedAdapter:insert(slot, qty) function RefinedAdapter:insert()
-- self.pullItems(self.direction, slot, qty) -- self.pullItems(self.direction, slot, qty)
end end

View File

@@ -11,14 +11,14 @@ function TableDB:init(args)
Util.merge(defaults, args) Util.merge(defaults, args)
Util.merge(self, defaults) Util.merge(self, defaults)
end end
function TableDB:load() function TableDB:load()
local t = Util.readTable(self.fileName) local t = Util.readTable(self.fileName)
if t then if t then
self.data = t.data or t self.data = t.data or t
end end
end end
function TableDB:add(key, entry) function TableDB:add(key, entry)
if type(key) == 'table' then if type(key) == 'table' then
key = table.concat(key, ':') key = table.concat(key, ':')
@@ -26,19 +26,19 @@ function TableDB:add(key, entry)
self.data[key] = entry self.data[key] = entry
self.dirty = true self.dirty = true
end end
function TableDB:get(key) function TableDB:get(key)
if type(key) == 'table' then if type(key) == 'table' then
key = table.concat(key, ':') key = table.concat(key, ':')
end end
return self.data[key] return self.data[key]
end end
function TableDB:remove(key) function TableDB:remove(key)
self.data[key] = nil self.data[key] = nil
self.dirty = true self.dirty = true
end end
function TableDB:flush() function TableDB:flush()
if self.dirty then if self.dirty then
Util.writeTable(self.fileName, self.data) Util.writeTable(self.fileName, self.data)

View File

@@ -1,6 +1,11 @@
local itemDB = require('itemDB') local itemDB = require('itemDB')
local Util = require('util') local Util = require('util')
local fs = _G.fs
local turtle = _G.turtle
local RECIPES_DIR = 'usr/etc/recipes'
local Craft = { } local Craft = { }
local function clearGrid(inventoryAdapter) local function clearGrid(inventoryAdapter)
@@ -9,6 +14,7 @@ local function clearGrid(inventoryAdapter)
if count > 0 then if count > 0 then
inventoryAdapter:insert(i, count) inventoryAdapter:insert(i, count)
if turtle.getItemCount(i) ~= 0 then if turtle.getItemCount(i) ~= 0 then
-- inventory is possibly full
return false return false
end end
end end
@@ -27,27 +33,44 @@ local function splitKey(key)
return item return item
end end
local function getItemCount(items, key) function Craft.getItemCount(items, item)
local item = splitKey(key) if type(item) == 'string' then
item = splitKey(item)
end
local count = 0
for _,v in pairs(items) do for _,v in pairs(items) do
if v.name == item.name and if v.name == item.name and
v.damage == item.damage and (not item.damage or v.damage == item.damage) and
v.nbtHash == item.nbtHash then v.nbtHash == item.nbtHash then
return v.count if item.damage then
return v.count
end
count = count + v.count
end end
end end
return 0 return count
end end
local function turtleCraft(recipe, qty, inventoryAdapter) local function turtleCraft(recipe, qty, inventoryAdapter)
if not clearGrid(inventoryAdapter) then
clearGrid(inventoryAdapter) return false
end
for k,v in pairs(recipe.ingredients) do for k,v in pairs(recipe.ingredients) do
local item = splitKey(v) local item = splitKey(v)
inventoryAdapter:provide(item, qty, k) local provideQty = qty
--[[
Turtles can only craft 1 item at a time when using a tool.
if recipe.craftingTools and recipe.craftingTools[k] then
provideQty = 1
end
]]--
inventoryAdapter:provide(item, provideQty, k)
if turtle.getItemCount(k) == 0 then -- ~= qty then if turtle.getItemCount(k) == 0 then -- ~= qty then
-- FIX: ingredients cannot be stacked -- FIX: ingredients cannot be stacked
--debug('failed ' .. v .. ' - ' .. provideQty)
return false return false
end end
end end
@@ -55,65 +78,166 @@ local function turtleCraft(recipe, qty, inventoryAdapter)
return turtle.craft() return turtle.craft()
end end
function Craft.loadRecipes()
Craft.recipes = Util.readTable(fs.combine(RECIPES_DIR, 'minecraft.db')) or { }
local files = fs.list('usr/etc/recipes')
table.sort(files)
Util.removeByValue(files, 'minecraft.db')
for _,file in ipairs(files) do
local recipes = Util.readTable(fs.combine(RECIPES_DIR, file))
Util.merge(Craft.recipes, recipes)
end
local recipes = Util.readTable('usr/config/recipes.db') or { }
Util.merge(Craft.recipes, recipes)
end
function Craft.sumIngredients(recipe)
-- produces { ['minecraft:planks:0'] = 8 }
local t = { }
for _,item in pairs(recipe.ingredients) do
t[item] = (t[item] or 0) + 1
end
-- need a check for crafting tool
return t
end
function Craft.craftRecipe(recipe, count, inventoryAdapter) function Craft.craftRecipe(recipe, count, inventoryAdapter)
if type(recipe) == 'string' then
recipe = Craft.recipes[recipe]
if not recipe then
return 0, 'No recipe'
end
end
local items = inventoryAdapter:listItems() local items = inventoryAdapter:listItems()
if not items then
local function sumItems(items) return 0, 'Inventory changed'
-- produces { ['minecraft:planks:0'] = 8 }
local t = {}
for _,item in pairs(items) do
t[item] = (t[item] or 0) + 1
end
return t
end end
count = math.ceil(count / recipe.count) count = math.ceil(count / recipe.count)
local maxCount = recipe.maxCount or math.floor(64 / recipe.count) local maxCount = recipe.maxCount or math.floor(64 / recipe.count)
local summedItems = sumItems(recipe.ingredients)
for key,icount in pairs(summedItems) do for key,icount in pairs(Craft.sumIngredients(recipe)) do
local itemCount = getItemCount(items, key) local itemCount = Craft.getItemCount(items, key)
if itemCount < icount * count then if itemCount < icount * count then
local irecipe = Craft.recipes[key] local irecipe = Craft.recipes[key]
if irecipe then if irecipe then
--Util.print('Crafting %d %s', icount * count - itemCount, key) local iqty = icount * count - itemCount
if not Craft.craftRecipe(irecipe, local crafted = Craft.craftRecipe(irecipe, iqty, inventoryAdapter)
icount * count - itemCount, if crafted ~= iqty then
inventoryAdapter) then
turtle.select(1) turtle.select(1)
return return 0
end end
end end
end end
end end
local crafted = 0
repeat repeat
if not turtleCraft(recipe, math.min(count, maxCount), inventoryAdapter) then if not turtleCraft(recipe, math.min(count, maxCount), inventoryAdapter) then
turtle.select(1) turtle.select(1)
return false break
end end
crafted = crafted + math.min(count, maxCount)
count = count - maxCount count = count - maxCount
until count <= 0 until count <= 0
turtle.select(1) turtle.select(1)
return true return crafted * recipe.count
end
local function makeRecipeKey(item)
if type(item) == 'string' then
item = splitKey(item)
end
return table.concat({ item.name, item.damage or 0, item.nbtHash }, ':')
end
function Craft.findRecipe(item)
return Craft.recipes[makeRecipeKey(item)]
end
-- determine the full list of ingredients needed to craft
-- a quantity of a recipe.
function Craft.getResourceList(recipe, items, inCount)
local summed = { }
local function sumItems(key, count)
local item = itemDB:splitKey(key)
local summedItem = summed[key]
if not summedItem then
summedItem = Util.shallowCopy(item)
summedItem.recipe = Craft.findRecipe(key)
summedItem.count = Craft.getItemCount(items, item)
summedItem.displayName = itemDB:getName(item)
summedItem.total = 0
summedItem.need = 0
summedItem.used = 0
summed[key] = summedItem
end
local total = count
local used = math.min(summedItem.count, total)
local need = total - used
if summedItem.recipe and summedItem.recipe.craftingTools and summedItem.recipe.craftingTools[key] then
summedItem.total = 1
if summedItem.count > 0 then
summedItem.used = 1
summedItem.need = 0
need = 0
else
if not summedItem.recipe then
summedItem.need = 1
need = 1
end
end
else
summedItem.total = summedItem.total + total
summedItem.count = summedItem.count - used
summedItem.used = summedItem.used + used
if not summedItem.recipe then
summedItem.need = summedItem.need + need
end
end
if need > 0 and summedItem.recipe then
need = math.ceil(need / summedItem.recipe.count)
for ikey,iqty in pairs(Craft.sumIngredients(summedItem.recipe)) do
sumItems(ikey, math.ceil(need * iqty))
end
end
end
inCount = math.ceil(inCount / recipe.count)
for ikey,iqty in pairs(Craft.sumIngredients(recipe)) do
sumItems(ikey, math.ceil(inCount * iqty))
end
return summed
end
function Craft.getResourceList4(inRecipe, items, count)
local summed = Craft.getResourceList(inRecipe, items, count)
-- filter down to just raw materials
return Util.filter(summed, function(a) return a.used > 0 or a.need > 0 end)
end end
-- given a certain quantity, return how many of those can be crafted -- given a certain quantity, return how many of those can be crafted
function Craft.getCraftableAmount(recipe, count, items, missing) function Craft.getCraftableAmount(recipe, count, items, missing)
local function sumItems(recipe, summedItems, count)
local function sumItems(recipe, items, summedItems, count)
local canCraft = 0 local canCraft = 0
for i = 1, count do for _ = 1, count do
for _,item in pairs(recipe.ingredients) do for _,item in pairs(recipe.ingredients) do
local summedItem = summedItems[item] or getItemCount(items, item) local summedItem = summedItems[item] or Craft.getItemCount(items, item)
local irecipe = Craft.recipes[item] local irecipe = Craft.recipes[item]
if irecipe and summedItem <= 0 then if irecipe and summedItem <= 0 then
summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) summedItem = summedItem + sumItems(irecipe, summedItems, 1)
end end
if summedItem <= 0 then if summedItem <= 0 then
if missing then if missing then
@@ -121,7 +245,9 @@ function Craft.getCraftableAmount(recipe, count, items, missing)
end end
return canCraft return canCraft
end end
summedItems[item] = summedItem - 1 if not recipe.craftingTools or not recipe.craftingTools[item] then
summedItems[item] = summedItem - 1
end
end end
canCraft = canCraft + recipe.count canCraft = canCraft + recipe.count
end end
@@ -129,7 +255,7 @@ function Craft.getCraftableAmount(recipe, count, items, missing)
return canCraft return canCraft
end end
return sumItems(recipe, items, { }, math.ceil(count / recipe.count), missing) return sumItems(recipe, { }, math.ceil(count / recipe.count))
end end
function Craft.canCraft(item, count, items) function Craft.canCraft(item, count, items)
@@ -148,13 +274,15 @@ function Craft.getCraftableAmountTest()
{ name = 'minecraft:planks', damage = 0, count = 5 }, { name = 'minecraft:planks', damage = 0, count = 5 },
{ name = 'minecraft:log', damage = 0, count = 2 }, { name = 'minecraft:log', damage = 0, count = 2 },
} }
results[1] = { item = 'chest', expected = 1, got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) } results[1] = { item = 'chest', expected = 1,
got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) }
items = { items = {
{ name = 'minecraft:log', damage = 0, count = 1 }, { name = 'minecraft:log', damage = 0, count = 1 },
{ name = 'minecraft:coal', damage = 1, count = 1 }, { name = 'minecraft:coal', damage = 1, count = 1 },
} }
results[2] = { item = 'torch', expected = 4, got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) } results[2] = { item = 'torch', expected = 4,
got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) }
return results return results
end end
@@ -166,4 +294,6 @@ function Craft.craftRecipeTest(name, count)
return { Craft.craftRecipe(Craft.recipes[name], count, chestAdapter) } return { Craft.craftRecipe(Craft.recipes[name], count, chestAdapter) }
end end
Craft.loadRecipes()
return Craft return Craft

67
apis/turtle/crafting.lua Normal file
View File

@@ -0,0 +1,67 @@
local Adapter = require('inventoryAdapter')
local Craft = require('turtle.craft')
local turtle = _G.turtle
local CRAFTING_TABLE = 'minecraft:crafting_table'
local function clearGrid(inventory)
print('clearing')
for i = 1, 16 do
local count = turtle.getItemCount(i)
if count > 0 then
inventory:insert(i, count)
if turtle.getItemCount(i) ~= 0 then
print('failed to insert')
return false
end
end
end
return true
end
function turtle.craftItem(item, count, inventoryInfo)
local success, msg
local inventory = Adapter.wrap(inventoryInfo)
if not inventory then
return false, 'Invalid inventory'
end
local equipped, side
if not turtle.isEquipped('workbench') then
local modemSide = turtle.isEquipped('modem') or 'right'
local osides = { left = 'right', right = 'left' }
side = osides[modemSide]
if not turtle.select(CRAFTING_TABLE) then
clearGrid(inventory)
if not turtle.selectOpenSlot() then
return false, 'Inventory is full'
end
if not inventory:provide({ name = CRAFTING_TABLE, damage = 0 }, 1) then
return false, 'Missing crafting table'
end
end
local slot = turtle.select(CRAFTING_TABLE)
turtle.equip(side, CRAFTING_TABLE)
equipped = turtle.getItemDetail(slot.index)
end
clearGrid(inventory)
success, msg = Craft.craftRecipe(item, count or 1, inventory)
if equipped then
turtle.selectOpenSlot()
inventory:provide({ name = equipped.name, damage = equipped.damage }, 1)
turtle.equip(side, equipped.name .. ':' .. equipped.damage)
end
return success, msg
end
function turtle.canCraft(item, count, items)
return Craft.canCraft(item, count, items)
end
return true

42
apis/turtle/home.lua Normal file
View File

@@ -0,0 +1,42 @@
local Config = require('config')
local GPS = require('gps')
local turtle = _G.turtle
local Home = { }
function Home.go()
local config = { }
Config.load('gps', config)
if config.home then
if turtle.enableGPS() then
return turtle.pathfind(config.home)
end
end
end
function Home.set()
local config = { }
Config.load('gps', config)
local pt = GPS.getPoint()
if pt then
local originalHeading = turtle.point.heading
local heading = GPS.getHeading()
if heading then
local turns = (turtle.point.heading - originalHeading) % 4
pt.heading = (heading - turns) % 4
config.home = pt
Config.update('gps', config)
pt = GPS.getPoint()
pt.heading = heading
turtle.setPoint(pt, true)
turtle._goto(config.home)
return config.home
end
end
end
return Home

View File

@@ -1,6 +1,8 @@
local Point = require('point') local Point = require('point')
local Util = require('util') local Util = require('util')
local turtle = _G.turtle
local checkedNodes = { } local checkedNodes = { }
local nodes = { } local nodes = { }
local box = { } local box = { }
@@ -11,7 +13,6 @@ local function toKey(pt)
end end
local function addNode(node) local function addNode(node)
for i = 0, 5 do for i = 0, 5 do
local hi = turtle.getHeadingInfo(i) local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd } local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd }
@@ -26,14 +27,13 @@ local function addNode(node)
end end
local function dig(action) local function dig(action)
local directions = { local directions = {
top = 'up', top = 'up',
bottom = 'down', bottom = 'down',
} }
-- convert to up, down, north, south, east, west -- convert to up, down, north, south, east, west
local direction = directions[action.side] or local direction = directions[action.side] or
turtle.getHeadingInfo(turtle.point.heading).direction turtle.getHeadingInfo(turtle.point.heading).direction
local hi = turtle.getHeadingInfo(direction) local hi = turtle.getHeadingInfo(direction)
@@ -75,7 +75,7 @@ end
-- find the closest block -- find the closest block
-- * favor same plane -- * favor same plane
-- * going backwards only if the dest is above or below -- * going backwards only if the dest is above or below
function closestPoint(reference, pts) local function closestPoint(reference, pts)
local lpt, lm -- lowest local lpt, lm -- lowest
for _,pt in pairs(pts) do for _,pt in pairs(pts) do
local m = Point.turtleDistance(reference, pt) local m = Point.turtleDistance(reference, pt)
@@ -113,8 +113,7 @@ local function getAdjacentPoint(pt)
return closestPoint(turtle.getPoint(), t) return closestPoint(turtle.getPoint(), t)
end end
return function(startPt, endPt, firstPt, verbose) function turtle.level(startPt, endPt, firstPt, verbose)
checkedNodes = { } checkedNodes = { }
nodes = { } nodes = { }
box = { } box = { }
@@ -126,6 +125,10 @@ return function(startPt, endPt, firstPt, verbose)
box.ey = math.max(startPt.y, endPt.y) box.ey = math.max(startPt.y, endPt.y)
box.ez = math.max(startPt.z, endPt.z) box.ez = math.max(startPt.z, endPt.z)
if not Point.inBox(firstPt, box) then
error('Starting point is not in leveling area')
end
if not turtle.pathfind(firstPt) then if not turtle.pathfind(firstPt) then
error('failed to reach starting point') error('failed to reach starting point')
end end
@@ -155,11 +158,13 @@ return function(startPt, endPt, firstPt, verbose)
local node = closestPoint(turtle.point, nodes) local node = closestPoint(turtle.point, nodes)
node = getAdjacentPoint(node) node = getAdjacentPoint(node)
if not turtle.gotoPoint(node) then if not turtle._goto(node) then
break break
end end
until turtle.abort until turtle.isAborted()
turtle.resetState() turtle.resetState()
turtle.setMoveCallback(oldCallback) turtle.setMoveCallback(oldCallback)
end end
return true

View File

@@ -1,25 +1,28 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Ansi = require('ansi') local Ansi = require('ansi')
local Config = require('config')
local SHA1 = require('sha1') local SHA1 = require('sha1')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
-- scrap this entire file. don't muck with standard apis local fs = _G.fs
local http = _G.http
local multishell = _ENV.multishell
local os = _G.os
local shell = _ENV.shell
local REGISTRY_DIR = 'usr/.registry' local REGISTRY_DIR = 'usr/.registry'
-- FIX SOMEDAY -- FIX SOMEDAY
function os.registerApp(app, key) local function registerApp(app, key)
app.key = SHA1.sha1(key) app.key = SHA1.sha1(key)
Util.writeTable(fs.combine(REGISTRY_DIR, app.key), app) Util.writeTable(fs.combine(REGISTRY_DIR, app.key), app)
os.queueEvent('os_register_app') os.queueEvent('os_register_app')
end end
function os.unregisterApp(key) local function unregisterApp(key)
local filename = fs.combine(REGISTRY_DIR, SHA1.sha1(key)) local filename = fs.combine(REGISTRY_DIR, SHA1.sha1(key))
if fs.exists(filename) then if fs.exists(filename) then
@@ -29,7 +32,7 @@ function os.unregisterApp(key)
end end
local sandboxEnv = Util.shallowCopy(getfenv(1)) local sandboxEnv = Util.shallowCopy(_ENV)
setmetatable(sandboxEnv, { __index = _G }) setmetatable(sandboxEnv, { __index = _G })
multishell.setTitle(multishell.getCurrent(), 'App Store') multishell.setTitle(multishell.getCurrent(), 'App Store')
@@ -56,7 +59,7 @@ local sources = {
shell.setDir(APP_DIR) shell.setDir(APP_DIR)
function downloadApp(app) local function downloadApp(app)
local h local h
if type(app.url) == "table" then if type(app.url) == "table" then
@@ -72,7 +75,7 @@ function downloadApp(app)
end end
end end
function runApp(app, checkExists, ...) local function runApp(app, checkExists, ...)
local path, fn local path, fn
local args = { ... } local args = { ... }
@@ -82,7 +85,7 @@ function runApp(app, checkExists, ...)
else else
local program = downloadApp(app) local program = downloadApp(app)
fn = function() fn = function()
if not program then if not program then
error('Failed to download') error('Failed to download')
@@ -173,37 +176,35 @@ local getSourceListing = function(source)
end end
end end
local appPage = UI.Page({ local appPage = UI.Page {
menuBar = UI.MenuBar({ menuBar = UI.MenuBar {
showBackButton = not pocket, -- showBackButton = not pocket,
buttons = { buttons = {
{ text = '\027', event = 'back' },
{ text = 'Install', event = 'install' }, { text = 'Install', event = 'install' },
{ text = 'Run', event = 'run' }, { text = 'Run', event = 'run' },
{ text = 'View', event = 'view' }, { text = 'View', event = 'view' },
{ text = 'Remove', event = 'uninstall', name = 'removeButton' }, { text = 'Remove', event = 'uninstall', name = 'removeButton' },
}, },
}), },
container = UI.Window({ container = UI.Window {
x = 2, x = 2, y = 3, ex = -2, ey = -3,
y = 3, viewport = UI.Viewport(),
height = UI.term.height - 3, },
width = UI.term.width - 2,
viewport = UI.ViewportWindow(),
}),
notification = UI.Notification(), notification = UI.Notification(),
accelerators = { accelerators = {
q = 'back', q = 'back',
backspace = 'back', backspace = 'back',
}, },
}) }
function appPage.container.viewport:draw() function appPage.container.viewport:draw()
local app = self.parent.parent.app local app = self.parent.parent.app
local str = string.format( local str = string.format(
'%s \nBy: %s \nCategory: %s\nFile name: %s\n\n%s', '%s \nBy: %s \nCategory: %s\nFile name: %s\n\n%s',
Ansi.yellow .. app.title .. Ansi.reset, Ansi.yellow .. app.title .. Ansi.reset,
app.creator, app.creator,
app.categoryName, app.name, app.categoryName, app.name,
Ansi.yellow .. app.description .. Ansi.reset) Ansi.yellow .. app.description .. Ansi.reset)
self:clear() self:clear()
@@ -245,7 +246,7 @@ function appPage:eventHandler(event)
elseif event.type == 'uninstall' then elseif event.type == 'uninstall' then
if self.app.runOnly then if self.app.runOnly then
s,m = runApp(self.app, false, 'uninstall') runApp(self.app, false, 'uninstall')
else else
fs.delete(fs.combine(APP_DIR, self.app.name)) fs.delete(fs.combine(APP_DIR, self.app.name))
self.notification:success("Uninstalled " .. self.app.name, 3) self.notification:success("Uninstalled " .. self.app.name, 3)
@@ -253,7 +254,7 @@ function appPage:eventHandler(event)
self.menuBar.removeButton:disable('Remove') self.menuBar.removeButton:disable('Remove')
self.menuBar:draw() self.menuBar:draw()
os.unregisterApp(self.app.creator .. '.' .. self.app.name) unregisterApp(self.app.creator .. '.' .. self.app.name)
end end
elseif event.type == 'install' then elseif event.type == 'install' then
@@ -277,7 +278,7 @@ function appPage:eventHandler(event)
category = 'Games' category = 'Games'
end end
os.registerApp({ registerApp({
run = fs.combine(APP_DIR, self.app.name), run = fs.combine(APP_DIR, self.app.name),
title = self.app.title, title = self.app.title,
category = category, category = category,
@@ -293,35 +294,30 @@ function appPage:eventHandler(event)
return true return true
end end
local categoryPage = UI.Page({ local categoryPage = UI.Page {
menuBar = UI.MenuBar({ menuBar = UI.MenuBar {
buttons = { buttons = {
{ text = 'Catalog', event = 'dropdown', dropdown = 'sourceMenu' }, { text = 'Catalog', dropdown = sources },
{ text = 'Category', event = 'dropdown', dropdown = 'categoryMenu' }, { text = 'Category', name = 'categoryButton', dropdown = { } },
}, },
}), },
sourceMenu = UI.DropMenu({ grid = UI.ScrollingGrid {
buttons = sources, y = 2, ey = -2,
}),
grid = UI.ScrollingGrid({
y = 2,
height = UI.term.height - 2,
columns = { columns = {
{ heading = 'Title', key = 'title' }, { heading = 'Title', key = 'title' },
}, },
sortColumn = 'title', sortColumn = 'title',
autospace = true, },
}),
statusBar = UI.StatusBar(), statusBar = UI.StatusBar(),
accelerators = { accelerators = {
l = 'lua', l = 'lua',
q = 'quit', q = 'quit',
}, },
}) }
function categoryPage:setCategory(source, name, index) function categoryPage:setCategory(source, name, index)
self.grid.values = { } self.grid.values = { }
for k,v in pairs(source.storeURLs) do for _,v in pairs(source.storeURLs) do
if index == 0 or index == v.catagory then if index == 0 or index == v.catagory then
table.insert(self.grid.values, v) table.insert(self.grid.values, v)
end end
@@ -346,7 +342,7 @@ function categoryPage:setSource(source)
end end
local buttons = { } local buttons = { }
for k,v in Util.spairs(source.storeCatagoryNames, for k,v in Util.spairs(source.storeCatagoryNames,
function(a, b) return a:lower() < b:lower() end) do function(a, b) return a:lower() < b:lower() end) do
if v ~= 'Operating System' then if v ~= 'Operating System' then
@@ -359,19 +355,17 @@ function categoryPage:setSource(source)
end end
source.categoryMenu = UI.DropMenu({ source.categoryMenu = UI.DropMenu({
y = 2,
x = 1,
buttons = buttons, buttons = buttons,
}) })
source.index, source.name = Util.first(source.storeCatagoryNames) source.index, source.name = Util.first(source.storeCatagoryNames)
categoryPage:add({ categoryPage.menuBar.categoryButton:add({
categoryMenu = source.categoryMenu categoryMenu = source.categoryMenu
}) })
end end
self.source = source self.source = source
self.categoryMenu = source.categoryMenu self.menuBar.categoryButton.dropmenu = source.categoryMenu
categoryPage:setCategory(source, source.name, source.index) categoryPage:setCategory(source, source.name, source.index)
end end

View File

@@ -1,9 +1,12 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
local multishell = _ENV.multishell
local os = _G.os
multishell.setTitle(multishell.getCurrent(), 'Events') multishell.setTitle(multishell.getCurrent(), 'Events')
UI:configure('Events', ...) UI:configure('Events', ...)
@@ -123,7 +126,7 @@ Event.addRoutine(function()
p4 = e[5], p4 = e[5],
p5 = e[6], p5 = e[6],
}) })
if #page.grid.values > page.grid.height - 1 then if #page.grid.values > page.grid.height then
table.remove(page.grid.values, #page.grid.values) table.remove(page.grid.values, #page.grid.values)
end end
page.grid:update() page.grid:update()

View File

@@ -1,24 +1,29 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Ansi = require('ansi')
local Event = require('event') local Event = require('event')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
local colors = _G.colors
local multishell = _ENV.multishell
local peripheral = _G.peripheral
multishell.setTitle(multishell.getCurrent(), 'Devices') multishell.setTitle(multishell.getCurrent(), 'Devices')
--[[ -- PeripheralsPage -- ]] -- --[[ -- PeripheralsPage -- ]] --
local peripheralsPage = UI.Page { local peripheralsPage = UI.Page {
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
columns = { ey = -2,
columns = {
{ heading = 'Type', key = 'type' }, { heading = 'Type', key = 'type' },
{ heading = 'Side', key = 'side' }, { heading = 'Side', key = 'side' },
}, },
sortColumn = 'type', sortColumn = 'type',
height = UI.term.height - 1,
autospace = true, autospace = true,
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
status = 'Select peripheral' values = 'Select peripheral',
}, },
accelerators = { accelerators = {
q = 'quit', q = 'quit',
@@ -60,16 +65,17 @@ end
--[[ -- MethodsPage -- ]] -- --[[ -- MethodsPage -- ]] --
local methodsPage = UI.Page { local methodsPage = UI.Page {
grid = UI.ScrollingGrid { backgroundColor = colors.black,
columns = { doc = UI.TextArea {
{ heading = 'Name', key = 'name', width = UI.term.width } backgroundColor = colors.black,
}, x = 2, y = 2, ex = -1, ey = -7,
sortColumn = 'name',
height = 7,
}, },
viewportConsole = UI.ViewportWindow { grid = UI.ScrollingGrid {
y = 8, y = -6, ey = -2,
height = UI.term.height - 8, columns = {
{ heading = 'Name', key = 'name', width = UI.term.width }
},
sortColumn = 'name',
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
status = 'q to return', status = 'q to return',
@@ -84,8 +90,9 @@ function methodsPage:enable(p)
self.peripheral = p or self.peripheral self.peripheral = p or self.peripheral
local p = peripheral.wrap(self.peripheral.side) p = peripheral.wrap(self.peripheral.side)
if p.getDocs then if p.getDocs then
-- plethora
self.grid.values = { } self.grid.values = { }
for k,v in pairs(p.getDocs()) do for k,v in pairs(p.getDocs()) do
table.insert(self.grid.values, { table.insert(self.grid.values, {
@@ -94,27 +101,31 @@ function methodsPage:enable(p)
}) })
end end
elseif not p.getAdvancedMethodsData then elseif not p.getAdvancedMethodsData then
-- computercraft
self.grid.values = { } self.grid.values = { }
for name,f in pairs(p) do for name in pairs(p) do
table.insert(self.grid.values, { table.insert(self.grid.values, {
name = name, name = name,
noext = true, noext = true,
}) })
end end
else else
-- open peripherals
self.grid.values = p.getAdvancedMethodsData() self.grid.values = p.getAdvancedMethodsData()
for name,f in pairs(self.grid.values) do for name,f in pairs(self.grid.values) do
f.name = name f.name = name
end end
end end
self.viewportConsole.offy = 0
self.grid:update() self.grid:update()
self.grid:setIndex(1) self.grid:setIndex(1)
self.doc:setText(self:getDocumentation())
self.statusBar:setStatus(self.peripheral.type) self.statusBar:setStatus(self.peripheral.type)
UI.Page.enable(self) UI.Page.enable(self)
self:setFocus(self.grid)
end end
function methodsPage:eventHandler(event) function methodsPage:eventHandler(event)
@@ -122,82 +133,62 @@ function methodsPage:eventHandler(event)
UI:setPage(peripheralsPage) UI:setPage(peripheralsPage)
return true return true
elseif event.type == 'grid_focus_row' then elseif event.type == 'grid_focus_row' then
self.viewportConsole.offy = 0 self.doc:setText(self:getDocumentation())
self.viewportConsole:draw()
end end
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
end end
function methodsPage.viewportConsole:draw() function methodsPage:getDocumentation()
local c = self
local method = methodsPage.grid:getSelected()
c:clear() local method = self.grid:getSelected()
c:setCursorPos(1, 1)
if method.noext then if method.noext then -- computercraft docs
c.cursorY = 2 return 'No documentation'
c:print('No extended Information')
return 2
end end
if method.doc then if method.doc then -- plethora docs
c:print(method.doc, nil, colors.yellow) return Ansi.yellow .. method.doc
c.ymax = c.cursorY + 1
return
end end
-- open peripherals docs
local sb = { }
if method.description then if method.description then
c:print(method.description) table.insert(sb, method.description .. '\n\n')
end end
c.cursorY = c.cursorY + 2
c.cursorX = 1
if method.returnTypes ~= '()' then if method.returnTypes ~= '()' then
c:print(method.returnTypes .. ' ', nil, colors.yellow) table.insert(sb, Ansi.yellow .. method.returnTypes .. ' ')
end end
c:print(method.name, nil, colors.black) table.insert(sb, Ansi.blue .. method.name .. Ansi.reset .. '(')
c:print('(')
local maxArgLen = 1
for k,arg in ipairs(method.args) do for k,arg in ipairs(method.args) do
if #arg.description > 0 then
maxArgLen = math.max(#arg.name, maxArgLen)
end
local argName = arg.name
local fg = colors.green
if arg.optional then if arg.optional then
argName = string.format('[%s]', arg.name) table.insert(sb, Ansi.orange .. string.format('[%s]', arg.name))
fg = colors.orange else
table.insert(sb, Ansi.green .. arg.name)
end end
c:print(argName, nil, fg)
if k < #method.args then if k < #method.args then
c:print(', ') table.insert(sb, ',')
end end
end end
c:print(')') table.insert(sb, Ansi.reset .. ')')
c.cursorY = c.cursorY + 1
Util.filterInplace(method.args, function(a) return #a.description > 0 end)
if #method.args > 0 then if #method.args > 0 then
for _,arg in ipairs(method.args) do table.insert(sb, '\n\n')
if #arg.description > 0 then for k,arg in ipairs(method.args) do
c.cursorY = c.cursorY + 1 if arg.optional then
c.cursorX = 1 table.insert(sb, Ansi.orange)
local fg = colors.green else
if arg.optional then table.insert(sb, Ansi.green)
fg = colors.orange end
end table.insert(sb, arg.name .. Ansi.reset .. ': ' .. arg.description)
c:print(arg.name .. ': ', nil, fg) if k ~= #method.args then
c.cursorX = maxArgLen + 3 table.insert(sb, '\n\n')
c:print(arg.description, nil, nil, maxArgLen + 3)
end end
end end
end end
return table.concat(sb)
c.ymax = c.cursorY + 1
end end
Event.on('peripheral', function() Event.on('peripheral', function()

View File

@@ -1,4 +1,4 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Config = require('config') local Config = require('config')
local Event = require('event') local Event = require('event')
@@ -6,6 +6,12 @@ local Socket = require('socket')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
local colors = _G.colors
local fs = _G.fs
local multishell = _ENV.multishell
local os = _G.os
local shell = _ENV.shell
local GROUPS_PATH = 'usr/groups' local GROUPS_PATH = 'usr/groups'
local SCRIPTS_PATH = 'usr/etc/scripts' local SCRIPTS_PATH = 'usr/etc/scripts'
@@ -26,7 +32,7 @@ if UI.term.width % 2 ~= 0 then
width = width + 1 width = width + 1
end end
function processVariables(script) local function processVariables(script)
local fn = loadstring('return ' .. config.variables) local fn = loadstring('return ' .. config.variables)
if fn then if fn then
@@ -40,7 +46,7 @@ function processVariables(script)
return script return script
end end
function invokeScript(computer, scriptName) local function invokeScript(computer, scriptName)
local script = Util.readFile(scriptName) local script = Util.readFile(scriptName)
if not script then if not script then
@@ -74,7 +80,7 @@ function invokeScript(computer, scriptName)
socket:close() socket:close()
end end
function runScript(computerOrGroup, scriptName) local function runScript(computerOrGroup, scriptName)
if computerOrGroup.id then if computerOrGroup.id then
invokeScript(computerOrGroup, scriptName) invokeScript(computerOrGroup, scriptName)
else else
@@ -208,14 +214,14 @@ local editorPage = UI.Page({
y = 3, y = 3,
}), }),
right = UI.Button({ right = UI.Button({
text = '>', text = '>',
event = 'right', event = 'right',
x = width - 2, x = width - 2,
y = 2, y = 2,
width = 3, width = 3,
}), }),
left = UI.Button({ left = UI.Button({
text = '<', text = '<',
event = 'left', event = 'left',
x = UI.term.width - width + 1, x = UI.term.width - width + 1,
y = 2, y = 2,
@@ -302,7 +308,6 @@ function editorPage:enable()
end end
function editorPage.grid2:draw() function editorPage.grid2:draw()
getActiveComputers(self.values) getActiveComputers(self.values)
for k in pairs(editorPage.grid1.values) do for k in pairs(editorPage.grid1.values) do
@@ -314,7 +319,6 @@ function editorPage.grid2:draw()
end end
function editorPage:eventHandler(event) function editorPage:eventHandler(event)
if event.type == 'back' then if event.type == 'back' then
UI:setPage(groupsPage) UI:setPage(groupsPage)
@@ -341,18 +345,17 @@ function editorPage:eventHandler(event)
end end
local function nameDialog(f) local function nameDialog(f)
local dialog = UI.Dialog({ local dialog = UI.Dialog {
-- x = (UI.term.width - 28) / 2,
width = 22, width = 22,
height = 6, height = 6,
title = 'Enter Name', title = 'Enter Name',
form = UI.Form { form = UI.Form {
x = 2, ex = -2, y = 2, x = 2, ex = -2, y = 2,
textEntry = UI.TextEntry({ y = 2, width = 20, limit = 20 }) textEntry = UI.TextEntry { y = 2, width = 20, limit = 20 },
}, },
}) }
dialog.eventHandler = function(self, event) function dialog:eventHandler(event)
if event.type == 'form_complete' then if event.type == 'form_complete' then
local name = self.form.textEntry.value local name = self.form.textEntry.value
if name then if name then
@@ -459,11 +462,6 @@ function mainPage:eventHandler(event)
elseif event.type == 'toggle' then elseif event.type == 'toggle' then
config.showGroups = not config.showGroups config.showGroups = not config.showGroups
local text = 'Computers'
if config.showGroups then
text = 'Groups'
end
-- self.statusBar.toggleButton.text = text
self:draw() self:draw()
Config.update('script', config) Config.update('script', config)

View File

@@ -1,4 +1,4 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Config = require('config') local Config = require('config')
local Event = require('event') local Event = require('event')
@@ -8,6 +8,14 @@ local Terminal = require('terminal')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
local colors = _G.colors
local fs = _G.fs
local multishell = _ENV.multishell
local network = _G.network
local os = _G.os
local shell = _ENV.shell
local term = _G.term
multishell.setTitle(multishell.getCurrent(), 'Turtles') multishell.setTitle(multishell.getCurrent(), 'Turtles')
UI.Button.defaults.focusIndicator = ' ' UI.Button.defaults.focusIndicator = ' '
UI:configure('Turtles', ...) UI:configure('Turtles', ...)
@@ -27,15 +35,7 @@ local options = {
local SCRIPTS_PATH = 'usr/etc/scripts' local SCRIPTS_PATH = 'usr/etc/scripts'
local nullTerm = Terminal.getNullTerm(term.current()) local nullTerm = Terminal.getNullTerm(term.current())
local turtles = { }
local socket local socket
local policies = {
{ label = 'none' },
{ label = 'digOnly' },
{ label = 'attackOnly' },
{ label = 'digAttack' },
{ label = 'turtleSafe' },
}
local page = UI.Page { local page = UI.Page {
coords = UI.Window { coords = UI.Window {
@@ -125,7 +125,8 @@ local page = UI.Page {
fn = 'turtle.turnRight', fn = 'turtle.turnRight',
}, },
info = UI.TextArea { info = UI.TextArea {
x = 2, y = 9 x = 2, y = 9,
inactive = true,
} }
}, },
}, },
@@ -142,7 +143,7 @@ function page:enable(turtle)
end end
function page:runFunction(script, nowrap) function page:runFunction(script, nowrap)
for i = 1, 2 do for _ = 1, 2 do
if not socket then if not socket then
socket = Socket.connect(self.turtle.id, 161) socket = Socket.connect(self.turtle.id, 161)
end end
@@ -186,7 +187,7 @@ function page.coords:draw()
if not t.point.gps then if not t.point.gps then
ind = 'REL' ind = 'REL'
end end
self:print(string.format('%s : %d,%d,%d\n Fuel: %s\n', self:print(string.format('%s : %d,%d,%d\n Fuel: %s\n',
ind, t.point.x, t.point.y, t.point.z, Util.toBytes(t.fuel))) ind, t.point.x, t.point.y, t.point.z, Util.toBytes(t.fuel)))
end end
end end
@@ -210,12 +211,6 @@ function page.tabs.inventory:draw()
v.selected = true v.selected = true
end end
if v.id then if v.id then
-- local item = itemDB:get({ v.id, v.dmg })
-- if item then
-- v.id = item.displayName
-- else
-- v.id = v.id:gsub('.*:(.*)', '%1')
-- end
v.id = itemDB:getName(v) v.id = itemDB:getName(v)
end end
end end
@@ -303,14 +298,6 @@ function page.statusBar:draw()
UI.StatusBar.draw(self) UI.StatusBar.draw(self)
end end
function page.tabs.tabBar:selectTab(tabTitle)
if tabTitle then
config.tab = tabTitle
Config.update('Turtles', config)
return UI.TabBar.selectTab(self, tabTitle)
end
end
function page:showBlocks() function page:showBlocks()
local script = [[ local script = [[
@@ -333,6 +320,11 @@ end
function page:eventHandler(event) function page:eventHandler(event)
if event.type == 'quit' then if event.type == 'quit' then
UI:exitPullEvents() UI:exitPullEvents()
elseif event.type == 'tab_select' then
config.tab = event.button.text
Config.update('Turtles', config)
elseif event.type == 'button_press' then elseif event.type == 'button_press' then
if event.button.fn then if event.button.fn then
self:runFunction(event.button.fn, event.button.nowrap) self:runFunction(event.button.fn, event.button.nowrap)
@@ -356,7 +348,7 @@ if not Util.getOptions(options, { ... }, true) then
end end
if options.turtle.value >= 0 then if options.turtle.value >= 0 then
for i = 1, 10 do for _ = 1, 10 do
page.turtle = _G.network[options.turtle.value] page.turtle = _G.network[options.turtle.value]
if page.turtle then if page.turtle then
break break
@@ -374,18 +366,10 @@ Event.onInterval(1, function()
end end
end) end)
UI:setPage(page) if config.tab then
page.tabs.tabBar:selectTab(config.tab)
local lookup = {
Run = page.tabs.scripts,
Select = page.tabs.turtles,
Inv = page.tabs.inventory,
-- Mod = page.tabs.policy,
Action = page.tabs.action,
}
if lookup[options.tab.value] then
page.tabs:activateTab(lookup[options.tab.value])
end end
UI:setPage(page)
UI:pullEvents() UI:pullEvents()

View File

@@ -1,6 +1,10 @@
requireInjector(getfenv(1)) _G.requireInjector()
Base64 = require('base64') local Base64 = require('base64')
local http = _G.http
local os = _G.os
local shell = _ENV.shell
local args = { ... } local args = { ... }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1055
apps/crafter.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,13 @@
shell.setCompletionFunction(shell.getRunningProgram(), function(shell, index, text) local colors = _G.colors
local fs = _G.fs
local keys = _G.keys
local multishell = _ENV.multishell
local os = _G.os
local shell = _ENV.shell
local term = _G.term
local textutils = _G.textutils
shell.setCompletionFunction(shell.getRunningProgram(), function(_, index, text)
if index == 1 then if index == 1 then
return fs.complete(text, shell.dir(), true, false) return fs.complete(text, shell.dir(), true, false)
end end
@@ -17,7 +26,7 @@ if fs.exists(sPath) and fs.isDir(sPath) then
end end
if multishell then if multishell then
multishell.setTitle(multishell.getCurrent(), sPath) multishell.setTitle(multishell.getCurrent(), fs.getName(sPath))
end end
local x, y = 1, 1 local x, y = 1, 1
@@ -26,43 +35,38 @@ local scrollX = 0
local scrollY = 0 local scrollY = 0
local lastPos = { x = 1, y = 1 } local lastPos = { x = 1, y = 1 }
local tLines = { } local tLines = { }
local input = { pressed = { } }
local bRunning = true local bRunning = true
local sStatus = "" local sStatus = ""
local isError local isError
local fileInfo local fileInfo
local lastAction
local dirty = { y = 1, ey = h } local dirty = { y = 1, ey = h }
local mark = { anchor, active, continue } local mark = { }
local keyboard
local searchPattern local searchPattern
local undo = { chain = { }, pointer = 0 } local undo = { chain = { }, pointer = 0 }
local complete = { } local complete = { }
local clipboard
if not clipboard then -- do we need a clipboard shim
_G.clipboard = { internal, data } if not multishell or not multishell.hook then -- is this OpusOS ?
clipboard.shim = true if _G.clipboard then -- has it been installed already
clipboard = _G.clipboard
else
clipboard = { }
function clipboard.setData(data) function clipboard.setData(data)
clipboard.data = data clipboard.data = data
if data then
clipboard.useInternal(true)
end end
end
function clipboard.getText() function clipboard.getText()
if clipboard.data then if clipboard.data then
return tostring(clipboard.data) return tostring(clipboard.data)
end
end end
end
function clipboard.isInternal() _G.clipboard = clipboard
return clipboard.internal
end
function clipboard.useInternal(mode)
if mode ~= clipboard.mode then
clipboard.internal = mode
end
end end
end end
@@ -110,7 +114,7 @@ local keyMapping = {
[ 'control-up' ] = 'scroll_up', [ 'control-up' ] = 'scroll_up',
[ 'scrollDown' ] = 'scroll_down', [ 'scrollDown' ] = 'scroll_down',
[ 'control-down' ] = 'scroll_down', [ 'control-down' ] = 'scroll_down',
[ 'mouse_click' ] = 'goto', [ 'mouse_click' ] = 'go_to',
[ 'control-l' ] = 'goto_line', [ 'control-l' ] = 'goto_line',
-- marking -- marking
@@ -139,8 +143,7 @@ local keyMapping = {
-- copy/paste -- copy/paste
[ 'control-x' ] = 'cut', [ 'control-x' ] = 'cut',
[ 'control-c' ] = 'copy', [ 'control-c' ] = 'copy',
[ 'control-v' ] = 'paste', [ 'shift-paste' ] = 'paste_internal',
[ 'control-t' ] = 'toggle_clipboard',
-- file -- file
[ 'control-s' ] = 'save', [ 'control-s' ] = 'save',
@@ -155,7 +158,7 @@ local keyMapping = {
-- misc -- misc
[ 'control-g' ] = 'status', [ 'control-g' ] = 'status',
[ 'control-r' ] = 'refresh', [ 'control-r' ] = 'refresh',
[ 'leftCtrl' ] = 'menu', [ 'control' ] = 'menu',
} }
local messages = { local messages = {
@@ -171,7 +174,7 @@ end
local function getFileInfo(path) local function getFileInfo(path)
local abspath = shell.resolve(path) local abspath = shell.resolve(path)
local fi = { local fi = {
abspath = abspath, abspath = abspath,
path = path, path = path,
@@ -184,7 +187,7 @@ local function getFileInfo(path)
else else
fi.isReadOnly = fs.isReadOnly(fi.abspath) fi.isReadOnly = fs.isReadOnly(fi.abspath)
end end
return fi return fi
end end
@@ -246,16 +249,16 @@ local function save( _sPath )
local function innerSave() local function innerSave()
file = fs.open( _sPath, "w" ) file = fs.open( _sPath, "w" )
if file then if file then
for n, sLine in ipairs( tLines ) do for _,sLine in ipairs( tLines ) do
file.write(sLine .. "\n") file.write(sLine .. "\n")
end end
else else
error( "Failed to open ".._sPath ) error( "Failed to open ".._sPath )
end end
end end
local ok, err = pcall( innerSave ) local ok, err = pcall( innerSave )
if file then if file then
file.close() file.close()
end end
return ok, err return ok, err
@@ -265,7 +268,7 @@ local function split(str, pattern)
pattern = pattern or "(.-)\n" pattern = pattern or "(.-)\n"
local t = {} local t = {}
local function helper(line) table.insert(t, line) return "" end local function helper(line) table.insert(t, line) return "" end
helper((str:gsub(pattern, helper))) helper((str:gsub(pattern, helper)))
return t return t
end end
@@ -299,8 +302,8 @@ local function writeHighlighted(sLine, ny)
text = '', text = '',
} }
local function tryWrite(sLine, regex, fgcolor) local function tryWrite(line, regex, fgcolor)
local match = sLine:match(regex) local match = line:match(regex)
if match then if match then
local fg local fg
if type(fgcolor) == "string" then if type(fgcolor) == "string" then
@@ -310,13 +313,13 @@ local function writeHighlighted(sLine, ny)
end end
buffer.text = buffer.text .. match buffer.text = buffer.text .. match
buffer.fg = buffer.fg .. string.rep(fg, #match) buffer.fg = buffer.fg .. string.rep(fg, #match)
return sLine:sub(#match + 1) return line:sub(#match + 1)
end end
return nil return nil
end end
while #sLine > 0 do while #sLine > 0 do
sLine = sLine =
tryWrite(sLine, "^%-%-%[%[.-%]%]", color.commentColor ) or tryWrite(sLine, "^%-%-%[%[.-%]%]", color.commentColor ) or
tryWrite(sLine, "^%-%-.*", color.commentColor ) or tryWrite(sLine, "^%-%-.*", color.commentColor ) or
tryWrite(sLine, "^\".-[^\\]\"", color.stringColor ) or tryWrite(sLine, "^\".-[^\\]\"", color.stringColor ) or
@@ -343,8 +346,8 @@ local function writeHighlighted(sLine, ny)
if ny == mark.ey then if ny == mark.ey then
ex = mark.ex ex = mark.ex
end end
buffer.bg = string.rep('f', sx - 1) .. buffer.bg = string.rep('f', sx - 1) ..
string.rep('7', ex - sx) .. string.rep('7', ex - sx) ..
string.rep('f', #buffer.text - ex + 1) string.rep('f', #buffer.text - ex + 1)
else else
@@ -388,18 +391,13 @@ local function redraw()
end end
if not (w < 32 and #sStatus > 0) then if not (w < 32 and #sStatus > 0) then
local clipboardIndicator = 'S'
if clipboard.isInternal() then
clipboardIndicator = 'I'
end
local modifiedIndicator = ' ' local modifiedIndicator = ' '
if undo.chain[1] then if undo.chain[1] then
modifiedIndicator = '*' modifiedIndicator = '*'
end end
local str = string.format(' %d:%d %s%s', local str = string.format(' %d:%d %s',
y, x, clipboardIndicator, modifiedIndicator) y, x, modifiedIndicator)
term.setTextColor(color.highlightColor) term.setTextColor(color.highlightColor)
term.setBackgroundColor(colors.gray) term.setBackgroundColor(colors.gray)
term.setCursorPos(w - #str + 1, h) term.setCursorPos(w - #str + 1, h)
@@ -434,15 +432,15 @@ local function hacky_read()
local _oldSetCursorPos = term.setCursorPos local _oldSetCursorPos = term.setCursorPos
local _oldGetCursorPos = term.getCursorPos local _oldGetCursorPos = term.getCursorPos
term.setCursorPos = function(x, y) term.setCursorPos = function(cx)
return _oldSetCursorPos(x, h) return _oldSetCursorPos(cx, h)
end end
term.getCursorPos = function() term.getCursorPos = function()
local x, y = _oldGetCursorPos() local cx = _oldGetCursorPos()
return x, 1 return cx, 1
end end
local s, m = pcall(function() return read() end) local s, m = pcall(function() return _G.read() end)
term.setCursorPos = _oldSetCursorPos term.setCursorPos = _oldSetCursorPos
term.getCursorPos = _oldGetCursorPos term.getCursorPos = _oldGetCursorPos
if s then if s then
@@ -465,7 +463,7 @@ local __actions = {
term.write(prompt) term.write(prompt)
local str = hacky_read() local str = hacky_read()
term.setCursorBlink(true) term.setCursorBlink(true)
keyboard.shift, keyboard.control = false, false input:reset()
term.setCursorPos(x - scrollX, y - scrollY) term.setCursorPos(x - scrollX, y - scrollY)
actions.dirty_line(scrollY + h) actions.dirty_line(scrollY + h)
return str return str
@@ -485,13 +483,6 @@ local __actions = {
addUndo = function(entry) addUndo = function(entry)
local last = undo.chain[#undo.chain] local last = undo.chain[#undo.chain]
if last and last.action == entry.action then if last and last.action == entry.action then
--[[
debug('---')
debug(last)
debug(last.args)
debug(entry)
debug(entry.args)
]]--
if last.action == 'deleteText' then if last.action == 'deleteText' then
if last.args[3] == entry.args[1] and if last.args[3] == entry.args[1] and
last.args[4] == entry.args[2] then last.args[4] == entry.args[2] then
@@ -512,7 +503,7 @@ local __actions = {
end, end,
autocomplete = function() autocomplete = function()
if keyboard.lastAction ~= 'autocomplete' or not complete.results then if lastAction ~= 'autocomplete' or not complete.results then
local sLine = tLines[y]:sub(1, x - 1) local sLine = tLines[y]:sub(1, x - 1)
local nStartPos = sLine:find("[a-zA-Z0-9_%.]+$") local nStartPos = sLine:find("[a-zA-Z0-9_%.]+$")
if nStartPos then if nStartPos then
@@ -575,7 +566,7 @@ local __actions = {
goto_line = function() goto_line = function()
local lineNo = tonumber(actions.input('Line: ')) local lineNo = tonumber(actions.input('Line: '))
if lineNo then if lineNo then
actions.goto(1, lineNo) actions.go_to(1, lineNo)
else else
setStatus('Invalid line number') setStatus('Invalid line number')
end end
@@ -593,9 +584,9 @@ local __actions = {
if ny < y or ny == y and nx <= x then if ny < y or ny == y and nx <= x then
setStatus(messages.wrapped) setStatus(messages.wrapped)
end end
actions.goto(nx, ny) actions.go_to(nx, ny)
actions.mark_to(nx + #pattern, ny) actions.mark_to(nx + #pattern, ny)
actions.goto(nx, ny) actions.go_to(nx, ny)
return return
end end
sx = 1 sx = 1
@@ -625,7 +616,7 @@ local __actions = {
if bReadOnly then if bReadOnly then
setError("Access denied") setError("Access denied")
else else
local ok, err = save(sPath) local ok = save(sPath)
if ok then if ok then
setStatus('"%s" %dL, %dC written', setStatus('"%s" %dL, %dC written',
fileInfo.path, #tLines, fs.getSize(fileInfo.abspath)) fileInfo.path, #tLines, fs.getSize(fileInfo.abspath))
@@ -641,7 +632,7 @@ local __actions = {
run = function() run = function()
local sTempPath = "/.temp" local sTempPath = "/.temp"
local ok, err = save(sTempPath) local ok = save(sTempPath)
if ok then if ok then
local nTask = shell.openTab(sTempPath) local nTask = shell.openTab(sTempPath)
if nTask then if nTask then
@@ -732,7 +723,7 @@ local __actions = {
mark_to = function(nx, ny) mark_to = function(nx, ny)
actions.mark_begin() actions.mark_begin()
actions.goto(nx, ny) actions.go_to(nx, ny)
actions.mark_finish() actions.mark_finish()
end, end,
@@ -795,9 +786,7 @@ local __actions = {
actions.dirty_all() actions.dirty_all()
end, end,
setCursor = function(newX, newY) setCursor = function()
local oldX, oldY = lastPos.x, lastPos.y
lastPos.x = x lastPos.x = x
lastPos.y = y lastPos.y = y
@@ -806,27 +795,23 @@ local __actions = {
if screenX < 1 then if screenX < 1 then
scrollX = x - 1 scrollX = x - 1
screenX = 1
actions.dirty_all() actions.dirty_all()
elseif screenX > w then elseif screenX > w then
scrollX = x - w scrollX = x - w
screenX = w
actions.dirty_all() actions.dirty_all()
end end
if screenY < 1 then if screenY < 1 then
scrollY = y - 1 scrollY = y - 1
screenY = 1
actions.dirty_all() actions.dirty_all()
elseif screenY > h - 1 then elseif screenY > h - 1 then
scrollY = y - (h - 1) scrollY = y - (h - 1)
screenY = h - 1
actions.dirty_all() actions.dirty_all()
end end
end, end,
top = function() top = function()
actions.goto(1, 1) actions.go_to(1, 1)
end, end,
bottom = function() bottom = function()
@@ -856,11 +841,11 @@ local __actions = {
end, end,
pageUp = function() pageUp = function()
actions.goto(x, y - (h - 1)) actions.go_to(x, y - (h - 1))
end, end,
pageDown = function() pageDown = function()
actions.goto(x, y + (h - 1)) actions.go_to(x, y + (h - 1))
end, end,
home = function() home = function()
@@ -966,7 +951,7 @@ local __actions = {
local front = tLines[sy]:sub(1, sx - 1) local front = tLines[sy]:sub(1, sx - 1)
local back = tLines[ey]:sub(ex, #tLines[ey]) local back = tLines[ey]:sub(ex, #tLines[ey])
for k = 2, ey - sy + 1 do for _ = 2, ey - sy + 1 do
table.remove(tLines, y + 1) table.remove(tLines, y + 1)
end end
tLines[y] = front .. back tLines[y] = front .. back
@@ -981,18 +966,18 @@ local __actions = {
local count = 0 local count = 0
local lines = { } local lines = { }
for y = csy, cey do for cy = csy, cey do
local line = tLines[y] local line = tLines[cy]
if line then if line then
local x = 1 local cx = 1
local ex = #line local ex = #line
if y == csy then if cy == csy then
x = csx cx = csx
end end
if y == cey then if cy == cey then
ex = cex - 1 ex = cex - 1
end end
local str = line:sub(x, ex) local str = line:sub(cx, ex)
count = count + #str count = count + #str
table.insert(lines, str) table.insert(lines, str)
end end
@@ -1041,23 +1026,14 @@ local __actions = {
actions.insertText(x, y, ch) actions.insertText(x, y, ch)
end, end,
toggle_clipboard = function()
if clipboard.shim then
clipboard.setInternal(not clipboard.internal)
end
if clipboard.isInternal() then
setStatus('Using internal clipboard')
else
setStatus('Using system clipboard')
end
end,
copy_marked = function() copy_marked = function()
local text, size = local text = actions.copyText(mark.x, mark.y, mark.ex, mark.ey)
actions.copyText(mark.x, mark.y, mark.ex, mark.ey) if clipboard then
clipboard.setData(text) clipboard.setData(text)
setStatus('%d chars copied', size) else
clipboard.useInternal(true) os.queueEvent('clipboard_copy', text)
end
setStatus('shift-^v to paste')
end, end,
cut = function() cut = function()
@@ -1078,9 +1054,6 @@ local __actions = {
if mark.active then if mark.active then
actions.delete() actions.delete()
end end
if clipboard.isInternal() then
text = clipboard.getText()
end
if text then if text then
actions.insertText(x, y, text) actions.insertText(x, y, text)
setStatus('%d chars added', #text) setStatus('%d chars added', #text)
@@ -1089,7 +1062,13 @@ local __actions = {
end end
end, end,
goto = function(cx, cy) paste_internal = function()
if clipboard then
actions.paste(clipboard.getText())
end
end,
go_to = function(cx, cy)
y = math.min(math.max(cy, 1), #tLines) y = math.min(math.max(cy, 1), #tLines)
x = math.min(math.max(cx, 1), #tLines[y] + 1) x = math.min(math.max(cx, 1), #tLines[y] + 1)
end, end,
@@ -1114,116 +1093,158 @@ local __actions = {
actions = __actions actions = __actions
-- Actual program functionality begins local modifiers = {
load(sPath) [ keys.leftCtrl ] = true,
[ keys.rightCtrl ] = true,
[ keys.leftShift ] = true,
[ keys.rightShift ] = true,
[ keys.leftAlt ] = true,
[ keys.rightAlt ] = true,
}
term.setCursorBlink(true) function input:modifierPressed()
redraw() return self.pressed[keys.leftCtrl] or
self.pressed[keys.rightCtrl] or
self.pressed[keys.leftAlt] or
self.pressed[keys.rightAlt]
end
if not keyboard then function input:toCode(ch, code)
keyboard = { control, shift, combo } local result = { }
function keyboard:translate(event, code) if self.pressed[keys.leftCtrl] or self.pressed[keys.rightCtrl] then
if event == 'key' then table.insert(result, 'control')
local ch = keys.getName(code) end
if ch then
if code == keys.leftCtrl or code == keys.rightCtrl then if self.pressed[keys.leftAlt] or self.pressed[keys.rightAlt] then
self.control = true table.insert(result, 'alt')
self.combo = false end
return
end
if code == keys.leftShift or code == keys.rightShift then if self.pressed[keys.leftShift] or self.pressed[keys.rightShift] then
self.shift = true if code and modifiers[code] then
self.combo = false table.insert(result, 'shift')
return elseif #ch == 1 then
end table.insert(result, ch:upper())
else
if self.shift then table.insert(result, 'shift')
if #ch > 1 then table.insert(result, ch)
ch = 'shift-' .. ch
elseif self.control then
-- will create control-X
-- better than shift-control-x
ch = ch:upper()
end
self.combo = true
end
if self.control then
ch = 'control-' .. ch
self.combo = true
-- even return numbers such as
-- control-seven
return ch
end
-- filter out characters that will be processed in
-- the subsequent char event
if ch and #ch > 1 and (code < 2 or code > 11) then
return ch
end
end
elseif event == 'key_up' then
if code == keys.leftCtrl or code == keys.rightCtrl then
self.control = false
elseif code == keys.leftShift or code == keys.rightShift then
self.shift = false
else
return
end
-- only send through the shift / control event if it wasn't
-- used in combination with another event
if not self.combo then
return keys.getName(code)
end
elseif event == 'char' then
if not self.control then
self.combo = true
return event
end
elseif event == 'mouse_click' then
local buttons = { 'mouse_click', 'mouse_rightclick', 'mouse_doubleclick' }
self.combo = true
if self.shift then
return 'shift-' .. buttons[code]
end
return buttons[code]
elseif event == "mouse_scroll" then
local directions = {
[ -1 ] = 'scrollUp',
[ 1 ] = 'scrollDown'
}
return directions[code]
elseif event == 'paste' then
self.combo = true
return event
elseif event == 'mouse_drag' then
return event
end end
elseif not code or not modifiers[code] then
table.insert(result, ch)
end
return table.concat(result, '-')
end
function input:reset()
self.pressed = { }
self.fired = nil
self.timer = nil
self.mch = nil
self.mfired = nil
end
function input:translate(event, code, p1, p2)
if event == 'key' then
if p1 then -- key is held down
if not modifiers[code] then
self.fired = true
return input:toCode(keys.getName(code), code)
end
else
self.pressed[code] = true
if self:modifierPressed() and not modifiers[code] or code == 57 then
self.fired = true
return input:toCode(keys.getName(code), code)
else
self.fired = false
end
end
elseif event == 'char' then
if not self:modifierPressed() then
self.fired = true
return input:toCode(code)
end
elseif event == 'key_up' then
if not self.fired then
if self.pressed[code] then
self.fired = true
local ch = input:toCode(keys.getName(code), code)
self.pressed[code] = nil
return ch
end
end
self.pressed[code] = nil
elseif event == 'paste' then
self.pressed[keys.leftCtrl] = nil
self.pressed[keys.rightCtrl] = nil
self.fired = true
if clipboard then
return 'paste'
end
return input:toCode('paste', 255)
elseif event == 'mouse_click' then
local buttons = { 'mouse_click', 'mouse_rightclick' }
self.mch = buttons[code]
self.mfired = nil
elseif event == 'mouse_drag' then
self.mfired = true
self.fired = true
return input:toCode('mouse_drag', 255)
elseif event == 'mouse_up' then
if not self.mfired then
local clock = os.clock()
if self.timer and
p1 == self.x and p2 == self.y and
(clock - self.timer < .5) then
self.mch = 'mouse_doubleclick'
self.timer = nil
else
self.timer = os.clock()
self.x = p1
self.y = p2
end
self.mfired = input:toCode(self.mch, 255)
else
self.mch = 'mouse_up'
self.mfired = input:toCode(self.mch, 255)
end
self.fired = true
return self.mfired
elseif event == "mouse_scroll" then
local directions = {
[ -1 ] = 'scrollUp',
[ 1 ] = 'scrollDown'
}
self.fired = true
return input:toCode(directions[code], 255)
end end
end end
load(sPath)
term.setCursorBlink(true)
redraw()
while bRunning do while bRunning do
local sEvent, param, param2, param3 = os.pullEventRaw() local sEvent, param, param2, param3 = os.pullEventRaw()
local action local action
if sEvent == 'terminate' then if sEvent == 'terminate' then
action = 'exit' action = 'exit'
elseif sEvent == "mouse_click" or sEvent == 'mouse_drag' then elseif sEvent == 'multishell_focus' then -- opus only event
input:reset()
elseif sEvent == "mouse_click" or sEvent == 'mouse_drag' or sEvent == 'mouse_up' then
local ch = input:translate(sEvent, param, param2, param3)
if param3 < h or sEvent == 'mouse_drag' then if param3 < h or sEvent == 'mouse_drag' then
local ch = keyboard:translate(sEvent, param)
if ch then if ch then
action = keyMapping[ch] action = keyMapping[ch]
param = param2 + scrollX param = param2 + scrollX
@@ -1231,9 +1252,14 @@ while bRunning do
end end
end end
else else
local ch = keyboard:translate(sEvent, param) local ch = input:translate(sEvent, param, param2)
if ch then if ch then
action = keyMapping[ch] if #ch == 1 then
action = keyMapping.char
param = ch
else
action = keyMapping[ch]
end
end end
end end
@@ -1247,7 +1273,7 @@ while bRunning do
actions[action](param, param2) actions[action](param, param2)
if action ~= 'menu' then if action ~= 'menu' then
keyboard.lastAction = action lastAction = action
end end
if x ~= lastPos.x or y ~= lastPos.y then if x ~= lastPos.x or y ~= lastPos.y then

376
apps/levelEmitter.lua Normal file
View File

@@ -0,0 +1,376 @@
_G.requireInjector()
local InventoryAdapter = require('inventoryAdapter')
local Config = require('config')
local Event = require('event')
local itemDB = require('itemDB')
local UI = require('ui')
local Util = require('util')
local colors = _G.colors
local multishell = _ENV.multishell
local rs = _G.rs
local RESOURCE_FILE = 'usr/config/levelEmitter.db'
multishell.setTitle(multishell.getCurrent(), 'Level Emitter')
local config = {
inventorySide = 'bottom',
}
Config.loadWithCheck('levelEmitter', config)
local inventoryAdapter = InventoryAdapter.wrap({ wrapSide = config.inventorySide })
if not inventoryAdapter then
error('No inventory found')
end
local resources
local function getItem(items, inItem, ignoreDamage, ignoreNbtHash)
for _,item in pairs(items) do
if item.name == inItem.name and
(ignoreDamage or item.damage == inItem.damage) and
(ignoreNbtHash or item.nbtHash == inItem.nbtHash) then
return item
end
end
end
local function uniqueKey(item)
return table.concat({ item.name, item.damage, item.nbtHash }, ':')
end
local function mergeResources(t)
for _,v in pairs(resources) do
local item = getItem(t, v)
if item then
Util.merge(item, v)
else
item = Util.shallowCopy(v)
item.count = 0
table.insert(t, item)
end
end
for _,v in pairs(t) do
if not v.displayName then
v.displayName = itemDB:getName(v)
end
v.lname = v.displayName:lower()
end
end
local function getItemWithQty(items, res, ignoreDamage, ignoreNbtHash)
local item = getItem(items, res, ignoreDamage, ignoreNbtHash)
if item and (ignoreDamage or ignoreNbtHash) then
local count = 0
for _,v in pairs(items) do
if item.name == v.name and
(ignoreDamage or item.damage == v.damage) and
(ignoreNbtHash or item.nbtHash == v.nbtHash) then
count = count + v.count
end
end
item.count = count
end
return item
end
local function loadResources()
resources = Util.readTable(RESOURCE_FILE) or { }
for k,v in pairs(resources) do
Util.merge(v, itemDB:splitKey(k))
end
end
local function saveResources()
local t = { }
for k,v in pairs(resources) do
v = Util.shallowCopy(v)
local keys = Util.transpose({ 'limit', 'low', 'ignoreDamage', 'ignoreNbtHash' })
for _,key in pairs(Util.keys(v)) do
if not keys[key] then
v[key] = nil
end
end
if not Util.empty(v) then
t[k] = v
end
end
Util.writeTable(RESOURCE_FILE, t)
end
local itemPage = UI.Page {
titleBar = UI.TitleBar {
title = 'Limit Resource',
previousPage = true,
event = 'form_cancel',
},
form = UI.Form {
x = 1, y = 2, height = 10, ex = -1,
[1] = UI.TextEntry {
width = 7,
formLabel = 'Min', formKey = 'low', help = 'Output a signal if below'
},
[2] = UI.TextEntry {
width = 7,
formLabel = 'Max', formKey = 'limit', help = 'Output a signal if above'
},
[4] = UI.Chooser {
width = 7,
formLabel = 'Ignore Dmg', formKey = 'ignoreDamage',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore damage of item'
},
[5] = UI.Chooser {
width = 7,
formLabel = 'Ignore NBT', formKey = 'ignoreNbtHash',
nochoice = 'No',
choices = {
{ name = 'Yes', value = true },
{ name = 'No', value = false },
},
help = 'Ignore NBT of item'
},
},
statusBar = UI.StatusBar { }
}
function itemPage:enable(item)
self.item = Util.shallowCopy(item)
self.form:setValues(item)
self.titleBar.title = item.displayName or item.name
UI.Page.enable(self)
self:focusFirst()
end
function itemPage:eventHandler(event)
if event.type == 'form_cancel' then
UI:setPreviousPage()
elseif event.type == 'focus_change' then
self.statusBar:setStatus(event.focused.help)
self.statusBar:draw()
elseif event.type == 'form_complete' then
local filtered = Util.shallowCopy(self.form.values)
if filtered.ignoreDamage == true then
filtered.damage = 0
else
filtered.ignoreDamage = nil
end
if filtered.ignoreNbtHash == true then
filtered.nbtHash = nil
else
filtered.ignoreNbtHash = nil
end
local originalKey = uniqueKey(self.item)
resources[originalKey] = nil
filtered.low = tonumber(filtered.low)
filtered.limit = tonumber(filtered.limit)
if filtered.limit or filtered.low then
resources[uniqueKey(filtered)] = filtered
else
resources[uniqueKey(filtered)] = nil
end
saveResources()
UI:setPreviousPage()
else
return UI.Page.eventHandler(self, event)
end
return true
end
local listingPage = UI.Page {
menuBar = UI.MenuBar {
buttons = {
{ text = 'Forget', event = 'forget' },
{ text = 'Refresh', event = 'refresh', x = -9 },
},
},
grid = UI.Grid {
y = 2, height = UI.term.height - 2,
columns = {
{ heading = 'Name', key = 'displayName' , width = 22 },
{ heading = 'Qty', key = 'count' , width = 5 },
{ heading = 'Min', key = 'limit' , width = 4 },
{ heading = 'Max', key = 'low' , width = 4 },
},
sortColumn = 'displayName',
},
statusBar = UI.StatusBar {
filterText = UI.Text {
x = 2,
value = 'Filter',
},
filter = UI.TextEntry {
x = 9, ex = -5,
limit = 50,
backgroundColor = colors.gray,
backgroundFocusColor = colors.gray,
},
display = UI.Button {
x = -3,
event = 'toggle_display',
value = 0,
text = 'A',
},
},
accelerators = {
r = 'refresh',
q = 'quit',
},
displayMode = 0,
}
function listingPage.grid:getDisplayValues(row)
row = Util.shallowCopy(row)
row.count = Util.toBytes(row.count)
if row.low then
row.low = Util.toBytes(row.low)
end
if row.limit then
row.limit = Util.toBytes(row.limit)
end
return row
end
function listingPage:eventHandler(event)
if event.type == 'quit' then
UI:exitPullEvents()
elseif event.type == 'grid_select' then
local selected = event.selected
UI:setPage('item', selected)
elseif event.type == 'refresh' then
self:refresh()
self.grid:draw()
self.statusBar.filter:focus()
elseif event.type == 'toggle_display' then
local values = {
[0] = 'A',
[1] = 'I',
[2] = 'C',
}
event.button.value = (event.button.value + 1) % 3
self.displayMode = event.button.value
event.button.text = values[event.button.value]
event.button:draw()
self:applyFilter()
self.grid:draw()
elseif event.type == 'forget' then
local item = self.grid:getSelected()
if item then
local key = uniqueKey(item)
if resources[key] then
resources[key] = nil
saveResources()
end
self.statusBar:timedStatus('Forgot: ' .. item.name, 3)
self:refresh()
self.grid:draw()
end
elseif event.type == 'text_change' then
self.filter = event.text
if #self.filter == 0 then
self.filter = nil
end
self:applyFilter()
self.grid:draw()
self.statusBar.filter:focus()
else
UI.Page.eventHandler(self, event)
end
return true
end
function listingPage:enable()
self:refresh()
self:setFocus(self.statusBar.filter)
UI.Page.enable(self)
end
function listingPage:refresh()
self.allItems = inventoryAdapter:listItems()
mergeResources(self.allItems)
self:applyFilter()
end
function listingPage:applyFilter()
local filter = self.filter
local displayMode = self.displayMode
local t = self.allItems
if filter or displayMode > 0 then
t = { }
if filter then
filter = filter:lower()
end
for _,v in pairs(self.allItems) do
if not filter or string.find(v.lname, filter, 1, true) then
if not displayMode or
displayMode == 0 or
displayMode == 1 and v.count > 0 or
displayMode == 2 and v.has_recipe then
table.insert(t, v)
end
end
end
end
self.grid:setValues(t)
end
loadResources()
UI:setPages({
listing = listingPage,
item = itemPage,
})
UI:setPage(listingPage)
listingPage:setFocus(listingPage.statusBar.filter)
Event.onInterval(5, function()
local items = inventoryAdapter:listItems()
if items and Util.size(items) > 0 then
for _,res in pairs(resources) do
local item = getItemWithQty(items, res, res.ignoreDamage, res.ignoreNbtHash)
rs.setOutput('bottom', (res.limit and
item and item.count > res.limit) or
(res.low and
(not item or item.count < res.low)) or false)
end
end
end)
UI:pullEvents()

View File

@@ -36,6 +36,31 @@ elseif device.monitor then
}) })
end end
--[[-- ScrollingText --]]--
UI.ScrollingText = class(UI.Window)
UI.ScrollingText.defaults = {
UIElement = 'ScrollingText',
backgroundColor = colors.black,
buffer = { },
}
function UI.ScrollingText:appendLine(text)
if #self.buffer+1 >= self.height then
table.remove(self.buffer, 1)
end
table.insert(self.buffer, text)
end
function UI.ScrollingText:clear()
self.buffer = { }
UI.Window.clear(self)
end
function UI.ScrollingText:draw()
for k,text in ipairs(self.buffer) do
self:write(1, k, Util.widthify(text, self.width), self.backgroundColor)
end
end
terminal:clear() terminal:clear()
function getClient(id) function getClient(id)

View File

@@ -1,9 +1,12 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Terminal = require('terminal') local Terminal = require('terminal')
local shell = _ENV.shell
local term = _G.term
local args = { ... } local args = { ... }
local mon = device[table.remove(args, 1) or 'monitor'] local mon = _G.device[table.remove(args, 1) or 'monitor']
if not mon then if not mon then
error('mirror: Invalid device') error('mirror: Invalid device')
end end

View File

@@ -1,11 +1,13 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local Logger = require('logger') local Logger = require('logger')
local Socket = require('socket') local Socket = require('socket')
local Terminal = require('terminal')
local Util = require('util') local Util = require('util')
local multishell = _ENV.multishell
local os = _G.os
Logger.setScreenLogging() Logger.setScreenLogging()
local remoteId local remoteId
@@ -14,7 +16,7 @@ if #args == 1 then
remoteId = tonumber(args[1]) remoteId = tonumber(args[1])
else else
print('Enter host ID') print('Enter host ID')
remoteId = tonumber(read()) remoteId = tonumber(_G.read())
end end
if not remoteId then if not remoteId then
@@ -70,7 +72,7 @@ while true do
while true do while true do
local e = Event.pullEvent() local e = Event.pullEvent()
if e[1] == 'terminate' then if e[1] == 'terminate' then
break break
end end
if not socket.connected then if not socket.connected then
break break

View File

@@ -1,15 +1,18 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local Logger = require('logger') local Logger = require('logger')
local Socket = require('socket') local Socket = require('socket')
local colors = _G.colors
local term = _G.term
Logger.setScreenLogging() Logger.setScreenLogging()
local mon = term.current() local mon = term.current()
local args = { ... } local args = { ... }
if args[1] then if args[1] then
mon = device[args[1]] mon = _G.device[args[1]]
end end
if not mon then if not mon then
@@ -36,13 +39,6 @@ while true do
end end
end) end)
-- ensure socket is connected
Event.onInterval(3, function(h)
if not socket:ping() then
Event.off(h)
end
end)
while true do while true do
Event.pullEvent() Event.pullEvent()
if not socket.connected then if not socket.connected then

View File

@@ -1,23 +1,27 @@
require = requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local UI = require('ui') local UI = require('ui')
local colors = _G.colors
local device = _G.device
local turtle = _G.turtle
local multishell = _ENV.multishell
multishell.setTitle(multishell.getCurrent(), 'Music') multishell.setTitle(multishell.getCurrent(), 'Music')
if not turtle then
error('This program can only be run on a turtle')
end
local radio = device.drive or error('No drive attached') local radio = device.drive or error('No drive attached')
if radio.side ~= 'top' and radio.side ~= 'bottom' then if radio.side ~= 'top' and radio.side ~= 'bottom' then
error('Disk drive must be above or below turtle') error('Disk drive must be above or below turtle')
end end
if not turtle then
error('This program can only be run on a turtle')
end
UI:configure('Music', ...) UI:configure('Music', ...)
local monitor = UI.term
UI.Button.defaults.backgroundFocusColor = colors.gray UI.Button.defaults.backgroundFocusColor = colors.gray
local page = UI.Page({ local page = UI.Page({
@@ -146,12 +150,12 @@ function page:eventHandler(event)
end end
end end
function page:setVolume(volume, displayOnly) function page:setVolume(volume)
volume = math.min(volume, 15) volume = math.min(volume, 15)
volume = math.max(volume, 1) volume = math.max(volume, 1)
self.volume = volume self.volume = volume
volume = math.ceil(volume / 2) volume = math.ceil(volume / 2)
for i = 1, volume do for i = 1, volume do
self.volumeControls[i].backgroundColor = self.volumeControls[i].backgroundColor =
self.volumeControls[i].color self.volumeControls[i].color
@@ -224,7 +228,7 @@ end
function page:updateStationName() function page:updateStationName()
local title = radio.getAudioTitle() local title = radio.getAudioTitle()
if title then if title then
self.stationName.value = title self.stationName.value = title
self.stationName:draw() self.stationName:draw()
@@ -248,9 +252,9 @@ page:setVolume(page.volume, true)
UI:setPage(page) UI:setPage(page)
turtle.status = 'Jamming' turtle.setStatus('Jamming')
UI:pullEvents() UI:pullEvents()
turtle.status = 'idle' turtle.setStatus('idle')
page:play(false) page:play(false)
UI.term:reset() UI.term:reset()

View File

@@ -1,9 +1,17 @@
local injector = requireInjector or load(http.get('https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis/injector.lua').readAll())() local injector = _G.requireInjector or load(http.get('https://raw.githubusercontent.com/kepler155c/opus/develop/sys/apis/injector.lua').readAll())()
injector(getfenv(1)) injector()
local Canvas = require('ui.canvas') local Canvas = require('ui.canvas')
local Util = require('util') local Util = require('util')
local colors = _G.colors
local os = _G.os
local peripheral = _G.peripheral
local printError = _G.printError
local shell = _ENV.shell
local term = _G.term
local window = _G.window
local function syntax() local function syntax()
printError('Syntax:') printError('Syntax:')
error('mwm sessionName [monitor]') error('mwm sessionName [monitor]')
@@ -14,11 +22,11 @@ local UID = 0
local multishell = { } local multishell = { }
local processes = { } local processes = { }
local parentTerm = term.current() local parentTerm = term.current()
local sessionFile = args[1] or syntax() local sessionFile = args[1] or 'usr/config/mwm'
local running local running
local monitor local monitor
local defaultEnv = Util.shallowCopy(getfenv(1)) local defaultEnv = Util.shallowCopy(_ENV)
defaultEnv.multishell = multishell defaultEnv.multishell = multishell
if args[2] then if args[2] then
@@ -55,7 +63,7 @@ end
local function getProcessAt(x, y) local function getProcessAt(x, y)
for k = #processes, 1, -1 do for k = #processes, 1, -1 do
local process = processes[k] local process = processes[k]
if x >= process.x and if x >= process.x and
y >= process.y and y >= process.y and
x <= process.x + process.width - 1 and x <= process.x + process.width - 1 and
y <= process.y + process.height - 1 then y <= process.y + process.height - 1 then
@@ -356,7 +364,7 @@ function multishell.removeProcess(process)
redraw() redraw()
end end
function multishell.saveSession(sessionFile) function multishell.saveSession(filename)
local t = { } local t = { }
for _,process in pairs(processes) do for _,process in pairs(processes) do
if process.path and not process.isShell then if process.path and not process.isShell then
@@ -370,11 +378,11 @@ function multishell.saveSession(sessionFile)
}) })
end end
end end
Util.writeTable(sessionFile, t) Util.writeTable(filename, t)
end end
function multishell.loadSession(sessionFile) function multishell.loadSession(filename)
local config = Util.readTable(sessionFile) local config = Util.readTable(filename)
if config then if config then
for _,v in pairs(config) do for _,v in pairs(config) do
multishell.openTab(v) multishell.openTab(v)

View File

@@ -1,12 +1,17 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local GPS = require('gps')
local ChestAdapter = require('chestAdapter18') local ChestAdapter = require('chestAdapter18')
local Point = require('point') local Point = require('point')
local Socket = require('socket') local Socket = require('socket')
local Util = require('util') local Util = require('util')
local device = _G.device
local os = _G.os
local peripheral = _G.peripheral
local printError = _G.printError
local turtle = _G.turtle
if not device.wireless_modem then if not device.wireless_modem then
error('Modem is required') error('Modem is required')
end end
@@ -35,7 +40,7 @@ local fuel = {
local slots local slots
turtle.setMoveCallback(function(action, pt) turtle.setMoveCallback(function()
if slots then if slots then
for _,slot in pairs(slots) do for _,slot in pairs(slots) do
if turtle.getItemCount(slot.index) ~= slot.qty then if turtle.getItemCount(slot.index) ~= slot.qty then
@@ -46,10 +51,38 @@ turtle.setMoveCallback(function(action, pt)
end end
end) end)
function refuel() local function gotoPoint(pt, doDetect)
slots = turtle.getInventory()
while not turtle.pathfind(pt, { blocks = blocks }) do
if turtle.isAborted() then
error('aborted')
end
turtle.setStatus('blocked')
os.sleep(5)
end
if doDetect and not turtle.detectDown() then
printError('Missing target')
Event.exitPullEvents()
end
end
local function dropOff(pt)
if turtle.selectSlotWithItems() then
gotoPoint(pt, true)
turtle.emptyInventory(turtle.dropDown)
if pt == locations.dropPt then
print('refreshing items')
local chestAdapter = ChestAdapter()
items = chestAdapter:refresh()
end
end
end
local function refuel()
if turtle.getFuelLevel() < 5000 and locations.dropPt then if turtle.getFuelLevel() < 5000 and locations.dropPt then
print('refueling') print('refueling')
turtle.status = 'refueling' turtle.setStatus('refueling')
gotoPoint(locations.dropPt, true) gotoPoint(locations.dropPt, true)
dropOff(locations.dropPt) dropOff(locations.dropPt)
local chestAdapter = ChestAdapter({ local chestAdapter = ChestAdapter({
@@ -66,8 +99,8 @@ function refuel()
end end
end end
function pickUp(pt) local function pickUp(pt)
turtle.status = 'picking up' turtle.setStatus('picking up')
gotoPoint(pt, true) gotoPoint(pt, true)
while true do while true do
if not turtle.selectOpenSlot() then if not turtle.selectOpenSlot() then
@@ -81,41 +114,13 @@ function pickUp(pt)
end end
end end
function dropOff(pt) local function checkCell(pt)
if turtle.selectSlotWithItems() then
gotoPoint(pt, true)
turtle.emptyInventory(turtle.dropDown)
if pt == locations.dropPt then
print('refreshing items')
chestAdapter = ChestAdapter()
items = chestAdapter:refresh()
end
end
end
function gotoPoint(pt, doDetect)
slots = turtle.getInventory()
while not turtle.pathfind(pt, { blocks = blocks }) do
if turtle.abort then
error('aborted')
end
turtle.status = 'blocked'
os.sleep(5)
end
if doDetect and not turtle.detectDown() then
printError('Missing target')
Event.exitPullEvents()
end
end
function checkCell(pt)
if not turtle.selectOpenSlot() then if not turtle.selectOpenSlot() then
dropOff(locations.dropPt) dropOff(locations.dropPt)
end end
print('checking cell') print('checking cell')
turtle.status = 'recharging' turtle.setStatus('recharging')
gotoPoint(pt, true) gotoPoint(pt, true)
local c = peripheral.wrap('bottom') local c = peripheral.wrap('bottom')
local energy = c.getMaxEnergyStored() - local energy = c.getMaxEnergyStored() -
@@ -136,9 +141,9 @@ function checkCell(pt)
end end
end end
function fluid(points) local function fluid(points)
print('checking fluid') print('checking fluid')
turtle.status = 'fluiding' turtle.setStatus('fluiding')
gotoPoint(points.source, true) gotoPoint(points.source, true)
turtle.select(1) turtle.select(1)
turtle.digDown() turtle.digDown()
@@ -152,10 +157,10 @@ function fluid(points)
turtle.placeDown() turtle.placeDown()
end end
function refill(entry) local function refill(entry)
dropOff(locations.dropPt) dropOff(locations.dropPt)
turtle.status = 'refilling' turtle.setStatus('refilling')
gotoPoint(locations.dropPt) gotoPoint(locations.dropPt)
local chestAdapter = ChestAdapter() local chestAdapter = ChestAdapter()
for _,item in pairs(entry.items) do for _,item in pairs(entry.items) do
@@ -169,21 +174,6 @@ function refill(entry)
end end
end end
function oldRefill(points)
gotoPoint(points.source)
repeat until not turtle.suckDown(64)
if points.target then
dropOff(points.target)
end
if points.targets then
for k,target in pairs(points.targets) do
dropOff(target)
end
end
dropOff(points.source)
dropOff(locations.dropPt)
end
local function makeKey(pt) local function makeKey(pt)
return string.format('%d:%d:%d', pt.x, pt.y, pt.z) return string.format('%d:%d:%d', pt.x, pt.y, pt.z)
end end
@@ -198,7 +188,7 @@ local function pickupHost(socket)
end end
print('command: ' .. data.type) print('command: ' .. data.type)
if data.type == 'pickup' then if data.type == 'pickup' then
local key = makeKey(data.point) local key = makeKey(data.point)
locations.pickups[key] = data.point locations.pickups[key] = data.point
@@ -207,7 +197,7 @@ local function pickupHost(socket)
elseif data.type == 'items' then elseif data.type == 'items' then
socket:write( { type = "response", response = items }) socket:write( { type = "response", response = items })
elseif data.type == 'refill' then elseif data.type == 'refill' then
local key = makeKey(data.entry.point) local key = makeKey(data.entry.point)
locations.refills[key] = data.entry locations.refills[key] = data.entry
@@ -223,14 +213,12 @@ local function pickupHost(socket)
locations.chargePt = data.point locations.chargePt = data.point
Util.writeTable('/usr/config/pickup', locations) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'Location set' }) socket:write( { type = "response", response = 'Location set' })
elseif data.type == 'charge' then elseif data.type == 'charge' then
local key = makeKey(data.point) local key = makeKey(data.point)
locations.cells[key] = data.point locations.cells[key] = data.point
Util.writeTable('/usr/config/pickup', locations) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'added' }) socket:write( { type = "response", response = 'added' })
elseif data.type == 'fluid' then
elseif data.type == 'clear' then elseif data.type == 'clear' then
local key = makeKey(data.point) local key = makeKey(data.point)
@@ -240,7 +228,7 @@ local function pickupHost(socket)
locations.pickups[key] = nil locations.pickups[key] = nil
Util.writeTable('/usr/config/pickup', locations) Util.writeTable('/usr/config/pickup', locations)
socket:write( { type = "response", response = 'cleared' }) socket:write( { type = "response", response = 'cleared' })
else else
print('unknown command') print('unknown command')
@@ -264,7 +252,7 @@ local function eachEntry(t, fn)
local keys = Util.keys(t) local keys = Util.keys(t)
for _,key in pairs(keys) do for _,key in pairs(keys) do
if t[key] then if t[key] then
if turtle.abort then if turtle.isAborted() then
return return
end end
fn(t[key]) fn(t[key])
@@ -283,7 +271,7 @@ local function eachClosestEntry(t, fn)
while not Util.empty(points) do while not Util.empty(points) do
local closest = Point.closest(turtle.point, points) local closest = Point.closest(turtle.point, points)
if turtle.abort then if turtle.isAborted() then
return return
end end
if t[closest.key] then if t[closest.key] then
@@ -299,7 +287,6 @@ local function eachClosestEntry(t, fn)
end end
Event.addRoutine(function() Event.addRoutine(function()
if not turtle.enableGPS() then if not turtle.enableGPS() then
error('turtle: No GPS found') error('turtle: No GPS found')
end end
@@ -318,8 +305,8 @@ Event.addRoutine(function()
eachEntry(locations.cells, checkCell) eachEntry(locations.cells, checkCell)
end end
print('sleeping') print('sleeping')
turtle.status = 'sleeping' turtle.setStatus('sleeping')
if turtle.abort then if turtle.isAborted() then
printError('aborted') printError('aborted')
break break
end end

View File

@@ -83,7 +83,10 @@ local function loadAPI(url, env)
apiEnv.shell = nil apiEnv.shell = nil
apiEnv.multishell = nil apiEnv.multishell = nil
setmetatable(apiEnv, { __index = _G }) setmetatable(apiEnv, { __index = _G })
local fn = Util.loadUrl(url, apiEnv) local fn, m = Util.loadUrl(url, apiEnv)
if not fn then
error(m)
end
fn() fn()
return apiEnv return apiEnv
end end
@@ -91,7 +94,10 @@ end
bbpack = loadAPI('http://pastebin.com/raw/PdrJjb5S', getfenv(1)) bbpack = loadAPI('http://pastebin.com/raw/PdrJjb5S', getfenv(1))
GIF = loadAPI('http://pastebin.com/raw/5uk9uRjC', getfenv(1)) GIF = loadAPI('http://pastebin.com/raw/5uk9uRjC', getfenv(1))
Util.runUrl(getfenv(1), 'http://pastebin.com/raw/cUYTGbpb', 'get', 'CnLzL5fg') local s, m = Util.runUrl(getfenv(1), 'http://pastebin.com/raw/cUYTGbpb', 'get', 'CnLzL5fg')
if not s then
error(m)
end
-- 'Y0eLUPtr') -- 'Y0eLUPtr')
-- CnLzL5fg -- CnLzL5fg
local function snooze() local function snooze()
@@ -141,7 +147,7 @@ end
local tabId = multishell.getCurrent() local tabId = multishell.getCurrent()
multishell.addHotkey(25, function() multishell.addHotkey('control-p', function()
os.queueEvent('recorder_stop') os.queueEvent('recorder_stop')
end) end)
@@ -179,7 +185,7 @@ while true do
end end
end end
multishell.removeHotkey(25) multishell.removeHotkey('control-p')
for k,fn in pairs(oldTerm) do for k,fn in pairs(oldTerm) do
multishell.term[k] = fn multishell.term[k] = fn

View File

@@ -1,283 +1,47 @@
requireInjector(getfenv(1)) _G.requireInjector()
local GPS = require('gps') local GPS = require('gps')
local Socket = require('socket') local Socket = require('socket')
local UI = require('ui') local UI = require('ui')
local Util = require('util') local Util = require('util')
local multishell = _ENV.multishell
local textutils = _G.textutils
multishell.setTitle(multishell.getCurrent(), 'Shapes') multishell.setTitle(multishell.getCurrent(), 'Shapes')
local args = { ... } local args = { ... }
local turtleId = args[1] or error('Supply turtle ID') local turtleId = args[1] or error('Supply turtle ID')
turtleId = tonumber(turtleId) turtleId = tonumber(turtleId)
local script = [[
requireInjector(getfenv(1))
local GPS = require('gps')
local ChestAdapter = require('chestAdapter18')
local Point = require('point')
local Util = require('util')
local itemAdapter
function dumpInventory()
for i = 1, 16 do
local qty = turtle.getItemCount(i)
if qty > 0 then
itemAdapter:insert(i, qty)
end
if turtle.getItemCount(i) ~= 0 then
print('Adapter is full or missing - make space or replace')
print('Press enter to continue')
read()
end
end
turtle.select(1)
end
local function refuel()
while turtle.getFuelLevel() < 4000 do
print('Refueling')
turtle.select(1)
itemAdapter:provide({ name = 'minecraft:coal', damage = 0 }, 64, 1)
if turtle.getItemCount(1) == 0 then
print('Out of fuel, add fuel to chest/ME system')
turtle.status = 'waiting'
os.sleep(5)
else
turtle.refuel(64)
end
end
end
local function goto(pt)
while not turtle.gotoPoint(pt) do
print('stuck')
os.sleep(5)
end
end
local function pathTo(pt)
while not turtle.pathfind(pt) do
print('stuck')
os.sleep(5)
end
end
local function resupply()
if data.suppliesPt then
pathTo(data.suppliesPt)
itemAdapter = ChestAdapter({ direction = 'up', wrapSide = 'bottom' })
dumpInventory()
refuel()
end
end
local function makePlane(y)
local pt = { x = math.min(data.startPt.x, data.endPt.x),
ex = math.max(data.startPt.x, data.endPt.x),
z = math.min(data.startPt.z, data.endPt.z),
ez = math.max(data.startPt.z, data.endPt.z) }
local blocks = { }
for z = pt.z, pt.ez do
for x = pt.x, pt.ex do
table.insert(blocks, { x = x, y = y, z = z })
end
end
return blocks
end
local function optimizeRoute(plane, ptb)
local maxDistance = 99999999
local function getNearestNeighbor(p, pt, threshold)
local key, block, heading
local moves = maxDistance
local function getMoves(b, k)
local distance = math.abs(pt.x - b.x) + math.abs(pt.z - b.z)
if distance < moves then
-- this operation is expensive - only run if distance is close
local c, h = Point.calculateMoves(pt, b, distance)
if c < moves then
block = b
key = k
moves = c
heading = h
end
end
end
local function blockReady(b)
return not b.u
end
local mid = pt.index
local forward = mid + 1
local backward = mid - 1
while forward <= #p or backward > 0 do
if forward <= #p then
local b = p[forward]
if blockReady(b) then
getMoves(b, forward)
if moves <= threshold then
break
end
if moves < maxDistance and math.abs(b.z - pt.z) > moves and pt.index > 0 then
forward = #p
end
end
forward = forward + 1
end
if backward > 0 then
local b = p[backward]
if blockReady(b) then
getMoves(b, backward)
if moves <= threshold then
break
end
if moves < maxDistance and math.abs(pt.z - b.z) > moves then
backward = 0
end
end
backward = backward - 1
end
end
pt.x = block.x
pt.z = block.z
pt.y = block.y
pt.heading = heading
pt.index = key
block.u = true
return block
end
local throttle = Util.throttle()
local t = { }
ptb.index = 0
local threshold = 0
for i = 1, #plane do
local b = getNearestNeighbor(plane, ptb, threshold)
table.insert(t, b)
throttle()
threshold = 1
end
return t
end
local function clear()
local pt = Util.shallowCopy(data.startPt)
pt.y = math.min(data.startPt.y, data.endPt.y)
pt.heading = 0
local osy = pt.y
local sy = osy + 1
local ey = math.max(data.startPt.y, data.endPt.y)
local firstPlane = true
resupply()
while true do
if sy > ey then
sy = ey
end
local plane = makePlane(sy)
plane = optimizeRoute(plane, pt)
if firstPlane then
turtle.pathfind(plane[1])
turtle.setPolicy(turtle.policies.digAttack)
firstPlane = false
end
for _,b in ipairs(plane) do
turtle.gotoPoint(b)
if sy < ey then
turtle.digUp()
end
if sy > osy then
turtle.digDown()
end
if turtle.abort then
break
end
end
if turtle.abort then
break
end
if sy + 1 >= ey then
break
end
sy = sy + 3
end
turtle.setPolicy(turtle.policies.none)
resupply()
end
turtle.run(function()
turtle.status = 'Clearing'
if turtle.enableGPS() then
local pt = Util.shallowCopy(turtle.point)
local s, m = pcall(clear)
pathTo(pt)
if not s and m then
error(m)
read()
end
end
end)
]]
local levelScript = [[ local levelScript = [[
requireInjector(getfenv(1))
requireInjector(getfenv(1)) local Util = require('util')
local Level = require('turtle.level') local s, m = turtle.run(function()
local Util = require('util') turtle.addFeatures('level')
turtle.setStatus('Leveling')
local s, m = turtle.run(function() if turtle.enableGPS() then
turtle.status = 'Leveling' local pt = Util.shallowCopy(turtle.point)
local s, m = pcall(function()
turtle.level(data.startPt, data.endPt, data.firstPt)
end)
if turtle.enableGPS() then turtle.pathfind(pt)
local pt = Util.shallowCopy(turtle.point) if not s and m then
local s, m = pcall(function() error(m)
Level(data.startPt, data.endPt, data.firstPt) end
end)
turtle.pathfind(pt)
if not s and m then
error(m)
end end
end)
if not s then
error(m)
end end
end)
if not s then
error(m)
end
]] ]]
local data = Util.readTable('/usr/config/shapes') or { } local data = Util.readTable('/usr/config/shapes') or { }
local page = UI.Page { local page = UI.Page {
@@ -295,7 +59,6 @@ local page = UI.Page {
} }
function page.info:draw() function page.info:draw()
local function size(a, b) local function size(a, b)
return (math.abs(a.x - b.x) + 1) * return (math.abs(a.x - b.x) + 1) *
(math.abs(a.y - b.y) + 1) * (math.abs(a.y - b.y) + 1) *
@@ -321,13 +84,12 @@ function page:getPoint()
end end
function page:runFunction(id, script) function page:runFunction(id, script)
--Util.writeFile('script.tmp', script) --Util.writeFile('script.tmp', script)
self.notification:info('Connecting') self.notification:info('Connecting')
local fn, msg = loadstring(script, 'script') local fn, msg = loadstring(script, 'script')
if not fn then if not fn then
self.notification:error('Error in script') self.notification:error('Error in script')
-- debug(msg) --debug(msg)
return return
end end
@@ -379,7 +141,7 @@ function page:eventHandler(event)
end end
self.statusBar:setStatus('') self.statusBar:setStatus('')
elseif event.type == 'cancel' then elseif event.type == 'cancel' then
self:runFunction(turtleId, 'turtle.abortAction()') self:runFunction(turtleId, 'turtle.abort(true)')
self.statusBar:setStatus('') self.statusBar:setStatus('')
else else
return UI.Page.eventHandler(self, event) return UI.Page.eventHandler(self, event)
@@ -388,6 +150,4 @@ function page:eventHandler(event)
end end
UI:setPage(page) UI:setPage(page)
UI:pullEvents() UI:pullEvents()
UI.term:reset()

View File

@@ -1,13 +1,13 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Logger = require('logger')
local Pathing = require('turtle.pathfind') local Pathing = require('turtle.pathfind')
local Point = require('point') local Point = require('point')
local Util = require('util') local Util = require('util')
if device and device.wireless_modem then local fs = _G.fs
Logger.setWirelessLogging() local read = _G.read
end local os = _G.os
local turtle = _G.turtle
local args = { ... } local args = { ... }
local options = { local options = {
@@ -37,25 +37,20 @@ local fortuneBlocks = {
local MIN_FUEL = 7500 local MIN_FUEL = 7500
local LOW_FUEL = 1500 local LOW_FUEL = 1500
local MAX_FUEL = 100000 local MAX_FUEL = turtle.getFuelLimit()
local PROGRESS_FILE = 'usr/config/mining.progress' local PROGRESS_FILE = 'usr/config/mining.progress'
local TRASH_FILE = 'usr/config/mining.trash' local TRASH_FILE = 'usr/config/mining.trash'
if not term.isColor() then
MAX_FUEL = 20000
end
local mining = { local mining = {
diameter = 1, diameter = 1,
chunkIndex = 0, chunkIndex = 0,
chunks = -1, chunks = -1,
} }
local trash local trash, boreDirection, unload
local boreDirection
function getChunkCoordinates(diameter, index, x, z) local function getChunkCoordinates(diameter, index, x, z)
local dirs = { -- circumference of grid local dirs = { -- circumference of grid
{ xd = 0, zd = 1, heading = 1 }, -- south { xd = 0, zd = 1, heading = 1 }, -- south
{ xd = -1, zd = 0, heading = 2 }, { xd = -1, zd = 0, heading = 2 },
@@ -68,13 +63,13 @@ function getChunkCoordinates(diameter, index, x, z)
dirs[4].z = z dirs[4].z = z
return dirs[4] return dirs[4]
end end
dir = dirs[math.floor(index / (diameter - 1)) + 1] local dir = dirs[math.floor(index / (diameter - 1)) + 1]
dir.x = x + dir.xd * 16 dir.x = x + dir.xd * 16
dir.z = z + dir.zd * 16 dir.z = z + dir.zd * 16
return dir return dir
end end
function getBoreLocations(x, z) local function getBoreLocations(x, z)
local locations = {} local locations = {}
@@ -116,7 +111,7 @@ function getBoreLocations(x, z)
end end
-- get the bore location closest to the miner -- get the bore location closest to the miner
local function getClosestLocation(points, b) local function getClosestLocation(points)
local key = 1 local key = 1
local leastMoves = 9000 local leastMoves = 9000
for k,pt in pairs(points) do for k,pt in pairs(points) do
@@ -124,21 +119,21 @@ local function getClosestLocation(points, b)
local moves = Point.calculateMoves(turtle.point, pt) local moves = Point.calculateMoves(turtle.point, pt)
if moves < leastMoves then if moves < leastMoves then
key = k key = k
leastMoves = moves leastMoves = moves
if leastMoves == 0 then if leastMoves == 0 then
break break
end end
end end
end end
return table.remove(points, key) return table.remove(points, key)
end end
function getCornerOf(c) local function getCornerOf(c)
return math.floor(c.x / 16) * 16, math.floor(c.z / 16) * 16 return math.floor(c.x / 16) * 16, math.floor(c.z / 16) * 16
end end
function nextChunk() local function nextChunk()
local x, z = getCornerOf({ x = mining.x, z = mining.z }) local x, z = getCornerOf({ x = mining.x, z = mining.z })
local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2) local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2)
@@ -168,15 +163,15 @@ function nextChunk()
return true return true
end end
function addTrash() local function addTrash()
if not trash then if not trash then
trash = { } trash = { }
end end
local slots = turtle.getFilledSlots() local slots = turtle.getFilledSlots()
for k,slot in pairs(slots) do for _,slot in pairs(slots) do
trash[slot.iddmg] = true trash[slot.iddmg] = true
end end
@@ -184,19 +179,18 @@ function addTrash()
Util.writeTable(TRASH_FILE, trash) Util.writeTable(TRASH_FILE, trash)
end end
function log(text) local function log(text)
print(text) print(text)
Logger.log('mineWorker', text)
end end
function status(status) local function status(newStatus)
turtle.status = status turtle.setStatus(newStatus)
log(status) log(newStatus)
end end
function refuel() local function refuel()
if turtle.getFuelLevel() < MIN_FUEL then if turtle.getFuelLevel() < MIN_FUEL then
local oldStatus = turtle.status local oldStatus = turtle.getStatus()
status('refueling') status('refueling')
if turtle.select('minecraft:coal:0') then if turtle.select('minecraft:coal:0') then
@@ -220,54 +214,37 @@ function refuel()
turtle.select(1) turtle.select(1)
end end
function enderChestUnload()
log('unloading')
turtle.select(1)
if not Util.tryTimed(5, function()
turtle.digDown()
return turtle.placeDown()
end) then
log('placedown failed')
else
turtle.reconcileInventory(slots, turtle.dropDown)
turtle.select(1)
turtle.drop(64)
turtle.digDown()
end
end
function safeGoto(x, z, y, h) local function safeGoto(x, z, y, h)
local oldStatus = turtle.status local oldStatus = turtle.getStatus()
-- only pathfind above or around other turtles (never down) -- only pathfind above or around other turtles (never down)
Pathing.setBox({ x = 0, y = 0, z = 0, ex = x, ey = y + 1, ez = z }) Pathing.setBox({ x = turtle.point.x, y = turtle.point.y, z = turtle.point.z, ex = x, ey = y, ez = z })
while not turtle.pathfind({ x = x, z = z, y = y or turtle.point.y, heading = h }) do while not turtle.pathfind({ x = x, z = z, y = y or turtle.point.y, heading = h }) do
--status('stuck') --status('stuck')
if turtle.abort then if turtle.isAborted() then
return false return false
end end
--os.sleep(1) os.sleep(3)
end end
turtle.status = oldStatus turtle.setStatus(oldStatus)
return true return true
end end
function safeGotoY(y) local function safeGotoY(y)
local oldStatus = turtle.status local oldStatus = turtle.getStatus()
while not turtle.gotoY(y) do while not turtle.gotoY(y) do
status('stuck') status('stuck')
if turtle.abort then if turtle.isAborted() then
return false return false
end end
os.sleep(1) os.sleep(1)
end end
turtle.status = oldStatus turtle.setStatus(oldStatus)
return true return true
end end
function makeWalkableTunnel(action, tpt, pt) local function makeWalkableTunnel(action, tpt, pt)
if action ~= 'turn' and not Point.compare(tpt, { x = 0, z = 0 }) then -- not at source if action ~= 'turn' and not Point.compare(tpt, { x = 0, z = 0 }) then -- not at source
if not Point.compare(tpt, pt) then -- not at dest if not Point.compare(tpt, pt) then -- not at dest
local r, block = turtle.inspectUp() local r, block = turtle.inspectUp()
@@ -281,8 +258,27 @@ function makeWalkableTunnel(action, tpt, pt)
end end
end end
function normalChestUnload() --[[
local oldStatus = turtle.status local function enderChestUnload()
log('unloading')
turtle.select(1)
if not Util.tryTimed(5, function()
turtle.digDown()
return turtle.placeDown()
end) then
log('placedown failed')
else
turtle.reconcileInventory(slots, turtle.dropDown)
turtle.select(1)
turtle.drop(64)
turtle.digDown()
end
end
]]
local function normalChestUnload()
local oldStatus = turtle.getStatus()
status('unloading') status('unloading')
local pt = Util.shallowCopy(turtle.point) local pt = Util.shallowCopy(turtle.point)
safeGotoY(0) safeGotoY(0)
@@ -291,13 +287,13 @@ function normalChestUnload()
makeWalkableTunnel(action, tpt, { x = pt.x, z = pt.z }) makeWalkableTunnel(action, tpt, { x = pt.x, z = pt.z })
end) end)
safeGoto(0, 0) safeGoto(0, 0, 0)
if not turtle.detectUp() then if not turtle.detectUp() then
error('no chest') error('no chest')
end end
local slots = turtle.getFilledSlots() local slots = turtle.getFilledSlots()
for _,slot in pairs(slots) do for _,slot in pairs(slots) do
if not trash[slot.iddmg] and if not trash[slot.iddmg] and
slot.iddmg ~= 'minecraft:bucket:0' and slot.iddmg ~= 'minecraft:bucket:0' and
slot.id ~= 'minecraft:diamond_pickaxe' and slot.id ~= 'minecraft:diamond_pickaxe' and
slot.id ~= 'cctweaks:toolHost' then slot.id ~= 'cctweaks:toolHost' then
@@ -317,7 +313,7 @@ function normalChestUnload()
status(oldStatus) status(oldStatus)
end end
function ejectTrash() local function ejectTrash()
local cobbleSlotCount = 0 local cobbleSlotCount = 0
@@ -325,7 +321,7 @@ function ejectTrash()
if slot.iddmg == 'minecraft:cobblestone:0' then if slot.iddmg == 'minecraft:cobblestone:0' then
if cobbleSlotCount == 0 and slot.count > 36 then if cobbleSlotCount == 0 and slot.count > 36 then
turtle.select(slot.index) turtle.select(slot.index)
turtle.dropDown(32) turtle.dropDown(slot.count - 36)
end end
cobbleSlotCount = cobbleSlotCount + 1 cobbleSlotCount = cobbleSlotCount + 1
end end
@@ -340,7 +336,35 @@ function ejectTrash()
end) end)
end end
function mineable(action) local function checkSpace()
if turtle.getItemCount(16) > 0 then
refuel()
local oldStatus = turtle.getStatus()
status('condensing')
ejectTrash()
turtle.condense()
local lastSlot = 16
if boreDirection == 'down' then
lastSlot = 15
end
if turtle.getItemCount(lastSlot) > 0 then
unload()
end
status(oldStatus)
turtle.select(1)
end
end
local function collectDrops(suckAction)
for _ = 1, 50 do
if not suckAction() then
break
end
checkSpace()
end
end
local function mineable(action)
local r, block = action.inspect() local r, block = action.inspect()
if not r then if not r then
return false return false
@@ -375,12 +399,12 @@ function mineable(action)
return block.name return block.name
end end
function fortuneDig(action, blockName) local function fortuneDig(action, blockName)
if options.fortunePick.value and fortuneBlocks[blockName] then if options.fortunePick.value and fortuneBlocks[blockName] then
turtle.select('cctweaks:toolHost') turtle.select('cctweaks:toolHost')
turtle.equipRight() turtle.equipRight()
turtle.select(options.fortunePick.value) turtle.select(options.fortunePick.value)
repeat until not turtle.dig() repeat until not action.dig()
turtle.select('minecraft:diamond_pickaxe') turtle.select('minecraft:diamond_pickaxe')
turtle.equipRight() turtle.equipRight()
turtle.select(1) turtle.select(1)
@@ -388,7 +412,7 @@ function fortuneDig(action, blockName)
end end
end end
function mine(action) local function mine(action)
local blockName = mineable(action) local blockName = mineable(action)
if blockName then if blockName then
checkSpace() checkSpace()
@@ -398,18 +422,18 @@ function mine(action)
end end
end end
end end
function bore() local function bore()
local loc = turtle.point local loc = turtle.point
local level = loc.y local level = loc.y
turtle.select(1) turtle.select(1)
status('boring down') status('boring down')
boreDirection = 'down' boreDirection = 'down'
while true do while true do
if turtle.abort then if turtle.isAborted() then
status('aborting') status('aborting')
return false return false
end end
@@ -417,15 +441,11 @@ function bore()
break break
end end
if turtle.point.y < -2 then
-- turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
end
mine(turtle.getAction('down')) mine(turtle.getAction('down'))
if not Util.tryTimed(3, turtle.down) then if not Util.tryTimed(3, turtle.down) then
break break
end end
if loc.y < level - 1 then if loc.y < level - 1 then
mine(turtle.getAction('forward')) mine(turtle.getAction('forward'))
turtle.turnRight() turtle.turnRight()
@@ -438,38 +458,34 @@ function bore()
turtle.turnRight() turtle.turnRight()
mine(turtle.getAction('forward')) mine(turtle.getAction('forward'))
turtle.turnRight() turtle.turnRight()
mine(turtle.getAction('forward')) mine(turtle.getAction('forward'))
turtle.turnLeft() turtle.turnLeft()
while true do while true do
if turtle.abort then if turtle.isAborted() then
status('aborting') status('aborting')
return false return false
end end
if turtle.point.y > -2 then
-- turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
end
while not Util.tryTimed(3, turtle.up) do while not Util.tryTimed(3, turtle.up) do
status('stuck') status('stuck')
end end
if turtle.status == 'stuck' then if turtle.getStatus() == 'stuck' then
status('boring up') status('boring up')
end end
if loc.y >= level - 1 then if loc.y >= level - 1 then
break break
end end
mine(turtle.getAction('forward')) mine(turtle.getAction('forward'))
turtle.turnLeft() turtle.turnLeft()
mine(turtle.getAction('forward')) mine(turtle.getAction('forward'))
end end
if turtle.getFuelLevel() < LOW_FUEL then if turtle.getFuelLevel() < LOW_FUEL then
refuel() refuel()
local veryMinFuel = Point.turtleDistance(turtle.point, { x = 0, y = 0, z = 0}) + 512 local veryMinFuel = Point.turtleDistance(turtle.point, { x = 0, y = 0, z = 0}) + 512
@@ -481,34 +497,6 @@ function bore()
return true return true
end end
function checkSpace()
if turtle.getItemCount(16) > 0 then
refuel()
local oldStatus = turtle.status
status('condensing')
ejectTrash()
turtle.condense()
local lastSlot = 16
if boreDirection == 'down' then
lastSlot = 15
end
if turtle.getItemCount(lastSlot) > 0 then
unload()
end
status(oldStatus)
turtle.select(1)
end
end
function collectDrops(suckAction)
for i = 1, 50 do
if not suckAction() then
break
end
checkSpace()
end
end
function Point.compare(pta, ptb) function Point.compare(pta, ptb)
if pta.x == ptb.x and pta.z == ptb.z then if pta.x == ptb.x and pta.z == ptb.z then
@@ -520,15 +508,15 @@ function Point.compare(pta, ptb)
return false return false
end end
function inspect(action, name) local function inspect(action, name)
local r, block = action.inspect() local r, block = action.inspect()
if r and block.name == name then if r and block.name == name then
return true return true
end end
end end
function boreCommand() local function boreCommand()
local pt = getClosestLocation(mining.locations, turtle.point) local pt = getClosestLocation(mining.locations)
turtle.setMoveCallback(function(action, tpt) turtle.setMoveCallback(function(action, tpt)
makeWalkableTunnel(action, tpt, pt) makeWalkableTunnel(action, tpt, pt)
@@ -566,6 +554,7 @@ if not Util.getOptions(options, args) then
return return
end end
-- TODO: this won't work - need to Util.merge file into mining
mining.depth = options.depth.value mining.depth = options.depth.value
mining.chunks = options.chunks.value mining.chunks = options.chunks.value
@@ -628,16 +617,14 @@ turtle.run(function()
turtle.reset() turtle.reset()
turtle.setPolicy(turtle.policies.digAttack) turtle.setPolicy(turtle.policies.digAttack)
turtle.setDigPolicy(turtle.digPolicies.turtleSafe) turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
unload() unload()
status('mining') status('mining')
local s, m = pcall(function() main() end) local s, m = pcall(main)
if not s and m then if not s and m then
printError(m) _G.printError(m)
end end
turtle.abort(false)
turtle.abort = false
safeGotoY(0) safeGotoY(0)
safeGoto(0, 0, 0, 0) safeGoto(0, 0, 0, 0)
unload() unload()

View File

@@ -1,22 +1,16 @@
requireInjector(getfenv(1)) _G.requireInjector()
local ChestAdapter = require('chestAdapter18') local InventoryAdapter = require('inventoryAdapter')
local Event = require('event') local Event = require('event')
local MEAdapter = require('meAdapter') local UI = require('ui')
local RefinedAdapter = require('refinedAdapter') local Util = require('util')
local UI = require('ui')
local Util = require('util')
local storage = RefinedAdapter() local colors = _G.colors
if not storage:isValid() then local multishell = _ENV.multishell
storage = MEAdapter({ auto = true })
if not storage:isValid() then
storage = ChestAdapter()
end
end
if not storage:isValid() then local storage = InventoryAdapter.wrap()
error('Not connected to a storage device') if not storage then
error('Not connected to a valid inventory')
end end
multishell.setTitle(multishell.getCurrent(), 'Storage Activity') multishell.setTitle(multishell.getCurrent(), 'Storage Activity')
@@ -26,8 +20,9 @@ local changedPage = UI.Page {
grid = UI.Grid { grid = UI.Grid {
ey = -6, ey = -6,
columns = { columns = {
{ heading = 'Qty', key = 'count', width = 5 }, { heading = 'Qty', key = 'count', width = 5 },
{ heading = 'Change', key = 'change', width = 6 }, { heading = 'Change', key = 'change', width = 6 },
{ heading = 'Rate', key = 'rate', width = 6 },
{ heading = 'Name', key = 'displayName' }, { heading = 'Name', key = 'displayName' },
}, },
sortColumn = 'displayName', sortColumn = 'displayName',
@@ -66,6 +61,7 @@ function changedPage.grid:getDisplayValues(row)
if row.change < 0 then if row.change < 0 then
ind = '' ind = ''
end end
row.change = ind .. Util.toBytes(row.change) row.change = ind .. Util.toBytes(row.change)
row.count = Util.toBytes(row.count) row.count = Util.toBytes(row.count)
@@ -73,7 +69,6 @@ function changedPage.grid:getDisplayValues(row)
end end
function changedPage:eventHandler(event) function changedPage:eventHandler(event)
if event.type == 'reset' then if event.type == 'reset' then
self.lastItems = nil self.lastItems = nil
self.grid:setValues({ }) self.grid:setValues({ })
@@ -102,22 +97,25 @@ end
function changedPage:refresh() function changedPage:refresh()
local t = storage:listItems() local t = storage:listItems()
if not t or Util.empty(t) then if not t or Util.empty(t) then
self:clear() self.grid:clear()
self:centeredWrite(math.ceil(self.height/2), 'Communication failure') self.grid:centeredWrite(math.ceil(self.height/2), 'Communication failure')
return return
end end
for k,v in pairs(t) do for k,v in pairs(t) do
t[k] = Util.shallowCopy(v) t[k] = Util.shallowCopy(v)
end end
if not self.lastItems then if not self.lastItems then
self.lastItems = t self.lastItems = t
self.timestamp = os.clock()
self.grid:setValues({ }) self.grid:setValues({ })
else else
local changedItems = {} self.elapsed = os.clock() - self.timestamp
local changedItems = { }
local found
for _,v in pairs(self.lastItems) do for _,v in pairs(self.lastItems) do
found = false found = false
for k2,v2 in pairs(t) do for k2,v2 in pairs(t) do
@@ -141,24 +139,26 @@ function changedPage:refresh()
end end
end end
-- No items left -- No items left
for k,v in pairs(t) do for _,v in pairs(t) do
v.lastCount = 0 v.lastCount = 0
table.insert(changedItems, v) table.insert(changedItems, v)
end end
for k,v in pairs(changedItems) do for _,v in pairs(changedItems) do
v.change = v.count - v.lastCount v.change = v.count - v.lastCount
v.rate = Util.round(60 / self.elapsed * v.change, 1)
end end
self.grid:setValues(changedItems) self.grid:setValues(changedItems)
end end
self.grid:draw() self.grid:draw()
end end
Event.onInterval(5, function() Event.onInterval(5, function()
changedPage:refresh() changedPage:refresh()
changedPage:sync() changedPage:sync()
end) end)
UI:setPage(changedPage) UI:setPage(changedPage)
changedPage:draw()
UI:pullEvents() UI:pullEvents()

View File

@@ -1,4 +1,4 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local Logger = require('logger') local Logger = require('logger')
@@ -8,6 +8,10 @@ local Point = require('point')
local TableDB = require('tableDB') local TableDB = require('tableDB')
local Util = require('util') local Util = require('util')
local device = _G.device
local os = _G.os
local turtle = _G.turtle
--[[ --[[
A supplier turtle for the builder turtle. For larger builds, use A supplier turtle for the builder turtle. For larger builds, use
ender modems. ender modems.
@@ -57,7 +61,7 @@ local maxStackDB = TableDB({
} }
} }
}) })
function maxStackDB:get(id, dmg) function maxStackDB:get(id, dmg)
return self.data[id .. ':' .. dmg] or 64 return self.data[id .. ':' .. dmg] or 64
end end
@@ -87,7 +91,7 @@ function Builder:dumpInventoryWithCheck()
print('Press enter to continue') print('Press enter to continue')
--turtle.setHeading(0) --turtle.setHeading(0)
self.ready = false self.ready = false
read() _G.read()
end end
self.ready = true self.ready = true
end end
@@ -95,7 +99,7 @@ end
function Builder:autocraft(supplies) function Builder:autocraft(supplies)
local t = { } local t = { }
for i,s in pairs(supplies) do for _,s in pairs(supplies) do
local key = s.id .. ':' .. s.dmg local key = s.id .. ':' .. s.dmg
local item = t[key] local item = t[key]
if not item then if not item then
@@ -108,7 +112,7 @@ function Builder:autocraft(supplies)
end end
item.qty = item.qty + (s.need-s.qty) item.qty = item.qty + (s.need-s.qty)
end end
Builder.itemProvider:craftItems(t) Builder.itemProvider:craftItems(t)
end end
@@ -133,9 +137,9 @@ function Builder:log(...)
end end
function Builder:getSupplies() function Builder:getSupplies()
Builder.itemProvider:refresh() Builder.itemProvider:refresh()
local t = { } local t = { }
for _,s in ipairs(self.slots) do for _,s in ipairs(self.slots) do
if s.need > 0 then if s.need > 0 then
@@ -171,7 +175,7 @@ function Builder:getSupplies()
Builder:log('Need %d %s', s.need - s.qty, name) Builder:log('Need %d %s', s.need - s.qty, name)
end end
end end
return t return t
end end
@@ -179,11 +183,11 @@ local function moveTowardsX(dx)
local direction = dx - turtle.point.x local direction = dx - turtle.point.x
local move local move
if direction == 0 then if direction == 0 then
return false return false
end end
if direction > 0 and turtle.point.heading == 0 or if direction > 0 and turtle.point.heading == 0 or
direction < 0 and turtle.point.heading == 2 then direction < 0 and turtle.point.heading == 2 then
move = turtle.forward move = turtle.forward
@@ -202,7 +206,7 @@ local function moveTowardsZ(dz)
if direction == 0 then if direction == 0 then
return false return false
end end
if direction > 0 and turtle.point.heading == 1 or if direction > 0 and turtle.point.heading == 1 or
direction < 0 and turtle.point.heading == 3 then direction < 0 and turtle.point.heading == 3 then
move = turtle.forward move = turtle.forward
@@ -214,7 +218,6 @@ local function moveTowardsZ(dz)
end end
function Builder:finish() function Builder:finish()
Builder.resupplying = true Builder.resupplying = true
Builder.ready = false Builder.ready = false
if turtle.gotoLocation('supplies') then if turtle.gotoLocation('supplies') then
@@ -227,9 +230,8 @@ function Builder:finish()
end end
function Builder:gotoBuilder() function Builder:gotoBuilder()
if Builder.lastPoint then if Builder.lastPoint then
turtle.status = 'tracking' turtle.setStatus('tracking')
while true do while true do
local pt = Point.copy(Builder.lastPoint) local pt = Point.copy(Builder.lastPoint)
pt.y = pt.y + 3 pt.y = pt.y + 3
@@ -260,140 +262,137 @@ function Builder:gotoBuilder()
end end
end end
Message.addHandler('builder', Message.addHandler('builder',
function(h, id, msg, distance) function(_, id, msg)
if not id or id ~= __BUILDER_ID then if not id or id ~= __BUILDER_ID then
return return
end end
if not Builder.resupplying then if not Builder.resupplying then
local pt = msg.contents local pt = msg.contents
pt.y = pt.y + 3 pt.y = pt.y + 3
turtle.status = 'supervising' turtle.setStatus('supervising')
turtle.gotoYfirst(pt) turtle.gotoYfirst(pt)
end end
end) end)
Message.addHandler('supplyList', Message.addHandler('supplyList',
function(h, id, msg, distance) function(_, id, msg)
if not id or id ~= __BUILDER_ID then if not id or id ~= __BUILDER_ID then
return return
end end
turtle.status = 'resupplying' turtle.setStatus('resupplying')
Builder.resupplying = true Builder.resupplying = true
Builder.slots = msg.contents.slots Builder.slots = msg.contents.slots
Builder.slotUid = msg.contents.uid Builder.slotUid = msg.contents.uid
Builder:log('Received supply list ' .. Builder.slotUid) Builder:log('Received supply list ' .. Builder.slotUid)
os.sleep(0) os.sleep(0)
if not turtle.gotoLocation('supplies') then if not turtle.gotoLocation('supplies') then
Builder:log('Failed to go to supply location') Builder:log('Failed to go to supply location')
self.ready = false Builder.ready = false
Event.exitPullEvents() Event.exitPullEvents()
end end
turtle.setHeading(1) turtle.setHeading(1)
os.sleep(.2) -- random 'Computer is not connected' error... os.sleep(.2) -- random 'Computer is not connected' error...
Builder:dumpInventoryWithCheck() Builder:dumpInventoryWithCheck()
Builder:refuel() Builder:refuel()
while true do while true do
local supplies = Builder:getSupplies() local supplies = Builder:getSupplies()
if #supplies == 0 then if #supplies == 0 then
break break
end end
Builder:autocraft(supplies) Builder:autocraft(supplies)
turtle.status = 'waiting' turtle.setStatus('waiting')
os.sleep(5) os.sleep(5)
end end
Builder:log('Got all supplies') Builder:log('Got all supplies')
os.sleep(0) os.sleep(0)
Builder:gotoBuilder() Builder:gotoBuilder()
Builder.resupplying = false Builder.resupplying = false
end) end)
Message.addHandler('needSupplies', Message.addHandler('needSupplies',
function(h, id, msg, distance) function(_, id, msg)
if not id or id ~= __BUILDER_ID then if not id or id ~= __BUILDER_ID then
return return
end end
if Builder.resupplying or msg.contents.uid ~= Builder.slotUid then if Builder.resupplying or msg.contents.uid ~= Builder.slotUid then
Builder:log('No supplies ready')
Builder:log('No supplies ready') Message.send(__BUILDER_ID, 'gotSupplies')
else
turtle.setStatus('supplying')
Builder:log('Supplying')
os.sleep(0)
Message.send(__BUILDER_ID, 'gotSupplies') local pt = msg.contents.point
else pt.y = turtle.getPoint().y
turtle.status = 'supplying' pt.heading = nil
Builder:log('Supplying') if not turtle.gotoYfirst(pt) then -- location of builder
os.sleep(0) Builder.resupplying = true
Message.send(__BUILDER_ID, 'gotSupplies')
local pt = msg.contents.point os.sleep(0)
pt.y = turtle.getPoint().y if not turtle.gotoLocation('supplies') then
pt.heading = nil Builder:log('failed to go to supply location')
if not turtle.gotoYfirst(pt) then -- location of builder Event.exitPullEvents()
Builder.resupplying = true end
Message.send(__BUILDER_ID, 'gotSupplies')
os.sleep(0)
if not turtle.gotoLocation('supplies') then
Builder:log('failed to go to supply location')
--self.ready = false
Event.exitPullEvents()
end
turtle.setHeading(1) turtle.setHeading(1)
return return
end end
pt.y = pt.y - 2 -- location where builder should go for the chest to be above pt.y = pt.y - 2 -- location where builder should go for the chest to be above
turtle.select(15) turtle.select(15)
turtle.placeDown() turtle.placeDown()
os.sleep(.1) -- random computer not connected error os.sleep(.1) -- random computer not connected error
local p = ChestProvider({ direction = 'up', wrapSide = 'bottom' }) local p = ChestProvider({ direction = 'up', wrapSide = 'bottom' })
for i = 1, 16 do for i = 1, 16 do
p:insert(i, 64) p:insert(i, 64)
end end
Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true, point = pt }) Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true, point = pt })
Message.waitForMessage('thanks', 5, __BUILDER_ID) Message.waitForMessage('thanks', 5, __BUILDER_ID)
--os.sleep(0) --os.sleep(0)
--p.condenseItems() --p.condenseItems()
for i = 1, 16 do for i = 1, 16 do
p:extract(i, 64) p:extract(i, 64)
end end
turtle.digDown() turtle.digDown()
turtle.status = 'waiting' turtle.setStatus('waiting')
end end
end) end)
Message.addHandler('finished', Message.addHandler('finished',
function(h, id) function(_, id)
if not id or id ~= __BUILDER_ID then if not id or id ~= __BUILDER_ID then
return return
end end
Builder:finish() Builder:finish()
end) end)
Event.on('turtle_abort', Event.on('turtle_abort',
function() function()
turtle.abort = false turtle.abort(false)
turtle.status = 'aborting' turtle.setStatus('aborting')
Builder:finish() Builder:finish()
end) end)
local function onTheWay() -- parallel routine local function onTheWay() -- parallel routine
while true do while true do
local e, side, _id, id, msg, distance = os.pullEvent('modem_message') local _, _, _, id, msg, _ = os.pullEvent('modem_message')
if Builder.ready then if Builder.ready then
if id == __BUILDER_ID and msg and msg.type then if id == __BUILDER_ID and msg and msg.type then
if msg.type == 'needSupplies' then if msg.type == 'needSupplies' then
Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true }) Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true })
elseif msg.type == 'builder' then elseif msg.type == 'builder' then
Builder.lastPoint = msg.contents Builder.lastPoint = msg.contents
end end
end end
end end
end end

22
apps/termShare.lua Normal file
View File

@@ -0,0 +1,22 @@
local device = _G.device
local multishell = _ENV.multishell
local os = _G.os
local term = _G.term
-- list this terminal in the devices list so it's available via
-- peripheral sharing
local args = { ... }
local name = args[1] or error('Syntax: termShare [device name] <title>')
local title = args[2]
device[name] = term.current()
device[name].name = name
device[name].side = name
device[name].type = 'terminal'
if title then
multishell.setTitle(multishell.getCurrent(), title)
end
os.pullEvent('terminate')
os.queueEvent('peripheral_detach', name)

View File

@@ -1,4 +1,4 @@
requireInjector(getfenv(1)) _G.requireInjector()
--[[ --[[
Requirements: Requirements:
@@ -6,7 +6,7 @@ requireInjector(getfenv(1))
Area around turtle must be flat and can only be dirt or grass Area around turtle must be flat and can only be dirt or grass
(10 blocks in each direction from turtle) (10 blocks in each direction from turtle)
Turtle must have: crafting table, chest Turtle must have: crafting table, chest
Turtle must have a pick equipped on the left side Turtle must have a pick equipped
Optional: Optional:
Add additional sapling types that can grow with a single sapling Add additional sapling types that can grow with a single sapling
@@ -20,12 +20,12 @@ requireInjector(getfenv(1))
place the turtle in the original position before restarting the program. place the turtle in the original position before restarting the program.
]]-- ]]--
local ChestAdapter = require('chestAdapter18') local Point = require('point')
local Craft = require('turtle.craft') local Util = require('util')
local Level = require('turtle.level')
local Pathing = require('turtle.pathfind') local os = _G.os
local Point = require('point') local read = _G.read
local Util = require('util') local turtle = _G.turtle
local FUEL_BASE = 0 local FUEL_BASE = 0
local FUEL_DIRE = FUEL_BASE + 10 local FUEL_DIRE = FUEL_BASE + 10
@@ -76,9 +76,6 @@ local state = Util.readTable('usr/config/treefarm') or {
} }
local clock = os.clock() local clock = os.clock()
local recipes = Util.readTable('usr/etc/recipes.db') or { }
Craft.setRecipes(recipes)
local function inspect(fn) local function inspect(fn)
local s, item = fn() local s, item = fn()
@@ -121,28 +118,21 @@ local function safePlaceBlock(item)
end end
local function craftItem(item, qty) local function craftItem(item, qty)
local success, msg
local success
if safePlaceBlock(CHEST) then if safePlaceBlock(CHEST) then
if turtle.equip('left', 'minecraft:crafting_table') then Util.print('Crafting %d %s', (qty or 1), item)
success, msg = turtle.craftItem(item, qty or 1, {
local chestAdapter = ChestAdapter({
wrapSide = 'top', wrapSide = 'top',
direction = 'down', direction = 'down',
}) })
if not chestAdapter:isValid() then repeat until not turtle.suckUp()
print('invalid chestAdapter')
read()
end
Util.print('Crafting %d %s', (qty or 1), item) if not success then
success = Craft.craftRecipe(recipes[item], qty or 1, chestAdapter) print(msg)
repeat until not turtle.suckUp()
end end
turtle.equip('left', 'minecraft:diamond_pickaxe')
turtle.digUp() turtle.digUp()
end end
@@ -175,7 +165,7 @@ local function makeSingleCharcoal()
local slots = turtle.getSummedInventory() local slots = turtle.getSummedInventory()
if not state.furnace or if not state.furnace or
slots[CHARCOAL] or slots[CHARCOAL] or
not slots[OAK_LOG] or not slots[OAK_LOG] or
slots[OAK_LOG].count < 2 then slots[OAK_LOG].count < 2 then
@@ -195,13 +185,13 @@ local function makeCharcoal()
local slots = turtle.getSummedInventory() local slots = turtle.getSummedInventory()
if not state.furnace or if not state.furnace or
not slots[CHARCOAL] or not slots[CHARCOAL] or
slots[CHARCOAL].count >= MIN_CHARCOAL then slots[CHARCOAL].count >= MIN_CHARCOAL then
return true return true
end end
local function getLogSlot(slots) local function getLogSlot()
local maxslot = { count = 0 } local maxslot = { count = 0 }
for k,slot in pairs(slots) do for k,slot in pairs(slots) do
if string.match(k, 'minecraft:log') then if string.match(k, 'minecraft:log') then
@@ -214,7 +204,8 @@ local function makeCharcoal()
end end
repeat repeat
local slots = turtle.getSummedInventory() slots = turtle.getSummedInventory()
local charcoal = slots[CHARCOAL].count local charcoal = slots[CHARCOAL].count
local slot = getLogSlot(slots) local slot = getLogSlot(slots)
@@ -266,7 +257,7 @@ local function getCobblestone(count)
turtle.select(1) turtle.select(1)
turtle.digDown() turtle.digDown()
turtle.down() turtle.down()
for i = 1, 4 do for _ = 1, 4 do
if inspect(turtle.inspect) == STONE then if inspect(turtle.inspect) == STONE then
turtle.dig() turtle.dig()
end end
@@ -281,7 +272,7 @@ local function getCobblestone(count)
until turtle.getItemCount(COBBLESTONE) >= count until turtle.getItemCount(COBBLESTONE) >= count
turtle.gotoPoint(pt) turtle._goto(pt)
turtle.placeDown(DIRT) turtle.placeDown(DIRT)
turtle.drop(DIRT) turtle.drop(DIRT)
@@ -297,8 +288,8 @@ local function createFurnace()
print('Adding a furnace') print('Adding a furnace')
getCobblestone(8) getCobblestone(8)
if craftItem(FURNACE) then if turtle.has(FURNACE) or craftItem(FURNACE) then
turtle.drop(COBBLESTONE) -- turtle.drop(COBBLESTONE)
local furnacePt = { x = GRID.BL.x + 2, y = 1, z = GRID.BL.z + 2 } local furnacePt = { x = GRID.BL.x + 2, y = 1, z = GRID.BL.z + 2 }
turtle.placeAt(furnacePt, FURNACE) turtle.placeAt(furnacePt, FURNACE)
setState('furnace', furnacePt) setState('furnace', furnacePt)
@@ -319,7 +310,9 @@ local function createPerimeter()
print('Creating a perimeter') print('Creating a perimeter')
getCobblestone(GRID_WIDTH * 2 + 1) getCobblestone(GRID_WIDTH * 2 + 1)
cook(COBBLESTONE, 2, STONE, OAK_PLANK, 2) if not turtle.has(STONE, 2) then
cook(COBBLESTONE, 2, STONE, OAK_PLANK, 2)
end
turtle.refuel(OAK_PLANK) turtle.refuel(OAK_PLANK)
turtle.pathfind(GRID.BL) turtle.pathfind(GRID.BL)
@@ -350,35 +343,32 @@ local function createPerimeter()
end end
local function createChests() local function createChests()
if state.chest_1 then if state.chest then
return return
end end
if state.perimeter and if state.perimeter and
turtle.getFuelLevel() > FUEL_GOOD and turtle.getFuelLevel() > FUEL_GOOD and
Craft.canCraft(CHEST, 4, turtle.getSummedInventory()) then turtle.canCraft(CHEST, 4, turtle.getSummedInventory()) then
print('Adding storage') print('Adding storage')
if craftItem(CHEST, 4) then if turtle.has(CHEST, 2) or craftItem(CHEST, 2) then
local pt = Point.copy(GRID.BL) local pt = Point.copy(GRID.BL)
pt.x = pt.x + 1 pt.x = pt.x + 1
pt.y = pt.y - 1 pt.y = pt.y - 1
for i = 1, 2 do pt.z = pt.z + 1
pt.z = pt.z + 1
turtle.digDownAt(pt) turtle.digDownAt(pt)
turtle.placeDown(CHEST) turtle.placeDown(CHEST)
pt.z = pt.z + 1 pt.z = pt.z + 1
turtle.digDownAt(pt) turtle.digDownAt(pt)
turtle.placeDown(CHEST) turtle.placeDown(CHEST)
setState('chest_' .. i, Util.shallowCopy(pt)) setState('chest', Util.shallowCopy(pt))
pt.z = pt.z + 1
end
turtle.drop(DIRT) turtle.drop(DIRT)
turtle.refuel(OAK_PLANK) turtle.refuel(OAK_PLANK)
end end
@@ -388,24 +378,27 @@ end
local function dropOffItems() local function dropOffItems()
if state.chest_1 then if state.chest then
local slots = turtle.getSummedInventory() local slots = turtle.getSummedInventory()
if state.chest_1 and if state.chest and
slots[CHARCOAL] and slots[CHARCOAL] and
slots[CHARCOAL].count >= MIN_CHARCOAL and slots[CHARCOAL].count >= MIN_CHARCOAL and
(turtle.getItemCount('minecraft:log') > 0 or (turtle.getItemCount('minecraft:log') > 0 or
turtle.getItemCount('minecraft:log2') > 0) then turtle.getItemCount('minecraft:log2') > 0) then
print('Storing logs') print('Storing logs')
turtle.pathfind(Point.above(state.chest_1)) turtle.pathfind(Point.above(state.chest))
turtle.dropDown('minecraft:log') turtle.dropDown('minecraft:log')
turtle.dropDown('minecraft:log2') turtle.dropDown('minecraft:log2')
end
if slots[APPLE] then for _, sapling in pairs(ALL_SAPLINGS) do
print('Storing apples') if slots[sapling] and slots[sapling].count > MAX_SAPLINGS then
turtle.dropDownAt(state.chest_2, APPLE) turtle.dropDown(sapling, slots[sapling].count - MAX_SAPLINGS)
end
end
turtle.dropDown(APPLE)
end end
end end
@@ -430,11 +423,11 @@ local function placeTorches()
end end
if turtle.getFuelLevel() > 100 and if turtle.getFuelLevel() > 100 and
Craft.canCraft(TORCH, 4, turtle.getSummedInventory()) then turtle.canCraft(TORCH, 4, turtle.getSummedInventory()) then
print('Placing torches') print('Placing torches')
if craftItem(TORCH, 4) then if turtle.has(TORCH, 4) or craftItem(TORCH, 4) then
local pts = { } local pts = { }
for x = -4, 4, 8 do for x = -4, 4, 8 do
for z = -4, 4, 8 do for z = -4, 4, 8 do
@@ -493,7 +486,7 @@ local function fellTree(pt)
desperateRefuel(FUEL_DIRE) desperateRefuel(FUEL_DIRE)
if turtle.digUpAt(Point.above(pt)) then if turtle.digUpAt(Point.above(pt)) then
Level( turtle.level(
{ x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 }, { x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 },
{ x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) }, { x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) },
Point.above(pt)) Point.above(pt))
@@ -510,10 +503,10 @@ local function fell()
local pts = Util.shallowCopy(state.trees) local pts = Util.shallowCopy(state.trees)
local pt = table.remove(pts, math.random(1, #pts)) local rpt = table.remove(pts, math.random(1, #pts))
-- give the pathfinder hints about what to avoid (state.trees) -- give the pathfinder hints about what to avoid (state.trees)
if not turtle.faceAgainst(pt, { blocks = Util.shallowCopy(state.trees) }) or if not turtle.faceAgainst(rpt, { blocks = Util.shallowCopy(state.trees) }) or
not string.match(inspect(turtle.inspect), 'minecraft:log') then not string.match(inspect(turtle.inspect), 'minecraft:log') then
return true return true
end end
@@ -523,7 +516,7 @@ local function fell()
local fuel = turtle.getFuelLevel() local fuel = turtle.getFuelLevel()
-- push this point to the start of this list -- push this point to the start of this list
table.insert(pts, 1, pt) table.insert(pts, 1, rpt)
Point.eachClosest(turtle.point, pts, function(pt) Point.eachClosest(turtle.point, pts, function(pt)
if turtle.faceAgainst(pt, { blocks = Util.shallowCopy(state.trees) }) and if turtle.faceAgainst(pt, { blocks = Util.shallowCopy(state.trees) }) and
@@ -545,7 +538,7 @@ local function moreTrees()
return return
end end
if not state.chest_1 or turtle.getItemCount('minecraft:sapling') < 15 then if not state.chest or turtle.getItemCount('minecraft:sapling') < 15 then
return true return true
end end
@@ -570,7 +563,7 @@ local function moreTrees()
end) end)
end end
function getTurtleFacing(block) local function getTurtleFacing(block)
local directions = { local directions = {
[5] = 2, [5] = 2,
[3] = 3, [3] = 3,
@@ -586,7 +579,7 @@ function getTurtleFacing(block)
return directions[bi.metadata] return directions[bi.metadata]
end end
function saveTurtleFacing() local function saveTurtleFacing()
if not state.facing then if not state.facing then
setState('facing', getTurtleFacing(CHEST)) setState('facing', getTurtleFacing(CHEST))
end end
@@ -600,9 +593,9 @@ local function findGround()
local s, block = turtle.inspectDown() local s, block = turtle.inspectDown()
if not s then block = { name = 'minecraft:air', metadata = 0 } end if not s then block = { name = 'minecraft:air', metadata = 0 } end
b = block.name .. ':' .. block.metadata local b = block.name .. ':' .. block.metadata
if b == 'minecraft:dirt:0' or if b == 'minecraft:dirt:0' or
b == 'minecraft:grass:0' or b == 'minecraft:grass:0' or
block.name == 'minecraft:chest' then block.name == 'minecraft:chest' then
break break
@@ -633,10 +626,7 @@ local function findHome()
end end
print('Determining location') print('Determining location')
turtle.point.heading = (getTurtleFacing(CHEST) - state.facing) % 4
turtle.point.heading = getTurtleFacing(CHEST)
turtle.setHeading(state.facing)
turtle.point.heading = 0
local pt = Point.copy(turtle.point) local pt = Point.copy(turtle.point)
@@ -663,7 +653,7 @@ local function findHome()
}) })
-- when pathfinding - don't leave this box -- when pathfinding - don't leave this box
Pathing.setBox({ turtle.setPathingBox({
x = GRID.TL.x, x = GRID.TL.x,
y = GRID.TL.y, y = GRID.TL.y,
z = GRID.TL.z, z = GRID.TL.z,
@@ -710,7 +700,7 @@ local tasks = {
{ desc = 'Emptying furnace', fn = emptyFurnace }, { desc = 'Emptying furnace', fn = emptyFurnace },
{ desc = 'Adding trees', fn = moreTrees }, { desc = 'Adding trees', fn = moreTrees },
{ desc = 'Chopping', fn = fell }, { desc = 'Chopping', fn = fell },
{ desc = 'Snacking', fn = eatSaplings }, -- { desc = 'Snacking', fn = eatSaplings },
{ desc = 'Creating chest', fn = createChests }, { desc = 'Creating chest', fn = createChests },
{ desc = 'Creating furnace', fn = createFurnace }, { desc = 'Creating furnace', fn = createFurnace },
{ desc = 'Making charcoal', fn = makeSingleCharcoal }, { desc = 'Making charcoal', fn = makeSingleCharcoal },
@@ -719,27 +709,28 @@ local tasks = {
{ desc = 'Placing torches', fn = placeTorches }, { desc = 'Placing torches', fn = placeTorches },
{ desc = 'Refueling', fn = refuel }, { desc = 'Refueling', fn = refuel },
{ desc = 'Dropping off items', fn = dropOffItems }, { desc = 'Dropping off items', fn = dropOffItems },
{ desc = 'Condensing', fn = turtle.condense }, { desc = 'Condensing', fn = turtle.condense },
{ desc = 'Sleeping', fn = updateClock }, { desc = 'Sleeping', fn = updateClock },
} }
local s, m = turtle.run(function() local s, m = turtle.run(function()
turtle.addFeatures('level', 'crafting')
turtle.setPolicy("attack") turtle.setPolicy("attack")
while not turtle.abort do while not turtle.isAborted() do
print('fuel: ' .. turtle.getFuelLevel()) print('fuel: ' .. turtle.getFuelLevel())
for _,task in ipairs(Util.shallowCopy(tasks)) do for _,task in ipairs(Util.shallowCopy(tasks)) do
--print(task.desc) --print(task.desc)
turtle.status = task.desc turtle.setStatus(task.desc)
turtle.select(1) turtle.select(1)
if not task.fn() then if not task.fn() then
Util.filterInplace(tasks, function(v) return v.fn ~= task.fn end) Util.filterInplace(tasks, function(v) return v.fn ~= task.fn end)
end end
end end
end end
end) end)
if not s then if not s then
error('Failed') error(m or 'Failed')
end end

1
etc/fstab.ignore Normal file
View File

@@ -0,0 +1 @@
forced fstab overwrite

View File

@@ -0,0 +1,87 @@
{
[ "appliedenergistics2:quartz_glass:0" ] = {
ingredients = {
"appliedenergistics2:material:2",
"minecraft:glass:0",
"appliedenergistics2:material:2",
[ 9 ] = "appliedenergistics2:material:2",
[ 10 ] = "minecraft:glass:0",
[ 11 ] = "appliedenergistics2:material:2",
[ 5 ] = "minecraft:glass:0",
[ 6 ] = "appliedenergistics2:material:2",
[ 7 ] = "minecraft:glass:0",
},
count = 4,
},
[ "appliedenergistics2:material:43" ] = {
ingredients = {
"appliedenergistics2:material:0",
"appliedenergistics2:material:8",
"appliedenergistics2:material:22",
},
count = 2,
},
[ "appliedenergistics2:material:44" ] = {
ingredients = {
[ 5 ] = "minecraft:quartz:0",
[ 6 ] = "appliedenergistics2:material:8",
[ 7 ] = "appliedenergistics2:material:22",
},
count = 2,
},
[ "appliedenergistics2:material:35" ] = {
ingredients = {
"minecraft:redstone:0",
"appliedenergistics2:material:0",
"minecraft:redstone:0",
[ 5 ] = "appliedenergistics2:material:0",
[ 6 ] = "appliedenergistics2:material:22",
[ 7 ] = "appliedenergistics2:material:0",
[ 9 ] = "minecraft:redstone:0",
[ 10 ] = "appliedenergistics2:material:0",
[ 11 ] = "minecraft:redstone:0",
},
count = 1,
},
[ "appliedenergistics2:interface:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"minecraft:glass:0",
"minecraft:iron_ingot:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "minecraft:glass:0",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "appliedenergistics2:material:44",
[ 7 ] = "appliedenergistics2:material:43",
},
count = 1,
},
[ "appliedenergistics2:material:36" ] = {
ingredients = {
"minecraft:redstone:0",
"appliedenergistics2:material:23",
"minecraft:redstone:0",
[ 5 ] = "appliedenergistics2:material:35",
[ 6 ] = "appliedenergistics2:quartz_glass:0",
[ 7 ] = "appliedenergistics2:material:35",
[ 9 ] = "minecraft:redstone:0",
[ 10 ] = "appliedenergistics2:material:35",
[ 11 ] = "minecraft:redstone:0",
},
count = 1,
},
[ "appliedenergistics2:material:37" ] = {
ingredients = {
"minecraft:glowstone_dust:0",
"appliedenergistics2:material:24",
"minecraft:glowstone_dust:0",
[ 5 ] = "appliedenergistics2:material:36",
[ 6 ] = "appliedenergistics2:quartz_glass:0",
[ 7 ] = "appliedenergistics2:material:36",
[ 9 ] = "minecraft:glowstone_dust:0",
[ 10 ] = "appliedenergistics2:material:36",
[ 11 ] = "minecraft:glowstone_dust:0",
},
count = 1,
},
}

View File

@@ -0,0 +1,87 @@
{
[ "computercraft:turtle_advanced:0" ] = {
ingredients = {
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
[ 9 ] = "minecraft:gold_ingot:0",
[ 10 ] = "minecraft:chest:0",
[ 11 ] = "minecraft:gold_ingot:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "computercraft:computer:16384",
[ 7 ] = "minecraft:gold_ingot:0",
},
count = 1,
},
[ "computercraft:pocket_computer:1" ] = {
count = 1,
ingredients = {
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
[ 9 ] = "minecraft:gold_ingot:0",
[ 10 ] = "minecraft:glass_pane:0",
[ 11 ] = "minecraft:gold_ingot:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "minecraft:golden_apple:0",
[ 7 ] = "minecraft:gold_ingot:0",
},
maxCount = 1,
},
[ "computercraft:peripheral:0" ] = {
ingredients = {
"minecraft:stone:0",
"minecraft:stone:0",
"minecraft:stone:0",
[ 9 ] = "minecraft:stone:0",
[ 10 ] = "minecraft:redstone:0",
[ 11 ] = "minecraft:stone:0",
[ 5 ] = "minecraft:stone:0",
[ 6 ] = "minecraft:redstone:0",
[ 7 ] = "minecraft:stone:0",
},
count = 1,
},
[ "computercraft:peripheral:4" ] = {
ingredients = {
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
[ 9 ] = "minecraft:gold_ingot:0",
[ 10 ] = "minecraft:gold_ingot:0",
[ 11 ] = "minecraft:gold_ingot:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "minecraft:glass_pane:0",
[ 7 ] = "minecraft:gold_ingot:0",
},
count = 4,
},
[ "computercraft:advanced_modem:0" ] = {
ingredients = {
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
[ 9 ] = "minecraft:gold_ingot:0",
[ 10 ] = "minecraft:gold_ingot:0",
[ 11 ] = "minecraft:gold_ingot:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "minecraft:ender_eye:0",
[ 7 ] = "minecraft:gold_ingot:0",
},
count = 1,
},
[ "computercraft:computer:16384" ] = {
ingredients = {
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
"minecraft:gold_ingot:0",
[ 9 ] = "minecraft:gold_ingot:0",
[ 10 ] = "minecraft:glass_pane:0",
[ 11 ] = "minecraft:gold_ingot:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "minecraft:redstone:0",
[ 7 ] = "minecraft:gold_ingot:0",
},
count = 1,
},
}

544
etc/recipes/enderio.db Normal file
View File

@@ -0,0 +1,544 @@
{
[ "enderio:blockAlloySmelter:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"minecraft:furnace:0",
"minecraft:iron_ingot:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "minecraft:cauldron:0",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "minecraft:furnace:0",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "minecraft:furnace:0",
},
count = 1,
},
[ "enderio:blockBuffer:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"enderio:itemAlloy:0",
"minecraft:iron_ingot:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "enderio:itemAlloy:0",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "enderio:itemAlloy:0",
[ 6 ] = "minecraft:chest:0",
[ 7 ] = "enderio:itemAlloy:0",
},
count = 1,
},
[ "enderio:blockCapBank:3" ] = {
ingredients = {
"enderio:itemAlloy:0",
"enderio:itemBasicCapacitor:2",
"enderio:itemAlloy:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "enderio:itemBasicCapacitor:2",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:itemBasicCapacitor:2",
[ 6 ] = "enderio:itemMaterial:6",
[ 7 ] = "enderio:itemBasicCapacitor:2",
},
count = 1,
},
[ "enderio:blockExperienceObelisk:0" ] = {
ingredients = {
[ 9 ] = "enderio:itemAlloy:7",
[ 10 ] = "enderio:itemMachinePart:0",
[ 11 ] = "enderio:itemAlloy:7",
[ 2 ] = "enderio:itemXpTransfer:0",
[ 6 ] = "enderio:itemAlloy:7",
},
count = 1,
},
[ "enderio:blockFarmStation:0" ] = {
ingredients = {
"enderio:itemAlloy:0",
"minecraft:diamond_hoe:*",
"enderio:itemAlloy:0",
[ 9 ] = "enderio:itemMaterial:5",
[ 10 ] = "enderio:itemFrankenSkull:1",
[ 11 ] = "enderio:itemMaterial:5",
[ 5 ] = "enderio:itemAlloy:0",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "enderio:itemAlloy:0",
},
count = 1,
},
[ "enderio:blockKillerJoe:0" ] = {
ingredients = {
"enderio:itemAlloy:6",
"enderio:itemAlloy:6",
"enderio:itemAlloy:6",
[ 9 ] = "enderio:blockFusedQuartz:0",
[ 10 ] = "enderio:blockFusedQuartz:0",
[ 11 ] = "enderio:blockFusedQuartz:0",
[ 5 ] = "enderio:blockFusedQuartz:0",
[ 6 ] = "enderio:itemFrankenSkull:2",
[ 7 ] = "enderio:blockFusedQuartz:0",
},
count = 1,
},
[ "enderio:blockPainter:0" ] = {
ingredients = {
"minecraft:quartz:0",
"minecraft:diamond:0",
"minecraft:quartz:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "enderio:itemAlloy:0",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:itemAlloy:0",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "enderio:itemAlloy:0",
},
count = 1,
},
[ "enderio:blockReservoir:0" ] = {
ingredients = {
"enderio:blockFusedQuartz:0",
"enderio:blockFusedQuartz:0",
"enderio:blockFusedQuartz:0",
[ 9 ] = "enderio:blockFusedQuartz:0",
[ 10 ] = "enderio:blockFusedQuartz:0",
[ 11 ] = "enderio:blockFusedQuartz:0",
[ 5 ] = "enderio:blockFusedQuartz:0",
[ 6 ] = "minecraft:cauldron:0",
[ 7 ] = "enderio:blockFusedQuartz:0",
},
count = 4,
},
[ "enderio:blockSagMill:0" ] = {
ingredients = {
"minecraft:flint:0",
"minecraft:flint:0",
"minecraft:flint:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "minecraft:piston:0",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "minecraft:iron_ingot:0",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "minecraft:iron_ingot:0",
},
count = 1,
},
[ "enderio:blockSliceAndSplice:0" ] = {
ingredients = {
"enderio:itemAlloy:7",
"minecraft:skull:0",
"enderio:itemAlloy:7",
[ 9 ] = "enderio:itemAlloy:7",
[ 10 ] = "enderio:itemAlloy:7",
[ 11 ] = "enderio:itemAlloy:7",
[ 5 ] = "minecraft:iron_axe:*",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "minecraft:shears:*",
},
count = 1,
},
[ "enderio:blockSolarPanel:0" ] = {
ingredients = {
"enderio:itemAlloy:1",
"enderio:blockFusedQuartz:0",
"enderio:itemAlloy:1",
[ 9 ] = "enderio:itemBasicCapacitor:0",
[ 10 ] = "minecraft:daylight_detector:0",
[ 11 ] = "enderio:itemBasicCapacitor:0",
[ 5 ] = "enderio:itemAlloy:2",
[ 6 ] = "enderio:blockFusedQuartz:0",
[ 7 ] = "enderio:itemAlloy:2",
},
count = 1,
},
[ "enderio:blockSolarPanel:1" ] = {
ingredients = {
"enderio:itemAlloy:5",
"enderio:blockFusedQuartz:2",
"enderio:itemAlloy:5",
[ 9 ] = "enderio:itemBasicCapacitor:1",
[ 10 ] = "minecraft:daylight_detector:0",
[ 11 ] = "enderio:itemBasicCapacitor:1",
[ 5 ] = "enderio:itemAlloy:2",
[ 6 ] = "enderio:blockFusedQuartz:2",
[ 7 ] = "enderio:itemAlloy:2",
},
count = 1,
},
[ "enderio:blockSolarPanel:2" ] = {
ingredients = {
"enderio:itemAlloy:7",
"enderio:blockFusedQuartz:4",
"enderio:itemAlloy:7",
[ 9 ] = "enderio:blockSolarPanel:1",
[ 10 ] = "enderio:blockSolarPanel:1",
[ 11 ] = "enderio:blockSolarPanel:1",
[ 5 ] = "enderio:itemBasicCapacitor:2",
[ 6 ] = "enderio:itemMaterial:8",
[ 7 ] = "enderio:itemBasicCapacitor:2",
},
count = 1,
},
[ "enderio:blockSoulBinder:0" ] = {
ingredients = {
"enderio:itemAlloy:7",
"enderio:blockEndermanSkull:0",
"enderio:itemAlloy:7",
[ 9 ] = "enderio:itemAlloy:7",
[ 10 ] = "minecraft:skull:0",
[ 11 ] = "enderio:itemAlloy:7",
[ 5 ] = "minecraft:skull:4",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "minecraft:skull:2",
},
count = 1,
},
[ "enderio:blockTank:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"minecraft:iron_bars:0",
"minecraft:iron_ingot:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "minecraft:iron_bars:0",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "minecraft:iron_bars:0",
[ 6 ] = "minecraft:glass:0",
[ 7 ] = "minecraft:iron_bars:0",
},
count = 1,
},
[ "enderio:blockTransceiver:0" ] = {
ingredients = {
"enderio:itemAlloy:0",
"enderio:itemFrankenSkull:3",
"enderio:itemAlloy:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "enderio:itemBasicCapacitor:2",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:blockFusedQuartz:0",
[ 6 ] = "enderio:itemMaterial:8",
[ 7 ] = "enderio:blockFusedQuartz:0",
},
count = 1,
},
[ "enderio:blockVacuumChest:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"minecraft:iron_ingot:0",
"minecraft:iron_ingot:0",
[ 9 ] = "minecraft:iron_ingot:0",
[ 10 ] = "enderio:itemMaterial:5",
[ 11 ] = "minecraft:iron_ingot:0",
[ 5 ] = "minecraft:iron_ingot:0",
[ 6 ] = "minecraft:chest:0",
[ 7 ] = "minecraft:iron_ingot:0",
},
count = 1,
},
[ "enderio:blockVat:0" ] = {
ingredients = {
"enderio:itemAlloy:0",
"minecraft:cauldron:0",
"enderio:itemAlloy:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "minecraft:furnace:0",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:blockTank:0",
[ 6 ] = "enderio:itemMachinePart:0",
[ 7 ] = "enderio:blockTank:0",
},
count = 1,
},
[ "enderio:blockWirelessCharger:0" ] = {
ingredients = {
"enderio:itemAlloy:0",
"enderio:itemAlloy:0",
"enderio:itemAlloy:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "enderio:itemBasicCapacitor:2",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:itemAlloy:0",
[ 6 ] = "enderio:itemFrankenSkull:3",
[ 7 ] = "enderio:itemAlloy:0",
},
count = 1,
},
[ "enderio:itemBasicCapacitor:2" ] = {
ingredients = {
[ 10 ] = "enderio:itemAlloy:2",
[ 2 ] = "enderio:itemAlloy:2",
[ 5 ] = "enderio:itemBasicCapacitor:1",
[ 6 ] = "minecraft:glowstone:0",
[ 7 ] = "enderio:itemBasicCapacitor:1",
},
count = 1,
},
[ "enderio:itemBasicFilterUpgrade:0" ] = {
ingredients = {
[ 10 ] = "minecraft:paper:0",
[ 2 ] = "minecraft:paper:0",
[ 5 ] = "minecraft:paper:0",
[ 6 ] = "minecraft:hopper:0",
[ 7 ] = "minecraft:paper:0",
},
count = 1,
},
[ "enderio:itemBasicFilterUpgrade:1" ] = {
ingredients = {
"minecraft:redstone:0",
"minecraft:paper:0",
"minecraft:redstone:0",
[ 9 ] = "minecraft:redstone:0",
[ 10 ] = "minecraft:paper:0",
[ 11 ] = "minecraft:redstone:0",
[ 5 ] = "minecraft:paper:0",
[ 6 ] = "enderio:itemFrankenSkull:1",
[ 7 ] = "minecraft:paper:0",
},
count = 1,
},
[ "enderio:itemBasicFilterUpgrade:2" ] = {
ingredients = {
"minecraft:comparator:0",
"enderio:itemBasicFilterUpgrade:1",
"minecraft:comparator:0",
},
count = 1,
},
[ "enderio:itemConduitFacade:0" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemMaterial:1",
[ 7 ] = "enderio:itemMaterial:1",
},
count = 1,
},
[ "enderio:itemExtractSpeedUpgrade:0" ] = {
ingredients = {
"minecraft:iron_ingot:0",
"minecraft:iron_ingot:0",
"minecraft:iron_ingot:0",
[ 9 ] = "enderio:itemAlloy:0",
[ 10 ] = "minecraft:redstone_torch:0",
[ 11 ] = "enderio:itemAlloy:0",
[ 5 ] = "enderio:itemAlloy:0",
[ 6 ] = "minecraft:piston:0",
[ 7 ] = "enderio:itemAlloy:0",
},
count = 1,
},
[ "enderio:itemItemConduit:0" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemMaterial:3",
[ 6 ] = "enderio:itemMaterial:3",
[ 7 ] = "enderio:itemMaterial:3",
},
count = 8,
},
[ "enderio:itemLiquidConduit:0" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:blockFusedQuartz:1",
[ 6 ] = "enderio:blockFusedQuartz:1",
[ 7 ] = "enderio:blockFusedQuartz:1",
},
count = 8,
},
[ "enderio:itemLiquidConduit:1" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:blockFusedQuartz:0",
[ 6 ] = "enderio:blockFusedQuartz:0",
[ 7 ] = "enderio:blockFusedQuartz:0",
},
count = 8,
},
[ "enderio:itemLiquidConduit:2" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemAlloy:2",
[ 6 ] = "enderio:blockFusedQuartz:0",
[ 7 ] = "enderio:itemAlloy:2",
},
count = 8,
},
[ "enderio:itemMachinePart:0" ] = {
ingredients = {
"minecraft:iron_bars:0",
"minecraft:iron_ingot:0",
"minecraft:iron_bars:0",
[ 9 ] = "minecraft:iron_bars:0",
[ 10 ] = "minecraft:iron_ingot:0",
[ 11 ] = "minecraft:iron_bars:0",
[ 5 ] = "minecraft:iron_ingot:0",
[ 6 ] = "enderio:itemBasicCapacitor:0",
[ 7 ] = "minecraft:iron_ingot:0",
},
count = 1,
},
[ "enderio:itemMachinePart:1" ] = {
ingredients = {
"minecraft:stick:0",
"minecraft:cobblestone:0",
"minecraft:stick:0",
[ 9 ] = "minecraft:stick:0",
[ 10 ] = "minecraft:cobblestone:0",
[ 11 ] = "minecraft:stick:0",
[ 5 ] = "minecraft:cobblestone:0",
[ 7 ] = "minecraft:cobblestone:0",
},
count = 1,
},
[ "enderio:itemMaterial:2" ] = {
ingredients = {
"minecraft:gravel:0",
"minecraft:clay_ball:0",
"minecraft:gravel:0",
[ 9 ] = "minecraft:gravel:0",
[ 10 ] = "minecraft:clay_ball:0",
[ 11 ] = "minecraft:gravel:0",
[ 5 ] = "minecraft:sand:0",
[ 6 ] = "minecraft:gravel:0",
[ 7 ] = "minecraft:sand:0",
},
count = 8,
},
[ "enderio:itemMaterial:3" ] = {
ingredients = {
"enderio:itemAlloy:5",
},
count = 9,
},
[ "enderio:itemMaterial:4" ] = {
ingredients = {
"enderio:itemAlloy:2",
},
count = 9,
},
[ "enderio:itemMaterial:5" ] = {
ingredients = {
"enderio:itemMaterial:3",
"enderio:itemMaterial:3",
"enderio:itemMaterial:3",
[ 9 ] = "enderio:itemMaterial:3",
[ 10 ] = "enderio:itemMaterial:3",
[ 11 ] = "enderio:itemMaterial:3",
[ 5 ] = "enderio:itemMaterial:3",
[ 6 ] = "minecraft:diamond:0",
[ 7 ] = "enderio:itemMaterial:3",
},
count = 1,
},
[ "enderio:itemMaterial:6" ] = {
ingredients = {
"enderio:itemMaterial:4",
"enderio:itemMaterial:4",
"enderio:itemMaterial:4",
[ 9 ] = "enderio:itemMaterial:4",
[ 10 ] = "enderio:itemMaterial:4",
[ 11 ] = "enderio:itemMaterial:4",
[ 5 ] = "enderio:itemMaterial:4",
[ 6 ] = "minecraft:emerald:0",
[ 7 ] = "enderio:itemMaterial:4",
},
count = 1,
},
[ "enderio:itemPowerConduit:0" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemAlloy:4",
[ 6 ] = "enderio:itemAlloy:4",
[ 7 ] = "enderio:itemAlloy:4",
},
count = 8,
},
[ "enderio:itemPowerConduit:1" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemAlloy:1",
[ 6 ] = "enderio:itemPowerConduit:0",
[ 7 ] = "enderio:itemAlloy:1",
},
count = 8,
},
[ "enderio:itemPowerConduit:2" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemAlloy:2",
[ 6 ] = "enderio:itemAlloy:2",
[ 7 ] = "enderio:itemAlloy:2",
},
count = 8,
},
[ "enderio:itemRedstoneConduit:0" ] = {
ingredients = {
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
"enderio:itemMaterial:1",
[ 9 ] = "enderio:itemMaterial:1",
[ 10 ] = "enderio:itemMaterial:1",
[ 11 ] = "enderio:itemMaterial:1",
[ 5 ] = "enderio:itemAlloy:3",
[ 6 ] = "enderio:itemAlloy:3",
[ 7 ] = "enderio:itemAlloy:3",
},
count = 8,
},
[ "enderio:itemSoulVessel:0" ] = {
ingredients = {
[ 7 ] = "enderio:blockFusedQuartz:0",
[ 2 ] = "enderio:itemAlloy:7",
[ 10 ] = "enderio:blockFusedQuartz:0",
[ 5 ] = "enderio:blockFusedQuartz:0",
},
count = 1,
},
[ "enderio:itemXpTransfer:0" ] = {
count = 1,
ingredients = {
[ 6 ] = "enderio:itemAlloy:1",
[ 3 ] = "enderio:itemAlloy:7",
[ 9 ] = "enderio:itemAlloy:7",
},
maxCount = 1,
},
}

12
etc/recipes/exnihilo.db Normal file
View File

@@ -0,0 +1,12 @@
{
[ "exnihiloadscensio:hammerStone:0" ] = {
maxCount = 1,
ingredients = {
[ 7 ] = "minecraft:cobblestone:0",
[ 9 ] = "minecraft:stick:0",
[ 2 ] = "minecraft:cobblestone:0",
[ 6 ] = "minecraft:stick:0",
},
count = 1,
},
}

View File

@@ -0,0 +1,21 @@
{
[ "extrautils2:user:0" ] = {
ingredients = {
"minecraft:dropper:0",
"extrautils2:ingredients:0",
[ 5 ] = "minecraft:lever:0",
},
count = 1,
},
[ "extrautils2:endershard:0" ] = {
ingredients = {
"minecraft:ender_pearl:0",
"extrautils2:glasscutter:*",
},
craftingTools = {
[ "extrautils2:glasscutter:*" ] = true,
},
maxCount = 1,
count = 8,
},
}

58
etc/recipes/mekanism.db Normal file
View File

@@ -0,0 +1,58 @@
{
[ "mekanism:EnergyTablet:0:3a153e5a66ba42a2d96ffd50ba64918b" ] = {
ingredients = {
"minecraft:redstone:0",
"minecraft:gold_ingot:0",
"minecraft:redstone:0",
[ 9 ] = "minecraft:redstone:0",
[ 10 ] = "minecraft:gold_ingot:0",
[ 11 ] = "minecraft:redstone:0",
[ 5 ] = "mekanism:EnrichedAlloy:0",
[ 6 ] = "minecraft:gold_ingot:0",
[ 7 ] = "mekanism:EnrichedAlloy:0",
},
count = 1,
},
[ "mekanism:SpeedUpgrade:0" ] = {
ingredients = {
[ 10 ] = "minecraft:glass:0",
[ 2 ] = "minecraft:glass:0",
[ 5 ] = "mekanism:EnrichedAlloy:0",
[ 6 ] = "mekanism:Dust:2",
[ 7 ] = "mekanism:EnrichedAlloy:0",
},
count = 1,
},
[ "mekanism:ControlCircuit:1" ] = {
ingredients = {
"mekanism:EnrichedAlloy:0",
"mekanism:ControlCircuit:0",
"mekanism:EnrichedAlloy:0",
},
count = 1,
},
[ "mekanism:BasicBlock:8" ] = {
ingredients = {
"bigreactors:ingotmetals:5",
"minecraft:glass:0",
"bigreactors:ingotmetals:5",
[ 9 ] = "bigreactors:ingotmetals:5",
[ 10 ] = "minecraft:glass:0",
[ 11 ] = "bigreactors:ingotmetals:5",
[ 5 ] = "minecraft:glass:0",
[ 6 ] = "mekanism:Ingot:1",
[ 7 ] = "minecraft:glass:0",
},
count = 1,
},
[ "mekanism:EnergyUpgrade:0" ] = {
ingredients = {
[ 10 ] = "minecraft:glass:0",
[ 2 ] = "minecraft:glass:0",
[ 5 ] = "mekanism:EnrichedAlloy:0",
[ 6 ] = "exnihiloadscensio:itemOreGold:2",
[ 7 ] = "mekanism:EnrichedAlloy:0",
},
count = 1,
},
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,178 @@
{
[ "mysticalagriculture:supremium_ingot:0" ] = {
ingredients = {
[ 10 ] = "mysticalagriculture:supremium_essence:0",
[ 2 ] = "mysticalagriculture:supremium_essence:0",
[ 5 ] = "mysticalagriculture:supremium_essence:0",
[ 6 ] = "mysticalagriculture:superium_ingot:0",
[ 7 ] = "mysticalagriculture:supremium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:prudentium_ingot:0" ] = {
ingredients = {
[ 10 ] = "mysticalagriculture:prudentium_essence:0",
[ 2 ] = "mysticalagriculture:prudentium_essence:0",
[ 5 ] = "mysticalagriculture:prudentium_essence:0",
[ 6 ] = "mysticalagriculture:inferium_ingot:0",
[ 7 ] = "mysticalagriculture:prudentium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:intermedium_ingot:0" ] = {
ingredients = {
[ 10 ] = "mysticalagriculture:intermedium_essence:0",
[ 2 ] = "mysticalagriculture:intermedium_essence:0",
[ 5 ] = "mysticalagriculture:intermedium_essence:0",
[ 6 ] = "mysticalagriculture:prudentium_ingot:0",
[ 7 ] = "mysticalagriculture:intermedium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:superium_armor_core:0" ] = {
ingredients = {
"mysticalagriculture:superium_essence:0",
"minecraft:diamond_block:0",
"mysticalagriculture:superium_essence:0",
[ 5 ] = "minecraft:emerald:0",
[ 6 ] = "mysticalagriculture:intermedium_armor_core:0",
[ 7 ] = "minecraft:emerald:0",
[ 9 ] = "mysticalagriculture:superium_essence:0",
[ 10 ] = "minecraft:emerald:0",
[ 11 ] = "mysticalagriculture:superium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:inferium_ingot:0" ] = {
ingredients = {
[ 10 ] = "mysticalagriculture:inferium_essence:0",
[ 2 ] = "mysticalagriculture:inferium_essence:0",
[ 5 ] = "mysticalagriculture:inferium_essence:0",
[ 6 ] = "mysticalagriculture:base_essence_ingot:0",
[ 7 ] = "mysticalagriculture:inferium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:intermedium_armor_core:0" ] = {
ingredients = {
"mysticalagriculture:intermedium_essence:0",
"minecraft:gold_block:0",
"mysticalagriculture:intermedium_essence:0",
[ 5 ] = "minecraft:diamond:0",
[ 6 ] = "mysticalagriculture:prudentium_armor_core:0",
[ 7 ] = "minecraft:diamond:0",
[ 9 ] = "mysticalagriculture:intermedium_essence:0",
[ 10 ] = "minecraft:diamond:0",
[ 11 ] = "mysticalagriculture:intermedium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:infusion_crystal:0" ] = {
ingredients = {
"mysticalagriculture:prosperity_shard:0",
"mysticalagriculture:inferium_essence:0",
"mysticalagriculture:prosperity_shard:0",
[ 9 ] = "mysticalagriculture:prosperity_shard:0",
[ 10 ] = "mysticalagriculture:inferium_essence:0",
[ 11 ] = "mysticalagriculture:prosperity_shard:0",
[ 5 ] = "mysticalagriculture:inferium_essence:0",
[ 6 ] = "minecraft:diamond:0",
[ 7 ] = "mysticalagriculture:inferium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:supremium_armor_core:0" ] = {
ingredients = {
"mysticalagriculture:supremium_essence:0",
"minecraft:nether_star:0",
"mysticalagriculture:supremium_essence:0",
[ 5 ] = "minecraft:skull:1",
[ 6 ] = "mysticalagriculture:superium_armor_core:0",
[ 7 ] = "minecraft:skull:1",
[ 9 ] = "mysticalagriculture:supremium_essence:0",
[ 10 ] = "minecraft:skull:1",
[ 11 ] = "mysticalagriculture:supremium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:inferium_armor_core:0" ] = {
ingredients = {
"mysticalagriculture:inferium_essence:0",
"minecraft:gold_ingot:0",
"mysticalagriculture:inferium_essence:0",
[ 5 ] = "minecraft:leather:0",
[ 6 ] = "mysticalagriculture:base_essence_ingot:0",
[ 7 ] = "minecraft:leather:0",
[ 9 ] = "mysticalagriculture:inferium_essence:0",
[ 10 ] = "minecraft:leather:0",
[ 11 ] = "mysticalagriculture:inferium_essence:0",
},
count = 1,
},
[ "mysticalagriculture:base_essence_ingot:0" ] = {
ingredients = {
[ 10 ] = "mysticalagriculture:prosperity_shard:0",
[ 2 ] = "mysticalagriculture:prosperity_shard:0",
[ 5 ] = "mysticalagriculture:prosperity_shard:0",
[ 6 ] = "thermalfoundation:material:136",
[ 7 ] = "mysticalagriculture:prosperity_shard:0",
},
count = 1,
},
[ "mysticalagriculture:tier2_inferium_seeds:0" ] = {
count = 1,
ingredients = {
"mysticalagriculture:prudentium_essence:0",
"mysticalagriculture:prudentium_essence:0",
"mysticalagriculture:prudentium_essence:0",
[ 9 ] = "mysticalagriculture:prudentium_essence:0",
[ 10 ] = "mysticalagriculture:prudentium_essence:0",
[ 11 ] = "mysticalagriculture:prudentium_essence:0",
[ 5 ] = "mysticalagriculture:prudentium_essence:0",
[ 6 ] = "mysticalagriculture:tier1_inferium_seeds:0",
[ 7 ] = "mysticalagriculture:prudentium_essence:0",
},
},
[ "mysticalagriculture:tier3_inferium_seeds:0" ] = {
count = 1,
ingredients = {
"mysticalagriculture:intermedium_essence:0",
"mysticalagriculture:intermedium_essence:0",
"mysticalagriculture:intermedium_essence:0",
[ 9 ] = "mysticalagriculture:intermedium_essence:0",
[ 10 ] = "mysticalagriculture:intermedium_essence:0",
[ 11 ] = "mysticalagriculture:intermedium_essence:0",
[ 5 ] = "mysticalagriculture:intermedium_essence:0",
[ 6 ] = "mysticalagriculture:tier2_inferium_seeds:0",
[ 7 ] = "mysticalagriculture:intermedium_essence:0",
},
},
[ "mysticalagriculture:tier1_inferium_seeds:0" ] = {
count = 1,
ingredients = {
"mysticalagriculture:inferium_essence:0",
"mysticalagriculture:inferium_essence:0",
"mysticalagriculture:inferium_essence:0",
[ 9 ] = "mysticalagriculture:inferium_essence:0",
[ 10 ] = "mysticalagriculture:inferium_essence:0",
[ 11 ] = "mysticalagriculture:inferium_essence:0",
[ 5 ] = "mysticalagriculture:inferium_essence:0",
[ 6 ] = "minecraft:wheat_seeds:0",
[ 7 ] = "mysticalagriculture:inferium_essence:0",
},
},
[ "mysticalagriculture:prudentium_armor_core:0" ] = {
ingredients = {
"mysticalagriculture:prudentium_essence:0",
"minecraft:lapis_block:0",
"mysticalagriculture:prudentium_essence:0",
[ 5 ] = "minecraft:gold_ingot:0",
[ 6 ] = "mysticalagriculture:inferium_armor_core:0",
[ 7 ] = "minecraft:gold_ingot:0",
[ 9 ] = "mysticalagriculture:prudentium_essence:0",
[ 10 ] = "minecraft:gold_ingot:0",
[ 11 ] = "mysticalagriculture:prudentium_essence:0",
},
count = 1,
},
}

View File

@@ -0,0 +1,28 @@
{
[ "storagedrawers:basicDrawers:0:b85f006d9f6aa0e06184f8931d4e85c1" ] = {
ingredients = {
"minecraft:planks:0",
"minecraft:planks:0",
"minecraft:planks:0",
[ 9 ] = "minecraft:planks:0",
[ 10 ] = "minecraft:planks:0",
[ 11 ] = "minecraft:planks:0",
[ 6 ] = "minecraft:chest:0",
},
count = 1,
},
[ "storagedrawers:upgradeTemplate:0" ] = {
ingredients = {
"minecraft:stick:0",
"minecraft:stick:0",
"minecraft:stick:0",
[ 9 ] = "minecraft:stick:0",
[ 10 ] = "minecraft:stick:0",
[ 11 ] = "minecraft:stick:0",
[ 5 ] = "minecraft:stick:0",
[ 6 ] = "storagedrawers:basicDrawers:0:b85f006d9f6aa0e06184f8931d4e85c1",
[ 7 ] = "minecraft:stick:0",
},
count = 2,
},
}

22
etc/recipes/tconstruct.db Normal file
View File

@@ -0,0 +1,22 @@
{
[ "minecraft:book:0" ] = {
ingredients = {
"minecraft:paper:0",
"minecraft:paper:0",
"minecraft:paper:0",
[ 5 ] = "minecraft:string:0",
[ 6 ] = "tconstruct:pattern:0",
[ 7 ] = "tconstruct:pattern:0",
},
count = 1,
},
[ "tconstruct:pattern:0" ] = {
ingredients = {
"minecraft:planks:0",
"minecraft:stick:0",
[ 5 ] = "minecraft:stick:0",
[ 6 ] = "minecraft:planks:0",
},
count = 4,
},
}

View File

@@ -1 +1 @@
turtle.abortAction() turtle.abort(true)

View File

@@ -1,12 +1,15 @@
local os = _G.os
local turtle = _G.turtle
local function follow(id) local function follow(id)
requireInjector(getfenv(1)) _G.requireInjector()
local Event = require('event') local Event = require('event')
local Point = require('point') local Point = require('point')
local Socket = require('socket') local Socket = require('socket')
turtle.status = 'follow ' .. id turtle.setStatus('follow ' .. id)
if not turtle.enableGPS() then if not turtle.enableGPS() then
error('turtle: No GPS found') error('turtle: No GPS found')
@@ -55,7 +58,7 @@ local function follow(id)
Event.onInterval(.5, function() Event.onInterval(.5, function()
local function getRemotePoint() local function getRemotePoint()
if not turtle.abort then if not turtle.isAborted() then
if socket:write({ type = 'gps' }) then if socket:write({ type = 'gps' }) then
return socket:read(3) return socket:read(3)
end end
@@ -65,7 +68,7 @@ local function follow(id)
-- sometimes gps will fail if moving -- sometimes gps will fail if moving
local pt, d local pt, d
for i = 1, 3 do for _ = 1, 3 do
pt, d = getRemotePoint() pt, d = getRemotePoint()
if pt then if pt then
break break
@@ -73,22 +76,22 @@ local function follow(id)
os.sleep(.5) os.sleep(.5)
end end
if not pt or turtle.abort then if not pt or turtle.isAborted() then
error('Did not receive GPS location') error('Did not receive GPS location')
end end
if not lastPoint or (lastPoint.x ~= pt.x or lastPoint.y ~= pt.y or lastPoint.z ~= pt.z) then if not lastPoint or (lastPoint.x ~= pt.x or lastPoint.y ~= pt.y or lastPoint.z ~= pt.z) then
if following then if following then
turtle.abort = true turtle.getState().abort = true
while following do while following do
os.sleep(.1) os.sleep(.1)
end end
turtle.abort = false turtle.getState().abort = false
end end
-- check if gps is inaccurate (player moving too fast) -- check if gps is inaccurate (player moving too fast)
if d < Point.pythagoreanDistance(turtle.point, pt) + 10 then if d < Point.distance(turtle.point, pt) + 10 then
lastPoint = Point.copy(pt) lastPoint = Point.copy(pt)
following = true following = true
os.queueEvent('turtle_follow', pt) os.queueEvent('turtle_follow', pt)

View File

@@ -1 +1,2 @@
turtle.run(turtle.gotoGPSHome) local Home = require('turtle.home')
turtle.run(Home.go)

View File

@@ -1,85 +0,0 @@
requireInjector(getfenv(1))
local Point = require('point')
local Util = require('util')
local checkedNodes = { }
local nodes = { }
local box = { x = 65, ex = 69, y = 65, ey = 70, z = -23, ez = -19 }
local function inBox(pt, box)
return pt.x >= box.x and
pt.y >= box.y and
pt.z >= box.z and
pt.x <= box.ex and
pt.y <= box.ey and
pt.z <= box.ez
end
local function toKey(pt)
return table.concat({ pt.x, pt.y, pt.z }, ':')
end
local function addNode(node)
for i = 0, 5 do
local hi = turtle.getHeadingInfo(i)
local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd }
if inBox(testNode, box) then
local key = toKey(testNode)
if not checkedNodes[key] then
nodes[key] = testNode
end
end
end
end
local function dig(facing)
local direction = facing
if direction == 'forward' then
direction = turtle.getHeadingInfo(turtle.point.heading).direction
end
local hi = turtle.getHeadingInfo(direction)
local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd }
if inBox(node, box) then
if turtle.getAction(facing).dig() then
addNode(node)
end
end
end
local function level()
repeat
local node = { x = turtle.point.x, y = turtle.point.y, z = turtle.point.z }
local key = toKey(node)
checkedNodes[key] = true
nodes[key] = nil
dig('down')
dig('up')
dig('forward')
print(string.format('%d nodes remaining', Util.size(nodes)))
if Util.size(nodes) == 0 then
break
end
local node = Point.closest(turtle.point, nodes)
if not turtle.gotoPoint(node) then
break
end
until turtle.abort
end
local pt = Util.shallowCopy(turtle.point)
turtle.setPolicy(turtle.policies.none)
if turtle.pathfind({ x = 65, y = 70, z = -23 }) then
--turtle.reset()
turtle.setPolicy(turtle.policies.digOnly)
level()
end
turtle.pathfind(pt)
--local s, m = turtle.run(level)

View File

@@ -1,8 +1,11 @@
requireInjector(getfenv(1)) _G.requireInjector()
local Point = require('point') local Point = require('point')
local Util = require('util') local Util = require('util')
local os = _G.os
local turtle = _G.turtle
local checkedNodes, nodes local checkedNodes, nodes
local function addNode(node) local function addNode(node)
@@ -47,7 +50,7 @@ local function findObsidian()
if turtle.getItemCount(16) > 0 then if turtle.getItemCount(16) > 0 then
print('Inventory full') print('Inventory full')
print('Enter to continue...') print('Enter to continue...')
read() _G.read()
end end
if b and b.name == 'minecraft:obsidian' then if b and b.name == 'minecraft:obsidian' then
@@ -63,40 +66,43 @@ local function findObsidian()
break break
end end
local node = Point.closest(turtle.point, nodes) node = Point.closest(turtle.point, nodes)
if not turtle.gotoPoint(node) then if not turtle._goto(node) then
break break
end end
until turtle.abort until turtle.isAborted()
end end
turtle.reset() turtle.run(function()
turtle.setPolicy(turtle.policies.digOnly) turtle.reset()
local s, m = turtle.run(function() turtle.setPolicy(turtle.policies.digOnly)
repeat
checkedNodes = { } local s, m = pcall(function()
nodes = { } repeat
checkedNodes = { }
nodes = { }
local _,b = turtle.inspectDown() local _,b = turtle.inspectDown()
if not b or b.name ~= 'minecraft:obsidian' then if not b or b.name ~= 'minecraft:obsidian' then
break break
end end
findObsidian() findObsidian()
if not turtle.select('minecraft:water_bucket') then if not turtle.select('minecraft:water_bucket') then
break break
end end
turtle.goto(0, 0) turtle._goto({ x = 0, z = 0 })
turtle.placeDown() turtle.placeDown()
os.sleep(2) os.sleep(2)
turtle.placeDown() turtle.placeDown()
turtle.down() turtle.down()
turtle.select(1) turtle.select(1)
until turtle.abort until turtle.isAborted()
end)
if not s and m then
error(m)
end
turtle._goto({ x = 0, y = 0, z = 0, heading = 0 })
end) end)
turtle.goto(0, 0, 0, 0)
turtle.reset()
if not s and m then
error(m)
end

View File

@@ -1 +1,2 @@
turtle.run(turtle.setGPSHome) local Home = require('turtle.home')
turtle.run(Home.set)

View File

@@ -6,7 +6,7 @@ local function summon(id)
local Point = require('point') local Point = require('point')
local Socket = require('socket') local Socket = require('socket')
turtle.status = 'GPSing' turtle.setStatus('GPSing')
turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 }) turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 })
local pts = { local pts = {
@@ -32,7 +32,7 @@ local function summon(id)
local function doGPS() local function doGPS()
tFixes = { } tFixes = { }
for i = 1, 4 do for i = 1, 4 do
if not turtle.gotoPoint(pts[i]) then if not turtle._goto(pts[i]) then
error('turtle: Unable to perform GPS maneuver') error('turtle: Unable to perform GPS maneuver')
end end
local distance = getDistance() local distance = getDistance()
@@ -64,7 +64,7 @@ local function summon(id)
local pt = { x = pos.x, y = pos.y, z = pos.z } local pt = { x = pos.x, y = pos.y, z = pos.z }
local _, h = Point.calculateMoves(turtle.getPoint(), pt) local _, h = Point.calculateMoves(turtle.getPoint(), pt)
local hi = turtle.getHeadingInfo(h) local hi = turtle.getHeadingInfo(h)
turtle.status = 'recalling' turtle.setStatus('recalling')
turtle.pathfind({ x = pt.x - hi.xd, z = pt.z - hi.zd, y = pt.y - hi.yd, heading = h }) turtle.pathfind({ x = pt.x - hi.xd, z = pt.z - hi.zd, y = pt.y - hi.yd, heading = h })
else else
error("turtle: Could not determine position") error("turtle: Could not determine position")