1
0
mirror of https://github.com/kepler155c/opus synced 2025-01-24 06:06:54 +00:00

builder improvements

This commit is contained in:
kepler155c@gmail.com 2017-06-23 02:04:56 -04:00
parent 3f66a9397c
commit 7f99c0c69a
20 changed files with 2827 additions and 675 deletions

View File

@ -1,5 +1,39 @@
local class = require('class') local class = require('class')
local TableDB = require('tableDB') local TableDB = require('tableDB')
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
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
local blockDB = TableDB({ local blockDB = TableDB({
fileName = 'block.db', fileName = 'block.db',
@ -16,7 +50,7 @@ local blockDB = TableDB({
} }
}) })
function blockDB:load(dir, sbDB, btDB) function blockDB:load(dir)
self.fileName = fs.combine(dir, self.fileName) self.fileName = fs.combine(dir, self.fileName)
if fs.exists(self.fileName) then if fs.exists(self.fileName) then
TableDB.load(self) TableDB.load(self)
@ -27,89 +61,25 @@ end
function blockDB:seedDB(dir) function blockDB:seedDB(dir)
-- http://lua-users.org/wiki/LuaCsv local blocks = JSON.decodeFromFile(fs.combine('sys/etc', 'blocks.json'))
function ParseCSVLine (line,sep)
local res = {} if not blocks then
local pos = 1 error('Unable to read blocks.json')
sep = sep or ',' end
while true do
local c = string.sub(line,pos,pos) for strId, block in pairs(blocks) do
if (c == "") then break end strId = 'minecraft:' .. strId
if (c == '"') then if type(block.name) == 'string' then
-- quoted value (ignore separator within) self:add(block.id, 0, block.name, strId)
local txt = ""
repeat
local startp,endp = string.find(line,'^%b""',pos)
txt = txt..string.sub(line,startp+1,endp-1)
pos = endp + 1
c = string.sub(line,pos,pos)
if (c == '"') then txt = txt..'"' end
-- check first char AFTER quoted string, if it is another
-- quoted string without separator, then append it
-- this is the way to "escape" the quote char in a quote. example:
-- value1,"blub""blip""boing",value3 will result in blub"blip"boing for the middle
until (c ~= '"')
table.insert(res,txt)
assert(c == sep or c == "")
pos = pos + 1
else else
-- no quotes used, just look for the first separator for nid,name in pairs(block.name) do
local startp,endp = string.find(line,sep,pos) self:add(block.id, nid - 1, name, strId)
if (startp) then
table.insert(res,string.sub(line,pos,startp-1))
pos = endp + 1
else
-- no separator found -> use rest of string and terminate
table.insert(res,string.sub(line,pos))
break
end end
end end
end end
return res
end
local f = fs.open(fs.combine('sys/etc', 'blockIds.csv'), "r")
if not f then
error('unable to read blockIds.csv')
end
local lastID = nil
while true do
local data = f.readLine()
if not data then
break
end
local line = ParseCSVLine(data, ',')
local strId = line[3] -- string ID
local nid -- schematic ID
local id = line[3]
local dmg = 0
local name = line[1]
if not strId or #strId == 0 then
strId = lastID
end
lastID = strId
local t = { }
string.gsub(line[2], '(%d+)', function(d) table.insert(t, d) end)
nid = tonumber(t[1])
dmg = 0
if t[2] then
dmg = tonumber(t[2])
end
self:add(nid, dmg, name, strId)
end
f.close()
self.dirty = true self.dirty = true
self:flush() -- self:flush()
end end
function blockDB:lookup(id, dmg) function blockDB:lookup(id, dmg)
@ -117,27 +87,12 @@ function blockDB:lookup(id, dmg)
if not id then if not id then
return return
end end
if not id or not dmg then error('blockDB:lookup: nil passed', 2) end if not id or not dmg then error('blockDB:lookup: nil passed', 2) end
local key = id .. ':' .. dmg local key = id .. ':' .. dmg
return self.data[key] return self.data[key]
end end
function blockDB:getName(id, dmg)
return self:lookupName(id, dmg) or id .. ':' .. dmg
end
function blockDB:lookupName(id, dmg)
if not id or not dmg then error('blockDB:lookupName: nil passed', 2) end
for _,v in pairs(self.data) do
if v.strId == id and v.dmg == dmg then
return v.name
end
end
end
function blockDB:add(id, dmg, name, strId) function blockDB:add(id, dmg, name, strId)
local key = id .. ':' .. dmg local key = id .. ':' .. dmg
@ -170,7 +125,7 @@ function placementDB:load(dir, sbDB, btDB)
end end
-- testing -- testing
-- self.dirty = true self.dirty = true
--self:flush() --self:flush()
end end
@ -192,11 +147,12 @@ function placementDB:addSubsForBlockType(id, dmg, bt)
odmg, odmg,
sub.sid or strId, sub.sid or strId,
sub.sdmg or dmg, sub.sdmg or dmg,
sub.dir) sub.dir,
sub.extra)
end end
end end
function placementDB:add(id, dmg, sid, sdmg, direction) function placementDB:add(id, dmg, sid, sdmg, direction, extra)
if not id or not dmg then error('placementDB:add: nil passed', 2) end if not id or not dmg then error('placementDB:add: nil passed', 2) end
local key = id .. ':' .. dmg local key = id .. ':' .. dmg
@ -212,6 +168,7 @@ function placementDB:add(id, dmg, sid, sdmg, direction)
sid = sid, -- string ID sid = sid, -- string ID
sdmg = sdmg, -- dmg without placement info sdmg = sdmg, -- dmg without placement info
direction = direction, direction = direction,
extra = extra,
} }
end end
@ -286,7 +243,7 @@ function standardBlockDB:seedDB()
[ '65:0' ] = 'wallsign-ladder', [ '65:0' ] = 'wallsign-ladder',
[ '66:0' ] = 'rail', [ '66:0' ] = 'rail',
[ '67:0' ] = 'stairs', [ '67:0' ] = 'stairs',
[ '68:0' ] = 'wallsign', [ '68:0' ] = 'wallsign-ladder',
[ '69:0' ] = 'lever', [ '69:0' ] = 'lever',
[ '71:0' ] = 'door', [ '71:0' ] = 'door',
[ '75:0' ] = 'torch', [ '75:0' ] = 'torch',
@ -295,6 +252,7 @@ function standardBlockDB:seedDB()
[ '78:0' ] = 'flatten', [ '78:0' ] = 'flatten',
[ '81:0' ] = 'flatten', [ '81:0' ] = 'flatten',
[ '83:0' ] = 'flatten', [ '83:0' ] = 'flatten',
[ '84:0' ] = 'flatten', -- jukebox
[ '86:0' ] = 'pumpkin', [ '86:0' ] = 'pumpkin',
[ '90:0' ] = 'air', [ '90:0' ] = 'air',
[ '91:0' ] = 'pumpkin', [ '91:0' ] = 'pumpkin',
@ -312,6 +270,7 @@ function standardBlockDB:seedDB()
[ '115:0' ] = 'flatten', [ '115:0' ] = 'flatten',
[ '117:0' ] = 'flatten', [ '117:0' ] = 'flatten',
[ '118:0' ] = 'cauldron', [ '118:0' ] = 'cauldron',
[ '120:0' ] = 'flatten', -- end portal
[ '126:0' ] = 'slab', [ '126:0' ] = 'slab',
[ '126:1' ] = 'slab', [ '126:1' ] = 'slab',
[ '126:2' ] = 'slab', [ '126:2' ] = 'slab',
@ -339,7 +298,7 @@ function standardBlockDB:seedDB()
[ '155:2' ] = 'quartz-pillar', [ '155:2' ] = 'quartz-pillar',
[ '156:0' ] = 'stairs', [ '156:0' ] = 'stairs',
[ '157:0' ] = 'adp-rail', [ '157:0' ] = 'adp-rail',
[ '158:0' ] = 'hopper', [ '158:0' ] = 'dispenser',
[ '161:0' ] = 'leaves', [ '161:0' ] = 'leaves',
[ '161:1' ] = 'leaves', [ '161:1' ] = 'leaves',
[ '162:0' ] = 'wood', [ '162:0' ] = 'wood',
@ -347,15 +306,15 @@ function standardBlockDB:seedDB()
[ '163:0' ] = 'stairs', [ '163:0' ] = 'stairs',
[ '164:0' ] = 'stairs', [ '164:0' ] = 'stairs',
[ '167:0' ] = 'trapdoor', [ '167:0' ] = 'trapdoor',
[ '170:0' ] = 'quartz-pillar', -- hay bale [ '170:0' ] = 'hay-bale', -- hay bale
[ '175:0' ] = 'largeplant', [ '175:0' ] = 'largeplant',
[ '175:1' ] = 'largeplant', [ '175:1' ] = 'largeplant',
[ '175:2' ] = 'largeplant', -- double tallgrass - an alternative would be to use grass as the bottom part, bonemeal as top part [ '175:2' ] = 'largeplant', -- double tallgrass - an alternative would be to use grass as the bottom part, bonemeal as top part
[ '175:3' ] = 'largeplant', [ '175:3' ] = 'largeplant',
[ '175:4' ] = 'largeplant', [ '175:4' ] = 'largeplant',
[ '175:5' ] = 'largeplant', [ '175:5' ] = 'largeplant',
[ '176:0' ] = 'banner', [ '176:0' ] = 'signpost',
[ '177:0' ] = 'wall_banner', [ '177:0' ] = 'wallsign-ladder',
[ '178:0' ] = 'truncate', [ '178:0' ] = 'truncate',
[ '180:0' ] = 'stairs', [ '180:0' ] = 'stairs',
[ '182:0' ] = 'slab', [ '182:0' ] = 'slab',
@ -369,7 +328,7 @@ function standardBlockDB:seedDB()
[ '195:0' ] = 'door', [ '195:0' ] = 'door',
[ '196:0' ] = 'door', [ '196:0' ] = 'door',
[ '197:0' ] = 'door', [ '197:0' ] = 'door',
[ '198:0' ] = 'flatten', [ '198:0' ] = 'end_rod', -- end rod
[ '205:0' ] = 'slab', [ '205:0' ] = 'slab',
[ '210:0' ] = 'flatten', [ '210:0' ] = 'flatten',
[ '355:0' ] = 'bed', [ '355:0' ] = 'bed',
@ -377,7 +336,7 @@ function standardBlockDB:seedDB()
[ '404:0' ] = 'comparator', [ '404:0' ] = 'comparator',
} }
self.dirty = true self.dirty = true
self:flush() -- self:flush()
end end
--[[-- BlockTypeDB --]]-- --[[-- BlockTypeDB --]]--
@ -415,7 +374,8 @@ function blockTypeDB:addTemp(blockType, subs)
odmg = sub[1], odmg = sub[1],
sid = sub[2], sid = sub[2],
sdmg = sub[3], sdmg = sub[3],
dir = sub[4] dir = sub[4],
extra = sub[5]
}) })
end end
self.dirty = true self.dirty = true
@ -512,6 +472,11 @@ function blockTypeDB:seedDB()
{ 3, nil, 2, 'north-south-block' }, { 3, nil, 2, 'north-south-block' },
{ 4, nil, 2, 'east-west-block' }, -- should be east-west-block { 4, nil, 2, 'east-west-block' }, -- should be east-west-block
}) })
blockTypeDB:addTemp('hay-bale', {
{ 0, nil, 0 },
{ 4, nil, 0, 'east-west-block' }, -- should be east-west-block
{ 8, nil, 0, 'north-south-block' },
})
blockTypeDB:addTemp('button', { blockTypeDB:addTemp('button', {
{ 1, nil, 0, 'west-block' }, { 1, nil, 0, 'west-block' },
{ 2, nil, 0, 'east-block' }, { 2, nil, 0, 'east-block' },
@ -526,14 +491,23 @@ function blockTypeDB:seedDB()
{ 3, nil, 0 }, { 3, nil, 0 },
}) })
blockTypeDB:addTemp('dispenser', { blockTypeDB:addTemp('dispenser', {
{ 0, nil, 0 }, { 0, nil, 0, 'wrench-down' },
{ 1, nil, 0 }, { 1, nil, 0, 'wrench-up' },
{ 2, nil, 0, 'south' }, { 2, nil, 0, 'south' },
{ 3, nil, 0, 'north' }, { 3, nil, 0, 'north' },
{ 4, nil, 0, 'east' }, { 4, nil, 0, 'east' },
{ 5, nil, 0, 'west' }, { 5, nil, 0, 'west' },
{ 9, nil, 0 }, { 9, nil, 0 },
}) })
blockTypeDB:addTemp('end_rod', {
{ 0, nil, 0, 'wrench-down' },
{ 1, nil, 0, 'wrench-up' },
{ 2, nil, 0, 'south-block-flip' },
{ 3, nil, 0, 'north-block-flip' },
{ 4, nil, 0, 'east-block-flip' },
{ 5, nil, 0, 'west-block-flip' },
{ 9, nil, 0 },
})
blockTypeDB:addTemp('hopper', { blockTypeDB:addTemp('hopper', {
{ 0, nil, 0 }, { 0, nil, 0 },
{ 1, nil, 0 }, { 1, nil, 0 },
@ -541,6 +515,7 @@ function blockTypeDB:seedDB()
{ 3, nil, 0, 'north-block' }, { 3, nil, 0, 'north-block' },
{ 4, nil, 0, 'east-block' }, { 4, nil, 0, 'east-block' },
{ 5, nil, 0, 'west-block' }, { 5, nil, 0, 'west-block' },
{ 8, nil, 0 },
{ 9, nil, 0 }, { 9, nil, 0 },
{ 10, nil, 0 }, { 10, nil, 0 },
{ 11, nil, 0, 'south-block' }, { 11, nil, 0, 'south-block' },
@ -583,22 +558,22 @@ function blockTypeDB:seedDB()
{ 13, nil, 0, 'south' }, { 13, nil, 0, 'south' },
}) })
blockTypeDB:addTemp('signpost', { blockTypeDB:addTemp('signpost', {
{ 0, nil, 0, 'south' }, { 0, nil, 0, 'north' },
{ 1, nil, 0, 'south' }, { 1, nil, 0, 'north', { facing = 1 } },
{ 2, nil, 0, 'south' }, { 2, nil, 0, 'north', { facing = 2 } },
{ 3, nil, 0, 'south' }, { 3, nil, 0, 'north', { facing = 3 } },
{ 4, nil, 0, 'west' }, { 4, nil, 0, 'east' },
{ 5, nil, 0, 'west' }, { 5, nil, 0, 'east', { facing = 1 } },
{ 6, nil, 0, 'west' }, { 6, nil, 0, 'east', { facing = 2 } },
{ 7, nil, 0, 'west' }, { 7, nil, 0, 'east', { facing = 3 } },
{ 8, nil, 0, 'north' }, { 8, nil, 0, 'south' },
{ 9, nil, 0, 'north' }, { 9, nil, 0, 'south', { facing = 1 } },
{ 10, nil, 0, 'north' }, { 10, nil, 0, 'south', { facing = 2 } },
{ 11, nil, 0, 'north' }, { 11, nil, 0, 'south', { facing = 3 } },
{ 12, nil, 0, 'east' }, { 12, nil, 0, 'west' },
{ 13, nil, 0, 'east' }, { 13, nil, 0, 'west', { facing = 1 } },
{ 14, nil, 0, 'east' }, { 14, nil, 0, 'west', { facing = 2 } },
{ 15, nil, 0, 'east' }, { 15, nil, 0, 'west', { facing = 3 } },
}) })
blockTypeDB:addTemp('vine', { blockTypeDB:addTemp('vine', {
{ 0, nil, 0 }, { 0, nil, 0 },
@ -684,18 +659,12 @@ function blockTypeDB:seedDB()
}) })
blockTypeDB:addTemp('wallsign-ladder', { blockTypeDB:addTemp('wallsign-ladder', {
{ 0, nil, 0 }, { 0, nil, 0 },
{ 1, nil, 0 },
{ 2, nil, 0, 'south-block' }, { 2, nil, 0, 'south-block' },
{ 3, nil, 0, 'north-block' }, { 3, nil, 0, 'north-block' },
{ 4, nil, 0, 'east-block' }, { 4, nil, 0, 'east-block' },
{ 5, nil, 0, 'west-block' }, { 5, nil, 0, 'west-block' },
}) })
blockTypeDB:addTemp('wallsign', {
{ 0, nil, 0 },
{ 2, 'minecraft:sign', 0, 'south-block' },
{ 3, 'minecraft:sign', 0, 'north-block' },
{ 4, 'minecraft:sign', 0, 'east-block' },
{ 5, 'minecraft:sign', 0, 'west-block' },
})
blockTypeDB:addTemp('chest-furnace', { blockTypeDB:addTemp('chest-furnace', {
{ 0, nil, 0 }, { 0, nil, 0 },
{ 2, nil, 0, 'south' }, { 2, nil, 0, 'south' },
@ -817,32 +786,6 @@ function blockTypeDB:seedDB()
{ 14,'minecraft:air', 0 }, { 14,'minecraft:air', 0 },
{ 15,'minecraft:air', 0 }, { 15,'minecraft:air', 0 },
}) })
blockTypeDB:addTemp('banner', {
{ 0, nil, 0, 'north' },
{ 1, nil, 0, 'east' },
{ 2, nil, 0, 'east' },
{ 3, nil, 0, 'east' },
{ 4, nil, 0, 'east' },
{ 5, nil, 0, 'east' },
{ 6, nil, 0, 'east' },
{ 7, nil, 0, 'east' },
{ 8, nil, 0, 'south' },
{ 9, nil, 0, 'west' },
{ 10, nil, 0, 'west' },
{ 11, nil, 0, 'west' },
{ 12, nil, 0, 'west' },
{ 13, nil, 0, 'west' },
{ 14, nil, 0, 'west' },
{ 15, nil, 0, 'west' },
})
blockTypeDB:addTemp('wall_banner', {
{ 0, nil, 0 },
{ 1, nil, 0 },
{ 2, nil, 0, 'south-block' },
{ 3, nil, 0, 'north-block' },
{ 4, nil, 0, 'east-block' },
{ 5, nil, 0, 'west-block' },
})
blockTypeDB:addTemp('cocoa', { blockTypeDB:addTemp('cocoa', {
{ 0, nil, 0, 'south-block' }, { 0, nil, 0, 'south-block' },
{ 1, nil, 0, 'west-block' }, { 1, nil, 0, 'west-block' },
@ -858,7 +801,7 @@ function blockTypeDB:seedDB()
{ 11, nil, 0, 'east-block' }, { 11, nil, 0, 'east-block' },
}) })
self.dirty = true self.dirty = true
self:flush() -- self:flush()
end end
local Blocks = class() local Blocks = class()
@ -866,10 +809,12 @@ function Blocks:init(args)
Util.merge(self, args) Util.merge(self, args)
self.blockDB = blockDB self.blockDB = blockDB
self.nameDB = nameDB
blockDB:load(self.dir) blockDB:load(self.dir)
standardBlockDB:load(self.dir) standardBlockDB:load(self.dir)
blockTypeDB:load(self.dir) blockTypeDB:load(self.dir)
nameDB:load(self.dir, blockDB)
placementDB:load(self.dir, standardBlockDB, blockTypeDB) placementDB:load(self.dir, standardBlockDB, blockTypeDB)
end end
@ -878,7 +823,7 @@ function Blocks:getRealBlock(id, dmg)
local p = placementDB:get({id, dmg}) local p = placementDB:get({id, dmg})
if p then if p then
return { id = p.sid, dmg = p.sdmg, direction = p.direction } return { id = p.sid, dmg = p.sdmg, direction = p.direction, extra = p.extra }
end end
local b = blockDB:get({id, dmg}) local b = blockDB:get({id, dmg})
@ -886,6 +831,11 @@ function Blocks:getRealBlock(id, dmg)
return { id = b.strId, dmg = b.dmg } return { id = b.strId, dmg = b.dmg }
end end
b = blockDB:get({id, 0})
if b then
return { id = b.strId, dmg = b.dmg }
end
return { id = id, dmg = dmg } return { id = id, dmg = dmg }
end end

