From 7f99c0c69ab8edcb6bd2dd37913d0297329d6c0a Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 23 Jun 2017 02:04:56 -0400 Subject: [PATCH] builder improvements --- sys/apis/blocks.lua | 276 +++--- sys/apis/chestProvider18.lua | 169 ++-- sys/apis/event.lua | 18 +- sys/apis/json.lua | 2 +- sys/apis/peripheral.lua | 14 +- sys/apis/refinedProvider.lua | 9 - sys/apis/schematic.lua | 59 +- sys/apis/ui.lua | 78 +- sys/apis/util.lua | 2 +- sys/apps/Turtles.lua | 4 + sys/apps/builder.lua | 715 ++++++-------- sys/apps/refinedManager.lua | 4 +- sys/apps/shapes.lua | 350 +++++++ sys/apps/storageActivity.lua | 6 +- sys/apps/supplier.lua | 14 +- sys/etc/blockIds.csv | 1 + sys/etc/blocks.json | 1775 ++++++++++++++++++++++++++++++++++ sys/extensions/scheduler.lua | 2 +- sys/extensions/tgps.lua | 2 +- sys/services/device.lua | 2 + 20 files changed, 2827 insertions(+), 675 deletions(-) create mode 100644 sys/apps/shapes.lua create mode 100644 sys/etc/blocks.json diff --git a/sys/apis/blocks.lua b/sys/apis/blocks.lua index 0934289..bedc466 100644 --- a/sys/apis/blocks.lua +++ b/sys/apis/blocks.lua @@ -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 diff --git a/sys/apis/chestProvider18.lua b/sys/apis/chestProvider18.lua index 02c587b..31fb65e 100644 --- a/sys/apis/chestProvider18.lua +++ b/sys/apis/chestProvider18.lua @@ -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 diff --git a/sys/apis/event.lua b/sys/apis/event.lua index 1d10479..bdf1562 100644 --- a/sys/apis/event.lua +++ b/sys/apis/event.lua @@ -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 diff --git a/sys/apis/json.lua b/sys/apis/json.lua index ecde99c..e6c5fca 100644 --- a/sys/apis/json.lua +++ b/sys/apis/json.lua @@ -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 diff --git a/sys/apis/peripheral.lua b/sys/apis/peripheral.lua index 19380e6..fc507f9 100644 --- a/sys/apis/peripheral.lua +++ b/sys/apis/peripheral.lua @@ -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) diff --git a/sys/apis/refinedProvider.lua b/sys/apis/refinedProvider.lua index 1434803..5ea3f75 100644 --- a/sys/apis/refinedProvider.lua +++ b/sys/apis/refinedProvider.lua @@ -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 diff --git a/sys/apis/schematic.lua b/sys/apis/schematic.lua index e5c9d8a..dfccb96 100644 --- a/sys/apis/schematic.lua +++ b/sys/apis/schematic.lua @@ -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 diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 6ccb121..eb876ad 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -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 = { diff --git a/sys/apis/util.lua b/sys/apis/util.lua index 28457b8..84c6cf7 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -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 diff --git a/sys/apps/Turtles.lua b/sys/apps/Turtles.lua index e2f8423..ce250e5 100644 --- a/sys/apps/Turtles.lua +++ b/sys/apps/Turtles.lua @@ -160,10 +160,14 @@ end function page:runScript(scriptName) if self.turtle then + self.notification:info('Connecting') + self:sync() + local cmd = string.format('Script %d %s', self.turtle.id, scriptName) local ot = term.redirect(nullTerm) pcall(function() shell.run(cmd) end) term.redirect(ot) + self.notification:success('Sent') end end diff --git a/sys/apps/builder.lua b/sys/apps/builder.lua index 3ef2be2..1b7413b 100644 --- a/sys/apps/builder.lua +++ b/sys/apps/builder.lua @@ -33,13 +33,12 @@ local schematic = Schematic() local blocks = Blocks({ dir = BUILDER_DIR }) local Builder = { - version = '1.70', - ccVersion = nil, + version = '1.71', slots = { }, index = 1, mode = 'build', fuelItem = { id = 'minecraft:coal', dmg = 0 }, - resourceSlots = 15, + resourceSlots = 14, facing = 'south', confirmFacing = false, } @@ -49,18 +48,8 @@ local pistonFacings --[[-- SubDB --]]-- subDB = TableDB({ 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() if fs.exists(self.fileName) then TableDB.load(self) @@ -71,222 +60,66 @@ end function subDB:seedDB() self.data = { - [ "minecraft:redstone_wire:0" ] = { - sdmg = 0, - sid = "minecraft:redstone", - dmg = 0, - id = "minecraft:redstone_wire", - }, - [ "minecraft:wall_sign:0" ] = { - sdmg = 0, - sid = "minecraft:sign", - dmg = 0, - id = "minecraft:wall_sign", - }, - [ "minecraft:standing_sign:0" ] = { - sdmg = 0, - sid = "minecraft:sign", - dmg = 0, - id = "minecraft:standing_sign", - }, - [ "minecraft:potatoes:0" ] = { - sdmg = 0, - sid = "minecraft:potato", - dmg = 0, - id = "minecraft:potatoes", - }, - --[[ - [ "minecraft:dirt:1" ] = { - sdmg = 0, - sid = "minecraft:dirt", - dmg = 1, - id = "minecraft:dirt", - }, - ]]-- - [ "minecraft:unlit_redstone_torch:0" ] = { - sdmg = 0, - sid = "minecraft:redstone", - 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", - }, + [ "minecraft:redstone_wire:0" ] = "minecraft:redstone:0", + [ "minecraft:wall_sign:0" ] = "minecraft:sign:0", + [ "minecraft:standing_sign:0" ] = "minecraft:sign:0", + [ "minecraft:potatoes:0" ] = "minecraft:potato:0", + [ "minecraft:unlit_redstone_torch:0" ] = "minecraft:redstone_torch:0", + [ "minecraft:powered_repeater:0" ] = "minecraft:repeater:0", + [ "minecraft:unpowered_repeater:0" ] = "minecraft:repeater:0", + [ "minecraft:carrots:0" ] = "minecraft:carrot:0", + [ "minecraft:cocoa:0" ] = "minecraft:dye:3", + [ "minecraft:unpowered_comparator:0" ] = "minecraft:comparator:0", + [ "minecraft:powered_comparator:0" ] = "minecraft:comparator:0", + [ "minecraft:piston_head:0" ] = "minecraft:air:0", + [ "minecraft:double_wooden_slab:0" ] = "minecraft:planks:0", + [ "minecraft:double_wooden_slab:1" ] = "minecraft:planks:1", + [ "minecraft:double_wooden_slab:2" ] = "minecraft:planks:2", + [ "minecraft:double_wooden_slab:3" ] = "minecraft:planks:3", + [ "minecraft:double_wooden_slab:4" ] = "minecraft:planks:4", + [ "minecraft:double_wooden_slab:5" ] = "minecraft:planks:5", + [ "minecraft:lit_redstone_lamp:0" ] = "minecraft:redstone_lamp:0", + [ "minecraft:double_stone_slab:1" ] = "minecraft:sandstone:0", + [ "minecraft:double_stone_slab:2" ] = "minecraft:planks:0", + [ "minecraft:double_stone_slab:3" ] = "minecraft:cobblestone:0", + [ "minecraft:double_stone_slab:4" ] = "minecraft:brick_block:0", + [ "minecraft:double_stone_slab:5" ] = "minecraft:stonebrick:0", + [ "minecraft:double_stone_slab:6" ] = "minecraft:nether_brick:0", + [ "minecraft:double_stone_slab:7" ] = "minecraft:quartz_block:0", + [ "minecraft:double_stone_slab:9" ] = "minecraft:sandstone:2", + [ "minecraft:double_stone_slab2:0" ] = "minecraft:sandstone:0", + [ "minecraft:stone_slab:2" ] = "minecraft:wooden_slab:0", + [ "minecraft:wheat:0" ] = "minecraft:wheat_seeds:0", + [ "minecraft:flowing_water:0" ] = "minecraft:air:0", + [ "minecraft:lit_furnace:0" ] = "minecraft:furnace:0", + [ "minecraft:wall_banner:0" ] = "minecraft:banner:0", + [ "minecraft:standing_banner:0" ] = "minecraft:banner:0", + [ "minecraft:tripwire:0" ] = "minecraft:string:0", } self.dirty = true self:flush() end function subDB:add(s) - - TableDB.add(self, { s.id, s.dmg}, s) + TableDB.add(self, { s.id, s.dmg }, table.concat({ s.sid, s.sdmg }, ':')) self:flush() end function subDB:remove(s) - -- TODO: tableDB.remove should take table key TableDB.remove(self, s.id .. ':' .. s.dmg) self:flush() end +function subDB:extract(s) + local id, dmg = s:match('(.+):(%d+)') + return id, tonumber(dmg) +end + function subDB:getSubstitutedItem(id, dmg) local sub = TableDB.get(self, { id, dmg }) if sub then - return { id = sub.sid, dmg = sub.sdmg } + id, dmg = self:extract(sub) end return { id = id, dmg = dmg } end @@ -294,26 +127,20 @@ end function subDB:lookupBlocksForSub(sid, sdmg) local t = { } for k,v in pairs(self.data) do - if v.sid == sid and v.sdmg == sdmg then - t[k] = v + local id, dmg = self:extract(v) + if id == sid and dmg == sdmg then + id, dmg = self:extract(k) + t[k] = { id = id, dmg = dmg, sid = sid, sdmg = sdmg } end end return t end - + --[[-- maxStackDB --]]-- maxStackDB = TableDB({ 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) return self.data[id .. ':' .. dmg] or 64 end @@ -348,8 +175,8 @@ function UI.Spinner:spin(text) end term.write(str) self.spinIndex = self.spinIndex + 1 - self.c = cc os.sleep(0) + self.c = os.clock() end end @@ -366,7 +193,7 @@ end --[[-- Builder --]]-- function Builder:getBlockCounts() local blocks = { } - + -- add a couple essential items to the supply list to allow replacements local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0) wrench.qty = 0 @@ -395,13 +222,13 @@ function Builder:getBlockCounts() block.need = 0 blocks[key] = block end - blocks[key].need = blocks[key].need + 1 + block.need = block.need + 1 end end return blocks end - + function Builder:selectItem(id, dmg) for k,s in ipairs(self.slots) do @@ -515,7 +342,7 @@ function Builder:getGenericSupplyList(blockIndex) end end end - + local lastBlock = blockIndex for k = blockIndex, #schematic.blocks do lastBlock = k @@ -529,19 +356,18 @@ function Builder:getGenericSupplyList(blockIndex) slot.need = slot.need + 1 end end - + for _,s in pairs(slots) do if s.id then - s.name = blocks.blockDB:getName(s.id, s.dmg) + s.name = blocks.nameDB:getName(s.id, s.dmg) end end return slots, lastBlock end - -function Builder:substituteBlocks() - local throttle = Util.throttle() - + +function Builder:substituteBlocks(throttle) + for _,b in pairs(schematic.blocks) do -- replace schematic block type with substitution @@ -550,17 +376,16 @@ function Builder:substituteBlocks() b.id = pb.id b.dmg = pb.dmg b.direction = pb.direction + b.extra = pb.extra local sub = subDB:get({ b.id, b.dmg }) if sub then - b.id = sub.sid - b.dmg = sub.sdmg + b.id, b.dmg = subDB:extract(sub) end - throttle() end end - + function Builder:dumpInventory() local success = true @@ -589,7 +414,7 @@ function Builder:dumpInventoryWithCheck() read() end end - + function Builder:autocraft(supplies) local t = { } @@ -606,20 +431,20 @@ function Builder:autocraft(supplies) end item.qty = item.qty + (s.need - s.qty) end - + Builder.itemProvider:craftItems(t) end - + function Builder:getSupplies() - + self.itemProvider:refresh() - + local t = { } for _,s in ipairs(self.slots) do if s.need > 0 then local item = self.itemProvider:getItemInfo(s.id, s.dmg) if item then - s.name = item.name + s.name = item.display_name local qty = math.min(s.need - s.qty, item.qty) @@ -635,7 +460,7 @@ function Builder:getSupplies() s.qty = turtle.getItemCount(s.index) end else - s.name = blocks.blockDB:getName(s.id, s.dmg) + s.name = blocks.nameDB:getName(s.id, s.dmg) end end if s.qty < s.need then @@ -644,14 +469,14 @@ function Builder:getSupplies() Logger.log('builder', 'Need %d %s', s.need - s.qty, name) end end - + return t end - + Event.addHandler('build', function() Builder:build() end) - + function Builder:refuel() while turtle.getFuelLevel() < 4000 and self.fuelItem do Logger.log('builder', 'Refueling') @@ -730,7 +555,6 @@ function Builder:inAirDropoff() return true end end - end function Builder:inAirResupply() @@ -779,7 +603,7 @@ function Builder:inAirResupply() local lastBlock = self:getSupplyList(self.index) local supplies = self:getSupplies() - + Message.broadcast('thanks', { }) self.itemProvider = oldProvider @@ -815,7 +639,7 @@ function Builder:sendSupplyRequest(lastBlock) end function Builder:resupply() - + if self.slotUid and self:inAirResupply() then os.queueEvent('build') return @@ -836,7 +660,7 @@ function Builder:resupply() end os.sleep(1) local supplies = self:getSupplies() - + if #supplies == 0 then os.queueEvent('build') else @@ -851,11 +675,11 @@ end function Builder:placeDown(slot) return turtle.placeDown(slot.index) end - + function Builder:placeUp(slot) return turtle.placeUp(slot.index) end - + function Builder:place(slot) return turtle.place(slot.index) end @@ -863,10 +687,10 @@ end function Builder:getWrenchSlot() local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0) - return Builder:selectItem(wrench.id, wrench.dmg) end +-- figure out our orientation in the world function Builder:getTurtleFacing() if os.getVersion() == 1.8 then @@ -889,7 +713,7 @@ function Builder:getTurtleFacing() return Builder.facing end -function Builder:wrenchBlock(side, facing) +function Builder:wrenchBlock(side, facing, cache) local s = Builder:getWrenchSlot() @@ -899,14 +723,16 @@ function Builder:wrenchBlock(side, facing) end local key = turtle.point.heading .. '-' .. facing - local count = pistonFacings[side][key] + if cache then + local count = cache[side][key] - if count then - turtle.select(s.index) - for i = 1,count do - turtle.getAction(side).place() + if count then + turtle.select(s.index) + for i = 1,count do + turtle.getAction(side).place() + end + return true end - return true end local directions = { @@ -928,10 +754,11 @@ function Builder:wrenchBlock(side, facing) print('determining wrench count') for i = 1, 6 do local _, bi = turtle.getAction(side).inspect() - local pistonFacing = directions[bi.metadata] - if facing == pistonFacing then - pistonFacings[side][key] = count + if facing == directions[bi.metadata] then + if cache then + cache[side][key] = count + end return true end count = count + 1 @@ -941,6 +768,43 @@ function Builder:wrenchBlock(side, facing) return false 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 function Builder:placePiston(b) @@ -957,7 +821,7 @@ function Builder:placePiston(b) return 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) os.sleep(.25) @@ -968,7 +832,7 @@ function Builder:placePiston(b) return success end - + function Builder:goto(x, z, y, heading) if not turtle.goto(x, z, y, heading) then Logger.log('builder', 'stuck') @@ -1000,7 +864,7 @@ end function Builder:placeDirectionalBlock(b, slot, travelPlane) local d = b.direction - + local function getAdjacentPoint(pt, direction) local hi = turtle.getHeadingInfo(direction) return { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = (hi.heading + 2) % 4 } @@ -1016,7 +880,7 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) self:gotoEx(b.x, b.z, b.y, turtle.getHeadingInfo(directions[d]).heading, travelPlane) b.placed = self:placeDown(slot) end - + if d == 'top' then self:gotoEx(b.x, b.z, b.y+1, nil, travelPlane) if self:placeDown(slot) then @@ -1041,7 +905,7 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) b.placed = self:placePiston(b) end end - + local stairDownDirections = { [ 'north-down' ] = 'north', [ 'south-down' ] = 'south', @@ -1094,9 +958,9 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) end end end - + local horizontalDirections = { - [ 'east-west-block' ] = { 'east', 'west' }, + [ 'east-west-block' ] = { 'east', 'west' }, [ 'north-south-block' ] = { 'north', 'south' }, } if horizontalDirections[d] then @@ -1118,10 +982,10 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) local pistonDirections = { [ 'piston-north' ] = 'north', [ 'piston-south' ] = 'south', - [ 'piston-west' ] = 'west', - [ 'piston-east' ] = 'east', + [ 'piston-west' ] = 'west', + [ 'piston-east' ] = 'east', [ 'piston-down' ] = 'down', - [ 'piston-up' ] = 'up', + [ 'piston-up' ] = 'up', } if pistonDirections[d] then @@ -1151,10 +1015,32 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) end 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 + local doorDirections = { [ 'east-door' ] = 'east', [ 'south-door' ] = 'south', @@ -1166,7 +1052,7 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) self:gotoEx(b.x - hi.xd, b.z - hi.zd, b.y - 1, hi.heading, travelPlane) b.placed = self:place(slot) end - + local blockDirections = { [ 'north-block' ] = 'north', [ 'south-block' ] = 'south', @@ -1179,6 +1065,10 @@ function Builder:placeDirectionalBlock(b, slot, travelPlane) b.placed = self:place(slot) end + if b.extra then + self:rotateBlock('down', b.extra.facing) + end + -- debug 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 @@ -1189,10 +1079,10 @@ end return b.placed end - -function Builder:reloadSchematic() - schematic:reload() - self:substituteBlocks() + +function Builder:reloadSchematic(throttle) + schematic:reload(throttle) + self:substituteBlocks(throttle) end function Builder:log(...) @@ -1267,14 +1157,14 @@ function Builder:gotoTravelPlane(travelPlane) turtle.gotoY(travelPlane) end end - + function Builder:build() - + local direction = 1 local last = #schematic.blocks local travelPlane = 0 local minFuel = schematic.height + schematic.width + schematic.length + 100 - + if self.mode == 'destroy' then direction = -1 last = 1 @@ -1290,15 +1180,15 @@ function Builder:build() end end end - + UI:setPage('blank') for i = self.index, last, direction do self.index = i local b = schematic:getComputedBlock(i) - + if b.id ~= 'minecraft:air' then - + if self.mode == 'destroy' then b.heading = nil -- don't make the supplier follow the block heading @@ -1424,7 +1314,7 @@ selectSubstitutionPage = UI.Page({ { heading = 'id', key = 'id' }, { heading = 'dmg', key = 'dmg' }, }, - sortColumn = 'odmg', + sortColumn = 'id', height = UI.term.height-1, autospace = true, y = 2, @@ -1438,7 +1328,7 @@ function selectSubstitutionPage:enable() end function selectSubstitutionPage:eventHandler(event) - + if event.type == 'grid_select' then substitutionPage.sub = event.selected UI:setPage(substitutionPage) @@ -1449,35 +1339,36 @@ function selectSubstitutionPage:eventHandler(event) end return true end - + --[[-- substitutionPage --]]-- -substitutionPage = UI.Page({ +substitutionPage = UI.Page { backgroundColor = colors.gray, - titleBar = UI.TitleBar({ + titleBar = UI.TitleBar { previousPage = true, title = 'Substitute a block' - }), - menuBar = UI.MenuBar({ + }, + menuBar = UI.MenuBar { y = 2, buttons = { { text = 'Accept', event = 'accept', help = 'Accept' }, { text = 'Revert', event = 'revert', help = 'Restore to original' }, { text = 'Air', event = 'air', help = 'Air' }, }, - }), - info = UI.Window({ y = 4, width = UI.term.width, height = 3 }), - grid = UI.ScrollingGrid({ + }, + info = UI.Window { y = 4, width = UI.term.width, height = 3 }, + grid = UI.ScrollingGrid { 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 }, }, sortColumn = 'name', height = UI.term.height-7, y = 7, - }), - statusBar = UI.StatusBar() -}) - + }, + throttle = UI.Throttle { }, + statusBar = UI.StatusBar { } +} + substitutionPage.menuBar:add({ filterLabel = UI.Text({ value = 'Search', @@ -1489,14 +1380,14 @@ substitutionPage.menuBar:add({ width = 7, }) }) - + function substitutionPage.info:draw() 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 = '' if sub.sid then - outName = blocks.blockDB:getName(sub.sid, sub.sdmg) + outName = blocks.nameDB:getName(sub.sid, sub.sdmg) end self:clear() @@ -1505,18 +1396,18 @@ function substitutionPage.info:draw() self:print(' ' .. sub.id .. ':' .. sub.dmg .. '\n', nil, colors.yellow) self:print(' With ' .. outName) end - + function substitutionPage:enable() - + self.allItems = Builder.itemProvider:refresh() self.grid.values = self.allItems for _,item in pairs(self.grid.values) do 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) end self.grid:update() - + self.menuBar.filter.value = '' self.menuBar.filter.pos = 1 self:setFocus(self.menuBar.filter) @@ -1526,31 +1417,31 @@ end --function substitutionPage:focusFirst() -- self.menuBar.filter:focus() --end - + function substitutionPage:applySubstitute(id, dmg) self.sub.sid = id self.sub.sdmg = dmg end - + function substitutionPage:eventHandler(event) - + if event.type == 'grid_focus_row' then local s = string.format('%s:%d', event.selected.id, event.selected.dmg) - + self.statusBar:setStatus(s) self.statusBar:draw() elseif event.type == 'grid_select' then - if not blocks.blockDB:lookupName(event.selected.id, event.selected.dmg) then - blocks.blockDB:add(event.selected.id, event.selected.dmg, event.selected.name, event.selected.id) - blocks.blockDB:flush() + if not blocks.nameDB:lookupName(event.selected.id, event.selected.dmg) then + blocks.nameDB:add({event.selected.id, event.selected.dmg}, event.selected.name) + blocks.nameDB:flush() end self:applySubstitute(event.selected.id, event.selected.dmg) self.info:draw() - + elseif event.type == 'text_change' then local text = event.text if #text == 0 then @@ -1567,12 +1458,12 @@ function substitutionPage:eventHandler(event) self.grid:update() self.grid:setIndex(1) self.grid:draw() - + elseif event.type == 'accept' or event.type == 'air' or event.type == 'revert' then self.statusBar:setStatus('Saving changes...') self.statusBar:draw() self:sync() - + if event.type == 'air' then self:applySubstitute('minecraft:air', 0) end @@ -1587,23 +1478,25 @@ function substitutionPage:eventHandler(event) subDB:add(self.sub) end - Builder:reloadSchematic() + self.throttle:enable() + Builder:reloadSchematic(function() self.throttle:update() end) + self.throttle:disable() UI:setPage('listing') - + elseif event.type == 'cancel' then UI:setPreviousPage() end - + return UI.Page.eventHandler(self, event) end - + --[[-- SupplyPage --]]-- -supplyPage = UI.Page({ - titleBar = UI.TitleBar({ +supplyPage = UI.Page { + titleBar = UI.TitleBar { title = 'Waiting for supplies', previousPage = 'start' - }), - menuBar = UI.MenuBar({ + }, + menuBar = UI.MenuBar { y = 2, buttons = { --{ text = 'Refresh', event = 'refresh', help = 'Refresh inventory' }, @@ -1611,8 +1504,8 @@ supplyPage = UI.Page({ { text = 'Menu', event = 'menu', help = 'Return to main menu' }, { text = 'Force Craft', event = 'craft', help = 'Request crafting (again)' }, } - }), - grid = UI.Grid({ + }, + grid = UI.Grid { columns = { { heading = 'Name', key = 'name', width = UI.term.width - 7 }, { heading = 'Need', key = 'need', width = 4 }, @@ -1621,23 +1514,23 @@ supplyPage = UI.Page({ y = 3, width = UI.term.width, height = UI.term.height - 3 - }), - statusBar = UI.StatusBar({ + }, + statusBar = UI.StatusBar { columns = { { 'Help', 'help', UI.term.width - 13 }, { 'Fuel', 'fuel', 11 } } - }), + }, accelerators = { c = 'craft', r = 'refresh', b = 'build', m = 'menu', }, -}) - +} + function supplyPage:eventHandler(event) - + if event.type == 'craft' then local s = self.grid:getSelected() if Builder.itemProvider:craft(s.id, s.dmg, s.need-s.qty) then @@ -1646,19 +1539,19 @@ function supplyPage:eventHandler(event) else self.statusBar:timedStatus('Unable to craft') end - + elseif event.type == 'refresh' then self:refresh() - + elseif event.type == 'build' then Builder:build() - + elseif event.type == 'menu' then Builder:dumpInventory() --Builder.status = 'idle' UI:setPage('start') turtle.status = 'idle' - + elseif event.type == 'grid_focus_row' then self.statusBar:setValue('help', event.selected.id .. ':' .. event.selected.dmg) self.statusBar:draw() @@ -1666,17 +1559,17 @@ function supplyPage:eventHandler(event) elseif event.type == 'focus_change' then self.statusBar:timedStatus(event.focused.help, 3) end - + return UI.Page.eventHandler(self, event) end - + function supplyPage:enable() self.grid:setIndex(1) self.statusBar:setValue('fuel', string.format('Fuel: %dk', math.floor(turtle.getFuelLevel() / 1024))) -- self.statusBar:setValue('block', - -- string.format('Block: %d', Builder.index)) - +-- string.format('Block: %d', Builder.index)) + Event.addNamedTimer('supplyRefresh', 6, true, function() if self.enabled then Builder:autocraft(Builder:getSupplies()) @@ -1687,7 +1580,7 @@ function supplyPage:enable() end) UI.Page.enable(self) end - + function supplyPage:disable() Event.cancelNamedTimer('supplyRefresh') end @@ -1719,7 +1612,7 @@ function supplyPage:refresh() self.grid:draw() end end - + --[[-- ListingPage --]]-- listingPage = UI.Page({ titleBar = UI.TitleBar({ @@ -1737,7 +1630,7 @@ listingPage = UI.Page({ }), grid = UI.ScrollingGrid({ columns = { - { heading = 'Name', key = 'name', width = UI.term.width - 14 }, + { heading = 'Name', key = 'name', width = UI.term.width - 14 }, { heading = 'Need', key = 'need', width = 5 }, { heading = 'Have', key = 'qty', width = 5 }, }, @@ -1755,14 +1648,14 @@ listingPage = UI.Page({ statusBar = UI.StatusBar(), fullList = true }) - -function listingPage:enable() - listingPage:refresh() + +function listingPage:enable(throttle) + listingPage:refresh(throttle) UI.Page.enable(self) end - + function listingPage:eventHandler(event) - + if event.type == 'craft' then local s = self.grid:getSelected() local item = Builder.itemProvider:getItemInfo(s.id, s.dmg) @@ -1786,24 +1679,24 @@ function listingPage:eventHandler(event) self:refresh() self:draw() self.statusBar:timedStatus('Refreshed ', 3) - + elseif event.type == 'toggle' then self.fullList = not self.fullList self:refresh() self:draw() - + elseif event.type == 'menu' then UI:setPage('start') - + elseif event.type == 'edit' or event.type == 'grid_select' then self:manageBlock(self.grid:getSelected()) - + elseif event.type == 'focus_change' then if event.focused.help then self.statusBar:timedStatus(event.focused.help, 3) end end - + return UI.Page.eventHandler(self, event) end @@ -1821,12 +1714,12 @@ function listingPage.grid:getRowTextColor(row, selected) return UI.Grid:getRowTextColor(row, selected) end -function listingPage:refresh() - +function listingPage:refresh(throttle) + local supplyList = Builder:getBlockCounts() - - Builder.itemProvider:refresh() - + + Builder.itemProvider:refresh(throttle) + for _,b in pairs(supplyList) do if b.need > 0 then local item = Builder.itemProvider:getItemInfo(b.id, b.dmg) @@ -1834,20 +1727,23 @@ function listingPage:refresh() if item then local block = blocks.blockDB:lookup(b.id, b.dmg) if not block then - blocks.blockDB:add(b.id, b.dmg, item.name, b.id) - elseif not block.name and item.name 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.display_name then + blocks.nameDB:add({b.id, b.dmg}, item.display_name) end - b.name = item.name + b.name = item.display_name b.qty = item.qty b.is_craftable = item.is_craftable else - b.name = blocks.blockDB:getName(b.id, b.dmg) + b.name = blocks.nameDB:getName(b.id, b.dmg) end end + if throttle then + throttle() + end end - blocks.blockDB:flush() - + blocks.nameDB:flush() + if self.fullList then self.grid:setValues(supplyList) else @@ -1861,7 +1757,7 @@ function listingPage:refresh() end self.grid:setIndex(1) end - + function listingPage:manageBlock(selected) local substitutes = subDB:lookupBlocksForSub(selected.id, selected.dmg) @@ -1879,17 +1775,17 @@ function listingPage:manageBlock(selected) UI:setPage(selectSubstitutionPage) end end - + --[[-- startPage --]]-- -local startPage = UI.Page({ +local startPage = UI.Page { -- titleBar = UI.TitleBar({ title = 'Builder v' .. Builder.version }), - window = UI.Window({ + window = UI.Window { x = UI.term.width-16, y = 2, width = 16, height = UI.term.height-2, backgroundColor = colors.gray, - grid = UI.Grid({ + grid = UI.Grid { columns = { { heading = 'Name', key = 'name', width = 6 }, { heading = 'Value', key = 'value', width = 7 }, @@ -1903,9 +1799,9 @@ local startPage = UI.Page({ --autospace = true, selectable = false, backgroundColor = colors.gray - }), - }), - menu = UI.Menu({ + }, + }, + menu = UI.Menu { x = 2, y = 4, menuItems = { @@ -1917,13 +1813,14 @@ local startPage = UI.Page({ { prompt = 'Begin', event = 'begin' }, { prompt = 'Quit', event = 'quit' } } - }), + }, + throttle = UI.Throttle { }, accelerators = { x = 'test', q = 'quit' } -}) - +} + function startPage:draw() local fuel = turtle.getFuelLevel() if fuel > 9999 then @@ -1939,7 +1836,7 @@ function startPage:draw() { name = 'width', value = schematic.width }, { name = 'height', value = schematic.height }, } - + self.window.grid:setValues(t) UI.Page.draw(self) end @@ -1948,9 +1845,9 @@ function startPage:enable() self:setFocus(self.menu) UI.Page.enable(self) end - + function startPage:eventHandler(event) - + if event.type == 'startLevel' then local dialog = UI.Dialog({ title = 'Enter Starting Level', @@ -1962,7 +1859,7 @@ function startPage:eventHandler(event) }, statusBar = UI.StatusBar(), }) - + dialog.eventHandler = function(self, event) if event.type == 'form_complete' then local l = tonumber(self.form.textEntry.value) @@ -1985,10 +1882,10 @@ function startPage:eventHandler(event) end return true end - + dialog:setFocus(dialog.form.textEntry) UI:setPage(dialog) - + elseif event.type == 'startBlock' then local dialog = UI.Dialog { title = 'Enter Block Number', @@ -2000,7 +1897,7 @@ function startPage:eventHandler(event) }, statusBar = UI.StatusBar(), } - + dialog.eventHandler = function(self, event) if event.type == 'form_complete' then local bn = tonumber(self.form.textEntry.value) @@ -2018,17 +1915,18 @@ function startPage:eventHandler(event) end return true end - + dialog:setFocus(dialog.form.textEntry) UI:setPage(dialog) - + elseif event.type == 'assignBlocks' then -- this might be an approximation of the blocks needed -- as the current level's route may or may not have been -- computed Builder:dumpInventory() - UI:setPage('listing') - + UI:setPage('listing', function() self.throttle:update() end) + self.throttle:disable() + elseif event.type == 'toggleMode' then if Builder.mode == 'build' then if Builder.index == 1 then @@ -2054,14 +1952,14 @@ function startPage:eventHandler(event) Builder.facing = directions[Builder.facing] Builder:saveProgress(Builder.index) self:draw() - + elseif event.type == 'begin' then UI:setPage('blank') --Builder.status = 'building' - + turtle.status = 'thinking' print('Reloading schematic') - Builder:reloadSchematic() + Builder:reloadSchematic(Util.throttle()) Builder:dumpInventory() Builder:refuel() @@ -2079,29 +1977,22 @@ function startPage:eventHandler(event) down = { }, forward = { }, } - + Builder:build() - + elseif event.type == 'quit' then Event.exitPullEvents() end - + return UI.Page.eventHandler(self, event) end - + --[[-- startup logic --]]-- local args = {...} if #args < 1 then error('supply file name') end - -if os.version() == 'CraftOS 1.7' then - Builder.ccVersion = 1.7 - Builder.resourceSlots = 14 -else - error('Unsupported ComputerCraft version') -end - + Builder.itemProvider = MEProvider() if not Builder.itemProvider:isValid() then Builder.itemProvider = ChestProvider() @@ -2109,7 +2000,7 @@ if not Builder.itemProvider:isValid() then error('A chest or ME interface must be below turtle') end end - + multishell.setTitle(multishell.getCurrent(), 'Builder v' .. Builder.version) maxStackDB:load() @@ -2117,17 +2008,18 @@ subDB:load() UI.term:reset() turtle.status = 'reading' -print('Loading ' .. args[1]) +print('Loading schematic') schematic:load(args[1]) print('Substituting blocks') -Builder:substituteBlocks() + +Builder:substituteBlocks(Util.throttle()) if not fs.exists(BUILDER_DIR) then fs.makeDir(BUILDER_DIR) end Builder:loadProgress(schematic.filename .. '.progress') - + UI:setPages({ listing = listingPage, start = startPage, @@ -2146,4 +2038,3 @@ turtle.run(function() end) UI.term:reset() ---turtle.status = 'idle' diff --git a/sys/apps/refinedManager.lua b/sys/apps/refinedManager.lua index b8f5a12..f22dbe1 100644 --- a/sys/apps/refinedManager.lua +++ b/sys/apps/refinedManager.lua @@ -189,10 +189,10 @@ itemPage = UI.Page { backgroundColor = colors.green }, 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 { - x = 4, y = 6, height = 10, rex = -4, + x = 4, y = 4, height = 10, rex = -4, [1] = UI.TextEntry { width = 7, backgroundColor = colors.gray, diff --git a/sys/apps/shapes.lua b/sys/apps/shapes.lua new file mode 100644 index 0000000..1828c59 --- /dev/null +++ b/sys/apps/shapes.lua @@ -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() diff --git a/sys/apps/storageActivity.lua b/sys/apps/storageActivity.lua index eec61be..d65714e 100644 --- a/sys/apps/storageActivity.lua +++ b/sys/apps/storageActivity.lua @@ -4,10 +4,14 @@ local Event = require('event') local UI = require('ui') local RefinedProvider = require('refinedProvider') local MEProvider = require('meProvider') +local ChestProvider = require('chestProvider18') local storage = RefinedProvider() if not storage:isValid() then storage = MEProvider() + if not storage:isValid() then + storage = ChestProvider() + end end if not storage:isValid() then @@ -106,7 +110,7 @@ local function uniqueKey(item) end function changedPage:refresh() - local t = storage:listItems('all') + local t = storage:listItems() if not t or Util.empty(t) then self:clear() diff --git a/sys/apps/supplier.lua b/sys/apps/supplier.lua index 28cc52b..4b586af 100644 --- a/sys/apps/supplier.lua +++ b/sys/apps/supplier.lua @@ -31,6 +31,7 @@ Logger.filter('modem_send', 'event', 'ui') Logger.setWirelessLogging() local __BUILDER_ID = 6 +local itemInfoDB local Builder = { version = '1.70', @@ -116,7 +117,7 @@ function Builder:refuel() self.itemProvider:provide(self.fuelItem, 64, 1) if turtle.getItemCount(1) == 0 then Builder:log('Out of fuel, add coal to chest/ME system') - turtle.setHeading(0) + --turtle.setHeading(0) os.sleep(5) else turtle.refuel(64) @@ -160,6 +161,11 @@ function Builder:getSupplies() if s.qty < s.need then table.insert(t, s) local name = s.name or s.id .. ':' .. s.dmg + local item = itemInfoDB:get({ s.id, s.dmg }) + if item then + name = item.displayName + end + Builder:log('Need %d %s', s.need - s.qty, name) end end @@ -400,6 +406,12 @@ __BUILDER_ID = tonumber(args[1]) maxStackDB:load() +itemInfoDB = TableDB({ + fileName = 'items.db' +}) + +itemInfoDB:load() + Builder.itemProvider = MEProvider({ direction = args[2] }) if not Builder.itemProvider:isValid() then local sides = { diff --git a/sys/etc/blockIds.csv b/sys/etc/blockIds.csv index 4194963..12ff13c 100644 --- a/sys/etc/blockIds.csv +++ b/sys/etc/blockIds.csv @@ -45,6 +45,7 @@ Leaves (Spruce),18:1,,Solid Block Leaves (Birch),18:2,,Solid Block Leaves (Jungle),18:3,,Solid Block Sponge,19,minecraft:sponge,Solid Block +Wet Sponge,19:1,minecraft:sponge,Solid Block Glass,20,minecraft:glass,Solid Block Lapis Lazuli Ore,21,minecraft:lapis_ore,Solid Block Lapis Lazuli Block,22,minecraft:lapis_block,Solid Block diff --git a/sys/etc/blocks.json b/sys/etc/blocks.json new file mode 100644 index 0000000..8ea39fc --- /dev/null +++ b/sys/etc/blocks.json @@ -0,0 +1,1775 @@ +{ + "air": { + "id": 0, + "name": "Air", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "stone": { + "id": 1, + "name": ["Stone", + "Granite", + "Polished Granite", + "Diorite", + "Polished Diorite", + "Andesite", + "Polished Andesite"], + "obtainable": true, + "maxdamage": 6, + "stacksize": 64 + }, + "grass": { + "id": 2, + "name": "Grass Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dirt": { + "id": 3, + "name": ["Dirt", + "Coarse Dirt", + "Podzol"], + "obtainable": true, + "maxdamage": 2, + "stacksize": 64 + }, + "cobblestone": { + "id": 4, + "name": "Cobblestone", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "planks": { + "id": 5, + "name": ["Oak Wood Planks", + "Spruce Wood Planks", + "Birch Wood Planks", + "Jungle Wood Planks", + "Acacia Wood Planks", + "Dark Oak Wood Planks"], + "obtainable": true, + "maxdamage": 5, + "stacksize": 64 + }, + "sapling": { + "id": 6, + "name": ["Oak Sapling", + "Spruce Sapling", + "Birch Sapling", + "Jungle Sapling", + "Acacia Sapling", + "Dark Oak Sapling"], + "obtainable": true, + "maxdamage": 5, + "stacksize": 64 + }, + "bedrock": { + "id": 7, + "name": "Bedrock", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "flowing_water": { + "id": 8, + "name": "Water", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "water": { + "id": 9, + "name": "Water", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "flowing_lava": { + "id": 10, + "name": "Lava", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "lava": { + "id": 11, + "name": "Lava", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "sand": { + "id": 12, + "name": ["Sand", + "Red Sand"], + "obtainable": true, + "maxdamage": 1, + "stacksize": 64 + }, + "gravel": { + "id": 13, + "name": "Gravel", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "gold_ore": { + "id": 14, + "name": "Gold Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "iron_ore": { + "id": 15, + "name": "Iron Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "coal_ore": { + "id": 16, + "name": "Coal Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "log": { + "id": 17, + "name": ["Oak Wood", + "Spruce Wood", + "Birch Wood", + "Jungle Wood"], + "obtainable": true, + "maxdamage": 3, + "stacksize": 64 + }, + "leaves": { + "id": 18, + "name": ["Oak Leaves", + "Spruce Leaves", + "Birch Leaves", + "Jungle Leaves"], + "obtainable": true, + "maxdamage": 3, + "stacksize": 64 + }, + "sponge": { + "id": 19, + "name": ["Sponge", + "Wet Sponge"], + "obtainable": true, + "maxdamage": 1, + "stacksize": 64 + }, + "glass": { + "id": 20, + "name": "Glass", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "lapis_ore": { + "id": 21, + "name": "Lapis Lazuli Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "lapis_block": { + "id": 22, + "name": "Lapis Lazuli Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dispenser": { + "id": 23, + "name": "Dispenser", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "sandstone": { + "id": 24, + "name": ["Sandstone", + "Chiseled Sandstone", + "Smooth Sandstone"], + "maxdamage": 2, + "stacksize": 64 + }, + "noteblock": { + "id": 25, + "name": "Note Block", + "maxdamage": 0, + "stacksize": 64 + }, + "bed": { + "id": 26, + "name": "Bed", + "maxdamage": 0, + "stacksize": 64 + }, + "golden_rail": { + "id": 27, + "name": "Powered Rail", + "maxdamage": 0, + "stacksize": 64 + }, + "detector_rail": { + "id": 28, + "name": "Detector Rail", + "maxdamage": 0, + "stacksize": 64 + }, + "sticky_piston": { + "id": 29, + "name": "Sticky Piston", + "maxdamage": 0, + "stacksize": 64 + }, + "web": { + "id": 30, + "name": "Cobweb", + "maxdamage": 0, + "stacksize": 64 + }, + "tallgrass": { + "id": 31, + "name": ["Shrub", + "Grass", + "Fern"], + "obtainable": true, + "maxdamage": 2, + "stacksize": 64 + }, + "deadbush": { + "id": 32, + "name": "Dead Bush", + "maxdamage": 0, + "stacksize": 64 + }, + "piston": { + "id": 33, + "name": "Piston", + "maxdamage": 0, + "stacksize": 64 + }, + "piston_head": { + "id": 34, + "name": "Piston Extension", + "maxdamage": 0, + "stacksize": 64 + }, + "wool": { + "id": 35, + "name": ["White Wool", + "Orange Wool", + "Magenta Wool", + "Light Blue Wool", + "Yellow Wool", + "Lime Wool", + "Pink Wool", + "Gray Wool", + "Light Gray Wool", + "Cyan Wool", + "Purple Wool", + "Blue Wool", + "Brown Wool", + "Green Wool", + "Red Wool", + "Black Wool"], + "maxdamage": 15, + "stacksize": 64 + }, + "piston_extension": { + "id": 36, + "name": "Block moved by Piston", + "maxdamage": 0, + "stacksize": 64 + }, + "yellow_flower": { + "id": 37, + "name": "Dandelion", + "maxdamage": 0, + "stacksize": 64 + }, + "red_flower": { + "id": 38, + "name": ["Poppy", + "Blue Orchid", + "Allium", + "Azure Bluet", + "Red Tulip", + "Orange Tulip", + "White Tulip", + "Pink Tulip", + "Oxeye Daisy"], + "maxdamage": 8, + "stacksize": 64 + }, + "brown_mushroom": { + "id": 39, + "name": "Brown Mushroom", + "maxdamage": 0, + "stacksize": 64 + }, + "red_mushroom": { + "id": 40, + "name": "Red Mushroom", + "maxdamage": 0, + "stacksize": 64 + }, + "gold_block": { + "id": 41, + "name": "Block of Gold", + "maxdamage": 0, + "stacksize": 64 + }, + "iron_block": { + "id": 42, + "name": "Block of Iron", + "maxdamage": 0, + "stacksize": 64 + }, + "double_stone_slab": { + "id": 43, + "name": "Double Stone Slab", + "maxdamage": 0, + "stacksize": 64 + }, + "stone_slab": { + "id": 44, + "name": ["Stone Slab", + "Sandstone Slab", + "Wooden Slab", + "Cobblestone Slab", + "Bricks Slab", + "Stone Bricks Slab", + "Nether Brick Slab", + "Quartz Slab"], + "maxdamage": 3, + "stacksize": 64 + }, + "brick_block": { + "id": 45, + "name": "Bricks", + "maxdamage": 0, + "stacksize": 64 + }, + "tnt": { + "id": 46, + "name": "TNT", + "maxdamage": 0, + "stacksize": 64 + }, + "bookshelf": { + "id": 47, + "name": "Bookshelf", + "maxdamage": 0, + "stacksize": 64 + }, + "mossy_cobblestone": { + "id": 48, + "name": "Moss Stone", + "maxdamage": 0, + "stacksize": 64 + }, + "obsidian": { + "id": 49, + "name": "Obsidian", + "maxdamage": 0, + "stacksize": 64 + }, + "torch": { + "id": 50, + "name": "Torch", + "maxdamage": 0, + "stacksize": 64 + }, + "fire": { + "id": 51, + "name": "Fire", + "maxdamage": 0, + "stacksize": 64 + }, + "mob_spawner": { + "id": 52, + "name": "Monster Spawner", + "maxdamage": 0, + "stacksize": 64 + }, + "oak_stairs": { + "id": 53, + "name": "Oak Wood Stairs", + "maxdamage": 0, + "stacksize": 64 + }, + "chest": { + "id": 54, + "name": "Chest", + "maxdamage": 0, + "stacksize": 64 + }, + "redstone_wire": { + "id": 55, + "name": "Redstone Wire", + "maxdamage": 0, + "stacksize": 64 + }, + "diamond_ore": { + "id": 56, + "name": "Diamond Ore", + "maxdamage": 0, + "stacksize": 64 + }, + "diamond_block": { + "id": 57, + "name": "Block of Diamond", + "maxdamage": 0, + "stacksize": 64 + }, + "crafting_table": { + "id": 58, + "name": "Crafting Table", + "maxdamage": 0, + "stacksize": 64 + }, + "wheat": { + "id": 59, + "name": "Wheat", + "maxdamage": 0, + "stacksize": 64 + }, + "farmland": { + "id": 60, + "name": "Farmland", + "maxdamage": 0, + "stacksize": 64 + }, + "furnace": { + "id": 61, + "name": "Furnace", + "maxdamage": 0, + "stacksize": 64 + }, + "lit_furnace": { + "id": 62, + "name": "Burning Furnace", + "maxdamage": 0, + "stacksize": 64 + }, + "standing_sign": { + "id": 63, + "name": "Sign", + "maxdamage": 0, + "stacksize": 64 + }, + "wooden_door": { + "id": 64, + "name": "Oak Door", + "maxdamage": 0, + "stacksize": 64 + }, + "ladder": { + "id": 65, + "name": "Ladder", + "maxdamage": 0, + "stacksize": 64 + }, + "rail": { + "id": 66, + "name": "Rail", + "maxdamage": 0, + "stacksize": 64 + }, + "stone_stairs": { + "id": 67, + "name": "Cobblestone Stairs", + "maxdamage": 0, + "stacksize": 64 + }, + "wall_sign": { + "id": 68, + "name": "Sign", + "maxdamage": 0, + "stacksize": 64 + }, + "lever": { + "id": 69, + "name": "Lever", + "maxdamage": 0, + "stacksize": 64 + }, + "stone_pressure_plate": { + "id": 70, + "name": "Stone Pressure Plate", + "maxdamage": 0, + "stacksize": 64 + }, + "iron_door": { + "id": 71, + "name": "Iron Door", + "maxdamage": 0, + "stacksize": 64 + }, + "wooden_pressure_plate": { + "id": 72, + "name": "Wooden Pressure Plate", + "maxdamage": 0, + "stacksize": 64 + }, + "redstone_ore": { + "id": 73, + "name": "Redstone Ore", + "maxdamage": 0, + "stacksize": 64 + }, + "lit_redstone_ore": { + "id": 74, + "name": "Redstone Ore", + "maxdamage": 0, + "stacksize": 64 + }, + "unlit_redstone_torch": { + "id": 75, + "name": "Redstone Torch (inactive)", + "maxdamage": 0, + "stacksize": 64 + }, + "redstone_torch": { + "id": 76, + "name": "Redstone Torch (active)", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "stone_button": { + "id": 77, + "name": "Stone Button", + "maxdamage": 0, + "stacksize": 64 + }, + "snow_layer": { + "id": 78, + "name": "Snow", + "maxdamage": 0, + "stacksize": 64 + }, + "ice": { + "id": 79, + "name": "Ice", + "maxdamage": 0, + "stacksize": 64 + }, + "snow": { + "id": 80, + "name": "Snow", + "maxdamage": 0, + "stacksize": 64 + }, + "cactus": { + "id": 81, + "name": "Cactus", + "maxdamage": 0, + "stacksize": 64 + }, + "clay": { + "id": 82, + "name": "Clay", + "maxdamage": 0, + "stacksize": 64 + }, + "reeds": { + "id": 83, + "name": "Sugar Cane", + "maxdamage": 0, + "stacksize": 64 + }, + "jukebox": { + "id": 84, + "name": "Jukebox", + "maxdamage": 0, + "stacksize": 64 + }, + "fence": { + "id": 85, + "name": "Fence", + "maxdamage": 0, + "stacksize": 64 + }, + "pumpkin": { + "id": 86, + "name": "Pumpkin", + "maxdamage": 0, + "stacksize": 64 + }, + "netherrack": { + "id": 87, + "name": "Netherrack", + "maxdamage": 0, + "stacksize": 64 + }, + "soul_sand": { + "id": 88, + "name": "Soul Sand", + "maxdamage": 0, + "stacksize": 64 + }, + "glowstone": { + "id": 89, + "name": "Glowstone", + "maxdamage": 0, + "stacksize": 64 + }, + "portal": { + "id": 90, + "name": "Portal", + "maxdamage": 0, + "stacksize": 64 + }, + "lit_pumpkin": { + "id": 91, + "name": "Jack o'Lantern", + "maxdamage": 0, + "stacksize": 64 + }, + "cake": { + "id": 92, + "name": "Cake", + "maxdamage": 0, + "stacksize": 64 + }, + "unpowered_repeater": { + "id": 93, + "name": "Redstone Repeater (inactive)", + "maxdamage": 0, + "stacksize": 64 + }, + "powered_repeater": { + "id": 94, + "name": "Redstone Repeater (active)", + "maxdamage": 0, + "stacksize": 64 + }, + "stained_glass": { + "id": 95, + "name": ["White Stained Glass", + "Orange Stained Glass", + "Magenta Stained Glass", + "Light Blue Stained Glass", + "Yellow Stained Glass", + "Lime Stained Glass", + "Pink Stained Glass", + "Gray Stained Glass", + "Light Gray Stained Glass", + "Cyan Stained Glass", + "Purple Stained Glass", + "Blue Stained Glass", + "Brown Stained Glass", + "Green Stained Glass", + "Red Stained Glass", + "Black Stained Glass"], + "maxdamage": 15, + "stacksize": 64 + }, + "trapdoor": { + "id": 96, + "name": "Trapdoor", + "maxdamage": 0, + "stacksize": 64 + }, + "monster_egg": { + "id": 97, + "name": ["Stone Monster Egg", + "Cobblestone Monster Egg", + "Stone Brick Monster Egg", + "Mossy Stone Brick Monster Egg", + "Cracked Stone Brick Monster Egg", + "Chiseled Stone Brick Monster Egg"], + "maxdamage": 5, + "stacksize": 64 + }, + "stonebrick": { + "id": 98, + "name": ["Stone Bricks", + "Mossy Stone Bricks", + "Cracked Stone Bricks", + "Chiseled Stone Bricks"], + "maxdamage": 3, + "stacksize": 64 + }, + "brown_mushroom_block": { + "id": 99, + "name": "Brown Mushroom (block)", + "maxdamage": 0, + "stacksize": 64 + }, + "red_mushroom_block": { + "id": 100, + "name": "Red Mushroom (block)", + "maxdamage": 0, + "stacksize": 64 + }, + "iron_bars": { + "id": 101, + "name": "Iron Bars", + "maxdamage": 0, + "stacksize": 64 + }, + "glass_pane": { + "id": 102, + "name": "Glass Pane", + "maxdamage": 0, + "stacksize": 64 + }, + "melon_block": { + "id": 103, + "name": "Melon", + "maxdamage": 0, + "stacksize": 64 + }, + "pumpkin_stem": { + "id": 104, + "name": "Pumpkin Stem", + "maxdamage": 0, + "stacksize": 64 + }, + "melon_stem": { + "id": 105, + "name": "Melon Stem", + "maxdamage": 0, + "stacksize": 64 + }, + "vine": { + "id": 106, + "name": "Vines", + "maxdamage": 0, + "stacksize": 64 + }, + "fence_gate": { + "id": 107, + "name": "Fence Gate", + "maxdamage": 0, + "stacksize": 64 + }, + "brick_stairs": { + "id": 108, + "name": "Brick Stairs", + "maxdamage": 0, + "stacksize": 64 + }, + "stone_brick_stairs": { + "id": 109, + "name": "Stone Brick Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "mycelium": { + "id": 110, + "name": "Mycelium", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "waterlily": { + "id": 111, + "name": "Lily Pad", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "nether_brick": { + "id": 112, + "name": "Nether Brick", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "nether_brick_fence": { + "id": 113, + "name": "Nether Brick Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "nether_brick_stairs": { + "id": 114, + "name": "Nether Brick Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "nether_wart": { + "id": 115, + "name": "Nether Wart", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "enchanting_table": { + "id": 116, + "name": "Enchantment Table", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "brewing_stand": { + "id": 117, + "name": "Brewing Stand", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "cauldron": { + "id": 118, + "name": "Cauldron", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "end_portal": { + "id": 119, + "name": "End Portal", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "end_portal_frame": { + "id": 120, + "name": "End Portal Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "end_stone": { + "id": 121, + "name": "End Stone", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dragon_egg": { + "id": 122, + "name": "Dragon Egg", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "redstone_lamp": { + "id": 123, + "name": "Redstone Lamp (inactive)", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "lit_redstone_lamp": { + "id": 124, + "name": "Redstone Lamp (active)", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "double_wooden_slab": { + "id": 125, + "name": "Double Wooden Slab", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "wooden_slab": { + "id": 126, + "name": ["Oak Wood Slab", + "Spruce Wood Slab", + "Birch Wood Slab", + "Jungle Wood Slab", + "Acacia Wood Slab", + "Dark Oak Wood Slab"], + "obtainable": true, + "maxdamage": 5, + "stacksize": 64 + }, + "cocoa": { + "id": 127, + "name": "Cocoa", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "sandstone_stairs": { + "id": 128, + "name": "Sandstone Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "emerald_ore": { + "id": 129, + "name": "Emerald Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "ender_chest": { + "id": 130, + "name": "Ender Chest", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "tripwire_hook": { + "id": 131, + "name": "Tripwire Hook", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "tripwire": { + "id": 132, + "name": "Tripwire", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "emerald_block": { + "id": 133, + "name": "Block of Emerald", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "spruce_stairs": { + "id": 134, + "name": "Spruce Wood Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "birch_stairs": { + "id": 135, + "name": "Birch Wood Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "jungle_stairs": { + "id": 136, + "name": "Jungle Wood Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "command_block": { + "id": 137, + "name": "Command Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "beacon": { + "id": 138, + "name": "Beacon", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "cobblestone_wall": { + "id": 139, + "name": ["Cobblestone Wall", + "Mossy Cobblestone Wall"], + "obtainable": true, + "maxdamage": 1, + "stacksize": 64 + }, + "flower_pot": { + "id": 140, + "name": "Flower Pot", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "carrots": { + "id": 141, + "name": "Carrot", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "potatoes": { + "id": 142, + "name": "Potato", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "wooden_button": { + "id": 143, + "name": "Wooden Button", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "skull": { + "id": 144, + "name": "Mob Head", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "anvil": { + "id": 145, + "name": ["Anvil", + "Slightly Damaged Anvil", + "Very Damaged Anvil"], + "obtainable": true, + "maxdamage": 2, + "stacksize": 64 + }, + "trapped_chest": { + "id": 146, + "name": "Trapped Chest", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "light_weighted_pressure_plate": { + "id": 147, + "name": "Weighted Pressure Plate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "heavy_weighted_pressure_plate": { + "id": 148, + "name": "Weighted Pressure Plate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "unpowered_comparator": { + "id": 149, + "name": "Redstone Comparator", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "powered_comparator": { + "id": 150, + "name": "Redstone Comparator", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "daylight_detector": { + "id": 151, + "name": "Daylight Sensor", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "redstone_block": { + "id": 152, + "name": "Block of Redstone", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "quartz_ore": { + "id": 153, + "name": "Nether Quartz Ore", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "hopper": { + "id": 154, + "name": "Hopper", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "quartz_block": { + "id": 155, + "name": ["Block of Quartz", + "Chiseled Quartz Block", + "Pillar Quartz Block"], + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "quartz_stairs": { + "id": 156, + "name": "Quartz Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "activator_rail": { + "id": 157, + "name": "Activator Rail", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dropper": { + "id": 158, + "name": "Dropper", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "stained_hardened_clay": { + "id": 159, + "name": ["White Stained Clay", + "Orange Stained Clay", + "Magenta Stained Clay", + "Light Blue Stained Clay", + "Yellow Stained Clay", + "Lime Stained Clay", + "Pink Stained Clay", + "Gray Stained Clay", + "Light Gray Stained Clay", + "Cyan Stained Clay", + "Purple Stained Clay", + "Blue Stained Clay", + "Brown Stained Clay", + "Green Stained Clay", + "Red Stained Clay", + "Black Stained Clay"], + "obtainable": true, + "maxdamage": 15, + "stacksize": 64 + }, + "stained_glass_pane": { + "id": 160, + "name": ["White Stained Glass Pane", + "Orange Stained Glass Pane", + "Magenta Stained Glass Pane", + "Light Blue Stained Glass Pane", + "Yellow Stained Glass Pane", + "Lime Stained Glass Pane", + "Pink Stained Glass Pane", + "Gray Stained Glass Pane", + "Light Gray Stained Glass Pane", + "Cyan Stained Glass Pane", + "Purple Stained Glass Pane", + "Blue Stained Glass Pane", + "Brown Stained Glass Pane", + "Green Stained Glass Pane", + "Red Stained Glass Pane", + "Black Stained Glass Pane"], + "obtainable": true, + "maxdamage": 15, + "stacksize": 64 + }, + "leaves2": { + "id": 161, + "name": ["Acacia Leaves", + "Dark Oak Leaves"], + "obtainable": true, + "maxdamage": 1, + "stacksize": 64 + }, + "log2": { + "id": 162, + "name": ["Acacia Wood", + "Dark Oak Wood"], + "obtainable": true, + "maxdamage": 1, + "stacksize": 64 + }, + "acacia_stairs": { + "id": 163, + "name": "Acacia Wood Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dark_oak_stairs": { + "id": 164, + "name": "Dark Oak Wood Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "slime": { + "id": 165, + "name": "Slime Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "barrier": { + "id": 166, + "name": "Barrier", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "iron_trapdoor": { + "id": 167, + "name": "Iron Trapdoor", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "prismarine": { + "id": 168, + "name": ["Prismarine", + "Prismarine Bricks", + "Dark Prismarine"], + "obtainable": true, + "maxdamage": 2, + "stacksize": 64 + }, + "sea_lantern": { + "id": 169, + "name": "Sea Lantern", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "hay_block": { + "id": 170, + "name": "Hay Block", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "carpet": { + "id": 171, + "name": ["Carpet", + "Orange Carpet", + "Magenta Carpet", + "Light Blue Carpet", + "Yellow Carpet", + "Lime Carpet", + "Pink Carpet", + "Gray Carpet", + "Light Gray Carpet", + "Cyan Carpet", + "Purple Carpet", + "Blue Carpet", + "Brown Carpet", + "Green Carpet", + "Red Carpet", + "Black Carpet"], + "obtainable": true, + "maxdamage": 15, + "stacksize": 64 + }, + "hardened_clay": { + "id": 172, + "name": "Hardened Clay", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "coal_block": { + "id": 173, + "name": "Block of Coal", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "packed_ice": { + "id": 174, + "name": "Packed Ice", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "double_plant": { + "id": 175, + "name": ["Sunflower", + "Lilac", + "Double Tallgrass", + "Large Fern", + "Rose Bush", + "Peony"], + "obtainable": true, + "maxdamage": 5, + "stacksize": 64 + }, + "standing_banner": { + "id": 176, + "name": "Banner", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "wall_banner": { + "id": 177, + "name": "Banner", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "daylight_detector_inverted": { + "id": 178, + "name": "Inverted Daylight Sensor", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "red_sandstone": { + "id": 179, + "name": ["Red Sandstone", + "Chiseled Red Sandstone", + "Smooth Red Sandstone"], + "obtainable": true, + "maxdamage": 2, + "stacksize": 64 + }, + "red_sandstone_stairs": { + "id": 180, + "name": "Red Sandstone Stairs", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "double_stone_slab2": { + "id": 181, + "name": "Double Red Sandstone Slab", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "stone_slab2": { + "id": 182, + "name": "Red Sandstone Slab", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "spruce_fence_gate": { + "id": 183, + "name": "Spruce Fence Gate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "birch_fence_gate": { + "id": 184, + "name": "Birch Fence Gate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "jungle_fence_gate": { + "id": 185, + "name": "Jungle Fence Gate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dark_oak_fence_gate": { + "id": 186, + "name": "Dark Oak Fence Gate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "acacia_fence_gate": { + "id": 187, + "name": "Acacia Fence Gate", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "spruce_fence": { + "id": 188, + "name": "Spruce Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "birch_fence": { + "id": 189, + "name": "Birch Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "jungle_fence": { + "id": 190, + "name": "Jungle Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "dark_oak_fence": { + "id": 191, + "name": "Dark Oak Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "acacia_fence": { + "id": 192, + "name": "Acacia Fence", + "obtainable": true, + "maxdamage": 0, + "stacksize": 64 + }, + "spruce_door": { + "id": 193, + "name": "Spruce Door", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "birch_door": { + "id": 194, + "name": "Birch Door", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "jungle_door": { + "id": 195, + "name": "Jungle Door", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "acacia_door": { + "id": 196, + "name": "Acacia Door", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "dark_oak_door": { + "id": 197, + "name": "Dark Oak Door", + "obtainable": false, + "maxdamage": 0, + "stacksize": 64 + }, + "end_rod": { + "id": 198 + "name": "End Rod", + }, + "chorus_plant": { + "id": 199 + "name": "Chorus Plant", + }, + "chorus_flower": { + "id": 200 + "name": "Chorus Flower", + }, + "purpur_block": { + "id": 201 + "name": "Purpur Block", + }, + "purpur_pillar": { + "id": 202 + "name": "Purpur Pillar", + }, + "purpur_stairs": { + "id": 203 + "name": "Purpur Stairs", + }, + "purpur_double_slab": { + "id": 204 + "name": "Double Purpur Slabs", + }, + "purpur_slab": { + "name": "Purpur Slab", + "id": 205 + }, + "end_bricks": { + "name": "End Stone Bricks", + "id": 206 + }, + "beetroots": { + "name": "Beetroot", + "id": 207 + }, + "grass_path": { + "name": "Path", + "id": 208 + }, + "end_gateway": { + "id": 209, + "name": "End Gateway" + }, + "repeating_command_block": { + "name": "Repeating Command Block", + "id": 210 + }, + "chain_command_block": { + "name": "Chain Command Block", + "id": 211 + }, + "frosted_ice": { + "name": "Frosted Ice", + "id": 212 + }, + "magma": { + "id": 213, + "name": "Magma Block", + }, + "nether_wart_block": { + "id": 214, + "name": "Nether Wart Block", + }, + "red_nether_brick": { + "id": 215, + "name": "Red Nether Brick", + }, + "bone_block": { + "id": 216, + "name": "Bone Block", + }, + "structure_void": { + "id": 217, + "name": "Structure Void", + }, + "observer": { + "name": "Observer", + "id": 218 + }, + "white_shulker_box": { + "name": "White Shulker Box", + "id": 219 + }, + "orange_shulker_box": { + "name": "Orange Shulker Box", + "id": 220 + }, + "magenta_shulker_box": { + "name": "Magenta Shulker Box", + "id": 221 + }, + "light_blue_shulker_box": { + "name": "Light Blue Shulker Box", + "id": 222 + }, + "yellow_shulker_box": { + "name": "Yellow Shulker Box", + "id": 223 + }, + "lime_shulker_box": { + "name": "Lime Shulker Box", + "id": 224 + }, + "pink_shulker_box": { + "name": "Pink Shulker Box", + "id": 225 + }, + "gray_shulker_box": { + "name": "Gray Shulker Box", + "id": 226 + }, + "silver_shulker_box": { + "name": "Light Gray Shulker Box", + "id": 227 + }, + "cyan_shulker_box": { + "name": "Cyan Shulker Box", + "id": 228 + }, + "purple_shulker_box": { + "name": "Purple Shulker Box", + "id": 229 + }, + "blue_shulker_box": { + "name": "Blue Shulker Box", + "id": 230 + }, + "brown_shulker_box": { + "name": "Brown Shulker Box", + "id": 231 + }, + "green_shulker_box": { + "name": "Green Shulker Box", + "id": 232 + }, + "red_shulker_box": { + "name": "Red Shulker Box", + "id": 233 + }, + "black_shulker_box": { + "name": "Black Shulker Box", + "id": 234 + }, + "white_glazed_terracotta": { + "id": 235, + "name": "White glazed terracotta", + }, + "orange_glazed_terracotta": { + "id": 236, + "name": "Orange glazed terracotta", + }, + "magenta_glazed_terracotta": { + "id": 237, + "name": "Magenta glazed terracotta", + }, + "light_blue_glazed_terracotta": { + "id": 238, + "name": "Light blue glazed terracotta", + }, + "yellow_glazed_terracotta": { + "id": 239, + "name": "Yellow glazed terracotta", + }, + "lime_glazed_terracotta": { + "id": 240, + "name": "Lime glazed terracotta", + }, + "pink_glazed_terracotta": { + "id": 241, + "name": "Pink glazed terracotta", + }, + "gray_glazed_terracotta": { + "id": 242, + "name": "Gray glazed terracotta", + }, + "light_gray_glazed_terracotta": { + "id": 243, + "name": "Light gray glazed terracotta", + }, + "cyan_glazed_terracotta": { + "id": 244, + "name": "Cyan glazed terracotta", + }, + "purple_glazed_terracotta": { + "id": 245, + "name": "Purple glazed terracotta", + }, + "blue_glazed_terracotta": { + "id": 246, + "name": "Blue glazed terracotta", + }, + "brown_glazed_terracotta": { + "id": 247, + "name": "Brown glazed terracotta", + }, + "green_glazed_terracotta": { + "id": 248, + "name": "Green glazed terracotta", + }, + "red_glazed_terracotta": { + "id": 249, + "name": "Red glazed terracotta", + }, + "black_glazed_terracotta": { + "id": 250, + "name": "Black glazed terracotta", + }, + "concrete": { + "id": 251, + "name": ["White concrete", + "Orange concrete", + "Magenta concrete", + "Light blue concrete", + "Yellow concrete", + "Lime concrete", + "Pink concrete", + "Gray concrete", + "Silver concrete", + "Cyan concrete", + "Purple concrete", + "Blue concrete", + "Brown concrete", + "Green concrete", + "Red concrete", + "Black concrete"], + }, + "concrete_powder": { + "id": 252, + "name": ["White concrete powder", + "Orange concrete powder", + "Magenta concrete powder", + "Light blue concrete powder", + "Yellow concrete powder", + "Lime concrete powder", + "Pink concrete powder", + "Gray concrete powder", + "Silver concrete powder", + "Cyan concrete powder", + "Purple concrete powder", + "Blue concrete powder", + "Brown concrete powder", + "Green concrete powder", + "Red concrete powder", + "Black concrete powder"], + }, + "structure_block": { + "name": ["Structure Block (Save)", + "Structure Block (Load)", + "Structure Block (Corner)", + "Structure Block (Data)"], + "id": 255 + }, + "string": { + "name": "String", + "id": 287 + }, + "coal": { + "name": ["Coal", + "Charcoal"], + "id": 263 + }, + "wheat_seeds": { + "id": 295, + "name": "Wheat Seeds", + }, + "sign": { + "id": 323, + "name": "Sign", + }, + "redstone": { + "id": 331, + "name": "Redstone Dust", + }, + "dye": { + "id": 351, + "name": ["Ink Sack", + "Rose Red", + "Cactus Green", + "Cocoa Bean", + "Lapis Lazuli", + "Purple Dye", + "Cyan Dye", + "Light Gray Dye", + "Gray Dye", + "Pink Dye", + "Lime Dye", + "Dandelion Yellow", + "Light Blue Dye", + "Magenta Dye", + "Orange Dye", + "Bone Meal"] + }, + "bed-block": { + "id": 355, + "name": "Bed", + }, + "repeater": { + "id": 356, + "name": "Redstone Repeater", + }, + "carrot": { + "id": 391, + "name": "Carrot", + }, + "potato": { + "id": 392, + "name": "Potato", + }, + "comparator": { + "id": 404, + "name": "Redstone Comparator", + }, + "banner": { + "id": 425, + "name": "Banner", + } +} diff --git a/sys/extensions/scheduler.lua b/sys/extensions/scheduler.lua index 3a2546f..7da3677 100644 --- a/sys/extensions/scheduler.lua +++ b/sys/extensions/scheduler.lua @@ -72,10 +72,10 @@ function turtle.run(fn, ...) local s, m = pcall(function() fn(unpack(args)) end) turtle.abort = false releaseTicket(ticketId) + os.queueEvent('turtle_response') if not s and m then printError(m) end - os.queueEvent('turtle_response') return s, m end end diff --git a/sys/extensions/tgps.lua b/sys/extensions/tgps.lua index 729ea2f..7679848 100644 --- a/sys/extensions/tgps.lua +++ b/sys/extensions/tgps.lua @@ -30,6 +30,6 @@ end function turtle.setGPSHome() if turtle.enableGPS() then turtle.storeLocation('gpsHome', turtle.point) - turtle.gotoPoint(tturtle.point) + turtle.gotoPoint(turtle.point) end end diff --git a/sys/services/device.lua b/sys/services/device.lua index b4ce2cf..857c1d6 100644 --- a/sys/services/device.lua +++ b/sys/services/device.lua @@ -19,6 +19,8 @@ Event.addHandler('peripheral', function(event, side) term.setTextColor(attachColor) Util.print('[%s] %s attached', dev.side, dev.name) os.queueEvent('device_attach', dev.name) + else + Util.print('[%s] attached failed', side) end end end)