spaces->tab, equipper improvements, supertreefarm rewrite, follow improvements, sensor cleanup, milo multiple items allowed in recipes, remote canvas access

This commit is contained in:
kepler155c@gmail.com
2019-06-18 15:23:20 -04:00
parent 3b9b509429
commit 045b32884f
162 changed files with 20448 additions and 20286 deletions

View File

@@ -15,37 +15,37 @@ local os = _G.os
local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
local function sixBitToBase64(input)
return _sub(alphabet, input+1, input+1)
return _sub(alphabet, input+1, input+1)
end
local function base64ToSixBit(input)
for i=1, 64 do
if input == _sub(alphabet, i, i) then
return i-1
end
end
for i=1, 64 do
if input == _sub(alphabet, i, i) then
return i-1
end
end
end
local function octetToBase64(o1, o2, o3)
local i1 = sixBitToBase64(_brshift(_band(o1, 0xFC), 2))
local i2
local i3 = "="
local i4 = "="
if o2 then
i2 = sixBitToBase64(_bor( _blshift(_band(o1, 3), 4), _brshift(_band(o2, 0xF0), 4) ))
if not o3 then
i3 = sixBitToBase64(_blshift(_band(o2, 0x0F), 2))
else
i3 = sixBitToBase64(_bor( _blshift(_band(o2, 0x0F), 2), _brshift(_band(o3, 0xC0), 6) ))
end
else
i2 = sixBitToBase64(_blshift(_band(o1, 3), 4))
end
if o3 then
i4 = sixBitToBase64(_band(o3, 0x3F))
end
local i1 = sixBitToBase64(_brshift(_band(o1, 0xFC), 2))
local i2
local i3 = "="
local i4 = "="
if o2 then
i2 = sixBitToBase64(_bor( _blshift(_band(o1, 3), 4), _brshift(_band(o2, 0xF0), 4) ))
if not o3 then
i3 = sixBitToBase64(_blshift(_band(o2, 0x0F), 2))
else
i3 = sixBitToBase64(_bor( _blshift(_band(o2, 0x0F), 2), _brshift(_band(o3, 0xC0), 6) ))
end
else
i2 = sixBitToBase64(_blshift(_band(o1, 3), 4))
end
if o3 then
i4 = sixBitToBase64(_band(o3, 0x3F))
end
return i1..i2..i3..i4
return i1..i2..i3..i4
end
-- octet 1 needs characters 1/2
@@ -53,61 +53,61 @@ end
-- octet 3 needs characters 3/4
local function base64ToThreeOctet(s1)
local c1 = base64ToSixBit(_sub(s1, 1, 1))
local c2 = base64ToSixBit(_sub(s1, 2, 2))
local c3
local c4
local o1
local o2
local o3
if _sub(s1, 3, 3) == "=" then
c3 = nil
c4 = nil
elseif _sub(s1, 4, 4) == "=" then
c3 = base64ToSixBit(_sub(s1, 3, 3))
c4 = nil
else
c3 = base64ToSixBit(_sub(s1, 3, 3))
c4 = base64ToSixBit(_sub(s1, 4, 4))
end
o1 = _bor( _blshift(c1, 2), _brshift(_band( c2, 0x30 ), 4) )
if c3 then
o2 = _bor( _blshift(_band(c2, 0x0F), 4), _brshift(_band( c3, 0x3C ), 2) )
else
o2 = nil
end
if c4 then
o3 = _bor( _blshift(_band(c3, 3), 6), c4 )
else
o3 = nil
end
return o1, o2, o3
local c1 = base64ToSixBit(_sub(s1, 1, 1))
local c2 = base64ToSixBit(_sub(s1, 2, 2))
local c3
local c4
local o1
local o2
local o3
if _sub(s1, 3, 3) == "=" then
c3 = nil
c4 = nil
elseif _sub(s1, 4, 4) == "=" then
c3 = base64ToSixBit(_sub(s1, 3, 3))
c4 = nil
else
c3 = base64ToSixBit(_sub(s1, 3, 3))
c4 = base64ToSixBit(_sub(s1, 4, 4))
end
o1 = _bor( _blshift(c1, 2), _brshift(_band( c2, 0x30 ), 4) )
if c3 then
o2 = _bor( _blshift(_band(c2, 0x0F), 4), _brshift(_band( c3, 0x3C ), 2) )
else
o2 = nil
end
if c4 then
o3 = _bor( _blshift(_band(c3, 3), 6), c4 )
else
o3 = nil
end
return o1, o2, o3
end
local function splitIntoBlocks(bytes)
local blockNum = 1
local blocks = {}
for i=1, #bytes, 3 do
blocks[blockNum] = {bytes[i], bytes[i+1], bytes[i+2]}
--[[
if #blocks[blockNum] < 3 then
for j=#blocks[blockNum]+1, 3 do
table.insert(blocks[blockNum], 0)
end
end
]]
blockNum = blockNum+1
end
return blocks
local blockNum = 1
local blocks = {}
for i=1, #bytes, 3 do
blocks[blockNum] = {bytes[i], bytes[i+1], bytes[i+2]}
--[[
if #blocks[blockNum] < 3 then
for j=#blocks[blockNum]+1, 3 do
table.insert(blocks[blockNum], 0)
end
end
]]
blockNum = blockNum+1
end
return blocks
end
function Base64.encode(bytes)
local blocks = splitIntoBlocks(bytes)
local output = ""
for i=1, #blocks do
output = output..octetToBase64( unpack(blocks[i]) )
end
return output
local blocks = splitIntoBlocks(bytes)
local output = ""
for i=1, #blocks do
output = output..octetToBase64( unpack(blocks[i]) )
end
return output
end
local function Throttle()
@@ -123,32 +123,32 @@ local function Throttle()
end
function Base64.decode(str)
local bytes = {}
local blocks = {}
local blockNum = 1
local throttle = Throttle()
for i=1, #str, 4 do
blocks[blockNum] = _sub(str, i, i+3)
blockNum = blockNum+1
end
for i=1, #blocks do
local o1, o2, o3 = base64ToThreeOctet(blocks[i])
table.insert(bytes, o1)
table.insert(bytes, o2)
table.insert(bytes, o3)
throttle()
end
-- Remove padding:
--[[
for i=#bytes, 1, -1 do
if bytes[i] ~= 0 then
break
else
bytes[i] = nil
end
end
]]
return bytes
local bytes = {}
local blocks = {}
local blockNum = 1
local throttle = Throttle()
for i=1, #str, 4 do
blocks[blockNum] = _sub(str, i, i+3)
blockNum = blockNum+1
end
for i=1, #blocks do
local o1, o2, o3 = base64ToThreeOctet(blocks[i])
table.insert(bytes, o1)
table.insert(bytes, o2)
table.insert(bytes, o3)
throttle()
end
-- Remove padding:
--[[
for i=#bytes, 1, -1 do
if bytes[i] ~= 0 then
break
else
bytes[i] = nil
end
end
]]
return bytes
end
return Base64

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,10 @@ local turtle = _G.turtle
local Builder = class()
Util.merge(Builder, {
isCommandComputer = not turtle,
loc = { },
index = 1,
mode = 'build',
isCommandComputer = not turtle,
loc = { },
index = 1,
mode = 'build',
})
local BUILDER_DIR = 'usr/builder'
@@ -20,82 +20,82 @@ local BUILDER_DIR = 'usr/builder'
local blockInfo = Blocks()
function Builder:getBlockCounts()
local blocks = { }
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
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
return blocks
end
function Builder:substituteBlocks(throttle)
for _,b in pairs(self.schematic.blocks) do
for _,b in pairs(self.schematic.blocks) do
-- replace schematic block type with substitution
local pb = blockInfo:getPlaceableBlock(b.id, b.dmg)
-- replace schematic block type with substitution
local pb = blockInfo:getPlaceableBlock(b.id, b.dmg)
Util.merge(b, pb)
Util.merge(b, pb)
b.odmg = pb.odmg or pb.dmg
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
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)
self.schematic:reload(throttle)
self:substituteBlocks(throttle)
end
function Builder:log(...)
Util.print(...)
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
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
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 }
)
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
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

