builder improvements
This commit is contained in:
@@ -1,5 +1,39 @@
|
||||
local class = require('class')
|
||||
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({
|
||||
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)
|
||||
if fs.exists(self.fileName) then
|
||||
TableDB.load(self)
|
||||
@@ -26,90 +60,26 @@ function blockDB:load(dir, sbDB, btDB)
|
||||
end
|
||||
|
||||
function blockDB:seedDB(dir)
|
||||
|
||||
-- http://lua-users.org/wiki/LuaCsv
|
||||
function ParseCSVLine (line,sep)
|
||||
local res = {}
|
||||
local pos = 1
|
||||
sep = sep or ','
|
||||
while true do
|
||||
local c = string.sub(line,pos,pos)
|
||||
if (c == "") then break end
|
||||
if (c == '"') then
|
||||
-- quoted value (ignore separator within)
|
||||
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
|
||||
-- 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
|
||||
|
||||
local blocks = JSON.decodeFromFile(fs.combine('sys/etc', 'blocks.json'))
|
||||
|
||||
if not blocks then
|
||||
error('Unable to read blocks.json')
|
||||
end
|
||||
|
||||
for strId, block in pairs(blocks) do
|
||||
strId = 'minecraft:' .. strId
|
||||
if type(block.name) == 'string' then
|
||||
self:add(block.id, 0, block.name, strId)
|
||||
else
|
||||
for nid,name in pairs(block.name) do
|
||||
self:add(block.id, nid - 1, name, strId)
|
||||
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:flush()
|
||||
-- self:flush()
|
||||
end
|
||||
|
||||
function blockDB:lookup(id, dmg)
|
||||
@@ -117,27 +87,12 @@ function blockDB:lookup(id, dmg)
|
||||
if not id then
|
||||
return
|
||||
end
|
||||
|
||||
if not id or not dmg then error('blockDB:lookup: nil passed', 2) end
|
||||
local key = id .. ':' .. dmg
|
||||
|
||||
return self.data[key]
|
||||
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)
|
||||
local key = id .. ':' .. dmg
|
||||
|
||||
@@ -170,8 +125,8 @@ function placementDB:load(dir, sbDB, btDB)
|
||||
end
|
||||
|
||||
-- testing
|
||||
-- self.dirty = true
|
||||
-- self:flush()
|
||||
self.dirty = true
|
||||
--self:flush()
|
||||
end
|
||||
|
||||
function placementDB:addSubsForBlockType(id, dmg, bt)
|
||||
@@ -192,11 +147,12 @@ function placementDB:addSubsForBlockType(id, dmg, bt)
|
||||
odmg,
|
||||
sub.sid or strId,
|
||||
sub.sdmg or dmg,
|
||||
sub.dir)
|
||||
sub.dir,
|
||||
sub.extra)
|
||||
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
|
||||
|
||||
local key = id .. ':' .. dmg
|
||||
@@ -212,6 +168,7 @@ function placementDB:add(id, dmg, sid, sdmg, direction)
|
||||
sid = sid, -- string ID
|
||||
sdmg = sdmg, -- dmg without placement info
|
||||
direction = direction,
|
||||
extra = extra,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -286,7 +243,7 @@ function standardBlockDB:seedDB()
|
||||
[ '65:0' ] = 'wallsign-ladder',
|
||||
[ '66:0' ] = 'rail',
|
||||
[ '67:0' ] = 'stairs',
|
||||
[ '68:0' ] = 'wallsign',
|
||||
[ '68:0' ] = 'wallsign-ladder',
|
||||
[ '69:0' ] = 'lever',
|
||||
[ '71:0' ] = 'door',
|
||||
[ '75:0' ] = 'torch',
|
||||
@@ -295,6 +252,7 @@ function standardBlockDB:seedDB()
|
||||
[ '78:0' ] = 'flatten',
|
||||
[ '81:0' ] = 'flatten',
|
||||
[ '83:0' ] = 'flatten',
|
||||
[ '84:0' ] = 'flatten', -- jukebox
|
||||
[ '86:0' ] = 'pumpkin',
|
||||
[ '90:0' ] = 'air',
|
||||
[ '91:0' ] = 'pumpkin',
|
||||
@@ -312,6 +270,7 @@ function standardBlockDB:seedDB()
|
||||
[ '115:0' ] = 'flatten',
|
||||
[ '117:0' ] = 'flatten',
|
||||
[ '118:0' ] = 'cauldron',
|
||||
[ '120:0' ] = 'flatten', -- end portal
|
||||
[ '126:0' ] = 'slab',
|
||||
[ '126:1' ] = 'slab',
|
||||
[ '126:2' ] = 'slab',
|
||||
@@ -339,7 +298,7 @@ function standardBlockDB:seedDB()
|
||||
[ '155:2' ] = 'quartz-pillar',
|
||||
[ '156:0' ] = 'stairs',
|
||||
[ '157:0' ] = 'adp-rail',
|
||||
[ '158:0' ] = 'hopper',
|
||||
[ '158:0' ] = 'dispenser',
|
||||
[ '161:0' ] = 'leaves',
|
||||
[ '161:1' ] = 'leaves',
|
||||
[ '162:0' ] = 'wood',
|
||||
@@ -347,15 +306,15 @@ function standardBlockDB:seedDB()
|
||||
[ '163:0' ] = 'stairs',
|
||||
[ '164:0' ] = 'stairs',
|
||||
[ '167:0' ] = 'trapdoor',
|
||||
[ '170:0' ] = 'quartz-pillar', -- hay bale
|
||||
[ '170:0' ] = 'hay-bale', -- hay bale
|
||||
[ '175:0' ] = '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:3' ] = 'largeplant',
|
||||
[ '175:4' ] = 'largeplant',
|
||||
[ '175:5' ] = 'largeplant',
|
||||
[ '176:0' ] = 'banner',
|
||||
[ '177:0' ] = 'wall_banner',
|
||||
[ '176:0' ] = 'signpost',
|
||||
[ '177:0' ] = 'wallsign-ladder',
|
||||
[ '178:0' ] = 'truncate',
|
||||
[ '180:0' ] = 'stairs',
|
||||
[ '182:0' ] = 'slab',
|
||||
@@ -369,7 +328,7 @@ function standardBlockDB:seedDB()
|
||||
[ '195:0' ] = 'door',
|
||||
[ '196:0' ] = 'door',
|
||||
[ '197:0' ] = 'door',
|
||||
[ '198:0' ] = 'flatten',
|
||||
[ '198:0' ] = 'end_rod', -- end rod
|
||||
[ '205:0' ] = 'slab',
|
||||
[ '210:0' ] = 'flatten',
|
||||
[ '355:0' ] = 'bed',
|
||||
@@ -377,9 +336,9 @@ function standardBlockDB:seedDB()
|
||||
[ '404:0' ] = 'comparator',
|
||||
}
|
||||
self.dirty = true
|
||||
self:flush()
|
||||
-- self:flush()
|
||||
end
|
||||
|
||||
|
||||
--[[-- BlockTypeDB --]]--
|
||||
local blockTypeDB = TableDB({
|
||||
fileName = 'blocktype.db',
|
||||
@@ -393,7 +352,7 @@ local blockTypeDB = TableDB({
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function blockTypeDB:load(dir)
|
||||
self.fileName = fs.combine(dir, self.fileName)
|
||||
|
||||
@@ -403,7 +362,7 @@ function blockTypeDB:load(dir)
|
||||
self:seedDB()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function blockTypeDB:addTemp(blockType, subs)
|
||||
local bt = self.data[blockType]
|
||||
if not bt then
|
||||
@@ -415,7 +374,8 @@ function blockTypeDB:addTemp(blockType, subs)
|
||||
odmg = sub[1],
|
||||
sid = sub[2],
|
||||
sdmg = sub[3],
|
||||
dir = sub[4]
|
||||
dir = sub[4],
|
||||
extra = sub[5]
|
||||
})
|
||||
end
|
||||
self.dirty = true
|
||||
@@ -512,6 +472,11 @@ function blockTypeDB:seedDB()
|
||||
{ 3, nil, 2, 'north-south-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', {
|
||||
{ 1, nil, 0, 'west-block' },
|
||||
{ 2, nil, 0, 'east-block' },
|
||||
@@ -526,14 +491,23 @@ function blockTypeDB:seedDB()
|
||||
{ 3, nil, 0 },
|
||||
})
|
||||
blockTypeDB:addTemp('dispenser', {
|
||||
{ 0, nil, 0 },
|
||||
{ 1, nil, 0 },
|
||||
{ 0, nil, 0, 'wrench-down' },
|
||||
{ 1, nil, 0, 'wrench-up' },
|
||||
{ 2, nil, 0, 'south' },
|
||||
{ 3, nil, 0, 'north' },
|
||||
{ 4, nil, 0, 'east' },
|
||||
{ 5, nil, 0, 'west' },
|
||||
{ 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', {
|
||||
{ 0, nil, 0 },
|
||||
{ 1, nil, 0 },
|
||||
@@ -541,6 +515,7 @@ function blockTypeDB:seedDB()
|
||||
{ 3, nil, 0, 'north-block' },
|
||||
{ 4, nil, 0, 'east-block' },
|
||||
{ 5, nil, 0, 'west-block' },
|
||||
{ 8, nil, 0 },
|
||||
{ 9, nil, 0 },
|
||||
{ 10, nil, 0 },
|
||||
{ 11, nil, 0, 'south-block' },
|
||||
@@ -583,22 +558,22 @@ function blockTypeDB:seedDB()
|
||||
{ 13, nil, 0, 'south' },
|
||||
})
|
||||
blockTypeDB:addTemp('signpost', {
|
||||
{ 0, nil, 0, 'south' },
|
||||
{ 1, nil, 0, 'south' },
|
||||
{ 2, nil, 0, 'south' },
|
||||
{ 3, nil, 0, 'south' },
|
||||
{ 4, nil, 0, 'west' },
|
||||
{ 5, nil, 0, 'west' },
|
||||
{ 6, nil, 0, 'west' },
|
||||
{ 7, nil, 0, 'west' },
|
||||
{ 8, nil, 0, 'north' },
|
||||
{ 9, nil, 0, 'north' },
|
||||
{ 10, nil, 0, 'north' },
|
||||
{ 11, nil, 0, 'north' },
|
||||
{ 12, nil, 0, 'east' },
|
||||
{ 13, nil, 0, 'east' },
|
||||
{ 14, nil, 0, 'east' },
|
||||
{ 15, nil, 0, 'east' },
|
||||
{ 0, nil, 0, 'north' },
|
||||
{ 1, nil, 0, 'north', { facing = 1 } },
|
||||
{ 2, nil, 0, 'north', { facing = 2 } },
|
||||
{ 3, nil, 0, 'north', { facing = 3 } },
|
||||
{ 4, nil, 0, 'east' },
|
||||
{ 5, nil, 0, 'east', { facing = 1 } },
|
||||
{ 6, nil, 0, 'east', { facing = 2 } },
|
||||
{ 7, nil, 0, 'east', { facing = 3 } },
|
||||
{ 8, nil, 0, 'south' },
|
||||
{ 9, nil, 0, 'south', { facing = 1 } },
|
||||
{ 10, nil, 0, 'south', { facing = 2 } },
|
||||
{ 11, nil, 0, 'south', { facing = 3 } },
|
||||
{ 12, nil, 0, 'west' },
|
||||
{ 13, nil, 0, 'west', { facing = 1 } },
|
||||
{ 14, nil, 0, 'west', { facing = 2 } },
|
||||
{ 15, nil, 0, 'west', { facing = 3 } },
|
||||
})
|
||||
blockTypeDB:addTemp('vine', {
|
||||
{ 0, nil, 0 },
|
||||
@@ -684,18 +659,12 @@ function blockTypeDB:seedDB()
|
||||
})
|
||||
blockTypeDB:addTemp('wallsign-ladder', {
|
||||
{ 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('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', {
|
||||
{ 0, nil, 0 },
|
||||
{ 2, nil, 0, 'south' },
|
||||
@@ -817,32 +786,6 @@ function blockTypeDB:seedDB()
|
||||
{ 14,'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', {
|
||||
{ 0, nil, 0, 'south-block' },
|
||||
{ 1, nil, 0, 'west-block' },
|
||||
@@ -858,7 +801,7 @@ function blockTypeDB:seedDB()
|
||||
{ 11, nil, 0, 'east-block' },
|
||||
})
|
||||
self.dirty = true
|
||||
self:flush()
|
||||
-- self:flush()
|
||||
end
|
||||
|
||||
local Blocks = class()
|
||||
@@ -866,10 +809,12 @@ function Blocks:init(args)
|
||||
|
||||
Util.merge(self, args)
|
||||
self.blockDB = blockDB
|
||||
self.nameDB = nameDB
|
||||
|
||||
blockDB:load(self.dir)
|
||||
standardBlockDB:load(self.dir)
|
||||
blockTypeDB:load(self.dir)
|
||||
nameDB:load(self.dir, blockDB)
|
||||
placementDB:load(self.dir, standardBlockDB, blockTypeDB)
|
||||
end
|
||||
|
||||
@@ -878,13 +823,18 @@ function Blocks:getRealBlock(id, dmg)
|
||||
|
||||
local p = placementDB:get({id, dmg})
|
||||
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
|
||||
|
||||
local b = blockDB:get({id, dmg})
|
||||
if b then
|
||||
return { id = b.strId, dmg = b.dmg }
|
||||
end
|
||||
|
||||
b = blockDB:get({id, 0})
|
||||
if b then
|
||||
return { id = b.strId, dmg = b.dmg }
|
||||
end
|
||||
|
||||
return { id = id, dmg = dmg }
|
||||
end
|
||||
|
||||
@@ -1,65 +1,124 @@
|
||||
local class = require('class')
|
||||
local TableDB = require('tableDB')
|
||||
local Peripheral = require('peripheral')
|
||||
|
||||
local ChestProvider = class()
|
||||
|
||||
|
||||
local keys = Util.transpose({
|
||||
'damage',
|
||||
'displayName',
|
||||
'maxCount',
|
||||
'maxDamage',
|
||||
'name',
|
||||
'nbtHash',
|
||||
})
|
||||
|
||||
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
|
||||
self.cache = { }
|
||||
self.name = 'chest'
|
||||
self.direction = args.direction or 'up'
|
||||
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
|
||||
|
||||
function ChestProvider:isValid()
|
||||
return self.p and self.p.list
|
||||
return not not self.list
|
||||
end
|
||||
|
||||
function ChestProvider:refresh()
|
||||
if self.p then
|
||||
self.items = { }
|
||||
for k,s in pairs(self.p.list()) do
|
||||
function ChestProvider:getCachedItemDetails(item, k)
|
||||
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
|
||||
|
||||
local key = s.name .. ':' .. s.damage
|
||||
local entry = self.items[key]
|
||||
if not entry then
|
||||
entry = self.cache[key]
|
||||
if not entry then
|
||||
local meta = self.p.getItemMeta(k) -- slow method.. cache for speed
|
||||
if meta then
|
||||
entry = {
|
||||
id = s.name,
|
||||
dmg = s.damage,
|
||||
name = meta.displayName,
|
||||
max_size = meta.maxCount,
|
||||
}
|
||||
self.cache[key] = entry
|
||||
end
|
||||
end
|
||||
if entry then
|
||||
entry = Util.shallowCopy(entry)
|
||||
self.items[key] = entry
|
||||
entry.qty = 0
|
||||
end
|
||||
local detail = self.itemInfoDB:get(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
|
||||
entry = self:getCachedItemDetails(v, k)
|
||||
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
|
||||
|
||||
if entry then
|
||||
entry.count = entry.count + v.count
|
||||
entry.qty = entry.count
|
||||
end
|
||||
throttle()
|
||||
end
|
||||
return self.items
|
||||
|
||||
self.itemInfoDB:flush()
|
||||
|
||||
return items
|
||||
end
|
||||
|
||||
function ChestProvider:getItemInfo(id, dmg)
|
||||
|
||||
for key,item in pairs(self.items) do
|
||||
if item.id == id and item.dmg == dmg then
|
||||
return item
|
||||
end
|
||||
function ChestProvider:getItemInfo(id, dmg, nbtHash)
|
||||
if not self.cache then
|
||||
self:listItems()
|
||||
end
|
||||
local key = table.concat({ id, dmg, nbtHash }, ':')
|
||||
return self.cache[key]
|
||||
end
|
||||
|
||||
function ChestProvider:craft(id, dmg, qty)
|
||||
@@ -69,31 +128,25 @@ function ChestProvider:craftItems(items)
|
||||
end
|
||||
|
||||
function ChestProvider:provide(item, qty, slot)
|
||||
if self.p then
|
||||
local stacks = self.p.list()
|
||||
for key,stack in pairs(stacks) do
|
||||
if stack.name == item.id and stack.damage == item.dmg then
|
||||
local amount = math.min(qty, stack.count)
|
||||
self.p.pushItems(self.direction, key, amount, slot)
|
||||
qty = qty - amount
|
||||
if qty <= 0 then
|
||||
break
|
||||
end
|
||||
local stacks = self.list()
|
||||
for key,stack in pairs(stacks) do
|
||||
if stack.name == item.id and stack.damage == item.dmg then
|
||||
local amount = math.min(qty, stack.count)
|
||||
self.pushItems(self.direction, key, amount, slot)
|
||||
qty = qty - amount
|
||||
if qty <= 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ChestProvider:extract(slot, qty)
|
||||
if self.p then
|
||||
self.p.pushItems(self.direction, slot, qty)
|
||||
end
|
||||
self.pushItems(self.direction, slot, qty)
|
||||
end
|
||||
|
||||
function ChestProvider:insert(slot, qty)
|
||||
if self.p then
|
||||
self.p.pullItems(self.direction, slot, qty)
|
||||
end
|
||||
self.pullItems(self.direction, slot, qty)
|
||||
end
|
||||
|
||||
return ChestProvider
|
||||
|
||||
@@ -139,17 +139,25 @@ function Event.addThread(fn)
|
||||
end
|
||||
|
||||
function Event.pullEvents(...)
|
||||
Process:addThread(_pullEvents)
|
||||
local routines = { ... }
|
||||
if #routines > 0 then
|
||||
Process:addThread(_pullEvents)
|
||||
for _, routine in ipairs(routines) do
|
||||
Process:addThread(routine)
|
||||
end
|
||||
end
|
||||
while true do
|
||||
local e = Process:pullEvent()
|
||||
if exitPullEvents or e == 'terminate' then
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
while true do
|
||||
local e = Process:pullEvent()
|
||||
if exitPullEvents or e == 'terminate' then
|
||||
break
|
||||
local e = { os.pullEvent() }
|
||||
Event.processEvent(e)
|
||||
if exitPullEvents or e == 'terminate' then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -205,7 +205,7 @@ end
|
||||
|
||||
function json.decodeFromFile(path)
|
||||
local file = assert(fs.open(path, "r"))
|
||||
local decoded = decode(file.readAll())
|
||||
local decoded = json.decode(file.readAll())
|
||||
file.close()
|
||||
return decoded
|
||||
end
|
||||
|
||||
@@ -51,13 +51,15 @@ function Peripheral.addDevice(deviceList, side)
|
||||
end
|
||||
|
||||
deviceList[name] = peripheral.wrap(side)
|
||||
Util.merge(deviceList[name], {
|
||||
name = name,
|
||||
type = ptype,
|
||||
side = side,
|
||||
})
|
||||
if deviceList[name] then
|
||||
Util.merge(deviceList[name], {
|
||||
name = name,
|
||||
type = ptype,
|
||||
side = side,
|
||||
})
|
||||
|
||||
return deviceList[name]
|
||||
return deviceList[name]
|
||||
end
|
||||
end
|
||||
|
||||
function Peripheral.getBySide(side)
|
||||
|
||||
@@ -62,13 +62,6 @@ function RefinedProvider:getCachedItemDetails(item)
|
||||
end
|
||||
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 = { }
|
||||
for _,key in pairs(keys) do
|
||||
t[key] = detail[key]
|
||||
@@ -76,8 +69,6 @@ function RefinedProvider:getCachedItemDetails(item)
|
||||
|
||||
detail = t
|
||||
self.itemInfoDB:add(key, detail)
|
||||
|
||||
os.sleep(0) -- prevent timeout on large inventories
|
||||
end
|
||||
end
|
||||
if detail then
|
||||
|
||||
@@ -148,20 +148,18 @@ function Schematic:parse(a, h, containsName, spinner)
|
||||
end
|
||||
-- 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
|
||||
oblocks[k] = Util.shallowCopy(b)
|
||||
if spinner then
|
||||
if (k % 1000) == 0 then
|
||||
spinner:spin()
|
||||
end
|
||||
if (k % 1000) == 0 then
|
||||
throttle()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Schematic:reload()
|
||||
function Schematic:reload(throttle)
|
||||
self.blocks = { }
|
||||
self:copyBlocks(self.originalBlocks, self.blocks)
|
||||
self:copyBlocks(self.originalBlocks, self.blocks, throttle)
|
||||
|
||||
for _,ri in pairs(self.rowIndex) do
|
||||
ri.loaded = false
|
||||
@@ -283,7 +281,7 @@ function Schematic:loadpass(fh, spinner)
|
||||
self:assignDamages(spinner)
|
||||
self.damages = nil
|
||||
|
||||
self:copyBlocks(self.blocks, self.originalBlocks, spinner)
|
||||
self:copyBlocks(self.blocks, self.originalBlocks, function() spinner:spin() end)
|
||||
|
||||
spinner:stop()
|
||||
end
|
||||
@@ -488,6 +486,37 @@ function Schematic:bestSide(b, chains, ...)
|
||||
})
|
||||
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
|
||||
|
||||
local sb
|
||||
@@ -617,12 +646,23 @@ function Schematic:determineBlockPlacement(y)
|
||||
[ 'west-block-vine' ] = 'west-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 dirtyBlocks2 = {}
|
||||
local chains = {}
|
||||
|
||||
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
|
||||
local b = self.blocks[k]
|
||||
local d = b.direction
|
||||
@@ -757,6 +797,8 @@ function Schematic:determineBlockPlacement(y)
|
||||
b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4
|
||||
end
|
||||
end
|
||||
elseif flipDirections[d] then
|
||||
self:bestFlipSide(b, chains)
|
||||
end
|
||||
|
||||
if blockDirections[d] then
|
||||
@@ -790,6 +832,7 @@ function Schematic:determineBlockPlacement(y)
|
||||
self:setPlacementOrder(spinner, chains)
|
||||
local plane = self:optimizeRoute(spinner, y)
|
||||
|
||||
term.clearLine()
|
||||
spinner:stop()
|
||||
|
||||
for k,b in ipairs(plane) do
|
||||
|
||||
@@ -331,7 +331,7 @@ function Manager:click(button, x, y)
|
||||
|
||||
if button == 1 then
|
||||
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.doubleClickElement == clickEvent.element then
|
||||
button = 3
|
||||
@@ -1076,8 +1076,8 @@ end
|
||||
UI.TransitionSlideLeft = class()
|
||||
UI.TransitionSlideLeft.defaults = {
|
||||
UIElement = 'TransitionSlideLeft',
|
||||
ticks = 12,
|
||||
easing = 'outBounce',
|
||||
ticks = 4,
|
||||
easing = 'outQuint',
|
||||
}
|
||||
function UI.TransitionSlideLeft:init(args)
|
||||
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args)
|
||||
@@ -1116,11 +1116,11 @@ end
|
||||
UI.TransitionSlideRight = class()
|
||||
UI.TransitionSlideRight.defaults = {
|
||||
UIElement = 'TransitionSlideRight',
|
||||
ticks = 12,
|
||||
easing = 'outBounce',
|
||||
ticks = 4,
|
||||
easing = 'outQuint',
|
||||
}
|
||||
function UI.TransitionSlideRight:init(args)
|
||||
local defaults = UI:getDefaults(UI.TransitionSlideLeft, args)
|
||||
local defaults = UI:getDefaults(UI.TransitionSlideRight, args)
|
||||
UI.setProperties(self, defaults)
|
||||
|
||||
self.pos = { x = self.x }
|
||||
@@ -2520,6 +2520,72 @@ function UI.Notification:display(value, timeout)
|
||||
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 --]]--
|
||||
UI.GridLayout = class(UI.Window)
|
||||
UI.GridLayout.defaults = {
|
||||
|
||||
@@ -27,8 +27,8 @@ function Util.throttle(fn)
|
||||
return function(...)
|
||||
local nts = os.clock()
|
||||
if nts > ts + timeout then
|
||||
ts = nts
|
||||
os.sleep(0)
|
||||
ts = os.clock()
|
||||
if fn then
|
||||
fn(...)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user