View File

@ -1,65 +1,124 @@
local class = require('class') local class = require('class')
local TableDB = require('tableDB')
local Peripheral = require('peripheral')
local ChestProvider = class() local ChestProvider = class()
local keys = Util.transpose({
'damage',
'displayName',
'maxCount',
'maxDamage',
'name',
'nbtHash',
})
function ChestProvider:init(args) function ChestProvider:init(args)
args = args or { } local defaults = {
items = { },
name = 'chest',
direction = 'up',
wrapSide = 'bottom',
}
Util.merge(self, defaults)
Util.merge(self, args)
self.items = { } -- consolidated item info local chest = Peripheral.getBySide(self.wrapSide)
self.cache = { } if chest then
self.name = 'chest' Util.merge(self, chest)
self.direction = args.direction or 'up' end
self.wrapSide = args.wrapSide or 'bottom'
self.p = peripheral.wrap(self.wrapSide) if not self.itemInfoDB then
self.itemInfoDB = TableDB({
fileName = 'items.db'
})
self.itemInfoDB:load()
end
end end
function ChestProvider:isValid() function ChestProvider:isValid()
return self.p and self.p.list return not not self.list
end end
function ChestProvider:refresh() function ChestProvider:getCachedItemDetails(item, k)
if self.p then local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
self.items = { }
for k,s in pairs(self.p.list()) do
local key = s.name .. ':' .. s.damage local detail = self.itemInfoDB:get(key)
local entry = self.items[key] if not detail then
pcall(function() detail = self.getItemMeta(k) end)
if not detail then
return
end
if detail.name ~= item.name then
return
end
if detail.maxDamage and detail.maxDamage > 0 and detail.damage > 0 then
detail.displayName = detail.displayName .. ' (damaged)'
end
for _,k in ipairs(Util.keys(detail)) do
if not keys[k] then
detail[k] = nil
end
end
self.itemInfoDB:add(key, detail)
end
if detail then
return Util.shallowCopy(detail)
end
end
function ChestProvider:refresh(throttle)
return self:listItems(throttle)
end
-- provide a consolidated list of items
function ChestProvider:listItems(throttle)
self.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 }, ':')
local entry = self.cache[key]
if not entry then if not entry then
entry = self.cache[key] entry = self:getCachedItemDetails(v, k)
if not entry then if entry then
local meta = self.p.getItemMeta(k) -- slow method.. cache for speed entry.dmg = entry.damage
if meta then entry.id = entry.name
entry = { entry.count = 0
id = s.name, entry.display_name = entry.displayName
dmg = s.damage, entry.max_size = entry.maxCount
name = meta.displayName, entry.nbt_hash = entry.nbtHash
max_size = meta.maxCount, entry.lname = entry.displayName:lower()
}
self.cache[key] = entry self.cache[key] = entry
table.insert(items, entry)
end end
end end
if entry then
entry = Util.shallowCopy(entry)
self.items[key] = entry
entry.qty = 0
end
end
if entry then
entry.qty = entry.qty + s.count
end
end
end
return self.items
end
function ChestProvider:getItemInfo(id, dmg) if entry then
entry.count = entry.count + v.count
entry.qty = entry.count
end
throttle()
end
for key,item in pairs(self.items) do self.itemInfoDB:flush()
if item.id == id and item.dmg == dmg then
return item return items
end end
function ChestProvider:getItemInfo(id, dmg, nbtHash)
if not self.cache then
self:listItems()
end end
local key = table.concat({ id, dmg, nbtHash }, ':')
return self.cache[key]
end end
function ChestProvider:craft(id, dmg, qty) function ChestProvider:craft(id, dmg, qty)
@ -69,12 +128,11 @@ function ChestProvider:craftItems(items)
end end
function ChestProvider:provide(item, qty, slot) function ChestProvider:provide(item, qty, slot)
if self.p then local stacks = self.list()
local stacks = self.p.list()
for key,stack in pairs(stacks) do for key,stack in pairs(stacks) do
if stack.name == item.id and stack.damage == item.dmg then if stack.name == item.id and stack.damage == item.dmg then
local amount = math.min(qty, stack.count) local amount = math.min(qty, stack.count)
self.p.pushItems(self.direction, key, amount, slot) self.pushItems(self.direction, key, amount, slot)
qty = qty - amount qty = qty - amount
if qty <= 0 then if qty <= 0 then
break break
@ -82,18 +140,13 @@ function ChestProvider:provide(item, qty, slot)
end end
end end
end end
end
function ChestProvider:extract(slot, qty) function ChestProvider:extract(slot, qty)
if self.p then self.pushItems(self.direction, slot, qty)
self.p.pushItems(self.direction, slot, qty)
end
end end
function ChestProvider:insert(slot, qty) function ChestProvider:insert(slot, qty)
if self.p then self.pullItems(self.direction, slot, qty)
self.p.pullItems(self.direction, slot, qty)
end
end end
return ChestProvider return ChestProvider