View File

@@ -8,77 +8,77 @@ local os = _G.os
local read = _G.read
function Builder:begin()
local direction = 1
local last = #self.schematic.blocks
local throttle = Util.throttle()
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
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
if self.mode == 'destroy' then
direction = -1
last = 1
end
for i = self.index, last, direction do
self.index = i
for i = self.index, last, direction do
self.index = i
local b = self.schematic:getComputedBlock(i)
local b = self.schematic:getComputedBlock(i)
if b.id ~= 'minecraft:air' then
if b.id ~= 'minecraft:air' then
self:logBlock(self.index, b)
self:logBlock(self.index, b)
local id = b.id
if self.mode == 'destroy' then
id = 'minecraft:air'
end
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,
}, ' ')
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)
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
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)
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 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
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()
fs.delete(self.schematic.filename .. '.progress')
print('Finished')
Event.exitPullEvents()
end
return Builder

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,390 +10,390 @@ local os = _G.os
local turtle = _G.turtle
--[[
A supplier turtle for the builder turtle. For larger builds, use
ender modems.
A supplier turtle for the builder turtle. For larger builds, use
ender modems.
Setup:
Setup:
1. chest or ME interface at level 0 (bottom of build area)
2. builder turtle on top facing the build area
3. If facing the build turtle, the supplier turtle is to the right
pointing at the chest/interface
1. chest or ME interface at level 0 (bottom of build area)
2. builder turtle on top facing the build area
3. If facing the build turtle, the supplier turtle is to the right
pointing at the chest/interface
]]--
local ChestProvider = require('core.chestProvider')
if Util.getVersion() == 1.8 then
ChestProvider = require('core.chestProvider18')
ChestProvider = require('core.chestProvider18')
end
if not device.wireless_modem then
error('No wireless modem detected')
error('No wireless modem detected')
end
local __BUILDER_ID = 6
local itemInfoDB
local Builder = {
version = '1.70',
ccVersion = nil,
slots = { },
index = 1,
fuelItem = { id = 'minecraft:coal', dmg = 0 },
resupplying = true,
ready = true,
version = '1.70',
ccVersion = nil,
slots = { },
index = 1,
fuelItem = { id = 'minecraft:coal', dmg = 0 },
resupplying = true,
ready = true,
}
--[[-- maxStackDB --]]--
local maxStackDB = TableDB({
fileName = 'maxstack.db',
tabledef = {
autokeys = false,
type = 'simple',
columns = {
{ label = 'Key', type = 'key', length = 8 },
{ label = 'Quantity', type = 'number', length = 2 }
}
}
fileName = 'maxstack.db',
tabledef = {
autokeys = false,
type = 'simple',
columns = {
{ label = 'Key', type = 'key', length = 8 },
{ label = 'Quantity', type = 'number', length = 2 }
}
}
})
function maxStackDB:get(id, dmg)
return self.data[id .. ':' .. dmg] or 64
return self.data[id .. ':' .. dmg] or 64
end
function Builder:dumpInventory()
local success = true
local success = true
for i = 1, 16 do
local qty = turtle.getItemCount(i)
if qty > 0 then
self.itemProvider:insert(i, qty)
end
if turtle.getItemCount(i) ~= 0 then
success = false
end
end
turtle.select(1)
for i = 1, 16 do
local qty = turtle.getItemCount(i)
if qty > 0 then
self.itemProvider:insert(i, qty)
end
if turtle.getItemCount(i) ~= 0 then
success = false
end
end
turtle.select(1)
return success
return success
end
function Builder:dumpInventoryWithCheck()
while not self:dumpInventory() do
Builder:log('Unable to dump inventory')
print('Provider is full or missing - make space or replace')
print('Press enter to continue')
--turtle.setHeading(0)
self.ready = false
_G.read()
end
self.ready = true
while not self:dumpInventory() do
Builder:log('Unable to dump inventory')
print('Provider is full or missing - make space or replace')
print('Press enter to continue')
--turtle.setHeading(0)
self.ready = false
_G.read()
end
self.ready = true
end
function Builder:autocraft(supplies)
local t = { }
local t = { }
for _,s in pairs(supplies) do
local key = s.id .. ':' .. s.dmg
local item = t[key]
if not item then
item = {
id = s.id,
dmg = s.dmg,
qty = 0,
}
t[key] = item
end
item.qty = item.qty + (s.need-s.qty)
end
for _,s in pairs(supplies) do
local key = s.id .. ':' .. s.dmg
local item = t[key]
if not item then
item = {
id = s.id,
dmg = s.dmg,
qty = 0,
}
t[key] = item
end
item.qty = item.qty + (s.need-s.qty)
end
Builder.itemProvider:craftItems(t)
Builder.itemProvider:craftItems(t)
end
function Builder:refuel()
while turtle.getFuelLevel() < 4000 and self.fuelItem do
Builder:log('Refueling')
turtle.select(1)
self.itemProvider:provide(self.fuelItem, 64, 1)
if turtle.getItemCount(1) == 0 then
Builder:log('Out of fuel, add coal to chest/ME system')
--turtle.setHeading(0)
os.sleep(5)
else
turtle.refuel(64)
end
end
while turtle.getFuelLevel() < 4000 and self.fuelItem do
Builder:log('Refueling')
turtle.select(1)
self.itemProvider:provide(self.fuelItem, 64, 1)
if turtle.getItemCount(1) == 0 then
Builder:log('Out of fuel, add coal to chest/ME system')
--turtle.setHeading(0)
os.sleep(5)
else
turtle.refuel(64)
end
end
end
function Builder:log(...)
Util.print(...)
Util.print(...)
end
function Builder:getSupplies()
Builder.itemProvider:refresh()
Builder.itemProvider:refresh()
local t = { }
for _,s in ipairs(self.slots) do
if s.need > 0 then
local item = Builder.itemProvider:getItemInfo(s)
if item then
if item.name then
s.name = item.name
end
local t = { }
for _,s in ipairs(self.slots) do
if s.need > 0 then
local item = Builder.itemProvider:getItemInfo(s)
if item then
if item.name then
s.name = item.name
end
local qty = math.min(s.need-s.qty, item.qty)
local qty = math.min(s.need-s.qty, item.qty)
if qty + s.qty > item.max_size then
maxStackDB:add({ s.id, s.dmg }, item.max_size)
maxStackDB.dirty = true
maxStackDB:flush()
qty = item.max_size
s.need = qty
end
if qty > 0 then
self.itemProvider:provide(item, qty, s.index)
s.qty = turtle.getItemCount(s.index)
end
end
end
if s.qty < s.need then
table.insert(t, s)
local name = s.name or s.id .. ':' .. s.dmg
local item = itemInfoDB:get({ s.id, s.dmg })
if item then
name = item.displayName
end
if qty + s.qty > item.max_size then
maxStackDB:add({ s.id, s.dmg }, item.max_size)
maxStackDB.dirty = true
maxStackDB:flush()
qty = item.max_size
s.need = qty
end
if qty > 0 then
self.itemProvider:provide(item, qty, s.index)
s.qty = turtle.getItemCount(s.index)
end
end
end
if s.qty < s.need then
table.insert(t, s)
local name = s.name or s.id .. ':' .. s.dmg
local item = itemInfoDB:get({ s.id, s.dmg })
if item then
name = item.displayName
end
Builder:log('Need %d %s', s.need - s.qty, name)
end
end
Builder:log('Need %d %s', s.need - s.qty, name)
end
end
return t
return t
end
local function moveTowardsX(dx)
local direction = dx - turtle.point.x
local move
local direction = dx - turtle.point.x
local move
if direction == 0 then
return false
end
if direction == 0 then
return false
end
if direction > 0 and turtle.point.heading == 0 or
direction < 0 and turtle.point.heading == 2 then
move = turtle.forward
else
move = turtle.back
end
if direction > 0 and turtle.point.heading == 0 or
direction < 0 and turtle.point.heading == 2 then
move = turtle.forward
else
move = turtle.back
end
return move()
return move()
end
local function moveTowardsZ(dz)
local direction = dz - turtle.point.z
local move
local direction = dz - turtle.point.z
local move
if direction == 0 then
return false
end
if direction == 0 then
return false
end
if direction > 0 and turtle.point.heading == 1 or
direction < 0 and turtle.point.heading == 3 then
move = turtle.forward
else
move = turtle.back
end
if direction > 0 and turtle.point.heading == 1 or
direction < 0 and turtle.point.heading == 3 then
move = turtle.forward
else
move = turtle.back
end
return move()
return move()
end
function Builder:finish()
Builder.resupplying = true
Builder.ready = false
if turtle.gotoLocation('supplies') then
turtle.setHeading(1)
os.sleep(.1) -- random 'Computer is not connected' error...
Builder:dumpInventory()
Event.exitPullEvents()
print('Finished')
end
Builder.resupplying = true
Builder.ready = false
if turtle.gotoLocation('supplies') then
turtle.setHeading(1)
os.sleep(.1) -- random 'Computer is not connected' error...
Builder:dumpInventory()
Event.exitPullEvents()
print('Finished')
end
end
function Builder:gotoBuilder()
if Builder.lastPoint then
turtle.setStatus('tracking')
while true do
local pt = Point.copy(Builder.lastPoint)
pt.y = pt.y + 3
if turtle.point.y ~= pt.y then
turtle.gotoY(pt.y)
else
local distance = Point.turtleDistance(turtle.point, pt)
if distance <= 3 then
Builder:log('Synchronized')
break
end
if Builder.lastPoint then
turtle.setStatus('tracking')
while true do
local pt = Point.copy(Builder.lastPoint)
pt.y = pt.y + 3
if turtle.point.y ~= pt.y then
turtle.gotoY(pt.y)
else
local distance = Point.turtleDistance(turtle.point, pt)
if distance <= 3 then
Builder:log('Synchronized')
break
end
if turtle.point.heading % 2 == 0 then
if turtle.point.x == pt.x then
turtle.headTowardsZ(pt.z)
moveTowardsZ(pt.z)
else
moveTowardsX(pt.x)
end
elseif turtle.point.z ~= pt.z then
moveTowardsZ(pt.z)
else
turtle.headTowardsX(pt.x)
moveTowardsX(pt.x)
end
end
end
end
if turtle.point.heading % 2 == 0 then
if turtle.point.x == pt.x then
turtle.headTowardsZ(pt.z)
moveTowardsZ(pt.z)
else
moveTowardsX(pt.x)
end
elseif turtle.point.z ~= pt.z then
moveTowardsZ(pt.z)
else
turtle.headTowardsX(pt.x)
moveTowardsX(pt.x)
end
end
end
end
end
Message.addHandler('builder',
function(_, id, msg)
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
if not Builder.resupplying then
local pt = msg.contents
pt.y = pt.y + 3
turtle.setStatus('supervising')
turtle.gotoYfirst(pt)
end
end)
turtle.setStatus('supervising')
turtle.gotoYfirst(pt)
end
end)
Message.addHandler('supplyList',
function(_, id, msg)
if not id or id ~= __BUILDER_ID then
return
end
function(_, id, msg)
if not id or id ~= __BUILDER_ID then
return
end
turtle.setStatus('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)
Builder:log('Received supply list ' .. Builder.slotUid)
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()
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.setStatus('waiting')
os.sleep(5)
end
Builder:log('Got all supplies')
os.sleep(0)
Builder:gotoBuilder()
Builder.resupplying = false
end)
while true do
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(_, id, msg)
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
Builder:log('No supplies ready')
Message.send(__BUILDER_ID, 'gotSupplies')
else
turtle.setStatus('supplying')
Builder:log('Supplying')
os.sleep(0)
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)
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
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
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
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
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.setStatus('waiting')
end
end)
--p.condenseItems()
for i = 1, 16 do
p:extract(i, 64)
end
turtle.digDown()
turtle.setStatus('waiting')
end
end)
Message.addHandler('finished',
function(_, id)
if not id or id ~= __BUILDER_ID then
return
end
Builder:finish()
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.setStatus('aborting')
Builder:finish()
end)
function()
turtle.abort(false)
turtle.setStatus('aborting')
Builder:finish()
end)
local function onTheWay() -- parallel routine
while true do
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
end
end
end
while true do
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
end
end
end
end
local args = {...}
if #args < 2 then
error('syntax: <builder id> <facing>')
error('syntax: <builder id> <facing>')
end
__BUILDER_ID = tonumber(args[1])
@@ -401,30 +401,30 @@ __BUILDER_ID = tonumber(args[1])
maxStackDB:load()
itemInfoDB = TableDB({
fileName = 'items.db'
fileName = 'items.db'
})
itemInfoDB:load()
Builder.itemProvider = MEProvider({ direction = args[2] })
if not Builder.itemProvider:isValid() then
local sides = {
east = 'west',
west = 'east',
north = 'south',
south = 'north',
}
local sides = {
east = 'west',
west = 'east',
north = 'south',
south = 'north',
}
Builder.itemProvider = ChestProvider({ direction = sides[args[2]], wrapSide = 'front' })
if not Builder.itemProvider:isValid() then
error('A chest or ME interface must be in front of turtle')
end
Builder.itemProvider = ChestProvider({ direction = sides[args[2]], wrapSide = 'front' })
if not Builder.itemProvider:isValid() then
error('A chest or ME interface must be in front of turtle')
end
end
turtle.run(function()
turtle.setPoint({ x = -1, z = -2, y = -1, heading = 1 })
turtle.setPoint({ x = -1, z = -2, y = -1, heading = 1 })
turtle.saveLocation('supplies')
turtle.saveLocation('supplies')
Event.pullEvents(onTheWay)
Event.pullEvents(onTheWay)
end)

