Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4cf76b8e8 | ||
|
|
44932ac515 | ||
|
|
f2b9efc80f | ||
|
|
c48243eae5 | ||
|
|
45bbc72fc3 | ||
|
|
aa50b55ab1 | ||
|
|
85c5f542a8 | ||
|
|
863b7ff600 | ||
|
|
0ce537d4ce | ||
|
|
73dc16703a | ||
|
|
f6fb6a4433 | ||
|
|
2526308eb6 | ||
|
|
d97a9d7468 | ||
|
|
9939c75fc3 | ||
|
|
77107e1d57 | ||
|
|
a2f452dc90 | ||
|
|
e0cac06c2a | ||
|
|
5e80591160 | ||
|
|
c057f98830 | ||
|
|
11a005969c | ||
|
|
6a1f72f957 | ||
|
|
3622518b20 | ||
|
|
1eb47cf3c8 | ||
|
|
7892c0dbb7 | ||
|
|
fe79e582cd | ||
|
|
a5c7fde530 | ||
|
|
c04ec356e5 | ||
|
|
194e6f0a91 | ||
|
|
d0c8d2dc4f | ||
|
|
728cda2215 | ||
|
|
1f31f7ef40 | ||
|
|
3734afed92 | ||
|
|
5232b5a115 | ||
|
|
f5dede540e | ||
|
|
980c635037 | ||
|
|
ed2d6eeef1 | ||
|
|
bba7841c43 | ||
|
|
8ef97df223 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/etc/fstab
|
||||
/etc/recipes2.db
|
||||
|
||||
@@ -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/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 --]]--
|
||||
local blockDB = TableDB()
|
||||
|
||||
function blockDB:load()
|
||||
|
||||
local blocks = JSON.decodeFromFile('usr/etc/blocks.json')
|
||||
|
||||
if not blocks then
|
||||
@@ -85,19 +53,6 @@ end
|
||||
local placementDB = TableDB()
|
||||
|
||||
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
|
||||
if v.place then
|
||||
local bt = btDB.data[v.place]
|
||||
@@ -113,7 +68,6 @@ function placementDB:load2(sbDB, btDB)
|
||||
self:addSubsForBlockType(155, 2, btDB.data['quartz-pillar'])
|
||||
end
|
||||
|
||||
|
||||
function placementDB:addSubsForBlockType(id, dmg, bt)
|
||||
for _,sub in pairs(bt) do
|
||||
local odmg = sub.odmg
|
||||
@@ -178,7 +132,6 @@ function blockTypeDB:addTemp(blockType, subs)
|
||||
end
|
||||
|
||||
function blockTypeDB:load()
|
||||
|
||||
blockTypeDB:addTemp('stairs', {
|
||||
{ 0, nil, 0, 'east-up' },
|
||||
{ 1, nil, 0, 'west-up' },
|
||||
@@ -564,20 +517,17 @@ end
|
||||
|
||||
local Blocks = class()
|
||||
function Blocks:init(args)
|
||||
|
||||
Util.merge(self, args)
|
||||
self.blockDB = blockDB
|
||||
self.nameDB = nameDB
|
||||
|
||||
blockDB:load()
|
||||
blockTypeDB:load()
|
||||
nameDB:load(self.dir, blockDB)
|
||||
placementDB:load2(blockDB, blockTypeDB)
|
||||
placementDB:load(blockDB, blockTypeDB)
|
||||
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)
|
||||
|
||||
local p = placementDB:get({id, dmg})
|
||||
if p then
|
||||
return Util.shallowCopy(p)
|
||||
101
apis/builder/builder.lua
Normal file
101
apis/builder/builder.lua
Normal 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
84
apis/builder/commands.lua
Normal 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
|
||||
@@ -1,9 +1,17 @@
|
||||
local class = require('class')
|
||||
local Util = require('util')
|
||||
local DEFLATE = require('deflatelua')
|
||||
local UI = require('ui')
|
||||
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
|
||||
--]]
|
||||
@@ -11,8 +19,54 @@ local Point = require('point')
|
||||
local schematicMagic = 0x0a00
|
||||
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()
|
||||
function Schematic:init(args)
|
||||
function Schematic:init()
|
||||
self.blocks = { }
|
||||
self.damages = { }
|
||||
self.originalBlocks = { }
|
||||
@@ -48,7 +102,7 @@ function Schematic:readname(h)
|
||||
local n = n1*256 + n2
|
||||
|
||||
local str = ""
|
||||
for i=1,n do
|
||||
for _=1,n do
|
||||
local c = h:readbyte(h)
|
||||
if c == nil then
|
||||
return
|
||||
@@ -218,11 +272,11 @@ function DiskFile:close()
|
||||
end
|
||||
|
||||
local MemoryFile = class()
|
||||
function MemoryFile:init(args)
|
||||
function MemoryFile:init()
|
||||
self.s = { }
|
||||
self.i = 1
|
||||
end
|
||||
function MemoryFile:open(filename)
|
||||
function MemoryFile:open()
|
||||
self.i = 1
|
||||
end
|
||||
function MemoryFile:close() end
|
||||
@@ -247,7 +301,7 @@ function Schematic:decompress(ifname, spinner)
|
||||
local mh = MemoryFile()
|
||||
|
||||
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,
|
||||
disable_crc=true
|
||||
})
|
||||
@@ -276,7 +330,7 @@ function Schematic:loadpass(fh, spinner)
|
||||
|
||||
fh:close()
|
||||
|
||||
print('Assigning coords ')
|
||||
spinner.text = 'Assigning coords '
|
||||
local index = 1
|
||||
for _, b in ipairs(self.blocks) do
|
||||
while index < b.index do
|
||||
@@ -309,11 +363,10 @@ function Schematic:loadpass(fh, spinner)
|
||||
end
|
||||
|
||||
function Schematic:load(filename)
|
||||
|
||||
local cursorX, cursorY = term.getCursorPos()
|
||||
local spinner = UI.Spinner({
|
||||
x = UI.term.width,
|
||||
y = cursorY - 1
|
||||
local _, cy = term.getCursorPos()
|
||||
local spinner = Spinner({
|
||||
x = 1,
|
||||
y = cy,
|
||||
})
|
||||
local f
|
||||
|
||||
@@ -322,7 +375,7 @@ function Schematic:load(filename)
|
||||
filename = originalFile .. '.uncompressed'
|
||||
|
||||
if not fs.exists(filename) then
|
||||
print('Decompressing')
|
||||
spinner.text = 'Decompressing'
|
||||
f = self:decompress(originalFile, spinner)
|
||||
end
|
||||
end
|
||||
@@ -335,7 +388,7 @@ function Schematic:load(filename)
|
||||
|
||||
self:checkFileType(f)
|
||||
|
||||
print('Loading blocks ')
|
||||
spinner.text = 'Loading blocks '
|
||||
self:loadpass(f, spinner)
|
||||
|
||||
self.rowIndex = { }
|
||||
@@ -352,7 +405,7 @@ function Schematic:load(filename)
|
||||
end
|
||||
|
||||
function Schematic:assignDamages(spinner)
|
||||
print('Assigning damages')
|
||||
spinner.text = 'Assigning damages'
|
||||
|
||||
for _,b in pairs(self.blocks) do
|
||||
b.dmg = self.damages[b.index] or 0
|
||||
@@ -382,7 +435,7 @@ function Schematic:findIndexAt(x, z, y, allBlocks)
|
||||
end
|
||||
|
||||
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)
|
||||
if index then
|
||||
return self.blocks[index] -- could be better
|
||||
@@ -416,10 +469,10 @@ function Schematic:bestSide(b, chains, ...)
|
||||
local blocks = { }
|
||||
|
||||
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)
|
||||
if not sb then
|
||||
b.heading = turtle.getHeadingInfo(d).heading
|
||||
b.heading = getHeadingInfo(d).heading
|
||||
b.direction = d .. '-block'
|
||||
return
|
||||
end
|
||||
@@ -476,7 +529,7 @@ function Schematic:bestFlipSide(b, chains)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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 }, -- 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
|
||||
|
||||
@@ -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 })
|
||||
|
||||
b.direction = side1 .. '-block'
|
||||
b.heading = turtle.getHeadingInfo(side1).heading
|
||||
b.heading = getHeadingInfo(side1).heading
|
||||
|
||||
if b == lb then
|
||||
break
|
||||
@@ -550,7 +603,7 @@ function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
|
||||
local ub = self:findBlockAtSide(fb, 'down')
|
||||
if not ub then
|
||||
fb.direction = side1 .. '-block'
|
||||
fb.heading = turtle.getHeadingInfo(side1).heading
|
||||
fb.heading = getHeadingInfo(side1).heading
|
||||
else
|
||||
fb.direction = od
|
||||
end
|
||||
@@ -564,7 +617,7 @@ function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
|
||||
local ub = self:findBlockAtSide(lb, 'down')
|
||||
if not ub then
|
||||
lb.direction = side1 .. '-block'
|
||||
lb.heading = turtle.getHeadingInfo(side1).heading
|
||||
lb.heading = getHeadingInfo(side1).heading
|
||||
else
|
||||
fb.direction = od
|
||||
end
|
||||
@@ -581,7 +634,7 @@ function Schematic:determineBlockPlacement(y)
|
||||
|
||||
print('Processing level ' .. y)
|
||||
|
||||
local spinner = UI.Spinner({
|
||||
local spinner = Spinner({
|
||||
x = 1,
|
||||
spinSymbols = { 'o.....', '.o....', '..o...', '...o..', '....o.', '.....o' }
|
||||
})
|
||||
@@ -709,12 +762,12 @@ function Schematic:determineBlockPlacement(y)
|
||||
spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ')
|
||||
|
||||
if directions[d] then
|
||||
b.heading = turtle.getHeadingInfo(directions[d]).heading
|
||||
b.heading = getHeadingInfo(directions[d]).heading
|
||||
end
|
||||
|
||||
if doorDirections[d] then
|
||||
|
||||
local hi = turtle.getHeadingInfo(doorDirections[d])
|
||||
local hi = getHeadingInfo(doorDirections[d])
|
||||
b.heading = hi.heading
|
||||
|
||||
self:addPlacementChain(chains, {
|
||||
@@ -726,9 +779,9 @@ function Schematic:determineBlockPlacement(y)
|
||||
if stairDownDirections[d] then
|
||||
if not self:findIndexAt(b.x, b.z, b.y-1) then
|
||||
b.direction = stairDownDirections[b.direction]
|
||||
b.heading = turtle.getHeadingInfo(b.direction).heading
|
||||
b.heading = getHeadingInfo(b.direction).heading
|
||||
else
|
||||
b.heading = turtle.getHeadingInfo(stairDownDirections[b.direction]).heading
|
||||
b.heading = getHeadingInfo(stairDownDirections[b.direction]).heading
|
||||
end
|
||||
end
|
||||
|
||||
@@ -767,7 +820,7 @@ function Schematic:determineBlockPlacement(y)
|
||||
if self:findIndexAt(b.x, b.z, b.y-1) then
|
||||
-- there's a block below
|
||||
b.direction = sd[1]
|
||||
b.heading = turtle.getHeadingInfo(b.direction).heading
|
||||
b.heading = getHeadingInfo(b.direction).heading
|
||||
else
|
||||
local _,pb = self:findIndexAt(b.x + sd[3], b.z + sd[4], b.y)
|
||||
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
|
||||
b.direction = sd[2]
|
||||
else
|
||||
b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4
|
||||
b.heading = (getHeadingInfo(sd[1]).heading + 2) % 4
|
||||
end
|
||||
end
|
||||
elseif flipDirections[d] then
|
||||
@@ -784,7 +837,7 @@ function Schematic:determineBlockPlacement(y)
|
||||
|
||||
if blockDirections[d] then
|
||||
-- placing a block from the side
|
||||
local hi = turtle.getHeadingInfo(blockDirections[d])
|
||||
local hi = getHeadingInfo(blockDirections[d])
|
||||
b.heading = hi.heading
|
||||
self:addPlacementChain(chains, {
|
||||
{ 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
|
||||
function Schematic:setPlacementOrder(spinner, placementChains)
|
||||
|
||||
local cursorX, cursorY = term.getCursorPos()
|
||||
|
||||
-- optimize for overlapping check
|
||||
for _,chain in pairs(placementChains) do
|
||||
for index,_ in pairs(chain.keys) do
|
||||
@@ -1040,8 +1091,6 @@ v.info = 'Unplaceable'
|
||||
end
|
||||
|
||||
term.clearLine()
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
function Schematic:optimizeRoute(spinner, y)
|
||||
@@ -1115,8 +1164,8 @@ function Schematic:optimizeRoute(spinner, y)
|
||||
return block
|
||||
end
|
||||
|
||||
local pt = Util.shallowCopy(self.cache[y - 1] or turtle.point)
|
||||
local t = {}
|
||||
local pt = Util.shallowCopy(self.cache[y - 1] or { x = -1, y = 0, z = -1, heading = 0 })
|
||||
local t = { }
|
||||
local ri = self.rowIndex[y]
|
||||
local blockCount = ri.e - ri.s + 1
|
||||
|
||||
@@ -1146,7 +1195,6 @@ function Schematic:optimizeRoute(spinner, y)
|
||||
|
||||
local maxDistance = self.width*self.length
|
||||
local plane, doors = extractPlane(y)
|
||||
spinner:spin(percent)
|
||||
pt.index = 0
|
||||
for i = 1, #plane do
|
||||
local b = getNearestNeighbor(plane, pt, maxDistance)
|
||||
1248
apis/builder/turtle.lua
Normal file
1248
apis/builder/turtle.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ local function safeString(text)
|
||||
|
||||
local newText = {}
|
||||
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
|
||||
end
|
||||
return string.char(unpack(newText))
|
||||
@@ -86,13 +86,12 @@ function ChestAdapter:listItems(throttle)
|
||||
if not entry then
|
||||
self.cache[key] = v
|
||||
|
||||
local ikey = { v.name, v.damage, v.nbtHash }
|
||||
if not itemDB:get(ikey) then
|
||||
if not itemDB:get(v) then
|
||||
local t = { }
|
||||
for _,k in pairs(keys) do
|
||||
t[k] = v[k]
|
||||
end
|
||||
itemDB:add(ikey, t)
|
||||
itemDB:add(t)
|
||||
end
|
||||
else
|
||||
entry.count = entry.count + v.count
|
||||
@@ -110,11 +109,10 @@ function ChestAdapter:getItemInfo(item)
|
||||
return self.cache[key]
|
||||
end
|
||||
|
||||
function ChestAdapter:craft(id, dmg, qty)
|
||||
return false
|
||||
function ChestAdapter:craft()
|
||||
end
|
||||
|
||||
function ChestAdapter:craftItems(items)
|
||||
function ChestAdapter:craftItems()
|
||||
end
|
||||
|
||||
function ChestAdapter:provide(item, qty, slot, direction)
|
||||
@@ -144,7 +142,7 @@ end
|
||||
function ChestAdapter:insert(slot, qty)
|
||||
local s, m = pcall(function() self.pullItem(self.direction, slot, qty) end)
|
||||
if not s and m then
|
||||
sleep(1)
|
||||
os.sleep(1)
|
||||
pcall(function() self.pullItem(self.direction, slot, qty) end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,28 +5,23 @@ local Peripheral = require('peripheral')
|
||||
|
||||
local ChestAdapter = class()
|
||||
|
||||
local keys = Util.transpose({
|
||||
'damage',
|
||||
'displayName',
|
||||
'maxCount',
|
||||
'maxDamage',
|
||||
'name',
|
||||
'nbtHash',
|
||||
})
|
||||
|
||||
function ChestAdapter:init(args)
|
||||
local defaults = {
|
||||
name = 'chest',
|
||||
direction = 'up',
|
||||
wrapSide = 'bottom',
|
||||
name = 'chest',
|
||||
}
|
||||
Util.merge(self, defaults)
|
||||
Util.merge(self, args)
|
||||
|
||||
local chest = Peripheral.getBySide(self.wrapSide)
|
||||
if not chest then
|
||||
local chest
|
||||
if not self.side then
|
||||
chest = Peripheral.getByMethod('list')
|
||||
else
|
||||
chest = Peripheral.getBySide(self.side)
|
||||
if chest and not chest.list then
|
||||
chest = nil
|
||||
end
|
||||
end
|
||||
|
||||
if chest then
|
||||
Util.merge(self, chest)
|
||||
end
|
||||
@@ -37,30 +32,19 @@ function ChestAdapter:isValid()
|
||||
end
|
||||
|
||||
function ChestAdapter:getCachedItemDetails(item, k)
|
||||
local key = { item.name, item.damage, item.nbtHash }
|
||||
|
||||
local detail = itemDB:get(key)
|
||||
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)
|
||||
local cached = itemDB:get(item)
|
||||
if cached then
|
||||
return cached
|
||||
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
|
||||
|
||||
return itemDB:add(detail)
|
||||
end
|
||||
|
||||
function ChestAdapter:refresh(throttle)
|
||||
@@ -69,33 +53,38 @@ end
|
||||
|
||||
-- provide a consolidated list of items
|
||||
function ChestAdapter:listItems(throttle)
|
||||
self.cache = { }
|
||||
local cache = { }
|
||||
local items = { }
|
||||
|
||||
throttle = throttle or Util.throttle()
|
||||
|
||||
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]
|
||||
if not entry then
|
||||
entry = self:getCachedItemDetails(v, k)
|
||||
if entry then
|
||||
local entry = cache[key]
|
||||
if not entry then
|
||||
entry = self:getCachedItemDetails(v, k)
|
||||
if not entry then
|
||||
return -- Inventory has changed
|
||||
end
|
||||
entry = Util.shallowCopy(entry)
|
||||
entry.count = 0
|
||||
self.cache[key] = entry
|
||||
cache[key] = entry
|
||||
table.insert(items, entry)
|
||||
end
|
||||
end
|
||||
|
||||
if entry then
|
||||
entry.count = entry.count + v.count
|
||||
if entry then
|
||||
entry.count = entry.count + v.count
|
||||
end
|
||||
throttle()
|
||||
end
|
||||
throttle()
|
||||
end
|
||||
|
||||
itemDB:flush()
|
||||
|
||||
return items
|
||||
if not Util.empty(items) then
|
||||
self.cache = cache
|
||||
return items
|
||||
end
|
||||
end
|
||||
|
||||
function ChestAdapter:getItemInfo(item)
|
||||
@@ -106,34 +95,68 @@ function ChestAdapter:getItemInfo(item)
|
||||
return self.cache[key]
|
||||
end
|
||||
|
||||
function ChestAdapter:craft(name, damage, qty)
|
||||
function ChestAdapter:craft()
|
||||
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
|
||||
|
||||
function ChestAdapter:provide(item, qty, slot, direction)
|
||||
local stacks = self.list()
|
||||
for key,stack in pairs(stacks) do
|
||||
if stack.name == item.name and stack.damage == item.damage then
|
||||
local amount = math.min(qty, stack.count)
|
||||
if amount > 0 then
|
||||
self.pushItems(direction or self.direction, key, amount, slot)
|
||||
end
|
||||
qty = qty - amount
|
||||
if qty <= 0 then
|
||||
break
|
||||
local s, m = pcall(function()
|
||||
local stacks = self.list()
|
||||
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(qty, stack.count)
|
||||
if amount > 0 then
|
||||
self.pushItems(direction or self.direction, key, amount, slot)
|
||||
end
|
||||
qty = qty - amount
|
||||
if qty <= 0 then
|
||||
break
|
||||
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
|
||||
|
||||
function ChestAdapter:extract(slot, qty, toSlot)
|
||||
self.pushItems(self.direction, slot, qty, toSlot)
|
||||
end
|
||||
|
||||
function ChestAdapter:insert(slot, qty)
|
||||
self.pullItems(self.direction, slot, qty)
|
||||
function ChestAdapter:insert(slot, qty, toSlot)
|
||||
self.pullItems(self.direction, slot, qty, toSlot)
|
||||
end
|
||||
|
||||
return ChestAdapter
|
||||
|
||||
18
apis/controllerAdapter.lua
Normal file
18
apis/controllerAdapter.lua
Normal 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
52
apis/inventoryAdapter.lua
Normal 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
|
||||
137
apis/itemDB.lua
137
apis/itemDB.lua
@@ -4,73 +4,165 @@ local Util = require('util')
|
||||
|
||||
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 { }
|
||||
|
||||
local t = Util.split(key, '(.-):')
|
||||
if #t[#t] > 8 then
|
||||
item.nbtHash = table.remove(t)
|
||||
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, ':')
|
||||
|
||||
return item
|
||||
end
|
||||
|
||||
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
|
||||
return item
|
||||
end
|
||||
|
||||
if key[2] ~= 0 then
|
||||
item = TableDB.get(self, { key[1], 0, key[3] })
|
||||
if item and item.maxDamage > 0 then
|
||||
-- try finding an item that has damage values
|
||||
if type(key.damage) == 'number' then
|
||||
item = TableDB.get(self, makeKey({ name = key.name, nbtHash = key.nbtHash }))
|
||||
if item and item.maxDamage then
|
||||
item = Util.shallowCopy(item)
|
||||
item.damage = key[2]
|
||||
item.displayName = string.format('%s (damage: %d)', item.displayName, item.damage)
|
||||
item.damage = key.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
|
||||
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
|
||||
key = { key[1], 0, key[3] }
|
||||
nItem.displayName = safeString(baseItem.displayName)
|
||||
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
|
||||
TableDB.add(self, key, item)
|
||||
end
|
||||
|
||||
function itemDB:makeKey(item)
|
||||
return { item.name, item.damage, item.nbtHash }
|
||||
TableDB.add(self, makeKey(nItem), nItem)
|
||||
nItem = Util.shallowCopy(nItem)
|
||||
nItem.damage = baseItem.damage
|
||||
nItem.nbtHash = baseItem.nbtHash
|
||||
|
||||
return nItem
|
||||
end
|
||||
|
||||
-- Accepts: "minecraft:stick:0" or { name = 'minecraft:stick', damage = 0 }
|
||||
function itemDB:getName(item)
|
||||
|
||||
if type(item) == 'string' then
|
||||
item = splitKey(item)
|
||||
item = self:splitKey(item)
|
||||
end
|
||||
|
||||
local detail = self:get(self:makeKey(item))
|
||||
local detail = self:get(item)
|
||||
if detail then
|
||||
return detail.displayName
|
||||
end
|
||||
|
||||
-- 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
|
||||
|
||||
function itemDB:load()
|
||||
|
||||
TableDB.load(self)
|
||||
|
||||
for key,item in pairs(self.data) do
|
||||
splitKey(key, item)
|
||||
self:splitKey(key, item)
|
||||
item.maxDamage = item.maxDamage or 0
|
||||
item.maxCount = item.maxCount or 64
|
||||
end
|
||||
@@ -85,6 +177,7 @@ function itemDB:flush()
|
||||
v.name = nil
|
||||
v.damage = nil
|
||||
v.nbtHash = nil
|
||||
v.count = nil -- wipe out previously saved counts - temporary
|
||||
if v.maxDamage == 0 then
|
||||
v.maxDamage = nil
|
||||
end
|
||||
|
||||
@@ -3,7 +3,8 @@ local itemDB = require('itemDB')
|
||||
local Peripheral = require('peripheral')
|
||||
local Util = require('util')
|
||||
|
||||
local MEAdapter = class()
|
||||
local os = _G.os
|
||||
local peripheral = _G.peripheral
|
||||
|
||||
local convertNames = {
|
||||
name = 'id',
|
||||
@@ -31,7 +32,7 @@ local function safeString(text)
|
||||
|
||||
local newText = {}
|
||||
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
|
||||
end
|
||||
return string.char(unpack(newText))
|
||||
@@ -48,29 +49,31 @@ local function convertItem(item)
|
||||
item.displayName = safeString(item.displayName)
|
||||
end
|
||||
|
||||
local MEAdapter = class()
|
||||
|
||||
function MEAdapter:init(args)
|
||||
local defaults = {
|
||||
items = { },
|
||||
name = 'ME',
|
||||
jobList = { },
|
||||
direction = 'up',
|
||||
wrapSide = 'bottom',
|
||||
auto = false,
|
||||
}
|
||||
Util.merge(self, defaults)
|
||||
Util.merge(self, args)
|
||||
|
||||
if self.auto then
|
||||
local mep = Peripheral.getByMethod('getAvailableItems')
|
||||
if mep then
|
||||
Util.merge(self, mep)
|
||||
end
|
||||
local chest
|
||||
|
||||
if not self.side then
|
||||
chest = Peripheral.getByMethod('getAvailableItems')
|
||||
else
|
||||
local mep = peripheral.wrap(self.wrapSide)
|
||||
if mep then
|
||||
Util.merge(self, mep)
|
||||
chest = Peripheral.getBySide(self.side)
|
||||
if chest and not chest.getAvailableItems then
|
||||
chest = nil
|
||||
end
|
||||
end
|
||||
|
||||
if chest then
|
||||
Util.merge(self, chest)
|
||||
end
|
||||
end
|
||||
|
||||
function MEAdapter:isValid()
|
||||
@@ -84,13 +87,8 @@ function MEAdapter:refresh()
|
||||
Util.merge(v, v.item)
|
||||
convertItem(v)
|
||||
|
||||
local key = { v.name, v.damage, v.nbtHash }
|
||||
if not itemDB:get(key) then
|
||||
local t = { }
|
||||
for _,k in pairs(keys) do
|
||||
t[k] = v[k]
|
||||
end
|
||||
itemDB:add(key, t)
|
||||
if not itemDB:get(v) then
|
||||
itemDB:add(v, v)
|
||||
end
|
||||
end
|
||||
itemDB:flush()
|
||||
@@ -104,7 +102,7 @@ function MEAdapter:listItems()
|
||||
end
|
||||
|
||||
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
|
||||
return i
|
||||
end
|
||||
@@ -133,7 +131,7 @@ function MEAdapter:craft(item, count)
|
||||
|
||||
self:refresh()
|
||||
|
||||
local item = self:getItemInfo(item)
|
||||
item = self:getItemInfo(item)
|
||||
if item and item.is_craftable then
|
||||
|
||||
local cpus = self.getCraftingCPUs() or { }
|
||||
@@ -220,7 +218,7 @@ function MEAdapter:provide(item, count, slot, direction)
|
||||
return pcall(function()
|
||||
while count > 0 do
|
||||
local qty = math.min(count, 64)
|
||||
local s, m = self.exportItem({
|
||||
local s = self.exportItem({
|
||||
id = item.name,
|
||||
dmg = item.damage
|
||||
}, direction or self.direction, qty, slot)
|
||||
@@ -236,14 +234,10 @@ end
|
||||
function MEAdapter:insert(slot, count)
|
||||
local s, m = pcall(function() self.pullItem(self.direction, slot, count) end)
|
||||
if not s and m then
|
||||
print('MEAdapter:pullItem')
|
||||
print(m)
|
||||
sleep(1)
|
||||
os.sleep(1)
|
||||
s, m = pcall(function() self.pullItem(self.direction, slot, count) end)
|
||||
if not s and m then
|
||||
print('MEAdapter:pullItem')
|
||||
print(m)
|
||||
read()
|
||||
error(m)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ function nameDB:load()
|
||||
end
|
||||
|
||||
for strId, block in pairs(blocks) do
|
||||
local strId = 'minecraft:' .. strId
|
||||
strId = 'minecraft:' .. strId
|
||||
if type(block.name) == 'string' then
|
||||
self.data[strId .. ':0'] = block.name
|
||||
else
|
||||
|
||||
@@ -18,11 +18,22 @@ function RefinedAdapter:init(args)
|
||||
local defaults = {
|
||||
items = { },
|
||||
name = 'refinedStorage',
|
||||
direction = 'up',
|
||||
wrapSide = 'bottom',
|
||||
}
|
||||
Util.merge(self, defaults)
|
||||
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
|
||||
Util.merge(self, controller)
|
||||
end
|
||||
@@ -37,9 +48,7 @@ function RefinedAdapter:isOnline()
|
||||
end
|
||||
|
||||
function RefinedAdapter:getCachedItemDetails(item)
|
||||
local key = { item.name, item.damage, item.nbtHash }
|
||||
|
||||
local detail = itemDB:get(key)
|
||||
local detail = itemDB:get(item)
|
||||
if not detail then
|
||||
detail = self.findItem(item)
|
||||
if detail then
|
||||
@@ -56,7 +65,7 @@ function RefinedAdapter:getCachedItemDetails(item)
|
||||
end
|
||||
|
||||
detail = t
|
||||
itemDB:add(key, detail)
|
||||
itemDB:add(detail)
|
||||
end
|
||||
end
|
||||
if detail then
|
||||
@@ -91,10 +100,7 @@ function RefinedAdapter:listItems()
|
||||
end
|
||||
|
||||
function RefinedAdapter:getItemInfo(fingerprint)
|
||||
|
||||
local key = { fingerprint.name, fingerprint.damage, fingerprint.nbtHash }
|
||||
|
||||
local item = itemDB:get(key)
|
||||
local item = itemDB:get(fingerprint)
|
||||
if not item then
|
||||
return self:getCachedItemDetails(fingerprint)
|
||||
end
|
||||
@@ -125,18 +131,18 @@ function RefinedAdapter:craft(item, qty)
|
||||
end
|
||||
end
|
||||
|
||||
function RefinedAdapter:craftItems(items)
|
||||
function RefinedAdapter:craftItems()
|
||||
return false
|
||||
end
|
||||
|
||||
function RefinedAdapter:provide(item, qty, slot)
|
||||
function RefinedAdapter:provide()
|
||||
end
|
||||
|
||||
function RefinedAdapter:extract(slot, qty)
|
||||
function RefinedAdapter:extract()
|
||||
-- self.pushItems(self.direction, slot, qty)
|
||||
end
|
||||
|
||||
function RefinedAdapter:insert(slot, qty)
|
||||
function RefinedAdapter:insert()
|
||||
-- self.pullItems(self.direction, slot, qty)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
local itemDB = require('itemDB')
|
||||
local Util = require('util')
|
||||
|
||||
local fs = _G.fs
|
||||
local turtle = _G.turtle
|
||||
|
||||
local RECIPES_DIR = 'usr/etc/recipes'
|
||||
|
||||
local Craft = { }
|
||||
|
||||
local function clearGrid(inventoryAdapter)
|
||||
@@ -9,6 +14,7 @@ local function clearGrid(inventoryAdapter)
|
||||
if count > 0 then
|
||||
inventoryAdapter:insert(i, count)
|
||||
if turtle.getItemCount(i) ~= 0 then
|
||||
-- inventory is possibly full
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -27,27 +33,44 @@ local function splitKey(key)
|
||||
return item
|
||||
end
|
||||
|
||||
local function getItemCount(items, key)
|
||||
local item = splitKey(key)
|
||||
function Craft.getItemCount(items, item)
|
||||
if type(item) == 'string' then
|
||||
item = splitKey(item)
|
||||
end
|
||||
|
||||
local count = 0
|
||||
for _,v in pairs(items) do
|
||||
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
|
||||
return v.count
|
||||
if item.damage then
|
||||
return v.count
|
||||
end
|
||||
count = count + v.count
|
||||
end
|
||||
end
|
||||
return 0
|
||||
return count
|
||||
end
|
||||
|
||||
local function turtleCraft(recipe, qty, inventoryAdapter)
|
||||
|
||||
clearGrid(inventoryAdapter)
|
||||
if not clearGrid(inventoryAdapter) then
|
||||
return false
|
||||
end
|
||||
|
||||
for k,v in pairs(recipe.ingredients) do
|
||||
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
|
||||
-- FIX: ingredients cannot be stacked
|
||||
--debug('failed ' .. v .. ' - ' .. provideQty)
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -55,65 +78,166 @@ local function turtleCraft(recipe, qty, inventoryAdapter)
|
||||
return turtle.craft()
|
||||
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)
|
||||
if type(recipe) == 'string' then
|
||||
recipe = Craft.recipes[recipe]
|
||||
if not recipe then
|
||||
return 0, 'No recipe'
|
||||
end
|
||||
end
|
||||
|
||||
local items = inventoryAdapter:listItems()
|
||||
|
||||
local function sumItems(items)
|
||||
-- produces { ['minecraft:planks:0'] = 8 }
|
||||
local t = {}
|
||||
for _,item in pairs(items) do
|
||||
t[item] = (t[item] or 0) + 1
|
||||
end
|
||||
return t
|
||||
if not items then
|
||||
return 0, 'Inventory changed'
|
||||
end
|
||||
|
||||
count = math.ceil(count / recipe.count)
|
||||
|
||||
local maxCount = recipe.maxCount or math.floor(64 / recipe.count)
|
||||
local summedItems = sumItems(recipe.ingredients)
|
||||
|
||||
for key,icount in pairs(summedItems) do
|
||||
local itemCount = getItemCount(items, key)
|
||||
for key,icount in pairs(Craft.sumIngredients(recipe)) do
|
||||
local itemCount = Craft.getItemCount(items, key)
|
||||
if itemCount < icount * count then
|
||||
local irecipe = Craft.recipes[key]
|
||||
if irecipe then
|
||||
--Util.print('Crafting %d %s', icount * count - itemCount, key)
|
||||
if not Craft.craftRecipe(irecipe,
|
||||
icount * count - itemCount,
|
||||
inventoryAdapter) then
|
||||
local iqty = icount * count - itemCount
|
||||
local crafted = Craft.craftRecipe(irecipe, iqty, inventoryAdapter)
|
||||
if crafted ~= iqty then
|
||||
|
||||
turtle.select(1)
|
||||
return
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local crafted = 0
|
||||
repeat
|
||||
if not turtleCraft(recipe, math.min(count, maxCount), inventoryAdapter) then
|
||||
turtle.select(1)
|
||||
return false
|
||||
break
|
||||
end
|
||||
crafted = crafted + math.min(count, maxCount)
|
||||
count = count - maxCount
|
||||
until count <= 0
|
||||
|
||||
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
|
||||
|
||||
-- given a certain quantity, return how many of those can be crafted
|
||||
function Craft.getCraftableAmount(recipe, count, items, missing)
|
||||
|
||||
local function sumItems(recipe, items, summedItems, count)
|
||||
|
||||
local function sumItems(recipe, summedItems, count)
|
||||
local canCraft = 0
|
||||
|
||||
for i = 1, count do
|
||||
for _ = 1, count 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]
|
||||
if irecipe and summedItem <= 0 then
|
||||
summedItem = summedItem + sumItems(irecipe, items, summedItems, 1)
|
||||
summedItem = summedItem + sumItems(irecipe, summedItems, 1)
|
||||
end
|
||||
if summedItem <= 0 then
|
||||
if missing then
|
||||
@@ -121,7 +245,9 @@ function Craft.getCraftableAmount(recipe, count, items, missing)
|
||||
end
|
||||
return canCraft
|
||||
end
|
||||
summedItems[item] = summedItem - 1
|
||||
if not recipe.craftingTools or not recipe.craftingTools[item] then
|
||||
summedItems[item] = summedItem - 1
|
||||
end
|
||||
end
|
||||
canCraft = canCraft + recipe.count
|
||||
end
|
||||
@@ -129,7 +255,7 @@ function Craft.getCraftableAmount(recipe, count, items, missing)
|
||||
return canCraft
|
||||
end
|
||||
|
||||
return sumItems(recipe, items, { }, math.ceil(count / recipe.count), missing)
|
||||
return sumItems(recipe, { }, math.ceil(count / recipe.count))
|
||||
end
|
||||
|
||||
function Craft.canCraft(item, count, items)
|
||||
@@ -148,13 +274,15 @@ function Craft.getCraftableAmountTest()
|
||||
{ name = 'minecraft:planks', damage = 0, count = 5 },
|
||||
{ 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 = {
|
||||
{ name = 'minecraft:log', damage = 0, 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
|
||||
end
|
||||
@@ -166,4 +294,6 @@ function Craft.craftRecipeTest(name, count)
|
||||
return { Craft.craftRecipe(Craft.recipes[name], count, chestAdapter) }
|
||||
end
|
||||
|
||||
Craft.loadRecipes()
|
||||
|
||||
return Craft
|
||||
|
||||
67
apis/turtle/crafting.lua
Normal file
67
apis/turtle/crafting.lua
Normal 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
42
apis/turtle/home.lua
Normal 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
|
||||
@@ -1,6 +1,8 @@
|
||||
local Point = require('point')
|
||||
local Util = require('util')
|
||||
|
||||
local turtle = _G.turtle
|
||||
|
||||
local checkedNodes = { }
|
||||
local nodes = { }
|
||||
local box = { }
|
||||
@@ -11,7 +13,6 @@ local function toKey(pt)
|
||||
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 }
|
||||
@@ -26,7 +27,6 @@ local function addNode(node)
|
||||
end
|
||||
|
||||
local function dig(action)
|
||||
|
||||
local directions = {
|
||||
top = 'up',
|
||||
bottom = 'down',
|
||||
@@ -75,7 +75,7 @@ end
|
||||
-- find the closest block
|
||||
-- * favor same plane
|
||||
-- * going backwards only if the dest is above or below
|
||||
function closestPoint(reference, pts)
|
||||
local function closestPoint(reference, pts)
|
||||
local lpt, lm -- lowest
|
||||
for _,pt in pairs(pts) do
|
||||
local m = Point.turtleDistance(reference, pt)
|
||||
@@ -113,8 +113,7 @@ local function getAdjacentPoint(pt)
|
||||
return closestPoint(turtle.getPoint(), t)
|
||||
end
|
||||
|
||||
return function(startPt, endPt, firstPt, verbose)
|
||||
|
||||
function turtle.level(startPt, endPt, firstPt, verbose)
|
||||
checkedNodes = { }
|
||||
nodes = { }
|
||||
box = { }
|
||||
@@ -126,6 +125,10 @@ return function(startPt, endPt, firstPt, verbose)
|
||||
box.ey = math.max(startPt.y, endPt.y)
|
||||
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
|
||||
error('failed to reach starting point')
|
||||
end
|
||||
@@ -155,11 +158,13 @@ return function(startPt, endPt, firstPt, verbose)
|
||||
|
||||
local node = closestPoint(turtle.point, nodes)
|
||||
node = getAdjacentPoint(node)
|
||||
if not turtle.gotoPoint(node) then
|
||||
if not turtle._goto(node) then
|
||||
break
|
||||
end
|
||||
until turtle.abort
|
||||
until turtle.isAborted()
|
||||
|
||||
turtle.resetState()
|
||||
turtle.setMoveCallback(oldCallback)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Ansi = require('ansi')
|
||||
local Config = require('config')
|
||||
local SHA1 = require('sha1')
|
||||
local UI = require('ui')
|
||||
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'
|
||||
|
||||
|
||||
-- FIX SOMEDAY
|
||||
function os.registerApp(app, key)
|
||||
local function registerApp(app, key)
|
||||
|
||||
app.key = SHA1.sha1(key)
|
||||
Util.writeTable(fs.combine(REGISTRY_DIR, app.key), app)
|
||||
os.queueEvent('os_register_app')
|
||||
end
|
||||
|
||||
function os.unregisterApp(key)
|
||||
local function unregisterApp(key)
|
||||
|
||||
local filename = fs.combine(REGISTRY_DIR, SHA1.sha1(key))
|
||||
if fs.exists(filename) then
|
||||
@@ -29,7 +32,7 @@ function os.unregisterApp(key)
|
||||
end
|
||||
|
||||
|
||||
local sandboxEnv = Util.shallowCopy(getfenv(1))
|
||||
local sandboxEnv = Util.shallowCopy(_ENV)
|
||||
setmetatable(sandboxEnv, { __index = _G })
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'App Store')
|
||||
@@ -56,7 +59,7 @@ local sources = {
|
||||
|
||||
shell.setDir(APP_DIR)
|
||||
|
||||
function downloadApp(app)
|
||||
local function downloadApp(app)
|
||||
local h
|
||||
|
||||
if type(app.url) == "table" then
|
||||
@@ -72,7 +75,7 @@ function downloadApp(app)
|
||||
end
|
||||
end
|
||||
|
||||
function runApp(app, checkExists, ...)
|
||||
local function runApp(app, checkExists, ...)
|
||||
|
||||
local path, fn
|
||||
local args = { ... }
|
||||
@@ -173,29 +176,27 @@ local getSourceListing = function(source)
|
||||
end
|
||||
end
|
||||
|
||||
local appPage = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
showBackButton = not pocket,
|
||||
local appPage = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
-- showBackButton = not pocket,
|
||||
buttons = {
|
||||
{ text = '\027', event = 'back' },
|
||||
{ text = 'Install', event = 'install' },
|
||||
{ text = 'Run', event = 'run' },
|
||||
{ text = 'View', event = 'view' },
|
||||
{ text = 'Remove', event = 'uninstall', name = 'removeButton' },
|
||||
},
|
||||
}),
|
||||
container = UI.Window({
|
||||
x = 2,
|
||||
y = 3,
|
||||
height = UI.term.height - 3,
|
||||
width = UI.term.width - 2,
|
||||
viewport = UI.ViewportWindow(),
|
||||
}),
|
||||
},
|
||||
container = UI.Window {
|
||||
x = 2, y = 3, ex = -2, ey = -3,
|
||||
viewport = UI.Viewport(),
|
||||
},
|
||||
notification = UI.Notification(),
|
||||
accelerators = {
|
||||
q = 'back',
|
||||
backspace = 'back',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function appPage.container.viewport:draw()
|
||||
local app = self.parent.parent.app
|
||||
@@ -245,7 +246,7 @@ function appPage:eventHandler(event)
|
||||
|
||||
elseif event.type == 'uninstall' then
|
||||
if self.app.runOnly then
|
||||
s,m = runApp(self.app, false, 'uninstall')
|
||||
runApp(self.app, false, 'uninstall')
|
||||
else
|
||||
fs.delete(fs.combine(APP_DIR, self.app.name))
|
||||
self.notification:success("Uninstalled " .. self.app.name, 3)
|
||||
@@ -253,7 +254,7 @@ function appPage:eventHandler(event)
|
||||
self.menuBar.removeButton:disable('Remove')
|
||||
self.menuBar:draw()
|
||||
|
||||
os.unregisterApp(self.app.creator .. '.' .. self.app.name)
|
||||
unregisterApp(self.app.creator .. '.' .. self.app.name)
|
||||
end
|
||||
|
||||
elseif event.type == 'install' then
|
||||
@@ -277,7 +278,7 @@ function appPage:eventHandler(event)
|
||||
category = 'Games'
|
||||
end
|
||||
|
||||
os.registerApp({
|
||||
registerApp({
|
||||
run = fs.combine(APP_DIR, self.app.name),
|
||||
title = self.app.title,
|
||||
category = category,
|
||||
@@ -293,35 +294,30 @@ function appPage:eventHandler(event)
|
||||
return true
|
||||
end
|
||||
|
||||
local categoryPage = UI.Page({
|
||||
menuBar = UI.MenuBar({
|
||||
local categoryPage = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
buttons = {
|
||||
{ text = 'Catalog', event = 'dropdown', dropdown = 'sourceMenu' },
|
||||
{ text = 'Category', event = 'dropdown', dropdown = 'categoryMenu' },
|
||||
{ text = 'Catalog', dropdown = sources },
|
||||
{ text = 'Category', name = 'categoryButton', dropdown = { } },
|
||||
},
|
||||
}),
|
||||
sourceMenu = UI.DropMenu({
|
||||
buttons = sources,
|
||||
}),
|
||||
grid = UI.ScrollingGrid({
|
||||
y = 2,
|
||||
height = UI.term.height - 2,
|
||||
},
|
||||
grid = UI.ScrollingGrid {
|
||||
y = 2, ey = -2,
|
||||
columns = {
|
||||
{ heading = 'Title', key = 'title' },
|
||||
},
|
||||
sortColumn = 'title',
|
||||
autospace = true,
|
||||
}),
|
||||
},
|
||||
statusBar = UI.StatusBar(),
|
||||
accelerators = {
|
||||
l = 'lua',
|
||||
q = 'quit',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function categoryPage:setCategory(source, name, index)
|
||||
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
|
||||
table.insert(self.grid.values, v)
|
||||
end
|
||||
@@ -359,19 +355,17 @@ function categoryPage:setSource(source)
|
||||
end
|
||||
|
||||
source.categoryMenu = UI.DropMenu({
|
||||
y = 2,
|
||||
x = 1,
|
||||
buttons = buttons,
|
||||
})
|
||||
source.index, source.name = Util.first(source.storeCatagoryNames)
|
||||
|
||||
categoryPage:add({
|
||||
categoryPage.menuBar.categoryButton:add({
|
||||
categoryMenu = source.categoryMenu
|
||||
})
|
||||
end
|
||||
|
||||
self.source = source
|
||||
self.categoryMenu = source.categoryMenu
|
||||
self.menuBar.categoryButton.dropmenu = source.categoryMenu
|
||||
categoryPage:setCategory(source, source.name, source.index)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
||||
local multishell = _ENV.multishell
|
||||
local os = _G.os
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Events')
|
||||
UI:configure('Events', ...)
|
||||
|
||||
@@ -123,7 +126,7 @@ Event.addRoutine(function()
|
||||
p4 = e[5],
|
||||
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)
|
||||
end
|
||||
page.grid:update()
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Ansi = require('ansi')
|
||||
local Event = require('event')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
||||
local colors = _G.colors
|
||||
local multishell = _ENV.multishell
|
||||
local peripheral = _G.peripheral
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Devices')
|
||||
|
||||
--[[ -- PeripheralsPage -- ]] --
|
||||
local peripheralsPage = UI.Page {
|
||||
grid = UI.ScrollingGrid {
|
||||
ey = -2,
|
||||
columns = {
|
||||
{ heading = 'Type', key = 'type' },
|
||||
{ heading = 'Side', key = 'side' },
|
||||
},
|
||||
sortColumn = 'type',
|
||||
height = UI.term.height - 1,
|
||||
autospace = true,
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
status = 'Select peripheral'
|
||||
values = 'Select peripheral',
|
||||
},
|
||||
accelerators = {
|
||||
q = 'quit',
|
||||
@@ -60,16 +65,17 @@ end
|
||||
|
||||
--[[ -- MethodsPage -- ]] --
|
||||
local methodsPage = UI.Page {
|
||||
backgroundColor = colors.black,
|
||||
doc = UI.TextArea {
|
||||
backgroundColor = colors.black,
|
||||
x = 2, y = 2, ex = -1, ey = -7,
|
||||
},
|
||||
grid = UI.ScrollingGrid {
|
||||
y = -6, ey = -2,
|
||||
columns = {
|
||||
{ heading = 'Name', key = 'name', width = UI.term.width }
|
||||
},
|
||||
sortColumn = 'name',
|
||||
height = 7,
|
||||
},
|
||||
viewportConsole = UI.ViewportWindow {
|
||||
y = 8,
|
||||
height = UI.term.height - 8,
|
||||
},
|
||||
statusBar = UI.StatusBar {
|
||||
status = 'q to return',
|
||||
@@ -84,8 +90,9 @@ function methodsPage:enable(p)
|
||||
|
||||
self.peripheral = p or self.peripheral
|
||||
|
||||
local p = peripheral.wrap(self.peripheral.side)
|
||||
p = peripheral.wrap(self.peripheral.side)
|
||||
if p.getDocs then
|
||||
-- plethora
|
||||
self.grid.values = { }
|
||||
for k,v in pairs(p.getDocs()) do
|
||||
table.insert(self.grid.values, {
|
||||
@@ -94,27 +101,31 @@ function methodsPage:enable(p)
|
||||
})
|
||||
end
|
||||
elseif not p.getAdvancedMethodsData then
|
||||
-- computercraft
|
||||
self.grid.values = { }
|
||||
for name,f in pairs(p) do
|
||||
for name in pairs(p) do
|
||||
table.insert(self.grid.values, {
|
||||
name = name,
|
||||
noext = true,
|
||||
})
|
||||
end
|
||||
else
|
||||
-- open peripherals
|
||||
self.grid.values = p.getAdvancedMethodsData()
|
||||
for name,f in pairs(self.grid.values) do
|
||||
f.name = name
|
||||
end
|
||||
end
|
||||
|
||||
self.viewportConsole.offy = 0
|
||||
|
||||
self.grid:update()
|
||||
self.grid:setIndex(1)
|
||||
|
||||
self.doc:setText(self:getDocumentation())
|
||||
|
||||
self.statusBar:setStatus(self.peripheral.type)
|
||||
UI.Page.enable(self)
|
||||
|
||||
self:setFocus(self.grid)
|
||||
end
|
||||
|
||||
function methodsPage:eventHandler(event)
|
||||
@@ -122,82 +133,62 @@ function methodsPage:eventHandler(event)
|
||||
UI:setPage(peripheralsPage)
|
||||
return true
|
||||
elseif event.type == 'grid_focus_row' then
|
||||
self.viewportConsole.offy = 0
|
||||
self.viewportConsole:draw()
|
||||
self.doc:setText(self:getDocumentation())
|
||||
end
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
|
||||
function methodsPage.viewportConsole:draw()
|
||||
local c = self
|
||||
local method = methodsPage.grid:getSelected()
|
||||
function methodsPage:getDocumentation()
|
||||
|
||||
c:clear()
|
||||
c:setCursorPos(1, 1)
|
||||
local method = self.grid:getSelected()
|
||||
|
||||
if method.noext then
|
||||
c.cursorY = 2
|
||||
c:print('No extended Information')
|
||||
return 2
|
||||
if method.noext then -- computercraft docs
|
||||
return 'No documentation'
|
||||
end
|
||||
|
||||
if method.doc then
|
||||
c:print(method.doc, nil, colors.yellow)
|
||||
c.ymax = c.cursorY + 1
|
||||
return
|
||||
if method.doc then -- plethora docs
|
||||
return Ansi.yellow .. method.doc
|
||||
end
|
||||
|
||||
-- open peripherals docs
|
||||
local sb = { }
|
||||
if method.description then
|
||||
c:print(method.description)
|
||||
table.insert(sb, method.description .. '\n\n')
|
||||
end
|
||||
|
||||
c.cursorY = c.cursorY + 2
|
||||
c.cursorX = 1
|
||||
|
||||
if method.returnTypes ~= '()' then
|
||||
c:print(method.returnTypes .. ' ', nil, colors.yellow)
|
||||
table.insert(sb, Ansi.yellow .. method.returnTypes .. ' ')
|
||||
end
|
||||
c:print(method.name, nil, colors.black)
|
||||
c:print('(')
|
||||
|
||||
local maxArgLen = 1
|
||||
table.insert(sb, Ansi.blue .. method.name .. Ansi.reset .. '(')
|
||||
|
||||
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
|
||||
argName = string.format('[%s]', arg.name)
|
||||
fg = colors.orange
|
||||
table.insert(sb, Ansi.orange .. string.format('[%s]', arg.name))
|
||||
else
|
||||
table.insert(sb, Ansi.green .. arg.name)
|
||||
end
|
||||
c:print(argName, nil, fg)
|
||||
if k < #method.args then
|
||||
c:print(', ')
|
||||
table.insert(sb, ',')
|
||||
end
|
||||
end
|
||||
c:print(')')
|
||||
|
||||
c.cursorY = c.cursorY + 1
|
||||
table.insert(sb, Ansi.reset .. ')')
|
||||
|
||||
Util.filterInplace(method.args, function(a) return #a.description > 0 end)
|
||||
if #method.args > 0 then
|
||||
for _,arg in ipairs(method.args) do
|
||||
if #arg.description > 0 then
|
||||
c.cursorY = c.cursorY + 1
|
||||
c.cursorX = 1
|
||||
local fg = colors.green
|
||||
if arg.optional then
|
||||
fg = colors.orange
|
||||
end
|
||||
c:print(arg.name .. ': ', nil, fg)
|
||||
c.cursorX = maxArgLen + 3
|
||||
c:print(arg.description, nil, nil, maxArgLen + 3)
|
||||
table.insert(sb, '\n\n')
|
||||
for k,arg in ipairs(method.args) do
|
||||
if arg.optional then
|
||||
table.insert(sb, Ansi.orange)
|
||||
else
|
||||
table.insert(sb, Ansi.green)
|
||||
end
|
||||
table.insert(sb, arg.name .. Ansi.reset .. ': ' .. arg.description)
|
||||
if k ~= #method.args then
|
||||
table.insert(sb, '\n\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
c.ymax = c.cursorY + 1
|
||||
return table.concat(sb)
|
||||
end
|
||||
|
||||
Event.on('peripheral', function()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Config = require('config')
|
||||
local Event = require('event')
|
||||
@@ -6,6 +6,12 @@ local Socket = require('socket')
|
||||
local UI = require('ui')
|
||||
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 SCRIPTS_PATH = 'usr/etc/scripts'
|
||||
|
||||
@@ -26,7 +32,7 @@ if UI.term.width % 2 ~= 0 then
|
||||
width = width + 1
|
||||
end
|
||||
|
||||
function processVariables(script)
|
||||
local function processVariables(script)
|
||||
|
||||
local fn = loadstring('return ' .. config.variables)
|
||||
if fn then
|
||||
@@ -40,7 +46,7 @@ function processVariables(script)
|
||||
return script
|
||||
end
|
||||
|
||||
function invokeScript(computer, scriptName)
|
||||
local function invokeScript(computer, scriptName)
|
||||
|
||||
local script = Util.readFile(scriptName)
|
||||
if not script then
|
||||
@@ -74,7 +80,7 @@ function invokeScript(computer, scriptName)
|
||||
socket:close()
|
||||
end
|
||||
|
||||
function runScript(computerOrGroup, scriptName)
|
||||
local function runScript(computerOrGroup, scriptName)
|
||||
if computerOrGroup.id then
|
||||
invokeScript(computerOrGroup, scriptName)
|
||||
else
|
||||
@@ -302,7 +308,6 @@ function editorPage:enable()
|
||||
end
|
||||
|
||||
function editorPage.grid2:draw()
|
||||
|
||||
getActiveComputers(self.values)
|
||||
|
||||
for k in pairs(editorPage.grid1.values) do
|
||||
@@ -314,7 +319,6 @@ function editorPage.grid2:draw()
|
||||
end
|
||||
|
||||
function editorPage:eventHandler(event)
|
||||
|
||||
if event.type == 'back' then
|
||||
UI:setPage(groupsPage)
|
||||
|
||||
@@ -341,18 +345,17 @@ function editorPage:eventHandler(event)
|
||||
end
|
||||
|
||||
local function nameDialog(f)
|
||||
local dialog = UI.Dialog({
|
||||
-- x = (UI.term.width - 28) / 2,
|
||||
local dialog = UI.Dialog {
|
||||
width = 22,
|
||||
height = 6,
|
||||
title = 'Enter Name',
|
||||
form = UI.Form {
|
||||
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
|
||||
local name = self.form.textEntry.value
|
||||
if name then
|
||||
@@ -459,11 +462,6 @@ function mainPage:eventHandler(event)
|
||||
|
||||
elseif event.type == 'toggle' then
|
||||
config.showGroups = not config.showGroups
|
||||
local text = 'Computers'
|
||||
if config.showGroups then
|
||||
text = 'Groups'
|
||||
end
|
||||
-- self.statusBar.toggleButton.text = text
|
||||
self:draw()
|
||||
|
||||
Config.update('script', config)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Config = require('config')
|
||||
local Event = require('event')
|
||||
@@ -8,6 +8,14 @@ local Terminal = require('terminal')
|
||||
local UI = require('ui')
|
||||
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')
|
||||
UI.Button.defaults.focusIndicator = ' '
|
||||
UI:configure('Turtles', ...)
|
||||
@@ -27,15 +35,7 @@ local options = {
|
||||
local SCRIPTS_PATH = 'usr/etc/scripts'
|
||||
|
||||
local nullTerm = Terminal.getNullTerm(term.current())
|
||||
local turtles = { }
|
||||
local socket
|
||||
local policies = {
|
||||
{ label = 'none' },
|
||||
{ label = 'digOnly' },
|
||||
{ label = 'attackOnly' },
|
||||
{ label = 'digAttack' },
|
||||
{ label = 'turtleSafe' },
|
||||
}
|
||||
|
||||
local page = UI.Page {
|
||||
coords = UI.Window {
|
||||
@@ -125,7 +125,8 @@ local page = UI.Page {
|
||||
fn = 'turtle.turnRight',
|
||||
},
|
||||
info = UI.TextArea {
|
||||
x = 2, y = 9
|
||||
x = 2, y = 9,
|
||||
inactive = true,
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -142,7 +143,7 @@ function page:enable(turtle)
|
||||
end
|
||||
|
||||
function page:runFunction(script, nowrap)
|
||||
for i = 1, 2 do
|
||||
for _ = 1, 2 do
|
||||
if not socket then
|
||||
socket = Socket.connect(self.turtle.id, 161)
|
||||
end
|
||||
@@ -210,12 +211,6 @@ function page.tabs.inventory:draw()
|
||||
v.selected = true
|
||||
end
|
||||
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)
|
||||
end
|
||||
end
|
||||
@@ -303,14 +298,6 @@ function page.statusBar:draw()
|
||||
UI.StatusBar.draw(self)
|
||||
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()
|
||||
|
||||
local script = [[
|
||||
@@ -333,6 +320,11 @@ end
|
||||
function page:eventHandler(event)
|
||||
if event.type == 'quit' then
|
||||
UI:exitPullEvents()
|
||||
|
||||
elseif event.type == 'tab_select' then
|
||||
config.tab = event.button.text
|
||||
Config.update('Turtles', config)
|
||||
|
||||
elseif event.type == 'button_press' then
|
||||
if event.button.fn then
|
||||
self:runFunction(event.button.fn, event.button.nowrap)
|
||||
@@ -356,7 +348,7 @@ if not Util.getOptions(options, { ... }, true) then
|
||||
end
|
||||
|
||||
if options.turtle.value >= 0 then
|
||||
for i = 1, 10 do
|
||||
for _ = 1, 10 do
|
||||
page.turtle = _G.network[options.turtle.value]
|
||||
if page.turtle then
|
||||
break
|
||||
@@ -374,18 +366,10 @@ Event.onInterval(1, function()
|
||||
end
|
||||
end)
|
||||
|
||||
UI:setPage(page)
|
||||
|
||||
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])
|
||||
if config.tab then
|
||||
page.tabs.tabBar:selectTab(config.tab)
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
|
||||
UI:pullEvents()
|
||||
|
||||
@@ -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 = { ... }
|
||||
|
||||
|
||||
1639
apps/builder.lua
1639
apps/builder.lua
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
1055
apps/crafter.lua
Normal file
File diff suppressed because it is too large
Load Diff
414
apps/edit.lua
414
apps/edit.lua
@@ -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
|
||||
return fs.complete(text, shell.dir(), true, false)
|
||||
end
|
||||
@@ -17,7 +26,7 @@ if fs.exists(sPath) and fs.isDir(sPath) then
|
||||
end
|
||||
|
||||
if multishell then
|
||||
multishell.setTitle(multishell.getCurrent(), sPath)
|
||||
multishell.setTitle(multishell.getCurrent(), fs.getName(sPath))
|
||||
end
|
||||
|
||||
local x, y = 1, 1
|
||||
@@ -26,43 +35,38 @@ local scrollX = 0
|
||||
local scrollY = 0
|
||||
local lastPos = { x = 1, y = 1 }
|
||||
local tLines = { }
|
||||
local input = { pressed = { } }
|
||||
local bRunning = true
|
||||
local sStatus = ""
|
||||
local isError
|
||||
local fileInfo
|
||||
local lastAction
|
||||
|
||||
local dirty = { y = 1, ey = h }
|
||||
local mark = { anchor, active, continue }
|
||||
local keyboard
|
||||
local mark = { }
|
||||
local searchPattern
|
||||
local undo = { chain = { }, pointer = 0 }
|
||||
local complete = { }
|
||||
local clipboard
|
||||
|
||||
if not clipboard then
|
||||
_G.clipboard = { internal, data }
|
||||
clipboard.shim = true
|
||||
-- do we need a clipboard shim
|
||||
if not multishell or not multishell.hook then -- is this OpusOS ?
|
||||
if _G.clipboard then -- has it been installed already
|
||||
clipboard = _G.clipboard
|
||||
else
|
||||
clipboard = { }
|
||||
|
||||
function clipboard.setData(data)
|
||||
clipboard.data = data
|
||||
if data then
|
||||
clipboard.useInternal(true)
|
||||
function clipboard.setData(data)
|
||||
clipboard.data = data
|
||||
end
|
||||
end
|
||||
|
||||
function clipboard.getText()
|
||||
if clipboard.data then
|
||||
return tostring(clipboard.data)
|
||||
function clipboard.getText()
|
||||
if clipboard.data then
|
||||
return tostring(clipboard.data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function clipboard.isInternal()
|
||||
return clipboard.internal
|
||||
end
|
||||
|
||||
function clipboard.useInternal(mode)
|
||||
if mode ~= clipboard.mode then
|
||||
clipboard.internal = mode
|
||||
end
|
||||
_G.clipboard = clipboard
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,7 +114,7 @@ local keyMapping = {
|
||||
[ 'control-up' ] = 'scroll_up',
|
||||
[ 'scrollDown' ] = 'scroll_down',
|
||||
[ 'control-down' ] = 'scroll_down',
|
||||
[ 'mouse_click' ] = 'goto',
|
||||
[ 'mouse_click' ] = 'go_to',
|
||||
[ 'control-l' ] = 'goto_line',
|
||||
|
||||
-- marking
|
||||
@@ -139,8 +143,7 @@ local keyMapping = {
|
||||
-- copy/paste
|
||||
[ 'control-x' ] = 'cut',
|
||||
[ 'control-c' ] = 'copy',
|
||||
[ 'control-v' ] = 'paste',
|
||||
[ 'control-t' ] = 'toggle_clipboard',
|
||||
[ 'shift-paste' ] = 'paste_internal',
|
||||
|
||||
-- file
|
||||
[ 'control-s' ] = 'save',
|
||||
@@ -155,7 +158,7 @@ local keyMapping = {
|
||||
-- misc
|
||||
[ 'control-g' ] = 'status',
|
||||
[ 'control-r' ] = 'refresh',
|
||||
[ 'leftCtrl' ] = 'menu',
|
||||
[ 'control' ] = 'menu',
|
||||
}
|
||||
|
||||
local messages = {
|
||||
@@ -246,7 +249,7 @@ local function save( _sPath )
|
||||
local function innerSave()
|
||||
file = fs.open( _sPath, "w" )
|
||||
if file then
|
||||
for n, sLine in ipairs( tLines ) do
|
||||
for _,sLine in ipairs( tLines ) do
|
||||
file.write(sLine .. "\n")
|
||||
end
|
||||
else
|
||||
@@ -299,8 +302,8 @@ local function writeHighlighted(sLine, ny)
|
||||
text = '',
|
||||
}
|
||||
|
||||
local function tryWrite(sLine, regex, fgcolor)
|
||||
local match = sLine:match(regex)
|
||||
local function tryWrite(line, regex, fgcolor)
|
||||
local match = line:match(regex)
|
||||
if match then
|
||||
local fg
|
||||
if type(fgcolor) == "string" then
|
||||
@@ -310,7 +313,7 @@ local function writeHighlighted(sLine, ny)
|
||||
end
|
||||
buffer.text = buffer.text .. match
|
||||
buffer.fg = buffer.fg .. string.rep(fg, #match)
|
||||
return sLine:sub(#match + 1)
|
||||
return line:sub(#match + 1)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@@ -388,18 +391,13 @@ local function redraw()
|
||||
end
|
||||
|
||||
if not (w < 32 and #sStatus > 0) then
|
||||
local clipboardIndicator = 'S'
|
||||
if clipboard.isInternal() then
|
||||
clipboardIndicator = 'I'
|
||||
end
|
||||
|
||||
local modifiedIndicator = ' '
|
||||
if undo.chain[1] then
|
||||
modifiedIndicator = '*'
|
||||
end
|
||||
|
||||
local str = string.format(' %d:%d %s%s',
|
||||
y, x, clipboardIndicator, modifiedIndicator)
|
||||
local str = string.format(' %d:%d %s',
|
||||
y, x, modifiedIndicator)
|
||||
term.setTextColor(color.highlightColor)
|
||||
term.setBackgroundColor(colors.gray)
|
||||
term.setCursorPos(w - #str + 1, h)
|
||||
@@ -434,15 +432,15 @@ local function hacky_read()
|
||||
local _oldSetCursorPos = term.setCursorPos
|
||||
local _oldGetCursorPos = term.getCursorPos
|
||||
|
||||
term.setCursorPos = function(x, y)
|
||||
return _oldSetCursorPos(x, h)
|
||||
term.setCursorPos = function(cx)
|
||||
return _oldSetCursorPos(cx, h)
|
||||
end
|
||||
term.getCursorPos = function()
|
||||
local x, y = _oldGetCursorPos()
|
||||
return x, 1
|
||||
local cx = _oldGetCursorPos()
|
||||
return cx, 1
|
||||
end
|
||||
|
||||
local s, m = pcall(function() return read() end)
|
||||
local s, m = pcall(function() return _G.read() end)
|
||||
term.setCursorPos = _oldSetCursorPos
|
||||
term.getCursorPos = _oldGetCursorPos
|
||||
if s then
|
||||
@@ -465,7 +463,7 @@ local __actions = {
|
||||
term.write(prompt)
|
||||
local str = hacky_read()
|
||||
term.setCursorBlink(true)
|
||||
keyboard.shift, keyboard.control = false, false
|
||||
input:reset()
|
||||
term.setCursorPos(x - scrollX, y - scrollY)
|
||||
actions.dirty_line(scrollY + h)
|
||||
return str
|
||||
@@ -485,13 +483,6 @@ local __actions = {
|
||||
addUndo = function(entry)
|
||||
local last = undo.chain[#undo.chain]
|
||||
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.args[3] == entry.args[1] and
|
||||
last.args[4] == entry.args[2] then
|
||||
@@ -512,7 +503,7 @@ local __actions = {
|
||||
end,
|
||||
|
||||
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 nStartPos = sLine:find("[a-zA-Z0-9_%.]+$")
|
||||
if nStartPos then
|
||||
@@ -575,7 +566,7 @@ local __actions = {
|
||||
goto_line = function()
|
||||
local lineNo = tonumber(actions.input('Line: '))
|
||||
if lineNo then
|
||||
actions.goto(1, lineNo)
|
||||
actions.go_to(1, lineNo)
|
||||
else
|
||||
setStatus('Invalid line number')
|
||||
end
|
||||
@@ -593,9 +584,9 @@ local __actions = {
|
||||
if ny < y or ny == y and nx <= x then
|
||||
setStatus(messages.wrapped)
|
||||
end
|
||||
actions.goto(nx, ny)
|
||||
actions.go_to(nx, ny)
|
||||
actions.mark_to(nx + #pattern, ny)
|
||||
actions.goto(nx, ny)
|
||||
actions.go_to(nx, ny)
|
||||
return
|
||||
end
|
||||
sx = 1
|
||||
@@ -625,7 +616,7 @@ local __actions = {
|
||||
if bReadOnly then
|
||||
setError("Access denied")
|
||||
else
|
||||
local ok, err = save(sPath)
|
||||
local ok = save(sPath)
|
||||
if ok then
|
||||
setStatus('"%s" %dL, %dC written',
|
||||
fileInfo.path, #tLines, fs.getSize(fileInfo.abspath))
|
||||
@@ -641,7 +632,7 @@ local __actions = {
|
||||
|
||||
run = function()
|
||||
local sTempPath = "/.temp"
|
||||
local ok, err = save(sTempPath)
|
||||
local ok = save(sTempPath)
|
||||
if ok then
|
||||
local nTask = shell.openTab(sTempPath)
|
||||
if nTask then
|
||||
@@ -732,7 +723,7 @@ local __actions = {
|
||||
|
||||
mark_to = function(nx, ny)
|
||||
actions.mark_begin()
|
||||
actions.goto(nx, ny)
|
||||
actions.go_to(nx, ny)
|
||||
actions.mark_finish()
|
||||
end,
|
||||
|
||||
@@ -795,9 +786,7 @@ local __actions = {
|
||||
actions.dirty_all()
|
||||
end,
|
||||
|
||||
setCursor = function(newX, newY)
|
||||
local oldX, oldY = lastPos.x, lastPos.y
|
||||
|
||||
setCursor = function()
|
||||
lastPos.x = x
|
||||
lastPos.y = y
|
||||
|
||||
@@ -806,27 +795,23 @@ local __actions = {
|
||||
|
||||
if screenX < 1 then
|
||||
scrollX = x - 1
|
||||
screenX = 1
|
||||
actions.dirty_all()
|
||||
elseif screenX > w then
|
||||
scrollX = x - w
|
||||
screenX = w
|
||||
actions.dirty_all()
|
||||
end
|
||||
|
||||
if screenY < 1 then
|
||||
scrollY = y - 1
|
||||
screenY = 1
|
||||
actions.dirty_all()
|
||||
elseif screenY > h - 1 then
|
||||
scrollY = y - (h - 1)
|
||||
screenY = h - 1
|
||||
actions.dirty_all()
|
||||
end
|
||||
end,
|
||||
|
||||
top = function()
|
||||
actions.goto(1, 1)
|
||||
actions.go_to(1, 1)
|
||||
end,
|
||||
|
||||
bottom = function()
|
||||
@@ -856,11 +841,11 @@ local __actions = {
|
||||
end,
|
||||
|
||||
pageUp = function()
|
||||
actions.goto(x, y - (h - 1))
|
||||
actions.go_to(x, y - (h - 1))
|
||||
end,
|
||||
|
||||
pageDown = function()
|
||||
actions.goto(x, y + (h - 1))
|
||||
actions.go_to(x, y + (h - 1))
|
||||
end,
|
||||
|
||||
home = function()
|
||||
@@ -966,7 +951,7 @@ local __actions = {
|
||||
|
||||
local front = tLines[sy]:sub(1, sx - 1)
|
||||
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)
|
||||
end
|
||||
tLines[y] = front .. back
|
||||
@@ -981,18 +966,18 @@ local __actions = {
|
||||
local count = 0
|
||||
local lines = { }
|
||||
|
||||
for y = csy, cey do
|
||||
local line = tLines[y]
|
||||
for cy = csy, cey do
|
||||
local line = tLines[cy]
|
||||
if line then
|
||||
local x = 1
|
||||
local cx = 1
|
||||
local ex = #line
|
||||
if y == csy then
|
||||
x = csx
|
||||
if cy == csy then
|
||||
cx = csx
|
||||
end
|
||||
if y == cey then
|
||||
if cy == cey then
|
||||
ex = cex - 1
|
||||
end
|
||||
local str = line:sub(x, ex)
|
||||
local str = line:sub(cx, ex)
|
||||
count = count + #str
|
||||
table.insert(lines, str)
|
||||
end
|
||||
@@ -1041,23 +1026,14 @@ local __actions = {
|
||||
actions.insertText(x, y, ch)
|
||||
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()
|
||||
local text, size =
|
||||
actions.copyText(mark.x, mark.y, mark.ex, mark.ey)
|
||||
clipboard.setData(text)
|
||||
setStatus('%d chars copied', size)
|
||||
clipboard.useInternal(true)
|
||||
local text = actions.copyText(mark.x, mark.y, mark.ex, mark.ey)
|
||||
if clipboard then
|
||||
clipboard.setData(text)
|
||||
else
|
||||
os.queueEvent('clipboard_copy', text)
|
||||
end
|
||||
setStatus('shift-^v to paste')
|
||||
end,
|
||||
|
||||
cut = function()
|
||||
@@ -1078,9 +1054,6 @@ local __actions = {
|
||||
if mark.active then
|
||||
actions.delete()
|
||||
end
|
||||
if clipboard.isInternal() then
|
||||
text = clipboard.getText()
|
||||
end
|
||||
if text then
|
||||
actions.insertText(x, y, text)
|
||||
setStatus('%d chars added', #text)
|
||||
@@ -1089,7 +1062,13 @@ local __actions = {
|
||||
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)
|
||||
x = math.min(math.max(cx, 1), #tLines[y] + 1)
|
||||
end,
|
||||
@@ -1114,116 +1093,158 @@ local __actions = {
|
||||
|
||||
actions = __actions
|
||||
|
||||
-- Actual program functionality begins
|
||||
load(sPath)
|
||||
local modifiers = {
|
||||
[ keys.leftCtrl ] = true,
|
||||
[ keys.rightCtrl ] = true,
|
||||
[ keys.leftShift ] = true,
|
||||
[ keys.rightShift ] = true,
|
||||
[ keys.leftAlt ] = true,
|
||||
[ keys.rightAlt ] = true,
|
||||
}
|
||||
|
||||
term.setCursorBlink(true)
|
||||
redraw()
|
||||
function input:modifierPressed()
|
||||
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
|
||||
keyboard = { control, shift, combo }
|
||||
function input:toCode(ch, code)
|
||||
local result = { }
|
||||
|
||||
function keyboard:translate(event, code)
|
||||
if event == 'key' then
|
||||
local ch = keys.getName(code)
|
||||
if ch then
|
||||
if self.pressed[keys.leftCtrl] or self.pressed[keys.rightCtrl] then
|
||||
table.insert(result, 'control')
|
||||
end
|
||||
|
||||
if code == keys.leftCtrl or code == keys.rightCtrl then
|
||||
self.control = true
|
||||
self.combo = false
|
||||
return
|
||||
end
|
||||
if self.pressed[keys.leftAlt] or self.pressed[keys.rightAlt] then
|
||||
table.insert(result, 'alt')
|
||||
end
|
||||
|
||||
if code == keys.leftShift or code == keys.rightShift then
|
||||
self.shift = true
|
||||
self.combo = false
|
||||
return
|
||||
end
|
||||
|
||||
if self.shift then
|
||||
if #ch > 1 then
|
||||
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
|
||||
if self.pressed[keys.leftShift] or self.pressed[keys.rightShift] then
|
||||
if code and modifiers[code] then
|
||||
table.insert(result, 'shift')
|
||||
elseif #ch == 1 then
|
||||
table.insert(result, ch:upper())
|
||||
else
|
||||
table.insert(result, 'shift')
|
||||
table.insert(result, ch)
|
||||
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
|
||||
|
||||
load(sPath)
|
||||
term.setCursorBlink(true)
|
||||
redraw()
|
||||
|
||||
while bRunning do
|
||||
local sEvent, param, param2, param3 = os.pullEventRaw()
|
||||
local action
|
||||
|
||||
if sEvent == 'terminate' then
|
||||
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
|
||||
local ch = keyboard:translate(sEvent, param)
|
||||
if ch then
|
||||
action = keyMapping[ch]
|
||||
param = param2 + scrollX
|
||||
@@ -1231,9 +1252,14 @@ while bRunning do
|
||||
end
|
||||
end
|
||||
else
|
||||
local ch = keyboard:translate(sEvent, param)
|
||||
local ch = input:translate(sEvent, param, param2)
|
||||
if ch then
|
||||
action = keyMapping[ch]
|
||||
if #ch == 1 then
|
||||
action = keyMapping.char
|
||||
param = ch
|
||||
else
|
||||
action = keyMapping[ch]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1247,7 +1273,7 @@ while bRunning do
|
||||
|
||||
actions[action](param, param2)
|
||||
if action ~= 'menu' then
|
||||
keyboard.lastAction = action
|
||||
lastAction = action
|
||||
end
|
||||
|
||||
if x ~= lastPos.x or y ~= lastPos.y then
|
||||
|
||||
376
apps/levelEmitter.lua
Normal file
376
apps/levelEmitter.lua
Normal 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()
|
||||
@@ -36,6 +36,31 @@ elseif device.monitor then
|
||||
})
|
||||
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()
|
||||
|
||||
function getClient(id)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Terminal = require('terminal')
|
||||
|
||||
local shell = _ENV.shell
|
||||
local term = _G.term
|
||||
|
||||
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
|
||||
error('mirror: Invalid device')
|
||||
end
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local Logger = require('logger')
|
||||
local Socket = require('socket')
|
||||
local Terminal = require('terminal')
|
||||
local Util = require('util')
|
||||
|
||||
local multishell = _ENV.multishell
|
||||
local os = _G.os
|
||||
|
||||
Logger.setScreenLogging()
|
||||
|
||||
local remoteId
|
||||
@@ -14,7 +16,7 @@ if #args == 1 then
|
||||
remoteId = tonumber(args[1])
|
||||
else
|
||||
print('Enter host ID')
|
||||
remoteId = tonumber(read())
|
||||
remoteId = tonumber(_G.read())
|
||||
end
|
||||
|
||||
if not remoteId then
|
||||
@@ -70,7 +72,7 @@ while true do
|
||||
while true do
|
||||
local e = Event.pullEvent()
|
||||
if e[1] == 'terminate' then
|
||||
break
|
||||
break
|
||||
end
|
||||
if not socket.connected then
|
||||
break
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local Logger = require('logger')
|
||||
local Socket = require('socket')
|
||||
|
||||
local colors = _G.colors
|
||||
local term = _G.term
|
||||
|
||||
Logger.setScreenLogging()
|
||||
|
||||
local mon = term.current()
|
||||
local args = { ... }
|
||||
if args[1] then
|
||||
mon = device[args[1]]
|
||||
mon = _G.device[args[1]]
|
||||
end
|
||||
|
||||
if not mon then
|
||||
@@ -36,13 +39,6 @@ while true do
|
||||
end
|
||||
end)
|
||||
|
||||
-- ensure socket is connected
|
||||
Event.onInterval(3, function(h)
|
||||
if not socket:ping() then
|
||||
Event.off(h)
|
||||
end
|
||||
end)
|
||||
|
||||
while true do
|
||||
Event.pullEvent()
|
||||
if not socket.connected then
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
require = requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
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')
|
||||
|
||||
if not turtle then
|
||||
error('This program can only be run on a turtle')
|
||||
end
|
||||
|
||||
local radio = device.drive or error('No drive attached')
|
||||
if radio.side ~= 'top' and radio.side ~= 'bottom' then
|
||||
error('Disk drive must be above or below turtle')
|
||||
end
|
||||
|
||||
if not turtle then
|
||||
error('This program can only be run on a turtle')
|
||||
end
|
||||
|
||||
UI:configure('Music', ...)
|
||||
|
||||
local monitor = UI.term
|
||||
|
||||
UI.Button.defaults.backgroundFocusColor = colors.gray
|
||||
|
||||
local page = UI.Page({
|
||||
@@ -146,7 +150,7 @@ function page:eventHandler(event)
|
||||
end
|
||||
end
|
||||
|
||||
function page:setVolume(volume, displayOnly)
|
||||
function page:setVolume(volume)
|
||||
volume = math.min(volume, 15)
|
||||
volume = math.max(volume, 1)
|
||||
self.volume = volume
|
||||
@@ -248,9 +252,9 @@ page:setVolume(page.volume, true)
|
||||
|
||||
UI:setPage(page)
|
||||
|
||||
turtle.status = 'Jamming'
|
||||
turtle.setStatus('Jamming')
|
||||
UI:pullEvents()
|
||||
turtle.status = 'idle'
|
||||
turtle.setStatus('idle')
|
||||
page:play(false)
|
||||
|
||||
UI.term:reset()
|
||||
|
||||
24
apps/mwm.lua
24
apps/mwm.lua
@@ -1,9 +1,17 @@
|
||||
local injector = requireInjector or load(http.get('https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis/injector.lua').readAll())()
|
||||
injector(getfenv(1))
|
||||
local injector = _G.requireInjector or load(http.get('https://raw.githubusercontent.com/kepler155c/opus/develop/sys/apis/injector.lua').readAll())()
|
||||
injector()
|
||||
|
||||
local Canvas = require('ui.canvas')
|
||||
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()
|
||||
printError('Syntax:')
|
||||
error('mwm sessionName [monitor]')
|
||||
@@ -14,11 +22,11 @@ local UID = 0
|
||||
local multishell = { }
|
||||
local processes = { }
|
||||
local parentTerm = term.current()
|
||||
local sessionFile = args[1] or syntax()
|
||||
local sessionFile = args[1] or 'usr/config/mwm'
|
||||
local running
|
||||
local monitor
|
||||
|
||||
local defaultEnv = Util.shallowCopy(getfenv(1))
|
||||
local defaultEnv = Util.shallowCopy(_ENV)
|
||||
defaultEnv.multishell = multishell
|
||||
|
||||
if args[2] then
|
||||
@@ -356,7 +364,7 @@ function multishell.removeProcess(process)
|
||||
redraw()
|
||||
end
|
||||
|
||||
function multishell.saveSession(sessionFile)
|
||||
function multishell.saveSession(filename)
|
||||
local t = { }
|
||||
for _,process in pairs(processes) do
|
||||
if process.path and not process.isShell then
|
||||
@@ -370,11 +378,11 @@ function multishell.saveSession(sessionFile)
|
||||
})
|
||||
end
|
||||
end
|
||||
Util.writeTable(sessionFile, t)
|
||||
Util.writeTable(filename, t)
|
||||
end
|
||||
|
||||
function multishell.loadSession(sessionFile)
|
||||
local config = Util.readTable(sessionFile)
|
||||
function multishell.loadSession(filename)
|
||||
local config = Util.readTable(filename)
|
||||
if config then
|
||||
for _,v in pairs(config) do
|
||||
multishell.openTab(v)
|
||||
|
||||
113
apps/pickup.lua
113
apps/pickup.lua
@@ -1,12 +1,17 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local GPS = require('gps')
|
||||
local ChestAdapter = require('chestAdapter18')
|
||||
local Point = require('point')
|
||||
local Socket = require('socket')
|
||||
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
|
||||
error('Modem is required')
|
||||
end
|
||||
@@ -35,7 +40,7 @@ local fuel = {
|
||||
|
||||
local slots
|
||||
|
||||
turtle.setMoveCallback(function(action, pt)
|
||||
turtle.setMoveCallback(function()
|
||||
if slots then
|
||||
for _,slot in pairs(slots) do
|
||||
if turtle.getItemCount(slot.index) ~= slot.qty then
|
||||
@@ -46,10 +51,38 @@ turtle.setMoveCallback(function(action, pt)
|
||||
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
|
||||
print('refueling')
|
||||
turtle.status = 'refueling'
|
||||
turtle.setStatus('refueling')
|
||||
gotoPoint(locations.dropPt, true)
|
||||
dropOff(locations.dropPt)
|
||||
local chestAdapter = ChestAdapter({
|
||||
@@ -66,8 +99,8 @@ function refuel()
|
||||
end
|
||||
end
|
||||
|
||||
function pickUp(pt)
|
||||
turtle.status = 'picking up'
|
||||
local function pickUp(pt)
|
||||
turtle.setStatus('picking up')
|
||||
gotoPoint(pt, true)
|
||||
while true do
|
||||
if not turtle.selectOpenSlot() then
|
||||
@@ -81,41 +114,13 @@ function pickUp(pt)
|
||||
end
|
||||
end
|
||||
|
||||
function dropOff(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)
|
||||
local function checkCell(pt)
|
||||
if not turtle.selectOpenSlot() then
|
||||
dropOff(locations.dropPt)
|
||||
end
|
||||
|
||||
print('checking cell')
|
||||
turtle.status = 'recharging'
|
||||
turtle.setStatus('recharging')
|
||||
gotoPoint(pt, true)
|
||||
local c = peripheral.wrap('bottom')
|
||||
local energy = c.getMaxEnergyStored() -
|
||||
@@ -136,9 +141,9 @@ function checkCell(pt)
|
||||
end
|
||||
end
|
||||
|
||||
function fluid(points)
|
||||
local function fluid(points)
|
||||
print('checking fluid')
|
||||
turtle.status = 'fluiding'
|
||||
turtle.setStatus('fluiding')
|
||||
gotoPoint(points.source, true)
|
||||
turtle.select(1)
|
||||
turtle.digDown()
|
||||
@@ -152,10 +157,10 @@ function fluid(points)
|
||||
turtle.placeDown()
|
||||
end
|
||||
|
||||
function refill(entry)
|
||||
local function refill(entry)
|
||||
dropOff(locations.dropPt)
|
||||
|
||||
turtle.status = 'refilling'
|
||||
turtle.setStatus('refilling')
|
||||
gotoPoint(locations.dropPt)
|
||||
local chestAdapter = ChestAdapter()
|
||||
for _,item in pairs(entry.items) do
|
||||
@@ -169,21 +174,6 @@ function refill(entry)
|
||||
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)
|
||||
return string.format('%d:%d:%d', pt.x, pt.y, pt.z)
|
||||
end
|
||||
@@ -230,8 +220,6 @@ local function pickupHost(socket)
|
||||
Util.writeTable('/usr/config/pickup', locations)
|
||||
socket:write( { type = "response", response = 'added' })
|
||||
|
||||
elseif data.type == 'fluid' then
|
||||
|
||||
elseif data.type == 'clear' then
|
||||
local key = makeKey(data.point)
|
||||
locations.refills[key] = nil
|
||||
@@ -264,7 +252,7 @@ local function eachEntry(t, fn)
|
||||
local keys = Util.keys(t)
|
||||
for _,key in pairs(keys) do
|
||||
if t[key] then
|
||||
if turtle.abort then
|
||||
if turtle.isAborted() then
|
||||
return
|
||||
end
|
||||
fn(t[key])
|
||||
@@ -283,7 +271,7 @@ local function eachClosestEntry(t, fn)
|
||||
|
||||
while not Util.empty(points) do
|
||||
local closest = Point.closest(turtle.point, points)
|
||||
if turtle.abort then
|
||||
if turtle.isAborted() then
|
||||
return
|
||||
end
|
||||
if t[closest.key] then
|
||||
@@ -299,7 +287,6 @@ local function eachClosestEntry(t, fn)
|
||||
end
|
||||
|
||||
Event.addRoutine(function()
|
||||
|
||||
if not turtle.enableGPS() then
|
||||
error('turtle: No GPS found')
|
||||
end
|
||||
@@ -318,8 +305,8 @@ Event.addRoutine(function()
|
||||
eachEntry(locations.cells, checkCell)
|
||||
end
|
||||
print('sleeping')
|
||||
turtle.status = 'sleeping'
|
||||
if turtle.abort then
|
||||
turtle.setStatus('sleeping')
|
||||
if turtle.isAborted() then
|
||||
printError('aborted')
|
||||
break
|
||||
end
|
||||
|
||||
@@ -83,7 +83,10 @@ local function loadAPI(url, env)
|
||||
apiEnv.shell = nil
|
||||
apiEnv.multishell = nil
|
||||
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()
|
||||
return apiEnv
|
||||
end
|
||||
@@ -91,7 +94,10 @@ end
|
||||
bbpack = loadAPI('http://pastebin.com/raw/PdrJjb5S', 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')
|
||||
-- CnLzL5fg
|
||||
local function snooze()
|
||||
@@ -141,7 +147,7 @@ end
|
||||
|
||||
local tabId = multishell.getCurrent()
|
||||
|
||||
multishell.addHotkey(25, function()
|
||||
multishell.addHotkey('control-p', function()
|
||||
os.queueEvent('recorder_stop')
|
||||
end)
|
||||
|
||||
@@ -179,7 +185,7 @@ while true do
|
||||
end
|
||||
end
|
||||
|
||||
multishell.removeHotkey(25)
|
||||
multishell.removeHotkey('control-p')
|
||||
|
||||
for k,fn in pairs(oldTerm) do
|
||||
multishell.term[k] = fn
|
||||
|
||||
288
apps/shapes.lua
288
apps/shapes.lua
@@ -1,283 +1,47 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local GPS = require('gps')
|
||||
local Socket = require('socket')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
||||
local multishell = _ENV.multishell
|
||||
local textutils = _G.textutils
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Shapes')
|
||||
|
||||
local args = { ... }
|
||||
local turtleId = args[1] or error('Supply turtle ID')
|
||||
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 = [[
|
||||
requireInjector(getfenv(1))
|
||||
|
||||
requireInjector(getfenv(1))
|
||||
local Util = require('util')
|
||||
|
||||
local Level = require('turtle.level')
|
||||
local Util = require('util')
|
||||
local s, m = turtle.run(function()
|
||||
turtle.addFeatures('level')
|
||||
turtle.setStatus('Leveling')
|
||||
|
||||
local s, m = turtle.run(function()
|
||||
turtle.status = 'Leveling'
|
||||
if turtle.enableGPS() then
|
||||
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)
|
||||
local s, m = pcall(function()
|
||||
Level(data.startPt, data.endPt, data.firstPt)
|
||||
end)
|
||||
|
||||
turtle.pathfind(pt)
|
||||
|
||||
if not s and m then
|
||||
error(m)
|
||||
if not s and m then
|
||||
error(m)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if not s then
|
||||
error(m)
|
||||
end
|
||||
end)
|
||||
|
||||
if not s then
|
||||
error(m)
|
||||
end
|
||||
]]
|
||||
|
||||
|
||||
local data = Util.readTable('/usr/config/shapes') or { }
|
||||
|
||||
local page = UI.Page {
|
||||
@@ -295,7 +59,6 @@ local page = UI.Page {
|
||||
}
|
||||
|
||||
function page.info:draw()
|
||||
|
||||
local function size(a, b)
|
||||
return (math.abs(a.x - b.x) + 1) *
|
||||
(math.abs(a.y - b.y) + 1) *
|
||||
@@ -321,13 +84,12 @@ function page:getPoint()
|
||||
end
|
||||
|
||||
function page:runFunction(id, script)
|
||||
|
||||
--Util.writeFile('script.tmp', script)
|
||||
self.notification:info('Connecting')
|
||||
local fn, msg = loadstring(script, 'script')
|
||||
if not fn then
|
||||
self.notification:error('Error in script')
|
||||
-- debug(msg)
|
||||
--debug(msg)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -379,7 +141,7 @@ function page:eventHandler(event)
|
||||
end
|
||||
self.statusBar:setStatus('')
|
||||
elseif event.type == 'cancel' then
|
||||
self:runFunction(turtleId, 'turtle.abortAction()')
|
||||
self:runFunction(turtleId, 'turtle.abort(true)')
|
||||
self.statusBar:setStatus('')
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
@@ -388,6 +150,4 @@ function page:eventHandler(event)
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
|
||||
UI:pullEvents()
|
||||
UI.term:reset()
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Logger = require('logger')
|
||||
local Pathing = require('turtle.pathfind')
|
||||
local Point = require('point')
|
||||
local Util = require('util')
|
||||
|
||||
if device and device.wireless_modem then
|
||||
Logger.setWirelessLogging()
|
||||
end
|
||||
local fs = _G.fs
|
||||
local read = _G.read
|
||||
local os = _G.os
|
||||
local turtle = _G.turtle
|
||||
|
||||
local args = { ... }
|
||||
local options = {
|
||||
@@ -37,25 +37,20 @@ local fortuneBlocks = {
|
||||
|
||||
local MIN_FUEL = 7500
|
||||
local LOW_FUEL = 1500
|
||||
local MAX_FUEL = 100000
|
||||
local MAX_FUEL = turtle.getFuelLimit()
|
||||
|
||||
local PROGRESS_FILE = 'usr/config/mining.progress'
|
||||
local TRASH_FILE = 'usr/config/mining.trash'
|
||||
|
||||
if not term.isColor() then
|
||||
MAX_FUEL = 20000
|
||||
end
|
||||
|
||||
local mining = {
|
||||
diameter = 1,
|
||||
chunkIndex = 0,
|
||||
chunks = -1,
|
||||
}
|
||||
|
||||
local trash
|
||||
local boreDirection
|
||||
local trash, boreDirection, unload
|
||||
|
||||
function getChunkCoordinates(diameter, index, x, z)
|
||||
local function getChunkCoordinates(diameter, index, x, z)
|
||||
local dirs = { -- circumference of grid
|
||||
{ xd = 0, zd = 1, heading = 1 }, -- south
|
||||
{ xd = -1, zd = 0, heading = 2 },
|
||||
@@ -68,13 +63,13 @@ function getChunkCoordinates(diameter, index, x, z)
|
||||
dirs[4].z = z
|
||||
return dirs[4]
|
||||
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.z = z + dir.zd * 16
|
||||
return dir
|
||||
end
|
||||
|
||||
function getBoreLocations(x, z)
|
||||
local function getBoreLocations(x, z)
|
||||
|
||||
local locations = {}
|
||||
|
||||
@@ -116,7 +111,7 @@ function getBoreLocations(x, z)
|
||||
end
|
||||
|
||||
-- get the bore location closest to the miner
|
||||
local function getClosestLocation(points, b)
|
||||
local function getClosestLocation(points)
|
||||
local key = 1
|
||||
local leastMoves = 9000
|
||||
for k,pt in pairs(points) do
|
||||
@@ -134,11 +129,11 @@ local function getClosestLocation(points, b)
|
||||
return table.remove(points, key)
|
||||
end
|
||||
|
||||
function getCornerOf(c)
|
||||
local function getCornerOf(c)
|
||||
return math.floor(c.x / 16) * 16, math.floor(c.z / 16) * 16
|
||||
end
|
||||
|
||||
function nextChunk()
|
||||
local function nextChunk()
|
||||
|
||||
local x, z = getCornerOf({ x = mining.x, z = mining.z })
|
||||
local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2)
|
||||
@@ -168,7 +163,7 @@ function nextChunk()
|
||||
return true
|
||||
end
|
||||
|
||||
function addTrash()
|
||||
local function addTrash()
|
||||
|
||||
if not trash then
|
||||
trash = { }
|
||||
@@ -176,7 +171,7 @@ function addTrash()
|
||||
|
||||
local slots = turtle.getFilledSlots()
|
||||
|
||||
for k,slot in pairs(slots) do
|
||||
for _,slot in pairs(slots) do
|
||||
trash[slot.iddmg] = true
|
||||
end
|
||||
|
||||
@@ -184,19 +179,18 @@ function addTrash()
|
||||
Util.writeTable(TRASH_FILE, trash)
|
||||
end
|
||||
|
||||
function log(text)
|
||||
local function log(text)
|
||||
print(text)
|
||||
Logger.log('mineWorker', text)
|
||||
end
|
||||
|
||||
function status(status)
|
||||
turtle.status = status
|
||||
log(status)
|
||||
local function status(newStatus)
|
||||
turtle.setStatus(newStatus)
|
||||
log(newStatus)
|
||||
end
|
||||
|
||||
function refuel()
|
||||
local function refuel()
|
||||
if turtle.getFuelLevel() < MIN_FUEL then
|
||||
local oldStatus = turtle.status
|
||||
local oldStatus = turtle.getStatus()
|
||||
status('refueling')
|
||||
|
||||
if turtle.select('minecraft:coal:0') then
|
||||
@@ -221,7 +215,51 @@ function refuel()
|
||||
turtle.select(1)
|
||||
end
|
||||
|
||||
function enderChestUnload()
|
||||
local function safeGoto(x, z, y, h)
|
||||
local oldStatus = turtle.getStatus()
|
||||
|
||||
-- only pathfind above or around other turtles (never down)
|
||||
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
|
||||
--status('stuck')
|
||||
if turtle.isAborted() then
|
||||
return false
|
||||
end
|
||||
os.sleep(3)
|
||||
end
|
||||
turtle.setStatus(oldStatus)
|
||||
return true
|
||||
end
|
||||
|
||||
local function safeGotoY(y)
|
||||
local oldStatus = turtle.getStatus()
|
||||
while not turtle.gotoY(y) do
|
||||
status('stuck')
|
||||
if turtle.isAborted() then
|
||||
return false
|
||||
end
|
||||
os.sleep(1)
|
||||
end
|
||||
turtle.setStatus(oldStatus)
|
||||
return true
|
||||
end
|
||||
|
||||
local function makeWalkableTunnel(action, tpt, pt)
|
||||
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
|
||||
local r, block = turtle.inspectUp()
|
||||
if r and not turtle.isTurtleAtSide('top') then
|
||||
if block.name ~= 'minecraft:cobblestone' and
|
||||
block.name ~= 'minecraft:chest' then
|
||||
turtle.digUp()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
local function enderChestUnload()
|
||||
log('unloading')
|
||||
turtle.select(1)
|
||||
if not Util.tryTimed(5, function()
|
||||
@@ -237,52 +275,10 @@ function enderChestUnload()
|
||||
turtle.digDown()
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
function safeGoto(x, z, y, h)
|
||||
local oldStatus = turtle.status
|
||||
|
||||
-- only pathfind above or around other turtles (never down)
|
||||
Pathing.setBox({ x = 0, y = 0, z = 0, ex = x, ey = y + 1, ez = z })
|
||||
while not turtle.pathfind({ x = x, z = z, y = y or turtle.point.y, heading = h }) do
|
||||
--status('stuck')
|
||||
if turtle.abort then
|
||||
return false
|
||||
end
|
||||
--os.sleep(1)
|
||||
end
|
||||
turtle.status = oldStatus
|
||||
return true
|
||||
end
|
||||
|
||||
function safeGotoY(y)
|
||||
local oldStatus = turtle.status
|
||||
while not turtle.gotoY(y) do
|
||||
status('stuck')
|
||||
if turtle.abort then
|
||||
return false
|
||||
end
|
||||
os.sleep(1)
|
||||
end
|
||||
turtle.status = oldStatus
|
||||
return true
|
||||
end
|
||||
|
||||
function makeWalkableTunnel(action, tpt, pt)
|
||||
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
|
||||
local r, block = turtle.inspectUp()
|
||||
if r and not turtle.isTurtleAtSide('top') then
|
||||
if block.name ~= 'minecraft:cobblestone' and
|
||||
block.name ~= 'minecraft:chest' then
|
||||
turtle.digUp()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function normalChestUnload()
|
||||
local oldStatus = turtle.status
|
||||
local function normalChestUnload()
|
||||
local oldStatus = turtle.getStatus()
|
||||
status('unloading')
|
||||
local pt = Util.shallowCopy(turtle.point)
|
||||
safeGotoY(0)
|
||||
@@ -291,7 +287,7 @@ function normalChestUnload()
|
||||
makeWalkableTunnel(action, tpt, { x = pt.x, z = pt.z })
|
||||
end)
|
||||
|
||||
safeGoto(0, 0)
|
||||
safeGoto(0, 0, 0)
|
||||
if not turtle.detectUp() then
|
||||
error('no chest')
|
||||
end
|
||||
@@ -317,7 +313,7 @@ function normalChestUnload()
|
||||
status(oldStatus)
|
||||
end
|
||||
|
||||
function ejectTrash()
|
||||
local function ejectTrash()
|
||||
|
||||
local cobbleSlotCount = 0
|
||||
|
||||
@@ -325,7 +321,7 @@ function ejectTrash()
|
||||
if slot.iddmg == 'minecraft:cobblestone:0' then
|
||||
if cobbleSlotCount == 0 and slot.count > 36 then
|
||||
turtle.select(slot.index)
|
||||
turtle.dropDown(32)
|
||||
turtle.dropDown(slot.count - 36)
|
||||
end
|
||||
cobbleSlotCount = cobbleSlotCount + 1
|
||||
end
|
||||
@@ -340,7 +336,35 @@ function ejectTrash()
|
||||
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()
|
||||
if not r then
|
||||
return false
|
||||
@@ -375,12 +399,12 @@ function mineable(action)
|
||||
return block.name
|
||||
end
|
||||
|
||||
function fortuneDig(action, blockName)
|
||||
local function fortuneDig(action, blockName)
|
||||
if options.fortunePick.value and fortuneBlocks[blockName] then
|
||||
turtle.select('cctweaks:toolHost')
|
||||
turtle.equipRight()
|
||||
turtle.select(options.fortunePick.value)
|
||||
repeat until not turtle.dig()
|
||||
repeat until not action.dig()
|
||||
turtle.select('minecraft:diamond_pickaxe')
|
||||
turtle.equipRight()
|
||||
turtle.select(1)
|
||||
@@ -388,7 +412,7 @@ function fortuneDig(action, blockName)
|
||||
end
|
||||
end
|
||||
|
||||
function mine(action)
|
||||
local function mine(action)
|
||||
local blockName = mineable(action)
|
||||
if blockName then
|
||||
checkSpace()
|
||||
@@ -399,7 +423,7 @@ function mine(action)
|
||||
end
|
||||
end
|
||||
|
||||
function bore()
|
||||
local function bore()
|
||||
|
||||
local loc = turtle.point
|
||||
local level = loc.y
|
||||
@@ -409,7 +433,7 @@ function bore()
|
||||
boreDirection = 'down'
|
||||
|
||||
while true do
|
||||
if turtle.abort then
|
||||
if turtle.isAborted() then
|
||||
status('aborting')
|
||||
return false
|
||||
end
|
||||
@@ -417,10 +441,6 @@ function bore()
|
||||
break
|
||||
end
|
||||
|
||||
if turtle.point.y < -2 then
|
||||
-- turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
|
||||
end
|
||||
|
||||
mine(turtle.getAction('down'))
|
||||
if not Util.tryTimed(3, turtle.down) then
|
||||
break
|
||||
@@ -445,19 +465,15 @@ function bore()
|
||||
turtle.turnLeft()
|
||||
|
||||
while true do
|
||||
if turtle.abort then
|
||||
if turtle.isAborted() then
|
||||
status('aborting')
|
||||
return false
|
||||
end
|
||||
|
||||
if turtle.point.y > -2 then
|
||||
-- turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
|
||||
end
|
||||
|
||||
while not Util.tryTimed(3, turtle.up) do
|
||||
status('stuck')
|
||||
end
|
||||
if turtle.status == 'stuck' then
|
||||
if turtle.getStatus() == 'stuck' then
|
||||
status('boring up')
|
||||
end
|
||||
|
||||
@@ -482,34 +498,6 @@ function bore()
|
||||
return true
|
||||
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)
|
||||
if pta.x == ptb.x and pta.z == ptb.z then
|
||||
if pta.y and ptb.y then
|
||||
@@ -520,15 +508,15 @@ function Point.compare(pta, ptb)
|
||||
return false
|
||||
end
|
||||
|
||||
function inspect(action, name)
|
||||
local function inspect(action, name)
|
||||
local r, block = action.inspect()
|
||||
if r and block.name == name then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function boreCommand()
|
||||
local pt = getClosestLocation(mining.locations, turtle.point)
|
||||
local function boreCommand()
|
||||
local pt = getClosestLocation(mining.locations)
|
||||
|
||||
turtle.setMoveCallback(function(action, tpt)
|
||||
makeWalkableTunnel(action, tpt, pt)
|
||||
@@ -566,6 +554,7 @@ if not Util.getOptions(options, args) then
|
||||
return
|
||||
end
|
||||
|
||||
-- TODO: this won't work - need to Util.merge file into mining
|
||||
mining.depth = options.depth.value
|
||||
mining.chunks = options.chunks.value
|
||||
|
||||
@@ -628,16 +617,14 @@ turtle.run(function()
|
||||
turtle.reset()
|
||||
turtle.setPolicy(turtle.policies.digAttack)
|
||||
turtle.setDigPolicy(turtle.digPolicies.turtleSafe)
|
||||
|
||||
unload()
|
||||
status('mining')
|
||||
|
||||
local s, m = pcall(function() main() end)
|
||||
local s, m = pcall(main)
|
||||
if not s and m then
|
||||
printError(m)
|
||||
_G.printError(m)
|
||||
end
|
||||
|
||||
turtle.abort = false
|
||||
turtle.abort(false)
|
||||
safeGotoY(0)
|
||||
safeGoto(0, 0, 0, 0)
|
||||
unload()
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local ChestAdapter = require('chestAdapter18')
|
||||
local Event = require('event')
|
||||
local MEAdapter = require('meAdapter')
|
||||
local RefinedAdapter = require('refinedAdapter')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
local InventoryAdapter = require('inventoryAdapter')
|
||||
local Event = require('event')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
||||
local storage = RefinedAdapter()
|
||||
if not storage:isValid() then
|
||||
storage = MEAdapter({ auto = true })
|
||||
if not storage:isValid() then
|
||||
storage = ChestAdapter()
|
||||
end
|
||||
end
|
||||
local colors = _G.colors
|
||||
local multishell = _ENV.multishell
|
||||
|
||||
if not storage:isValid() then
|
||||
error('Not connected to a storage device')
|
||||
local storage = InventoryAdapter.wrap()
|
||||
if not storage then
|
||||
error('Not connected to a valid inventory')
|
||||
end
|
||||
|
||||
multishell.setTitle(multishell.getCurrent(), 'Storage Activity')
|
||||
@@ -26,8 +20,9 @@ local changedPage = UI.Page {
|
||||
grid = UI.Grid {
|
||||
ey = -6,
|
||||
columns = {
|
||||
{ heading = 'Qty', key = 'count', width = 5 },
|
||||
{ heading = 'Change', key = 'change', width = 6 },
|
||||
{ heading = 'Qty', key = 'count', width = 5 },
|
||||
{ heading = 'Change', key = 'change', width = 6 },
|
||||
{ heading = 'Rate', key = 'rate', width = 6 },
|
||||
{ heading = 'Name', key = 'displayName' },
|
||||
},
|
||||
sortColumn = 'displayName',
|
||||
@@ -66,6 +61,7 @@ function changedPage.grid:getDisplayValues(row)
|
||||
if row.change < 0 then
|
||||
ind = ''
|
||||
end
|
||||
|
||||
row.change = ind .. Util.toBytes(row.change)
|
||||
row.count = Util.toBytes(row.count)
|
||||
|
||||
@@ -73,7 +69,6 @@ function changedPage.grid:getDisplayValues(row)
|
||||
end
|
||||
|
||||
function changedPage:eventHandler(event)
|
||||
|
||||
if event.type == 'reset' then
|
||||
self.lastItems = nil
|
||||
self.grid:setValues({ })
|
||||
@@ -104,8 +99,8 @@ function changedPage:refresh()
|
||||
local t = storage:listItems()
|
||||
|
||||
if not t or Util.empty(t) then
|
||||
self:clear()
|
||||
self:centeredWrite(math.ceil(self.height/2), 'Communication failure')
|
||||
self.grid:clear()
|
||||
self.grid:centeredWrite(math.ceil(self.height/2), 'Communication failure')
|
||||
return
|
||||
end
|
||||
|
||||
@@ -115,9 +110,12 @@ function changedPage:refresh()
|
||||
|
||||
if not self.lastItems then
|
||||
self.lastItems = t
|
||||
self.timestamp = os.clock()
|
||||
self.grid:setValues({ })
|
||||
else
|
||||
local changedItems = {}
|
||||
self.elapsed = os.clock() - self.timestamp
|
||||
local changedItems = { }
|
||||
local found
|
||||
for _,v in pairs(self.lastItems) do
|
||||
found = false
|
||||
for k2,v2 in pairs(t) do
|
||||
@@ -141,13 +139,14 @@ function changedPage:refresh()
|
||||
end
|
||||
end
|
||||
-- No items left
|
||||
for k,v in pairs(t) do
|
||||
for _,v in pairs(t) do
|
||||
v.lastCount = 0
|
||||
table.insert(changedItems, v)
|
||||
end
|
||||
|
||||
for k,v in pairs(changedItems) do
|
||||
for _,v in pairs(changedItems) do
|
||||
v.change = v.count - v.lastCount
|
||||
v.rate = Util.round(60 / self.elapsed * v.change, 1)
|
||||
end
|
||||
|
||||
self.grid:setValues(changedItems)
|
||||
@@ -161,4 +160,5 @@ Event.onInterval(5, function()
|
||||
end)
|
||||
|
||||
UI:setPage(changedPage)
|
||||
changedPage:draw()
|
||||
UI:pullEvents()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local Logger = require('logger')
|
||||
@@ -8,6 +8,10 @@ local Point = require('point')
|
||||
local TableDB = require('tableDB')
|
||||
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
|
||||
ender modems.
|
||||
@@ -87,7 +91,7 @@ function Builder:dumpInventoryWithCheck()
|
||||
print('Press enter to continue')
|
||||
--turtle.setHeading(0)
|
||||
self.ready = false
|
||||
read()
|
||||
_G.read()
|
||||
end
|
||||
self.ready = true
|
||||
end
|
||||
@@ -95,7 +99,7 @@ end
|
||||
function Builder:autocraft(supplies)
|
||||
local t = { }
|
||||
|
||||
for i,s in pairs(supplies) do
|
||||
for _,s in pairs(supplies) do
|
||||
local key = s.id .. ':' .. s.dmg
|
||||
local item = t[key]
|
||||
if not item then
|
||||
@@ -214,7 +218,6 @@ local function moveTowardsZ(dz)
|
||||
end
|
||||
|
||||
function Builder:finish()
|
||||
|
||||
Builder.resupplying = true
|
||||
Builder.ready = false
|
||||
if turtle.gotoLocation('supplies') then
|
||||
@@ -227,9 +230,8 @@ function Builder:finish()
|
||||
end
|
||||
|
||||
function Builder:gotoBuilder()
|
||||
|
||||
if Builder.lastPoint then
|
||||
turtle.status = 'tracking'
|
||||
turtle.setStatus('tracking')
|
||||
while true do
|
||||
local pt = Point.copy(Builder.lastPoint)
|
||||
pt.y = pt.y + 3
|
||||
@@ -261,139 +263,136 @@ function Builder:gotoBuilder()
|
||||
end
|
||||
|
||||
Message.addHandler('builder',
|
||||
function(h, id, msg, distance)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
function(_, id, msg)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
|
||||
if not Builder.resupplying then
|
||||
local pt = msg.contents
|
||||
pt.y = pt.y + 3
|
||||
local pt = msg.contents
|
||||
pt.y = pt.y + 3
|
||||
|
||||
turtle.status = 'supervising'
|
||||
turtle.gotoYfirst(pt)
|
||||
end
|
||||
turtle.setStatus('supervising')
|
||||
turtle.gotoYfirst(pt)
|
||||
end
|
||||
end)
|
||||
|
||||
Message.addHandler('supplyList',
|
||||
function(h, id, msg, distance)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
function(_, id, msg)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
|
||||
turtle.status = 'resupplying'
|
||||
Builder.resupplying = true
|
||||
Builder.slots = msg.contents.slots
|
||||
Builder.slotUid = msg.contents.uid
|
||||
turtle.setStatus('resupplying')
|
||||
Builder.resupplying = true
|
||||
Builder.slots = msg.contents.slots
|
||||
Builder.slotUid = msg.contents.uid
|
||||
|
||||
Builder:log('Received supply list ' .. Builder.slotUid)
|
||||
|
||||
os.sleep(0)
|
||||
if not turtle.gotoLocation('supplies') then
|
||||
Builder:log('Failed to go to supply location')
|
||||
self.ready = false
|
||||
Event.exitPullEvents()
|
||||
end
|
||||
os.sleep(0)
|
||||
if not turtle.gotoLocation('supplies') then
|
||||
Builder:log('Failed to go to supply location')
|
||||
Builder.ready = false
|
||||
Event.exitPullEvents()
|
||||
end
|
||||
turtle.setHeading(1)
|
||||
os.sleep(.2) -- random 'Computer is not connected' error...
|
||||
Builder:dumpInventoryWithCheck()
|
||||
Builder:refuel()
|
||||
|
||||
while true do
|
||||
local supplies = Builder:getSupplies()
|
||||
if #supplies == 0 then
|
||||
break
|
||||
end
|
||||
Builder:autocraft(supplies)
|
||||
turtle.status = 'waiting'
|
||||
os.sleep(5)
|
||||
end
|
||||
Builder:log('Got all supplies')
|
||||
os.sleep(0)
|
||||
Builder:gotoBuilder()
|
||||
Builder.resupplying = false
|
||||
local supplies = Builder:getSupplies()
|
||||
if #supplies == 0 then
|
||||
break
|
||||
end
|
||||
Builder:autocraft(supplies)
|
||||
turtle.setStatus('waiting')
|
||||
os.sleep(5)
|
||||
end
|
||||
Builder:log('Got all supplies')
|
||||
os.sleep(0)
|
||||
Builder:gotoBuilder()
|
||||
Builder.resupplying = false
|
||||
end)
|
||||
|
||||
Message.addHandler('needSupplies',
|
||||
function(h, id, msg, distance)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
function(_, id, msg)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
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')
|
||||
Message.send(__BUILDER_ID, 'gotSupplies')
|
||||
else
|
||||
turtle.setStatus('supplying')
|
||||
Builder:log('Supplying')
|
||||
os.sleep(0)
|
||||
|
||||
Builder:log('No supplies ready')
|
||||
|
||||
Message.send(__BUILDER_ID, 'gotSupplies')
|
||||
else
|
||||
turtle.status = 'supplying'
|
||||
Builder:log('Supplying')
|
||||
os.sleep(0)
|
||||
|
||||
local pt = msg.contents.point
|
||||
pt.y = turtle.getPoint().y
|
||||
pt.heading = nil
|
||||
if not turtle.gotoYfirst(pt) then -- location of builder
|
||||
Builder.resupplying = true
|
||||
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
|
||||
local pt = msg.contents.point
|
||||
pt.y = turtle.getPoint().y
|
||||
pt.heading = nil
|
||||
if not turtle.gotoYfirst(pt) then -- location of builder
|
||||
Builder.resupplying = true
|
||||
Message.send(__BUILDER_ID, 'gotSupplies')
|
||||
os.sleep(0)
|
||||
if not turtle.gotoLocation('supplies') then
|
||||
Builder:log('failed to go to supply location')
|
||||
Event.exitPullEvents()
|
||||
end
|
||||
turtle.setHeading(1)
|
||||
return
|
||||
end
|
||||
pt.y = pt.y - 2 -- location where builder should go for the chest to be above
|
||||
return
|
||||
end
|
||||
pt.y = pt.y - 2 -- location where builder should go for the chest to be above
|
||||
|
||||
turtle.select(15)
|
||||
turtle.placeDown()
|
||||
os.sleep(.1) -- random computer not connected error
|
||||
turtle.select(15)
|
||||
turtle.placeDown()
|
||||
os.sleep(.1) -- random computer not connected error
|
||||
local p = ChestProvider({ direction = 'up', wrapSide = 'bottom' })
|
||||
for i = 1, 16 do
|
||||
p:insert(i, 64)
|
||||
end
|
||||
for i = 1, 16 do
|
||||
p:insert(i, 64)
|
||||
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)
|
||||
--os.sleep(0)
|
||||
Message.waitForMessage('thanks', 5, __BUILDER_ID)
|
||||
--os.sleep(0)
|
||||
|
||||
--p.condenseItems()
|
||||
for i = 1, 16 do
|
||||
p:extract(i, 64)
|
||||
end
|
||||
turtle.digDown()
|
||||
turtle.status = 'waiting'
|
||||
end
|
||||
--p.condenseItems()
|
||||
for i = 1, 16 do
|
||||
p:extract(i, 64)
|
||||
end
|
||||
turtle.digDown()
|
||||
turtle.setStatus('waiting')
|
||||
end
|
||||
end)
|
||||
|
||||
Message.addHandler('finished',
|
||||
function(h, id)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
function(_, id)
|
||||
if not id or id ~= __BUILDER_ID then
|
||||
return
|
||||
end
|
||||
Builder:finish()
|
||||
end)
|
||||
|
||||
Event.on('turtle_abort',
|
||||
function()
|
||||
turtle.abort = false
|
||||
turtle.status = 'aborting'
|
||||
turtle.abort(false)
|
||||
turtle.setStatus('aborting')
|
||||
Builder:finish()
|
||||
end)
|
||||
|
||||
local function onTheWay() -- parallel routine
|
||||
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 id == __BUILDER_ID and msg and msg.type then
|
||||
if msg.type == 'needSupplies' then
|
||||
Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true })
|
||||
elseif msg.type == 'builder' then
|
||||
Builder.lastPoint = msg.contents
|
||||
end
|
||||
if msg.type == 'needSupplies' then
|
||||
Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true })
|
||||
elseif msg.type == 'builder' then
|
||||
Builder.lastPoint = msg.contents
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
22
apps/termShare.lua
Normal file
22
apps/termShare.lua
Normal 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)
|
||||
@@ -1,4 +1,4 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
--[[
|
||||
Requirements:
|
||||
@@ -6,7 +6,7 @@ requireInjector(getfenv(1))
|
||||
Area around turtle must be flat and can only be dirt or grass
|
||||
(10 blocks in each direction from turtle)
|
||||
Turtle must have: crafting table, chest
|
||||
Turtle must have a pick equipped on the left side
|
||||
Turtle must have a pick equipped
|
||||
|
||||
Optional:
|
||||
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.
|
||||
]]--
|
||||
|
||||
local ChestAdapter = require('chestAdapter18')
|
||||
local Craft = require('turtle.craft')
|
||||
local Level = require('turtle.level')
|
||||
local Pathing = require('turtle.pathfind')
|
||||
local Point = require('point')
|
||||
local Util = require('util')
|
||||
local Point = require('point')
|
||||
local Util = require('util')
|
||||
|
||||
local os = _G.os
|
||||
local read = _G.read
|
||||
local turtle = _G.turtle
|
||||
|
||||
local FUEL_BASE = 0
|
||||
local FUEL_DIRE = FUEL_BASE + 10
|
||||
@@ -76,9 +76,6 @@ local state = Util.readTable('usr/config/treefarm') or {
|
||||
}
|
||||
|
||||
local clock = os.clock()
|
||||
local recipes = Util.readTable('usr/etc/recipes.db') or { }
|
||||
|
||||
Craft.setRecipes(recipes)
|
||||
|
||||
local function inspect(fn)
|
||||
local s, item = fn()
|
||||
@@ -121,28 +118,21 @@ local function safePlaceBlock(item)
|
||||
end
|
||||
|
||||
local function craftItem(item, qty)
|
||||
|
||||
local success
|
||||
local success, msg
|
||||
|
||||
if safePlaceBlock(CHEST) then
|
||||
|
||||
if turtle.equip('left', 'minecraft:crafting_table') then
|
||||
|
||||
local chestAdapter = ChestAdapter({
|
||||
Util.print('Crafting %d %s', (qty or 1), item)
|
||||
success, msg = turtle.craftItem(item, qty or 1, {
|
||||
wrapSide = 'top',
|
||||
direction = 'down',
|
||||
})
|
||||
if not chestAdapter:isValid() then
|
||||
print('invalid chestAdapter')
|
||||
read()
|
||||
end
|
||||
repeat until not turtle.suckUp()
|
||||
|
||||
Util.print('Crafting %d %s', (qty or 1), item)
|
||||
success = Craft.craftRecipe(recipes[item], qty or 1, chestAdapter)
|
||||
|
||||
repeat until not turtle.suckUp()
|
||||
if not success then
|
||||
print(msg)
|
||||
end
|
||||
turtle.equip('left', 'minecraft:diamond_pickaxe')
|
||||
|
||||
turtle.digUp()
|
||||
end
|
||||
|
||||
@@ -201,7 +191,7 @@ local function makeCharcoal()
|
||||
return true
|
||||
end
|
||||
|
||||
local function getLogSlot(slots)
|
||||
local function getLogSlot()
|
||||
local maxslot = { count = 0 }
|
||||
for k,slot in pairs(slots) do
|
||||
if string.match(k, 'minecraft:log') then
|
||||
@@ -214,7 +204,8 @@ local function makeCharcoal()
|
||||
end
|
||||
|
||||
repeat
|
||||
local slots = turtle.getSummedInventory()
|
||||
slots = turtle.getSummedInventory()
|
||||
|
||||
local charcoal = slots[CHARCOAL].count
|
||||
local slot = getLogSlot(slots)
|
||||
|
||||
@@ -266,7 +257,7 @@ local function getCobblestone(count)
|
||||
turtle.select(1)
|
||||
turtle.digDown()
|
||||
turtle.down()
|
||||
for i = 1, 4 do
|
||||
for _ = 1, 4 do
|
||||
if inspect(turtle.inspect) == STONE then
|
||||
turtle.dig()
|
||||
end
|
||||
@@ -281,7 +272,7 @@ local function getCobblestone(count)
|
||||
|
||||
until turtle.getItemCount(COBBLESTONE) >= count
|
||||
|
||||
turtle.gotoPoint(pt)
|
||||
turtle._goto(pt)
|
||||
turtle.placeDown(DIRT)
|
||||
|
||||
turtle.drop(DIRT)
|
||||
@@ -297,8 +288,8 @@ local function createFurnace()
|
||||
print('Adding a furnace')
|
||||
getCobblestone(8)
|
||||
|
||||
if craftItem(FURNACE) then
|
||||
turtle.drop(COBBLESTONE)
|
||||
if turtle.has(FURNACE) or craftItem(FURNACE) then
|
||||
-- turtle.drop(COBBLESTONE)
|
||||
local furnacePt = { x = GRID.BL.x + 2, y = 1, z = GRID.BL.z + 2 }
|
||||
turtle.placeAt(furnacePt, FURNACE)
|
||||
setState('furnace', furnacePt)
|
||||
@@ -319,7 +310,9 @@ local function createPerimeter()
|
||||
print('Creating a perimeter')
|
||||
|
||||
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.pathfind(GRID.BL)
|
||||
@@ -350,35 +343,32 @@ local function createPerimeter()
|
||||
end
|
||||
|
||||
local function createChests()
|
||||
if state.chest_1 then
|
||||
if state.chest then
|
||||
return
|
||||
end
|
||||
if state.perimeter and
|
||||
turtle.getFuelLevel() > FUEL_GOOD and
|
||||
Craft.canCraft(CHEST, 4, turtle.getSummedInventory()) then
|
||||
turtle.canCraft(CHEST, 4, turtle.getSummedInventory()) then
|
||||
|
||||
print('Adding storage')
|
||||
if craftItem(CHEST, 4) then
|
||||
if turtle.has(CHEST, 2) or craftItem(CHEST, 2) then
|
||||
|
||||
local pt = Point.copy(GRID.BL)
|
||||
pt.x = pt.x + 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.placeDown(CHEST)
|
||||
turtle.digDownAt(pt)
|
||||
turtle.placeDown(CHEST)
|
||||
|
||||
pt.z = pt.z + 1
|
||||
pt.z = pt.z + 1
|
||||
|
||||
turtle.digDownAt(pt)
|
||||
turtle.placeDown(CHEST)
|
||||
turtle.digDownAt(pt)
|
||||
turtle.placeDown(CHEST)
|
||||
|
||||
setState('chest_' .. i, Util.shallowCopy(pt))
|
||||
setState('chest', Util.shallowCopy(pt))
|
||||
|
||||
pt.z = pt.z + 1
|
||||
end
|
||||
turtle.drop(DIRT)
|
||||
turtle.refuel(OAK_PLANK)
|
||||
end
|
||||
@@ -388,24 +378,27 @@ end
|
||||
|
||||
local function dropOffItems()
|
||||
|
||||
if state.chest_1 then
|
||||
if state.chest then
|
||||
local slots = turtle.getSummedInventory()
|
||||
|
||||
if state.chest_1 and
|
||||
if state.chest and
|
||||
slots[CHARCOAL] and
|
||||
slots[CHARCOAL].count >= MIN_CHARCOAL and
|
||||
(turtle.getItemCount('minecraft:log') > 0 or
|
||||
turtle.getItemCount('minecraft:log2') > 0) then
|
||||
|
||||
print('Storing logs')
|
||||
turtle.pathfind(Point.above(state.chest_1))
|
||||
turtle.pathfind(Point.above(state.chest))
|
||||
turtle.dropDown('minecraft:log')
|
||||
turtle.dropDown('minecraft:log2')
|
||||
end
|
||||
|
||||
if slots[APPLE] then
|
||||
print('Storing apples')
|
||||
turtle.dropDownAt(state.chest_2, APPLE)
|
||||
for _, sapling in pairs(ALL_SAPLINGS) do
|
||||
if slots[sapling] and slots[sapling].count > MAX_SAPLINGS then
|
||||
turtle.dropDown(sapling, slots[sapling].count - MAX_SAPLINGS)
|
||||
end
|
||||
end
|
||||
|
||||
turtle.dropDown(APPLE)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -430,11 +423,11 @@ local function placeTorches()
|
||||
end
|
||||
|
||||
if turtle.getFuelLevel() > 100 and
|
||||
Craft.canCraft(TORCH, 4, turtle.getSummedInventory()) then
|
||||
turtle.canCraft(TORCH, 4, turtle.getSummedInventory()) then
|
||||
|
||||
print('Placing torches')
|
||||
|
||||
if craftItem(TORCH, 4) then
|
||||
if turtle.has(TORCH, 4) or craftItem(TORCH, 4) then
|
||||
local pts = { }
|
||||
for x = -4, 4, 8 do
|
||||
for z = -4, 4, 8 do
|
||||
@@ -493,7 +486,7 @@ local function fellTree(pt)
|
||||
desperateRefuel(FUEL_DIRE)
|
||||
|
||||
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 = 50, z = -(GRID_WIDTH-1) },
|
||||
Point.above(pt))
|
||||
@@ -510,10 +503,10 @@ local function fell()
|
||||
|
||||
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)
|
||||
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
|
||||
return true
|
||||
end
|
||||
@@ -523,7 +516,7 @@ local function fell()
|
||||
local fuel = turtle.getFuelLevel()
|
||||
|
||||
-- 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)
|
||||
if turtle.faceAgainst(pt, { blocks = Util.shallowCopy(state.trees) }) and
|
||||
@@ -545,7 +538,7 @@ local function moreTrees()
|
||||
return
|
||||
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
|
||||
end
|
||||
|
||||
@@ -570,7 +563,7 @@ local function moreTrees()
|
||||
end)
|
||||
end
|
||||
|
||||
function getTurtleFacing(block)
|
||||
local function getTurtleFacing(block)
|
||||
local directions = {
|
||||
[5] = 2,
|
||||
[3] = 3,
|
||||
@@ -586,7 +579,7 @@ function getTurtleFacing(block)
|
||||
return directions[bi.metadata]
|
||||
end
|
||||
|
||||
function saveTurtleFacing()
|
||||
local function saveTurtleFacing()
|
||||
if not state.facing then
|
||||
setState('facing', getTurtleFacing(CHEST))
|
||||
end
|
||||
@@ -600,7 +593,7 @@ local function findGround()
|
||||
local s, block = turtle.inspectDown()
|
||||
|
||||
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
|
||||
b == 'minecraft:grass:0' or
|
||||
@@ -633,10 +626,7 @@ local function findHome()
|
||||
end
|
||||
|
||||
print('Determining location')
|
||||
|
||||
turtle.point.heading = getTurtleFacing(CHEST)
|
||||
turtle.setHeading(state.facing)
|
||||
turtle.point.heading = 0
|
||||
turtle.point.heading = (getTurtleFacing(CHEST) - state.facing) % 4
|
||||
|
||||
local pt = Point.copy(turtle.point)
|
||||
|
||||
@@ -663,7 +653,7 @@ local function findHome()
|
||||
})
|
||||
|
||||
-- when pathfinding - don't leave this box
|
||||
Pathing.setBox({
|
||||
turtle.setPathingBox({
|
||||
x = GRID.TL.x,
|
||||
y = GRID.TL.y,
|
||||
z = GRID.TL.z,
|
||||
@@ -710,7 +700,7 @@ local tasks = {
|
||||
{ desc = 'Emptying furnace', fn = emptyFurnace },
|
||||
{ desc = 'Adding trees', fn = moreTrees },
|
||||
{ desc = 'Chopping', fn = fell },
|
||||
{ desc = 'Snacking', fn = eatSaplings },
|
||||
-- { desc = 'Snacking', fn = eatSaplings },
|
||||
{ desc = 'Creating chest', fn = createChests },
|
||||
{ desc = 'Creating furnace', fn = createFurnace },
|
||||
{ desc = 'Making charcoal', fn = makeSingleCharcoal },
|
||||
@@ -725,13 +715,14 @@ local tasks = {
|
||||
|
||||
local s, m = turtle.run(function()
|
||||
|
||||
turtle.addFeatures('level', 'crafting')
|
||||
turtle.setPolicy("attack")
|
||||
|
||||
while not turtle.abort do
|
||||
while not turtle.isAborted() do
|
||||
print('fuel: ' .. turtle.getFuelLevel())
|
||||
for _,task in ipairs(Util.shallowCopy(tasks)) do
|
||||
--print(task.desc)
|
||||
turtle.status = task.desc
|
||||
turtle.setStatus(task.desc)
|
||||
turtle.select(1)
|
||||
if not task.fn() then
|
||||
Util.filterInplace(tasks, function(v) return v.fn ~= task.fn end)
|
||||
@@ -741,5 +732,5 @@ local s, m = turtle.run(function()
|
||||
end)
|
||||
|
||||
if not s then
|
||||
error('Failed')
|
||||
error(m or 'Failed')
|
||||
end
|
||||
|
||||
1
etc/fstab.ignore
Normal file
1
etc/fstab.ignore
Normal file
@@ -0,0 +1 @@
|
||||
forced fstab overwrite
|
||||
87
etc/recipes/appliedenergistics2.db
Normal file
87
etc/recipes/appliedenergistics2.db
Normal 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,
|
||||
},
|
||||
}
|
||||
87
etc/recipes/computercraft.db
Normal file
87
etc/recipes/computercraft.db
Normal 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
544
etc/recipes/enderio.db
Normal 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
12
etc/recipes/exnihilo.db
Normal 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,
|
||||
},
|
||||
}
|
||||
21
etc/recipes/extrautils2.db
Normal file
21
etc/recipes/extrautils2.db
Normal 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
58
etc/recipes/mekanism.db
Normal 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
178
etc/recipes/mysticalagriculture.db
Normal file
178
etc/recipes/mysticalagriculture.db
Normal 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,
|
||||
},
|
||||
}
|
||||
28
etc/recipes/storagedrawers.db
Normal file
28
etc/recipes/storagedrawers.db
Normal 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
22
etc/recipes/tconstruct.db
Normal 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,
|
||||
},
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
turtle.abortAction()
|
||||
turtle.abort(true)
|
||||
@@ -1,12 +1,15 @@
|
||||
local os = _G.os
|
||||
local turtle = _G.turtle
|
||||
|
||||
local function follow(id)
|
||||
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Event = require('event')
|
||||
local Point = require('point')
|
||||
local Socket = require('socket')
|
||||
|
||||
turtle.status = 'follow ' .. id
|
||||
turtle.setStatus('follow ' .. id)
|
||||
|
||||
if not turtle.enableGPS() then
|
||||
error('turtle: No GPS found')
|
||||
@@ -55,7 +58,7 @@ local function follow(id)
|
||||
Event.onInterval(.5, function()
|
||||
|
||||
local function getRemotePoint()
|
||||
if not turtle.abort then
|
||||
if not turtle.isAborted() then
|
||||
if socket:write({ type = 'gps' }) then
|
||||
return socket:read(3)
|
||||
end
|
||||
@@ -65,7 +68,7 @@ local function follow(id)
|
||||
-- sometimes gps will fail if moving
|
||||
local pt, d
|
||||
|
||||
for i = 1, 3 do
|
||||
for _ = 1, 3 do
|
||||
pt, d = getRemotePoint()
|
||||
if pt then
|
||||
break
|
||||
@@ -73,22 +76,22 @@ local function follow(id)
|
||||
os.sleep(.5)
|
||||
end
|
||||
|
||||
if not pt or turtle.abort then
|
||||
if not pt or turtle.isAborted() then
|
||||
error('Did not receive GPS location')
|
||||
end
|
||||
|
||||
if not lastPoint or (lastPoint.x ~= pt.x or lastPoint.y ~= pt.y or lastPoint.z ~= pt.z) then
|
||||
|
||||
if following then
|
||||
turtle.abort = true
|
||||
turtle.getState().abort = true
|
||||
while following do
|
||||
os.sleep(.1)
|
||||
end
|
||||
turtle.abort = false
|
||||
turtle.getState().abort = false
|
||||
end
|
||||
|
||||
-- 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)
|
||||
following = true
|
||||
os.queueEvent('turtle_follow', pt)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
turtle.run(turtle.gotoGPSHome)
|
||||
local Home = require('turtle.home')
|
||||
turtle.run(Home.go)
|
||||
|
||||
@@ -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)
|
||||
@@ -1,8 +1,11 @@
|
||||
requireInjector(getfenv(1))
|
||||
_G.requireInjector()
|
||||
|
||||
local Point = require('point')
|
||||
local Util = require('util')
|
||||
|
||||
local os = _G.os
|
||||
local turtle = _G.turtle
|
||||
|
||||
local checkedNodes, nodes
|
||||
|
||||
local function addNode(node)
|
||||
@@ -47,7 +50,7 @@ local function findObsidian()
|
||||
if turtle.getItemCount(16) > 0 then
|
||||
print('Inventory full')
|
||||
print('Enter to continue...')
|
||||
read()
|
||||
_G.read()
|
||||
end
|
||||
|
||||
if b and b.name == 'minecraft:obsidian' then
|
||||
@@ -63,40 +66,43 @@ local function findObsidian()
|
||||
break
|
||||
end
|
||||
|
||||
local node = Point.closest(turtle.point, nodes)
|
||||
if not turtle.gotoPoint(node) then
|
||||
node = Point.closest(turtle.point, nodes)
|
||||
if not turtle._goto(node) then
|
||||
break
|
||||
end
|
||||
until turtle.abort
|
||||
until turtle.isAborted()
|
||||
end
|
||||
|
||||
turtle.reset()
|
||||
turtle.setPolicy(turtle.policies.digOnly)
|
||||
local s, m = turtle.run(function()
|
||||
repeat
|
||||
turtle.run(function()
|
||||
turtle.reset()
|
||||
turtle.setPolicy(turtle.policies.digOnly)
|
||||
|
||||
checkedNodes = { }
|
||||
nodes = { }
|
||||
local s, m = pcall(function()
|
||||
repeat
|
||||
checkedNodes = { }
|
||||
nodes = { }
|
||||
|
||||
local _,b = turtle.inspectDown()
|
||||
if not b or b.name ~= 'minecraft:obsidian' then
|
||||
break
|
||||
end
|
||||
local _,b = turtle.inspectDown()
|
||||
if not b or b.name ~= 'minecraft:obsidian' then
|
||||
break
|
||||
end
|
||||
|
||||
findObsidian()
|
||||
if not turtle.select('minecraft:water_bucket') then
|
||||
break
|
||||
end
|
||||
turtle.goto(0, 0)
|
||||
turtle.placeDown()
|
||||
os.sleep(2)
|
||||
turtle.placeDown()
|
||||
turtle.down()
|
||||
turtle.select(1)
|
||||
until turtle.abort
|
||||
findObsidian()
|
||||
if not turtle.select('minecraft:water_bucket') then
|
||||
break
|
||||
end
|
||||
turtle._goto({ x = 0, z = 0 })
|
||||
turtle.placeDown()
|
||||
os.sleep(2)
|
||||
turtle.placeDown()
|
||||
turtle.down()
|
||||
turtle.select(1)
|
||||
until turtle.isAborted()
|
||||
end)
|
||||
|
||||
if not s and m then
|
||||
error(m)
|
||||
end
|
||||
|
||||
turtle._goto({ x = 0, y = 0, z = 0, heading = 0 })
|
||||
end)
|
||||
turtle.goto(0, 0, 0, 0)
|
||||
turtle.reset()
|
||||
if not s and m then
|
||||
error(m)
|
||||
end
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
turtle.run(turtle.setGPSHome)
|
||||
local Home = require('turtle.home')
|
||||
turtle.run(Home.set)
|
||||
|
||||
@@ -6,7 +6,7 @@ local function summon(id)
|
||||
local Point = require('point')
|
||||
local Socket = require('socket')
|
||||
|
||||
turtle.status = 'GPSing'
|
||||
turtle.setStatus('GPSing')
|
||||
turtle.setPoint({ x = 0, y = 0, z = 0, heading = 0 })
|
||||
|
||||
local pts = {
|
||||
@@ -32,7 +32,7 @@ local function summon(id)
|
||||
local function doGPS()
|
||||
tFixes = { }
|
||||
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')
|
||||
end
|
||||
local distance = getDistance()
|
||||
@@ -64,7 +64,7 @@ local function summon(id)
|
||||
local pt = { x = pos.x, y = pos.y, z = pos.z }
|
||||
local _, h = Point.calculateMoves(turtle.getPoint(), pt)
|
||||
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 })
|
||||
else
|
||||
error("turtle: Could not determine position")
|
||||
|
||||
Reference in New Issue
Block a user