View File

@ -139,19 +139,27 @@ function Event.addThread(fn)
end end
function Event.pullEvents(...) function Event.pullEvents(...)
Process:addThread(_pullEvents)
local routines = { ... } local routines = { ... }
if #routines > 0 then if #routines > 0 then
Process:addThread(_pullEvents)
for _, routine in ipairs(routines) do for _, routine in ipairs(routines) do
Process:addThread(routine) Process:addThread(routine)
end end
end
while true do while true do
local e = Process:pullEvent() local e = Process:pullEvent()
if exitPullEvents or e == 'terminate' then if exitPullEvents or e == 'terminate' then
break break
end end
end end
else
while true do
local e = { os.pullEvent() }
Event.processEvent(e)
if exitPullEvents or e == 'terminate' then
break
end
end
end
end end
function Event.exitPullEvents() function Event.exitPullEvents()

View File

@ -205,7 +205,7 @@ end
function json.decodeFromFile(path) function json.decodeFromFile(path)
local file = assert(fs.open(path, "r")) local file = assert(fs.open(path, "r"))
local decoded = decode(file.readAll()) local decoded = json.decode(file.readAll())
file.close() file.close()
return decoded return decoded
end end

View File

@ -51,6 +51,7 @@ function Peripheral.addDevice(deviceList, side)
end end
deviceList[name] = peripheral.wrap(side) deviceList[name] = peripheral.wrap(side)
if deviceList[name] then
Util.merge(deviceList[name], { Util.merge(deviceList[name], {
name = name, name = name,
type = ptype, type = ptype,
@ -59,6 +60,7 @@ function Peripheral.addDevice(deviceList, side)
return deviceList[name] return deviceList[name]
end end
end
function Peripheral.getBySide(side) function Peripheral.getBySide(side)
return Util.find(getDeviceList(), 'side', side) return Util.find(getDeviceList(), 'side', side)

View File

@ -62,13 +62,6 @@ function RefinedProvider:getCachedItemDetails(item)
end end
detail.lname = detail.displayName:lower() detail.lname = detail.displayName:lower()
-- backwards capability
detail.dmg = detail.damage
detail.id = detail.name
detail.qty = detail.count
detail.display_name = detail.displayName
detail.nbtHash = item.nbtHash
local t = { } local t = { }
for _,key in pairs(keys) do for _,key in pairs(keys) do
t[key] = detail[key] t[key] = detail[key]
@ -76,8 +69,6 @@ function RefinedProvider:getCachedItemDetails(item)
detail = t detail = t
self.itemInfoDB:add(key, detail) self.itemInfoDB:add(key, detail)
os.sleep(0) -- prevent timeout on large inventories
end end
end end
if detail then if detail then

View File

@ -148,20 +148,18 @@ function Schematic:parse(a, h, containsName, spinner)
end end
-- end http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/ -- end http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/
function Schematic:copyBlocks(iblocks, oblocks, spinner) function Schematic:copyBlocks(iblocks, oblocks, throttle)
for k,b in ipairs(iblocks) do for k,b in ipairs(iblocks) do
oblocks[k] = Util.shallowCopy(b) oblocks[k] = Util.shallowCopy(b)
if spinner then
if (k % 1000) == 0 then if (k % 1000) == 0 then
spinner:spin() throttle()
end
end end
end end
end end
function Schematic:reload() function Schematic:reload(throttle)
self.blocks = { } self.blocks = { }
self:copyBlocks(self.originalBlocks, self.blocks) self:copyBlocks(self.originalBlocks, self.blocks, throttle)
for _,ri in pairs(self.rowIndex) do for _,ri in pairs(self.rowIndex) do
ri.loaded = false ri.loaded = false
@ -283,7 +281,7 @@ function Schematic:loadpass(fh, spinner)
self:assignDamages(spinner) self:assignDamages(spinner)
self.damages = nil self.damages = nil
self:copyBlocks(self.blocks, self.originalBlocks, spinner) self:copyBlocks(self.blocks, self.originalBlocks, function() spinner:spin() end)
spinner:stop() spinner:stop()
end end
@ -488,6 +486,37 @@ function Schematic:bestSide(b, chains, ...)
}) })
end end
function Schematic:bestFlipSide(b, chains)
-- If there is a block to place this one against
local directions = {
[ 'east-block-flip' ] = 'east',
[ 'west-block-flip' ] = 'west',
[ 'north-block-flip' ] = 'north',
[ 'south-block-flip' ] = 'south',
}
local d = directions[b.direction]
local hi = turtle.getHeadingInfo(d)
local _, fb = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y)
if fb then
self:addPlacementChain(chains, {
{ x = b.x + hi.xd, z = b.z + hi.zd, y = b.y }, -- block we are placing against
{ x = b.x, z = b.z, y = b.y }, -- the block (or torch, etc)
{ x = b.x - hi.xd, z = b.z - hi.zd, y = b.y }, -- room for the turtle
})
b.direction = d .. '-block'
else
self:addPlacementChain(chains, {
{ x = b.x, z = b.z, y = b.y }, -- the block (or torch, etc)
{ 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'
end
end
function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better function Schematic:bestOfTwoSides(b, chains, side1, side2) -- could be better
local sb local sb
@ -617,12 +646,23 @@ function Schematic:determineBlockPlacement(y)
[ 'west-block-vine' ] = 'west-block', [ 'west-block-vine' ] = 'west-block',
[ 'north-block-vine' ] = 'north-block' [ 'north-block-vine' ] = 'north-block'
} }
local flipDirections = {
[ 'east-block-flip' ] = 'east-block',
[ 'south-block-flip' ] = 'south-block',
[ 'west-block-flip' ] = 'west-block',
[ 'north-block-flip' ] = 'north-block'
}
local dirtyBlocks = {} local dirtyBlocks = {}
local dirtyBlocks2 = {} local dirtyBlocks2 = {}
local chains = {} local chains = {}
local ri = self.rowIndex[y] local ri = self.rowIndex[y]
if not ri then
ri = { s = -1, e = -2 }
self.rowIndex[y] = ri
end
for k = ri.s, ri.e do for k = ri.s, ri.e do
local b = self.blocks[k] local b = self.blocks[k]
local d = b.direction local d = b.direction
@ -757,6 +797,8 @@ function Schematic:determineBlockPlacement(y)
b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4 b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4
end end
end end
elseif flipDirections[d] then
self:bestFlipSide(b, chains)
end end
if blockDirections[d] then if blockDirections[d] then
@ -790,6 +832,7 @@ function Schematic:determineBlockPlacement(y)
self:setPlacementOrder(spinner, chains) self:setPlacementOrder(spinner, chains)
local plane = self:optimizeRoute(spinner, y) local plane = self:optimizeRoute(spinner, y)
term.clearLine()
spinner:stop() spinner:stop()
for k,b in ipairs(plane) do for k,b in ipairs(plane) do

View File

@ -331,7 +331,7 @@ function Manager:click(button, x, y)
if button == 1 then if button == 1 then
local c = os.clock() local c = os.clock()
if self.doubleClickTimer and (c - self.doubleClickTimer < 1) and if self.doubleClickTimer and (c - self.doubleClickTimer < 1.5) and
self.doubleClickX == x and self.doubleClickY == y and self.doubleClickX == x and self.doubleClickY == y and
self.doubleClickElement == clickEvent.element then self.doubleClickElement == clickEvent.element then
button = 3 button = 3
@ -1076,8 +1076,8 @@ end
UI.TransitionSlideLeft = class() UI.TransitionSlideLeft = class()
UI.TransitionSlideLeft.defaults = { UI.TransitionSlideLeft.defaults = {
UIElement = 'TransitionSlideLeft', UIElement = 'TransitionSlideLeft',
ticks = 12, ticks = 4,
easing = 'outBounce', easing = 'outQuint',
} }
function UI.TransitionSlideLeft:init(args) function UI.TransitionSlideLeft:init(args)
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args) local defaults = UI:getDefaults(UI.TransitionSlideLeft, args)
@ -1116,11 +1116,11 @@ end
UI.TransitionSlideRight = class() UI.TransitionSlideRight = class()
UI.TransitionSlideRight.defaults = { UI.TransitionSlideRight.defaults = {
UIElement = 'TransitionSlideRight', UIElement = 'TransitionSlideRight',
ticks = 12, ticks = 4,
easing = 'outBounce', easing = 'outQuint',
} }
function UI.TransitionSlideRight:init(args) function UI.TransitionSlideRight:init(args)
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args) local defaults = UI:getDefaults(UI.TransitionSlideRight, args)
UI.setProperties(self, defaults) UI.setProperties(self, defaults)
self.pos = { x = self.x } self.pos = { x = self.x }
@ -2520,6 +2520,72 @@ function UI.Notification:display(value, timeout)
end) end)
end end
--[[-- Throttle --]]--
UI.Throttle = class(UI.Window)
UI.Throttle.defaults = {
UIElement = 'Throttle',
backgroundColor = colors.gray,
height = 6,
width = 10,
timeout = .095,
ctr = 0,
image = {
' //) (O )~@ &~&-( ?Q ',
' //) (O )- @ \-( ?) && ',
' //) (O ), @ \-(?) && ',
' //) (O ). @ \-d ) (@ '
}
}
function UI.Throttle:init(args)
local defaults = UI:getDefaults(UI.Throttle, args)
UI.Window.init(self, defaults)
end
function UI.Throttle:setParent()
self.x = math.ceil((self.parent.width - self.width) / 2)
self.y = math.ceil((self.parent.height - self.height) / 2)
UI.Window.setParent(self)
end
function UI.Throttle:enable()
self.enabled = false
end
function UI.Throttle:disable()
if self.canvas then
self.enabled = false
self.canvas:removeLayer()
self.canvas = nil
self.c = nil
end
end
function UI.Throttle:update()
local cc = os.clock()
if not self.c then
self.c = cc
elseif cc > self.c + self.timeout then
os.sleep(0)
self.c = os.clock()
self.enabled = true
if not self.canvas then
self.canvas = UI.term.canvas:addLayer(self, self.backgroundColor, colors.cyan)
self.canvas:setVisible(true)
self:clear(colors.cyan)
end
local image = self.image[self.ctr + 1]
local width = self.width - 2
for i = 0, #self.image do
self:write(2, i + 2, image:sub(width * i + 1, width * i + width), colors.black, colors.white)
end
self.ctr = (self.ctr + 1) % #self.image
self:sync()
end
end
--[[-- GridLayout --]]-- --[[-- GridLayout --]]--
UI.GridLayout = class(UI.Window) UI.GridLayout = class(UI.Window)
UI.GridLayout.defaults = { UI.GridLayout.defaults = {

View File

@ -27,8 +27,8 @@ function Util.throttle(fn)
return function(...) return function(...)
local nts = os.clock() local nts = os.clock()
if nts > ts + timeout then if nts > ts + timeout then
ts = nts
os.sleep(0) os.sleep(0)
ts = os.clock()
if fn then if fn then
fn(...) fn(...)
end end

View File

@ -160,10 +160,14 @@ end
function page:runScript(scriptName) function page:runScript(scriptName)
if self.turtle then if self.turtle then
self.notification:info('Connecting')
self:sync()
local cmd = string.format('Script %d %s', self.turtle.id, scriptName) local cmd = string.format('Script %d %s', self.turtle.id, scriptName)
local ot = term.redirect(nullTerm) local ot = term.redirect(nullTerm)
pcall(function() shell.run(cmd) end) pcall(function() shell.run(cmd) end)
term.redirect(ot) term.redirect(ot)
self.notification:success('Sent')
end end
end end

View File

@ -33,13 +33,12 @@ local schematic = Schematic()
local blocks = Blocks({ dir = BUILDER_DIR }) local blocks = Blocks({ dir = BUILDER_DIR })
local Builder = { local Builder = {
version = '1.70', version = '1.71',
ccVersion = nil,
slots = { }, slots = { },
index = 1, index = 1,
mode = 'build', mode = 'build',
fuelItem = { id = 'minecraft:coal', dmg = 0 }, fuelItem = { id = 'minecraft:coal', dmg = 0 },
resourceSlots = 15, resourceSlots = 14,
facing = 'south', facing = 'south',
confirmFacing = false, confirmFacing = false,
} }
@ -49,16 +48,6 @@ local pistonFacings
--[[-- SubDB --]]-- --[[-- SubDB --]]--
subDB = TableDB({ subDB = TableDB({
fileName = fs.combine(BUILDER_DIR, 'sub.db'), fileName = fs.combine(BUILDER_DIR, 'sub.db'),
tabledef = {
autokeys = false,
columns = {
{ name = 'Key', type = 'key', length = 8 },
{ name = 'id', type = 'number', length = 5 },
{ name = 'dmg', type = 'number', length = 2 },
{ name = 'refid', type = 'number', length = 5 },
{ name = 'refdmg', type = 'number', length = 2 },
}
}
}) })
function subDB:load() function subDB:load()
@ -71,222 +60,66 @@ end
function subDB:seedDB() function subDB:seedDB()
self.data = { self.data = {
[ "minecraft:redstone_wire:0" ] = { [ "minecraft:redstone_wire:0" ] = "minecraft:redstone:0",
sdmg = 0, [ "minecraft:wall_sign:0" ] = "minecraft:sign:0",
sid = "minecraft:redstone", [ "minecraft:standing_sign:0" ] = "minecraft:sign:0",
dmg = 0, [ "minecraft:potatoes:0" ] = "minecraft:potato:0",
id = "minecraft:redstone_wire", [ "minecraft:unlit_redstone_torch:0" ] = "minecraft:redstone_torch:0",
}, [ "minecraft:powered_repeater:0" ] = "minecraft:repeater:0",
[ "minecraft:wall_sign:0" ] = { [ "minecraft:unpowered_repeater:0" ] = "minecraft:repeater:0",
sdmg = 0, [ "minecraft:carrots:0" ] = "minecraft:carrot:0",
sid = "minecraft:sign", [ "minecraft:cocoa:0" ] = "minecraft:dye:3",
dmg = 0, [ "minecraft:unpowered_comparator:0" ] = "minecraft:comparator:0",
id = "minecraft:wall_sign", [ "minecraft:powered_comparator:0" ] = "minecraft:comparator:0",
}, [ "minecraft:piston_head:0" ] = "minecraft:air:0",
[ "minecraft:standing_sign:0" ] = { [ "minecraft:double_wooden_slab:0" ] = "minecraft:planks:0",
sdmg = 0, [ "minecraft:double_wooden_slab:1" ] = "minecraft:planks:1",
sid = "minecraft:sign", [ "minecraft:double_wooden_slab:2" ] = "minecraft:planks:2",
dmg = 0, [ "minecraft:double_wooden_slab:3" ] = "minecraft:planks:3",
id = "minecraft:standing_sign", [ "minecraft:double_wooden_slab:4" ] = "minecraft:planks:4",
}, [ "minecraft:double_wooden_slab:5" ] = "minecraft:planks:5",
[ "minecraft:potatoes:0" ] = { [ "minecraft:lit_redstone_lamp:0" ] = "minecraft:redstone_lamp:0",
sdmg = 0, [ "minecraft:double_stone_slab:1" ] = "minecraft:sandstone:0",
sid = "minecraft:potato", [ "minecraft:double_stone_slab:2" ] = "minecraft:planks:0",
dmg = 0, [ "minecraft:double_stone_slab:3" ] = "minecraft:cobblestone:0",
id = "minecraft:potatoes", [ "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:dirt:1" ] = { [ "minecraft:double_stone_slab:7" ] = "minecraft:quartz_block:0",
sdmg = 0, [ "minecraft:double_stone_slab:9" ] = "minecraft:sandstone:2",
sid = "minecraft:dirt", [ "minecraft:double_stone_slab2:0" ] = "minecraft:sandstone:0",
dmg = 1, [ "minecraft:stone_slab:2" ] = "minecraft:wooden_slab:0",
id = "minecraft:dirt", [ "minecraft:wheat:0" ] = "minecraft:wheat_seeds:0",
}, [ "minecraft:flowing_water:0" ] = "minecraft:air:0",
]]-- [ "minecraft:lit_furnace:0" ] = "minecraft:furnace:0",
[ "minecraft:unlit_redstone_torch:0" ] = { [ "minecraft:wall_banner:0" ] = "minecraft:banner:0",
sdmg = 0, [ "minecraft:standing_banner:0" ] = "minecraft:banner:0",
sid = "minecraft:redstone", [ "minecraft:tripwire:0" ] = "minecraft:string:0",
dmg = 0,
id = "minecraft:unlit_redstone_torch",
},
[ "minecraft:powered_repeater:0" ] = {
sdmg = 0,
sid = "minecraft:repeater",
dmg = 0,
id = "minecraft:powered_repeater",
},
[ "minecraft:unpowered_repeater:0" ] = {
sdmg = 0,
sid = "minecraft:repeater",
dmg = 0,
id = "minecraft:unpowered_repeater",
},
[ "minecraft:carrots:0" ] = {
sdmg = 0,
sid = "minecraft:carrot",
dmg = 0,
id = "minecraft:carrots",
},
[ "minecraft:cocoa:0" ] = {
sdmg = 3,
sid = "minecraft:dye",
dmg = 0,
id = "minecraft:cocoa",
},
[ "minecraft:unpowered_comparator:0" ] = {
sdmg = 0,
sid = "minecraft:comparator",
dmg = 0,
id = "minecraft:unpowered_comparator",
},
[ "minecraft:piston_head:0" ] = {
sdmg = 0,
sid = "minecraft:air",
dmg = 0,
id = "minecraft:piston_head",
},
[ "minecraft:double_wooden_slab:0" ] = {
sdmg = 0,
sid = "minecraft:planks",
dmg = 0,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:double_wooden_slab:1" ] = {
sdmg = 1,
sid = "minecraft:planks",
dmg = 1,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:double_wooden_slab:2" ] = {
sdmg = 2,
sid = "minecraft:planks",
dmg = 2,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:double_wooden_slab:3" ] = {
sdmg = 3,
sid = "minecraft:planks",
dmg = 3,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:double_wooden_slab:4" ] = {
sdmg = 4,
sid = "minecraft:planks",
dmg = 4,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:double_wooden_slab:5" ] = {
sdmg = 5,
sid = "minecraft:planks",
dmg = 5,
id = "minecraft:double_wooden_slab",
},
[ "minecraft:lit_redstone_lamp:0" ] = {
sdmg = 0,
sid = "minecraft:redstone_lamp",
dmg = 0,
id = "minecraft:lit_redstone_lamp",
},
[ "minecraft:double_stone_slab:1" ] = {
sdmg = 0,
sid = "minecraft:sandstone",
dmg = 1,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:2" ] = {
sdmg = 0,
sid = "minecraft:planks",
dmg = 2,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:3" ] = {
sdmg = 0,
sid = "minecraft:cobblestone",
dmg = 3,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:4" ] = {
sdmg = 0,
sid = "minecraft:brick_block",
dmg = 4,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:5" ] = {
sdmg = 0,
sid = "minecraft:stonebrick",
dmg = 5,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:6" ] = {
sdmg = 0,
sid = "minecraft:nether_brick",
dmg = 6,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:7" ] = {
sdmg = 0,
sid = "minecraft:quartz_block",
dmg = 7,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab:9" ] = {
sdmg = 2,
sid = "minecraft:sandstone",
dmg = 9,
id = "minecraft:double_stone_slab",
},
[ "minecraft:double_stone_slab2:0" ] = {
sdmg = 0,
sid = "minecraft:sandstone",
dmg = 0,
id = "minecraft:double_stone_slab2",
},
[ "minecraft:stone_slab:2" ] = {
sdmg = 0,
sid = "minecraft:wooden_slab",
dmg = 2,
id = "minecraft:stone_slab",
},
[ "minecraft:wheat:0" ] = {
sdmg = 0,
sid = "minecraft:wheat_seeds",
dmg = 0,
id = "minecraft:wheat",
},
[ "minecraft:flowing_water:0" ] = {
sdmg = 0,
sid = "minecraft:air",
dmg = 0,
id = "minecraft:flowing_water",
},
[ "minecraft:lit_furnace:0" ] = {
sdmg = 0,
sid = "minecraft:furnace",
dmg = 0,
id = "minecraft:lit_furnace",
},
} }
self.dirty = true self.dirty = true
self:flush() self:flush()
end end
function subDB:add(s) function subDB:add(s)
TableDB.add(self, { s.id, s.dmg }, table.concat({ s.sid, s.sdmg }, ':'))
TableDB.add(self, { s.id, s.dmg}, s)
self:flush() self:flush()
end end
function subDB:remove(s) function subDB:remove(s)
-- TODO: tableDB.remove should take table key -- TODO: tableDB.remove should take table key
TableDB.remove(self, s.id .. ':' .. s.dmg) TableDB.remove(self, s.id .. ':' .. s.dmg)
self:flush() self:flush()
end end
function subDB:extract(s)
local id, dmg = s:match('(.+):(%d+)')
return id, tonumber(dmg)
end
function subDB:getSubstitutedItem(id, dmg) function subDB:getSubstitutedItem(id, dmg)
local sub = TableDB.get(self, { id, dmg }) local sub = TableDB.get(self, { id, dmg })
if sub then if sub then
return { id = sub.sid, dmg = sub.sdmg } id, dmg = self:extract(sub)
end end
return { id = id, dmg = dmg } return { id = id, dmg = dmg }
end end
@ -294,8 +127,10 @@ end
function subDB:lookupBlocksForSub(sid, sdmg) function subDB:lookupBlocksForSub(sid, sdmg)
local t = { } local t = { }
for k,v in pairs(self.data) do for k,v in pairs(self.data) do
if v.sid == sid and v.sdmg == sdmg then local id, dmg = self:extract(v)
t[k] = 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
end end
return t return t
@ -304,14 +139,6 @@ end
--[[-- maxStackDB --]]-- --[[-- maxStackDB --]]--
maxStackDB = TableDB({ maxStackDB = TableDB({
fileName = fs.combine(BUILDER_DIR, 'maxstack.db'), fileName = fs.combine(BUILDER_DIR, '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) function maxStackDB:get(id, dmg)
@ -348,8 +175,8 @@ function UI.Spinner:spin(text)
end end
term.write(str) term.write(str)
self.spinIndex = self.spinIndex + 1 self.spinIndex = self.spinIndex + 1
self.c = cc
os.sleep(0) os.sleep(0)
self.c = os.clock()
end end
end end
@ -395,7 +222,7 @@ function Builder:getBlockCounts()
block.need = 0 block.need = 0
blocks[key] = block blocks[key] = block
end end
blocks[key].need = blocks[key].need + 1 block.need = block.need + 1
end end
end end
@ -532,15 +359,14 @@ function Builder:getGenericSupplyList(blockIndex)
for _,s in pairs(slots) do for _,s in pairs(slots) do
if s.id then if s.id then
s.name = blocks.blockDB:getName(s.id, s.dmg) s.name = blocks.nameDB:getName(s.id, s.dmg)
end end
end end
return slots, lastBlock return slots, lastBlock
end end
function Builder:substituteBlocks() function Builder:substituteBlocks(throttle)
local throttle = Util.throttle()
for _,b in pairs(schematic.blocks) do for _,b in pairs(schematic.blocks) do
@ -550,13 +376,12 @@ function Builder:substituteBlocks()
b.id = pb.id b.id = pb.id
b.dmg = pb.dmg b.dmg = pb.dmg
b.direction = pb.direction b.direction = pb.direction
b.extra = pb.extra
local sub = subDB:get({ b.id, b.dmg }) local sub = subDB:get({ b.id, b.dmg })
if sub then if sub then
b.id = sub.sid b.id, b.dmg = subDB:extract(sub)
b.dmg = sub.sdmg
end end
throttle() throttle()
end end
end end
@ -619,7 +444,7 @@ function Builder:getSupplies()
if s.need > 0 then if s.need > 0 then
local item = self.itemProvider:getItemInfo(s.id, s.dmg) local item = self.itemProvider:getItemInfo(s.id, s.dmg)
if item then if item then
s.name = item.name s.name = item.display_name
local qty = math.min(s.need - s.qty, item.qty) local qty = math.min(s.need - s.qty, item.qty)
@ -635,7 +460,7 @@ function Builder:getSupplies()
s.qty = turtle.getItemCount(s.index) s.qty = turtle.getItemCount(s.index)
end end
else else
s.name = blocks.blockDB:getName(s.id, s.dmg) s.name = blocks.nameDB:getName(s.id, s.dmg)
end end
end end
if s.qty < s.need then if s.qty < s.need then
@ -730,7 +555,6 @@ function Builder:inAirDropoff()
return true return true
end end
end end
end end
function Builder:inAirResupply() function Builder:inAirResupply()
@ -863,10 +687,10 @@ end
function Builder:getWrenchSlot() function Builder:getWrenchSlot()
local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0) local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0)
return Builder:selectItem(wrench.id, wrench.dmg) return Builder:selectItem(wrench.id, wrench.dmg)
end end
-- figure out our orientation in the world
function Builder:getTurtleFacing() function Builder:getTurtleFacing()
if os.getVersion() == 1.8 then if os.getVersion() == 1.8 then
@ -889,7 +713,7 @@ function Builder:getTurtleFacing()
return Builder.facing return Builder.facing
end end
function Builder:wrenchBlock(side, facing) function Builder:wrenchBlock(side, facing, cache)
local s = Builder:getWrenchSlot() local s = Builder:getWrenchSlot()
@ -899,7 +723,8 @@ function Builder:wrenchBlock(side, facing)
end end
local key = turtle.point.heading .. '-' .. facing local key = turtle.point.heading .. '-' .. facing
local count = pistonFacings[side][key] if cache then
local count = cache[side][key]
if count then if count then
turtle.select(s.index) turtle.select(s.index)
@ -908,6 +733,7 @@ function Builder:wrenchBlock(side, facing)
end end
return true return true
end end
end
local directions = { local directions = {
[5] = 'east', [5] = 'east',
@ -928,10 +754,11 @@ function Builder:wrenchBlock(side, facing)
print('determining wrench count') print('determining wrench count')
for i = 1, 6 do for i = 1, 6 do
local _, bi = turtle.getAction(side).inspect() local _, bi = turtle.getAction(side).inspect()
local pistonFacing = directions[bi.metadata]
if facing == pistonFacing then if facing == directions[bi.metadata] then
pistonFacings[side][key] = count if cache then
cache[side][key] = count
end
return true return true
end end
count = count + 1 count = count + 1
@ -941,6 +768,43 @@ function Builder:wrenchBlock(side, facing)
return false return false
end end
function Builder:rotateBlock(side, facing)
local s = Builder:getWrenchSlot()
if not s then
b.needResupply = true
return false
end
for i = 1, facing do
turtle.getAction(side).place()
end
return true
--[[
local origFacing
while true do
local _, bi = turtle.getAction(side).inspect()
-- spin until it repeats
if not origFacing then
origFacing = bi.metadata
elseif bi.metadata == origFacing then
return false
end
if facing == bi.metadata then
return true
end
turtle.getAction(side).place()
end
return false
]]--
end
-- place piston, wrench piston to face downward, extend, remove piston -- place piston, wrench piston to face downward, extend, remove piston
function Builder:placePiston(b) function Builder:placePiston(b)
@ -957,7 +821,7 @@ function Builder:placePiston(b)
return return
end end
local success = self:wrenchBlock('forward', 'down') --wrench piston to point downwards local success = self:wrenchBlock('forward', 'down', pistonFacings) --wrench piston to point downwards
rs.setOutput('front', true) rs.setOutput('front', true)
os.sleep(.25) os.sleep(.25)
@ -1151,7 +1015,29 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane)
end end
if self:placeDown(slot) then if self:placeDown(slot) then
b.placed = self:wrenchBlock('down', pistonDirections[d]) b.placed = self:wrenchBlock('down', pistonDirections[d], pistonFacings)
end
end
local wrenchDirections = {
[ 'wrench-down' ] = 'down',
[ 'wrench-up' ] = 'up',
}
if wrenchDirections[d] then
local ws = Builder:getWrenchSlot()
if not ws then
b.needResupply = true
-- a hopper may have eaten the piston
return false
end
self:gotoEx(b.x, b.z, b.y, nil, travelPlane)
if self:placeDown(slot) then
b.placed = self:wrenchBlock('down', wrenchDirections[d])
end end
end end
@ -1179,6 +1065,10 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane)
b.placed = self:place(slot) b.placed = self:place(slot)
end end
if b.extra then
self:rotateBlock('down', b.extra.facing)
end
-- debug -- debug
if d ~= 'top' and d ~= 'bottom' and not horizontalDirections[d] and not pistonDirections[d] then if d ~= 'top' and d ~= 'bottom' and not horizontalDirections[d] and not pistonDirections[d] then
if not b.heading or turtle.getHeading() ~= b.heading then if not b.heading or turtle.getHeading() ~= b.heading then
@ -1190,9 +1080,9 @@ end
return b.placed return b.placed
end end
function Builder:reloadSchematic() function Builder:reloadSchematic(throttle)
schematic:reload() schematic:reload(throttle)
self:substituteBlocks() self:substituteBlocks(throttle)
end end
function Builder:log(...) function Builder:log(...)
@ -1424,7 +1314,7 @@ selectSubstitutionPage = UI.Page({
{ heading = 'id', key = 'id' }, { heading = 'id', key = 'id' },
{ heading = 'dmg', key = 'dmg' }, { heading = 'dmg', key = 'dmg' },
}, },
sortColumn = 'odmg', sortColumn = 'id',
height = UI.term.height-1, height = UI.term.height-1,
autospace = true, autospace = true,
y = 2, y = 2,
@ -1451,32 +1341,33 @@ function selectSubstitutionPage:eventHandler(event)
end end
--[[-- substitutionPage --]]-- --[[-- substitutionPage --]]--
substitutionPage = UI.Page({ substitutionPage = UI.Page {
backgroundColor = colors.gray, backgroundColor = colors.gray,
titleBar = UI.TitleBar({ titleBar = UI.TitleBar {
previousPage = true, previousPage = true,
title = 'Substitute a block' title = 'Substitute a block'
}), },
menuBar = UI.MenuBar({ menuBar = UI.MenuBar {
y = 2, y = 2,
buttons = { buttons = {
{ text = 'Accept', event = 'accept', help = 'Accept' }, { text = 'Accept', event = 'accept', help = 'Accept' },
{ text = 'Revert', event = 'revert', help = 'Restore to original' }, { text = 'Revert', event = 'revert', help = 'Restore to original' },
{ text = 'Air', event = 'air', help = 'Air' }, { text = 'Air', event = 'air', help = 'Air' },
}, },
}), },
info = UI.Window({ y = 4, width = UI.term.width, height = 3 }), info = UI.Window { y = 4, width = UI.term.width, height = 3 },
grid = UI.ScrollingGrid({ grid = UI.ScrollingGrid {
columns = { columns = {
{ heading = 'Name', key = 'name', width = UI.term.width-9 }, { heading = 'Name', key = 'display_name', width = UI.term.width-9 },
{ heading = 'Qty', key = 'fQty', width = 5 }, { heading = 'Qty', key = 'fQty', width = 5 },
}, },
sortColumn = 'name', sortColumn = 'name',
height = UI.term.height-7, height = UI.term.height-7,
y = 7, y = 7,
}), },
statusBar = UI.StatusBar() throttle = UI.Throttle { },
}) statusBar = UI.StatusBar { }
}
substitutionPage.menuBar:add({ substitutionPage.menuBar:add({
filterLabel = UI.Text({ filterLabel = UI.Text({
@ -1493,10 +1384,10 @@ substitutionPage.menuBar:add({
function substitutionPage.info:draw() function substitutionPage.info:draw()
local sub = self.parent.sub local sub = self.parent.sub
local inName = blocks.blockDB:getName(sub.id, sub.dmg) local inName = blocks.nameDB:getName(sub.id, sub.dmg)
local outName = '' local outName = ''
if sub.sid then if sub.sid then
outName = blocks.blockDB:getName(sub.sid, sub.sdmg) outName = blocks.nameDB:getName(sub.sid, sub.sdmg)
end end
self:clear() self:clear()
@ -1512,7 +1403,7 @@ function substitutionPage:enable()
self.grid.values = self.allItems self.grid.values = self.allItems
for _,item in pairs(self.grid.values) do for _,item in pairs(self.grid.values) do
item.key = item.id .. ':' .. item.dmg item.key = item.id .. ':' .. item.dmg
item.lname = string.lower(item.name) item.lname = string.lower(item.display_name)
item.fQty = Util.toBytes(item.qty) item.fQty = Util.toBytes(item.qty)
end end
self.grid:update() self.grid:update()
@ -1543,9 +1434,9 @@ function substitutionPage:eventHandler(event)
self.statusBar:draw() self.statusBar:draw()
elseif event.type == 'grid_select' then elseif event.type == 'grid_select' then
if not blocks.blockDB:lookupName(event.selected.id, event.selected.dmg) then if not blocks.nameDB:lookupName(event.selected.id, event.selected.dmg) then
blocks.blockDB:add(event.selected.id, event.selected.dmg, event.selected.name, event.selected.id) blocks.nameDB:add({event.selected.id, event.selected.dmg}, event.selected.name)
blocks.blockDB:flush() blocks.nameDB:flush()
end end
self:applySubstitute(event.selected.id, event.selected.dmg) self:applySubstitute(event.selected.id, event.selected.dmg)
@ -1587,7 +1478,9 @@ function substitutionPage:eventHandler(event)
subDB:add(self.sub) subDB:add(self.sub)
end end
Builder:reloadSchematic() self.throttle:enable()
Builder:reloadSchematic(function() self.throttle:update() end)
self.throttle:disable()
UI:setPage('listing') UI:setPage('listing')
elseif event.type == 'cancel' then elseif event.type == 'cancel' then
@ -1598,12 +1491,12 @@ function substitutionPage:eventHandler(event)
end end
--[[-- SupplyPage --]]-- --[[-- SupplyPage --]]--
supplyPage = UI.Page({ supplyPage = UI.Page {
titleBar = UI.TitleBar({ titleBar = UI.TitleBar {
title = 'Waiting for supplies', title = 'Waiting for supplies',
previousPage = 'start' previousPage = 'start'
}), },
menuBar = UI.MenuBar({ menuBar = UI.MenuBar {
y = 2, y = 2,
buttons = { buttons = {
--{ text = 'Refresh', event = 'refresh', help = 'Refresh inventory' }, --{ text = 'Refresh', event = 'refresh', help = 'Refresh inventory' },
@ -1611,8 +1504,8 @@ supplyPage = UI.Page({
{ text = 'Menu', event = 'menu', help = 'Return to main menu' }, { text = 'Menu', event = 'menu', help = 'Return to main menu' },
{ text = 'Force Craft', event = 'craft', help = 'Request crafting (again)' }, { text = 'Force Craft', event = 'craft', help = 'Request crafting (again)' },
} }
}), },
grid = UI.Grid({ grid = UI.Grid {
columns = { columns = {
{ heading = 'Name', key = 'name', width = UI.term.width - 7 }, { heading = 'Name', key = 'name', width = UI.term.width - 7 },
{ heading = 'Need', key = 'need', width = 4 }, { heading = 'Need', key = 'need', width = 4 },
@ -1621,20 +1514,20 @@ supplyPage = UI.Page({
y = 3, y = 3,
width = UI.term.width, width = UI.term.width,
height = UI.term.height - 3 height = UI.term.height - 3
}), },
statusBar = UI.StatusBar({ statusBar = UI.StatusBar {
columns = { columns = {
{ 'Help', 'help', UI.term.width - 13 }, { 'Help', 'help', UI.term.width - 13 },
{ 'Fuel', 'fuel', 11 } { 'Fuel', 'fuel', 11 }
} }
}), },
accelerators = { accelerators = {
c = 'craft', c = 'craft',
r = 'refresh', r = 'refresh',
b = 'build', b = 'build',
m = 'menu', m = 'menu',
}, },
}) }
function supplyPage:eventHandler(event) function supplyPage:eventHandler(event)
@ -1756,8 +1649,8 @@ listingPage = UI.Page({
fullList = true fullList = true
}) })
function listingPage:enable() function listingPage:enable(throttle)
listingPage:refresh() listingPage:refresh(throttle)
UI.Page.enable(self) UI.Page.enable(self)
end end
@ -1821,11 +1714,11 @@ function listingPage.grid:getRowTextColor(row, selected)
return UI.Grid:getRowTextColor(row, selected) return UI.Grid:getRowTextColor(row, selected)
end end
function listingPage:refresh() function listingPage:refresh(throttle)
local supplyList = Builder:getBlockCounts() local supplyList = Builder:getBlockCounts()
Builder.itemProvider:refresh() Builder.itemProvider:refresh(throttle)
for _,b in pairs(supplyList) do for _,b in pairs(supplyList) do
if b.need > 0 then if b.need > 0 then
@ -1834,19 +1727,22 @@ function listingPage:refresh()
if item then if item then
local block = blocks.blockDB:lookup(b.id, b.dmg) local block = blocks.blockDB:lookup(b.id, b.dmg)
if not block then if not block then
blocks.blockDB:add(b.id, b.dmg, item.name, b.id) blocks.nameDB:add({b.id, b.dmg}, item.display_name)
elseif not block.name and item.name then elseif not block.name and item.display_name then
blocks.blockDB:add(b.id, b.dmg, item.name, b.id) blocks.nameDB:add({b.id, b.dmg}, item.display_name)
end end
b.name = item.name b.name = item.display_name
b.qty = item.qty b.qty = item.qty
b.is_craftable = item.is_craftable b.is_craftable = item.is_craftable
else else
b.name = blocks.blockDB:getName(b.id, b.dmg) b.name = blocks.nameDB:getName(b.id, b.dmg)
end end
end end
if throttle then
throttle()
end end
blocks.blockDB:flush() end
blocks.nameDB:flush()
if self.fullList then if self.fullList then
self.grid:setValues(supplyList) self.grid:setValues(supplyList)
@ -1881,15 +1777,15 @@ function listingPage:manageBlock(selected)
end end
--[[-- startPage --]]-- --[[-- startPage --]]--
local startPage = UI.Page({ local startPage = UI.Page {
-- titleBar = UI.TitleBar({ title = 'Builder v' .. Builder.version }), -- titleBar = UI.TitleBar({ title = 'Builder v' .. Builder.version }),
window = UI.Window({ window = UI.Window {
x = UI.term.width-16, x = UI.term.width-16,
y = 2, y = 2,
width = 16, width = 16,
height = UI.term.height-2, height = UI.term.height-2,
backgroundColor = colors.gray, backgroundColor = colors.gray,
grid = UI.Grid({ grid = UI.Grid {
columns = { columns = {
{ heading = 'Name', key = 'name', width = 6 }, { heading = 'Name', key = 'name', width = 6 },
{ heading = 'Value', key = 'value', width = 7 }, { heading = 'Value', key = 'value', width = 7 },
@ -1903,9 +1799,9 @@ local startPage = UI.Page({
--autospace = true, --autospace = true,
selectable = false, selectable = false,
backgroundColor = colors.gray backgroundColor = colors.gray
}), },
}), },
menu = UI.Menu({ menu = UI.Menu {
x = 2, x = 2,
y = 4, y = 4,
menuItems = { menuItems = {
@ -1917,12 +1813,13 @@ local startPage = UI.Page({
{ prompt = 'Begin', event = 'begin' }, { prompt = 'Begin', event = 'begin' },
{ prompt = 'Quit', event = 'quit' } { prompt = 'Quit', event = 'quit' }
} }
}), },
throttle = UI.Throttle { },
accelerators = { accelerators = {
x = 'test', x = 'test',
q = 'quit' q = 'quit'
} }
}) }
function startPage:draw() function startPage:draw()
local fuel = turtle.getFuelLevel() local fuel = turtle.getFuelLevel()
@ -2027,7 +1924,8 @@ function startPage:eventHandler(event)
-- as the current level's route may or may not have been -- as the current level's route may or may not have been
-- computed -- computed
Builder:dumpInventory() Builder:dumpInventory()
UI:setPage('listing') UI:setPage('listing', function() self.throttle:update() end)
self.throttle:disable()
elseif event.type == 'toggleMode' then elseif event.type == 'toggleMode' then
if Builder.mode == 'build' then if Builder.mode == 'build' then
@ -2061,7 +1959,7 @@ function startPage:eventHandler(event)
turtle.status = 'thinking' turtle.status = 'thinking'
print('Reloading schematic') print('Reloading schematic')
Builder:reloadSchematic() Builder:reloadSchematic(Util.throttle())
Builder:dumpInventory() Builder:dumpInventory()
Builder:refuel() Builder:refuel()
@ -2095,13 +1993,6 @@ if #args < 1 then
error('supply file name') error('supply file name')
end end
if os.version() == 'CraftOS 1.7' then
Builder.ccVersion = 1.7
Builder.resourceSlots = 14
else
error('Unsupported ComputerCraft version')
end
Builder.itemProvider = MEProvider() Builder.itemProvider = MEProvider()
if not Builder.itemProvider:isValid() then if not Builder.itemProvider:isValid() then
Builder.itemProvider = ChestProvider() Builder.itemProvider = ChestProvider()
@ -2117,10 +2008,11 @@ subDB:load()
UI.term:reset() UI.term:reset()
turtle.status = 'reading' turtle.status = 'reading'
print('Loading ' .. args[1]) print('Loading schematic')
schematic:load(args[1]) schematic:load(args[1])
print('Substituting blocks') print('Substituting blocks')
Builder:substituteBlocks()
Builder:substituteBlocks(Util.throttle())
if not fs.exists(BUILDER_DIR) then if not fs.exists(BUILDER_DIR) then
fs.makeDir(BUILDER_DIR) fs.makeDir(BUILDER_DIR)
@ -2146,4 +2038,3 @@ turtle.run(function()
end) end)
UI.term:reset() UI.term:reset()
--turtle.status = 'idle'

View File

@ -189,10 +189,10 @@ itemPage = UI.Page {
backgroundColor = colors.green backgroundColor = colors.green
}, },
displayName = UI.Window { displayName = UI.Window {
x = 5, y = 3, width = UI.term.width - 10, height = 3, x = 5, y = 2, width = UI.term.width - 10, height = 3,
}, },
form = UI.Form { form = UI.Form {
x = 4, y = 6, height = 10, rex = -4, x = 4, y = 4, height = 10, rex = -4,
[1] = UI.TextEntry { [1] = UI.TextEntry {
width = 7, width = 7,
backgroundColor = colors.gray, backgroundColor = colors.gray,

350
sys/apps/shapes.lua Normal file
View File

@ -0,0 +1,350 @@
require = requireInjector(getfenv(1))
local UI = require('ui')
local GPS = require('gps')
local Socket = require('socket')
multishell.setTitle(multishell.getCurrent(), 'Shapes')
local args = { ... }
local turtleId = args[1] or error('Supply turtle ID')
turtleId = tonumber(turtleId)
local script = [[
require = requireInjector(getfenv(1))
local GPS = require('gps')
local ChestProvider = require('chestProvider18')
local Point = require('point')
local itemProvider
function dumpInventory()
for i = 1, 16 do
local qty = turtle.getItemCount(i)
if qty > 0 then
itemProvider:insert(i, qty)
end
if turtle.getItemCount(i) ~= 0 then
print('Provider 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)
itemProvider:provide({ id = 'minecraft:coal', dmg = 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)
itemProvider = ChestProvider({ 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 data = Util.readTable('/usr/config/shapes') or { }
local page = UI.Page {
titleBar = UI.TitleBar { title = 'Shapes' },
info = UI.Window { x = 5, y = 3, height = 1 },
startCoord = UI.Button { x = 2, y = 6, text = 'Start ', event = 'startCoord' },
endCoord = UI.Button { x = 2, y = 8, text = 'End ', event = 'endCoord' },
supplies = UI.Button { x = 2, y = 10, text = 'Supplies', event = 'supplies' },
cancel = UI.Button { rx = 2, ry = -2, text = 'Abort', event = 'cancel' },
begin = UI.Button { rx = -7, ry = -2, text = 'Begin', event = 'begin' },
accelerators = { q = 'quit' },
notification = UI.Notification(),
statusBar = UI.StatusBar(),
}
function page.info:draw()
local function size(a, b)
return (math.abs(a.x - b.x) + 1) *
(math.abs(a.y - b.y) + 1) *
(math.abs(a.z - b.z) + 1)
end
self:clear()
if not data.startPt then
self:write(1, 1, 'Set starting corner')
elseif not data.endPt then
self:write(1, 1, 'Set ending corner')
else
self:write(1, 1, 'Blocks: ' .. size(data.startPt, data.endPt))
end
end
function page:getPoint()
local pt = GPS.getPoint()
if not pt then
self.notification:error('GPS not available')
end
return pt
end
function page:runFunction(id, script)
self.notification:info('Connecting')
local fn, msg = loadstring(script, 'script')
if not fn then
self.notification:error('Error in script')
debug(msg)
return
end
local socket = Socket.connect(id, 161)
if not socket then
self.notification:error('Unable to connect')
return
end
socket:write({ type = 'script', args = script })
socket:close()
self.notification:success('Sent')
end
function page:eventHandler(event)
if event.type == 'startCoord' then
data.startPt = self:getPoint()
if data.startPt then
self.statusBar:setStatus('starting corner set')
Util.writeTable('/usr/config/shapes', data)
end
self:draw()
elseif event.type == 'endCoord' then
data.endPt = self:getPoint()
if data.endPt then
self.statusBar:setStatus('ending corner set')
Util.writeTable('/usr/config/shapes', data)
end
self:draw()
elseif event.type == 'supplies' then
data.suppliesPt = self:getPoint()
if data.suppliesPt then
self.statusBar:setStatus('supplies location set')
Util.writeTable('/usr/config/shapes', data)
end
elseif event.type == 'begin' then
if data.startPt and data.endPt then
local s = 'local data = ' .. textutils.serialize(data) .. script
self:runFunction(turtleId, s)
else
self.notification:error('Corners not set')
end
self.statusBar:setStatus('')
elseif event.type == 'cancel' then
self:runFunction(turtleId, 'turtle.abortAction()')
self.statusBar:setStatus('')
else
return UI.Page.eventHandler(self, event)
end
return true
end
UI:setPage(page)
UI:pullEvents()
UI.term:reset()

View File

@ -4,10 +4,14 @@ local Event = require('event')
local UI = require('ui') local UI = require('ui')
local RefinedProvider = require('refinedProvider') local RefinedProvider = require('refinedProvider')
local MEProvider = require('meProvider') local MEProvider = require('meProvider')
local ChestProvider = require('chestProvider18')
local storage = RefinedProvider() local storage = RefinedProvider()
if not storage:isValid() then if not storage:isValid() then
storage = MEProvider() storage = MEProvider()
if not storage:isValid() then
storage = ChestProvider()
end
end end
if not storage:isValid() then if not storage:isValid() then
@ -106,7 +110,7 @@ local function uniqueKey(item)
end end
function changedPage:refresh() function changedPage:refresh()
local t = storage:listItems('all') local t = storage:listItems()
if not t or Util.empty(t) then if not t or Util.empty(t) then
self:clear() self:clear()

View File

@ -31,6 +31,7 @@ Logger.filter('modem_send', 'event', 'ui')
Logger.setWirelessLogging() Logger.setWirelessLogging()
local __BUILDER_ID = 6 local __BUILDER_ID = 6
local itemInfoDB
local Builder = { local Builder = {
version = '1.70', version = '1.70',
@ -116,7 +117,7 @@ function Builder:refuel()
self.itemProvider:provide(self.fuelItem, 64, 1) self.itemProvider:provide(self.fuelItem, 64, 1)
if turtle.getItemCount(1) == 0 then if turtle.getItemCount(1) == 0 then
Builder:log('Out of fuel, add coal to chest/ME system') Builder:log('Out of fuel, add coal to chest/ME system')
turtle.setHeading(0) --turtle.setHeading(0)
os.sleep(5) os.sleep(5)
else else
turtle.refuel(64) turtle.refuel(64)
@ -160,6 +161,11 @@ function Builder:getSupplies()
if s.qty < s.need then if s.qty < s.need then
table.insert(t, s) table.insert(t, s)
local name = s.name or s.id .. ':' .. s.dmg 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) Builder:log('Need %d %s', s.need - s.qty, name)
end end
end end
@ -400,6 +406,12 @@ __BUILDER_ID = tonumber(args[1])
maxStackDB:load() maxStackDB:load()
itemInfoDB = TableDB({
fileName = 'items.db'
})
itemInfoDB:load()
Builder.itemProvider = MEProvider({ direction = args[2] }) Builder.itemProvider = MEProvider({ direction = args[2] })
if not Builder.itemProvider:isValid() then if not Builder.itemProvider:isValid() then
local sides = { local sides = {

View File

@ -45,6 +45,7 @@ Leaves (Spruce),18:1,,Solid Block
Leaves (Birch),18:2,,Solid Block Leaves (Birch),18:2,,Solid Block
Leaves (Jungle),18:3,,Solid Block Leaves (Jungle),18:3,,Solid Block
Sponge,19,minecraft:sponge,Solid Block Sponge,19,minecraft:sponge,Solid Block
Wet Sponge,19:1,minecraft:sponge,Solid Block
Glass,20,minecraft:glass,Solid Block Glass,20,minecraft:glass,Solid Block
Lapis Lazuli Ore,21,minecraft:lapis_ore,Solid Block Lapis Lazuli Ore,21,minecraft:lapis_ore,Solid Block
Lapis Lazuli Block,22,minecraft:lapis_block,Solid Block Lapis Lazuli Block,22,minecraft:lapis_block,Solid Block

1 Air 0 minecraft:air Non-Solid Block
45 Leaves (Birch) 18:2 Solid Block
46 Leaves (Jungle) 18:3 Solid Block
47 Sponge 19 minecraft:sponge Solid Block
48 Wet Sponge 19:1 minecraft:sponge Solid Block
49 Glass 20 minecraft:glass Solid Block
50 Lapis Lazuli Ore 21 minecraft:lapis_ore Solid Block
51 Lapis Lazuli Block 22 minecraft:lapis_block Solid Block

1775
sys/etc/blocks.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -72,10 +72,10 @@ function turtle.run(fn, ...)
local s, m = pcall(function() fn(unpack(args)) end) local s, m = pcall(function() fn(unpack(args)) end)
turtle.abort = false turtle.abort = false
releaseTicket(ticketId) releaseTicket(ticketId)
os.queueEvent('turtle_response')
if not s and m then if not s and m then
printError(m) printError(m)
end end
os.queueEvent('turtle_response')
return s, m return s, m
end end
end end

View File

@ -30,6 +30,6 @@ end
function turtle.setGPSHome() function turtle.setGPSHome()
if turtle.enableGPS() then if turtle.enableGPS() then
turtle.storeLocation('gpsHome', turtle.point) turtle.storeLocation('gpsHome', turtle.point)
turtle.gotoPoint(tturtle.point) turtle.gotoPoint(turtle.point)
end end
end end

View File

@ -19,6 +19,8 @@ Event.addHandler('peripheral', function(event, side)
term.setTextColor(attachColor) term.setTextColor(attachColor)
Util.print('[%s] %s attached', dev.side, dev.name) Util.print('[%s] %s attached', dev.side, dev.name)
os.queueEvent('device_attach', dev.name) os.queueEvent('device_attach', dev.name)
else
Util.print('[%s] attached failed', side)
end end
end end
end) end)