View File

@@ -13,15 +13,15 @@ local function Syntax(msg)
* Entity sensor
* Introspection module
]])
error(msg)
error(msg)
end
local neural = device['neuralInterface'] or Syntax('Must be run on a neural interface')
local function assertModule(module, name)
if not neural.hasModule(module) then
Syntax('Missing: ' .. name)
end
if not neural.hasModule(module) then
Syntax('Missing: ' .. name)
end
end
assertModule('plethora:glasses', 'Overlay glasses')
assertModule('plethora:sensor', 'Entity sensor')
@@ -31,102 +31,102 @@ local BUILDER_DIR = 'usr/builder'
--[[-- SubDB --]]--
local subDB = TableDB({
fileName = fs.combine(BUILDER_DIR, 'sub.db'),
fileName = fs.combine(BUILDER_DIR, 'sub.db'),
})
function subDB:load()
if fs.exists(self.fileName) then
TableDB.load(self)
elseif not Builder.isCommandComputer then
self:seedDB()
end
if fs.exists(self.fileName) then
TableDB.load(self)
elseif not Builder.isCommandComputer then
self:seedDB()
end
end
function subDB:seedDB()
self.data = {
[ "minecraft:redstone_wire:0" ] = "minecraft:redstone:0",
[ "minecraft:wall_sign:0" ] = "minecraft:sign:0",
[ "minecraft:standing_sign:0" ] = "minecraft:sign:0",
[ "minecraft:potatoes:0" ] = "minecraft:potato:0",
[ "minecraft:unlit_redstone_torch:0" ] = "minecraft:redstone_torch:0",
[ "minecraft:powered_repeater:0" ] = "minecraft:repeater:0",
[ "minecraft:unpowered_repeater:0" ] = "minecraft:repeater:0",
[ "minecraft:carrots:0" ] = "minecraft:carrot:0",
[ "minecraft:cocoa:0" ] = "minecraft:dye:3",
[ "minecraft:unpowered_comparator:0" ] = "minecraft:comparator:0",
[ "minecraft:powered_comparator:0" ] = "minecraft:comparator:0",
[ "minecraft:piston_head:0" ] = "minecraft:air:0",
[ "minecraft:piston_extension:0" ] = "minecraft:air:0",
[ "minecraft:portal:0" ] = "minecraft:air:0",
[ "minecraft:double_wooden_slab:0" ] = "minecraft:planks:0",
[ "minecraft:double_wooden_slab:1" ] = "minecraft:planks:1",
[ "minecraft:double_wooden_slab:2" ] = "minecraft:planks:2",
[ "minecraft:double_wooden_slab:3" ] = "minecraft:planks:3",
[ "minecraft:double_wooden_slab:4" ] = "minecraft:planks:4",
[ "minecraft:double_wooden_slab:5" ] = "minecraft:planks:5",
[ "minecraft:lit_redstone_lamp:0" ] = "minecraft:redstone_lamp:0",
[ "minecraft:double_stone_slab:1" ] = "minecraft:sandstone:0",
[ "minecraft:double_stone_slab:2" ] = "minecraft:planks:0",
[ "minecraft:double_stone_slab:3" ] = "minecraft:cobblestone:0",
[ "minecraft:double_stone_slab:4" ] = "minecraft:brick_block:0",
[ "minecraft:double_stone_slab:5" ] = "minecraft:stonebrick:0",
[ "minecraft:double_stone_slab:6" ] = "minecraft:nether_brick:0",
[ "minecraft:double_stone_slab:7" ] = "minecraft:quartz_block:0",
[ "minecraft:double_stone_slab:9" ] = "minecraft:sandstone:2",
[ "minecraft:double_stone_slab2:0" ] = "minecraft:sandstone:0",
[ "minecraft:stone_slab:2" ] = "minecraft:wooden_slab:0",
[ "minecraft:wheat:0" ] = "minecraft:wheat_seeds:0",
[ "minecraft:flowing_water:0" ] = "minecraft:air:0",
[ "minecraft:lit_furnace:0" ] = "minecraft:furnace:0",
[ "minecraft:wall_banner:0" ] = "minecraft:banner:0",
[ "minecraft:standing_banner:0" ] = "minecraft:banner:0",
[ "minecraft:tripwire:0" ] = "minecraft:string:0",
[ "minecraft:pumpkin_stem:0" ] = "minecraft:pumpkin_seeds:0",
}
self.dirty = true
self:flush()
self.data = {
[ "minecraft:redstone_wire:0" ] = "minecraft:redstone:0",
[ "minecraft:wall_sign:0" ] = "minecraft:sign:0",
[ "minecraft:standing_sign:0" ] = "minecraft:sign:0",
[ "minecraft:potatoes:0" ] = "minecraft:potato:0",
[ "minecraft:unlit_redstone_torch:0" ] = "minecraft:redstone_torch:0",
[ "minecraft:powered_repeater:0" ] = "minecraft:repeater:0",
[ "minecraft:unpowered_repeater:0" ] = "minecraft:repeater:0",
[ "minecraft:carrots:0" ] = "minecraft:carrot:0",
[ "minecraft:cocoa:0" ] = "minecraft:dye:3",
[ "minecraft:unpowered_comparator:0" ] = "minecraft:comparator:0",
[ "minecraft:powered_comparator:0" ] = "minecraft:comparator:0",
[ "minecraft:piston_head:0" ] = "minecraft:air:0",
[ "minecraft:piston_extension:0" ] = "minecraft:air:0",
[ "minecraft:portal:0" ] = "minecraft:air:0",
[ "minecraft:double_wooden_slab:0" ] = "minecraft:planks:0",
[ "minecraft:double_wooden_slab:1" ] = "minecraft:planks:1",
[ "minecraft:double_wooden_slab:2" ] = "minecraft:planks:2",
[ "minecraft:double_wooden_slab:3" ] = "minecraft:planks:3",
[ "minecraft:double_wooden_slab:4" ] = "minecraft:planks:4",
[ "minecraft:double_wooden_slab:5" ] = "minecraft:planks:5",
[ "minecraft:lit_redstone_lamp:0" ] = "minecraft:redstone_lamp:0",
[ "minecraft:double_stone_slab:1" ] = "minecraft:sandstone:0",
[ "minecraft:double_stone_slab:2" ] = "minecraft:planks:0",
[ "minecraft:double_stone_slab:3" ] = "minecraft:cobblestone:0",
[ "minecraft:double_stone_slab:4" ] = "minecraft:brick_block:0",
[ "minecraft:double_stone_slab:5" ] = "minecraft:stonebrick:0",
[ "minecraft:double_stone_slab:6" ] = "minecraft:nether_brick:0",
[ "minecraft:double_stone_slab:7" ] = "minecraft:quartz_block:0",
[ "minecraft:double_stone_slab:9" ] = "minecraft:sandstone:2",
[ "minecraft:double_stone_slab2:0" ] = "minecraft:sandstone:0",
[ "minecraft:stone_slab:2" ] = "minecraft:wooden_slab:0",
[ "minecraft:wheat:0" ] = "minecraft:wheat_seeds:0",
[ "minecraft:flowing_water:0" ] = "minecraft:air:0",
[ "minecraft:lit_furnace:0" ] = "minecraft:furnace:0",
[ "minecraft:wall_banner:0" ] = "minecraft:banner:0",
[ "minecraft:standing_banner:0" ] = "minecraft:banner:0",
[ "minecraft:tripwire:0" ] = "minecraft:string:0",
[ "minecraft:pumpkin_stem:0" ] = "minecraft:pumpkin_seeds:0",
}
self.dirty = true
self:flush()
end
function subDB:add(s)
TableDB.add(self, { s.id, s.dmg }, table.concat({ s.sid, s.sdmg }, ':'))
self:flush()
TableDB.add(self, { s.id, s.dmg }, table.concat({ s.sid, s.sdmg }, ':'))
self:flush()
end
function subDB:remove(s)
-- TODO: tableDB.remove should take table key
TableDB.remove(self, s.id .. ':' .. s.dmg)
self:flush()
-- TODO: tableDB.remove should take table key
TableDB.remove(self, s.id .. ':' .. s.dmg)
self:flush()
end
function subDB:extract(s)
local id, dmg = s:match('(.+):(%d+)')
return id, tonumber(dmg)
local id, dmg = s:match('(.+):(%d+)')
return id, tonumber(dmg)
end
function subDB:getSubstitutedItem(id, dmg)
local sub = TableDB.get(self, { id, dmg })
if sub then
id, dmg = self:extract(sub)
end
return { id = id, dmg = dmg }
local sub = TableDB.get(self, { id, dmg })
if sub then
id, dmg = self:extract(sub)
end
return { id = id, dmg = dmg }
end
function subDB:lookupBlocksForSub(sid, sdmg)
local t = { }
for k,v in pairs(self.data) do
local id, dmg = self:extract(v)
if id == sid and dmg == sdmg then
id, dmg = self:extract(k)
t[k] = { id = id, dmg = dmg, sid = sid, sdmg = sdmg }
end
end
return t
local t = { }
for k,v in pairs(self.data) do
local id, dmg = self:extract(v)
if id == sid and dmg == sdmg then
id, dmg = self:extract(k)
t[k] = { id = id, dmg = dmg, sid = sid, sdmg = sdmg }
end
end
return t
end
--[[-- startup logic --]]--
local args = {...}
if #args < 1 then
error('supply file name')
error('supply file name')
end
subDB:load()
@@ -142,18 +142,18 @@ Builder:substituteBlocks(Util.throttle())
local cn = neural.canvas3d().create()
local pos = neural.getMetaOwner().withinBlock
cn.recenter({-(pos.x + .5), -(pos.y + 2) + .5, -(pos.z + .5) })
cn.recenter({-pos.x + .5, -(pos.y + 2) + .5, -pos.z + .5 })
for i = 1, #Builder.schematic.blocks do
local b = Builder.schematic:getComputedBlock(i)
if b.id ~= "minecraft:air" and b.id ~= 'minecraft:water' then
local s, m = pcall(function()
cn.addItem({ b.x, b.y, b.z }, b.id, b.dmg)
end)
if not s and m then
_G.printError(m)
end
end
local b = Builder.schematic:getComputedBlock(i)
if b.id ~= "minecraft:air" and b.id ~= 'minecraft:water' then
local s, m = pcall(function()
cn.addItem({ b.x, b.y, b.z }, b.id, b.dmg)
end)
if not s and m then
_G.printError(m)
end
end
end
pcall(_G.read)