1
0
mirror of https://github.com/kepler155c/opus synced 2025-06-16 05:24:11 +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)
@ -26,90 +60,26 @@ function blockDB:load(dir, sbDB, btDB)
end 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 = "" else
repeat for nid,name in pairs(block.name) do
local startp,endp = string.find(line,'^%b""',pos) self:add(block.id, nid - 1, name, strId)
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
-- no quotes used, just look for the first separator
local startp,endp = string.find(line,sep,pos)
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
return res
end 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,8 +125,8 @@ function placementDB:load(dir, sbDB, btDB)
end end
-- testing -- testing
-- self.dirty = true self.dirty = true
-- self:flush() --self:flush()
end end
function placementDB:addSubsForBlockType(id, dmg, bt) function placementDB:addSubsForBlockType(id, dmg, bt)
@ -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,9 +336,9 @@ function standardBlockDB:seedDB()
[ '404:0' ] = 'comparator', [ '404:0' ] = 'comparator',
} }
self.dirty = true self.dirty = true
self:flush() -- self:flush()
end end
--[[-- BlockTypeDB --]]-- --[[-- BlockTypeDB --]]--
local blockTypeDB = TableDB({ local blockTypeDB = TableDB({
fileName = 'blocktype.db', fileName = 'blocktype.db',
@ -393,7 +352,7 @@ local blockTypeDB = TableDB({
} }
} }
}) })
function blockTypeDB:load(dir) function blockTypeDB:load(dir)
self.fileName = fs.combine(dir, self.fileName) self.fileName = fs.combine(dir, self.fileName)
@ -403,7 +362,7 @@ function blockTypeDB:load(dir)
self:seedDB() self:seedDB()
end end
end end
function blockTypeDB:addTemp(blockType, subs) function blockTypeDB:addTemp(blockType, subs)
local bt = self.data[blockType] local bt = self.data[blockType]
if not bt then if not bt then
@ -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,13 +823,18 @@ 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})
if b then if b then
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)
local chest = Peripheral.getBySide(self.wrapSide)
if chest then
Util.merge(self, chest)
end
self.items = { } -- consolidated item info if not self.itemInfoDB then
self.cache = { } self.itemInfoDB = TableDB({
self.name = 'chest' fileName = 'items.db'
self.direction = args.direction or 'up' })
self.wrapSide = args.wrapSide or 'bottom'
self.p = peripheral.wrap(self.wrapSide) 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
if not entry then pcall(function() detail = self.getItemMeta(k) end)
entry = self.cache[key] if not detail then
if not entry then return
local meta = self.p.getItemMeta(k) -- slow method.. cache for speed end
if meta then if detail.name ~= item.name then
entry = { return
id = s.name, end
dmg = s.damage, if detail.maxDamage and detail.maxDamage > 0 and detail.damage > 0 then
name = meta.displayName, detail.displayName = detail.displayName .. ' (damaged)'
max_size = meta.maxCount, end
}
self.cache[key] = entry for _,k in ipairs(Util.keys(detail)) do
end if not keys[k] then
end detail[k] = nil
if entry then
entry = Util.shallowCopy(entry)
self.items[key] = entry
entry.qty = 0
end
end 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
entry = self:getCachedItemDetails(v, k)
if entry then if entry then
entry.qty = entry.qty + s.count entry.dmg = entry.damage
entry.id = entry.name
entry.count = 0
entry.display_name = entry.displayName
entry.max_size = entry.maxCount
entry.nbt_hash = entry.nbtHash
entry.lname = entry.displayName:lower()
self.cache[key] = entry
table.insert(items, entry)
end end
end end
if entry then
entry.count = entry.count + v.count
entry.qty = entry.count
end
throttle()
end end
return self.items
self.itemInfoDB:flush()
return items
end end
function ChestProvider:getItemInfo(id, dmg) function ChestProvider:getItemInfo(id, dmg, nbtHash)
if not self.cache then
for key,item in pairs(self.items) do self:listItems()
if item.id == id and item.dmg == dmg then
return item
end
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,31 +128,25 @@ 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.pushItems(self.direction, key, amount, slot)
self.p.pushItems(self.direction, key, amount, slot) qty = qty - amount
qty = qty - amount if qty <= 0 then
if qty <= 0 then break
break
end
end 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,17 +139,25 @@ 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
local e = Process:pullEvent()
if exitPullEvents or e == 'terminate' then
break
end
end
else
while true do while true do
local e = Process:pullEvent() local e = { os.pullEvent() }
if exitPullEvents or e == 'terminate' then Event.processEvent(e)
break if exitPullEvents or e == 'terminate' then
break
end
end end
end end
end end

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,13 +51,15 @@ function Peripheral.addDevice(deviceList, side)
end end
deviceList[name] = peripheral.wrap(side) deviceList[name] = peripheral.wrap(side)
Util.merge(deviceList[name], { if deviceList[name] then
name = name, Util.merge(deviceList[name], {
type = ptype, name = name,
side = side, type = ptype,
}) side = side,
})
return deviceList[name] return deviceList[name]
end
end end
function Peripheral.getBySide(side) function Peripheral.getBySide(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 throttle()
spinner:spin()
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

File diff suppressed because it is too large Load Diff

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)