From 64c68f2662b9cc78c8e8a5de3cae2c88afd08462 Mon Sep 17 00:00:00 2001 From: "kepler155c@gmail.com" Date: Fri, 15 Sep 2017 01:08:04 -0400 Subject: [PATCH] reorganization --- sys/apis/base64.lua | 135 -- sys/apis/blocks.lua | 612 ---------- sys/apis/chestAdapter.lua | 111 -- sys/apis/chestAdapter18.lua | 140 --- sys/apis/deflatelua.lua | 870 ------------- sys/apis/fs/gitfs.lua | 6 +- sys/apis/fs/urlfs.lua | 5 + sys/apis/input.lua | 112 -- sys/apis/itemDB.lua | 39 - sys/apis/me.lua | 167 --- sys/apis/meAdapter.lua | 157 --- sys/apis/message.lua | 106 -- sys/apis/point.lua | 1 + sys/apis/profile.lua | 51 - sys/apis/refinedAdapter.lua | 143 --- sys/apis/schematic.lua | 1175 ------------------ sys/apis/tableDB.lua | 54 - sys/apis/turtle/craft.lua | 166 --- sys/apis/turtle/level.lua | 165 --- sys/apis/turtle/pathfind.lua | 80 +- sys/apis/ui.lua | 4 +- sys/apis/{ => ui}/fileui.lua | 0 sys/apis/{ => ui}/glasses.lua | 0 sys/apis/{ => ui}/region.lua | 0 sys/apis/{ => ui}/tween.lua | 0 sys/apis/util.lua | 4 + sys/apps/Overview.lua | 22 +- sys/apps/Script.lua | 2 +- sys/apps/Turtles.lua | 18 +- sys/apps/base64dl.lua | 36 - sys/apps/builder.lua | 2169 --------------------------------- sys/apps/chestManager.lua | 939 -------------- sys/apps/logMonitor.lua | 101 -- sys/apps/mirror.lua | 25 - sys/apps/mirrorClient.lua | 86 -- sys/apps/mirrorHost.lua | 53 - sys/apps/pickup.lua | 335 ----- sys/apps/pickupRemote.lua | 231 ---- sys/apps/recorder.lua | 538 -------- sys/apps/shapes.lua | 517 -------- sys/apps/shell | 17 +- sys/apps/simpleMiner.lua | 633 ---------- sys/apps/storageActivity.lua | 174 --- sys/apps/storageManager.lua | 901 -------------- sys/apps/supplier.lua | 438 ------- sys/apps/t.lua | 98 -- sys/apps/treefarm.lua | 709 ----------- sys/boot/multishell.boot | 6 +- sys/etc/app.db | 42 +- sys/etc/blocks.json | 1370 --------------------- sys/etc/fstab | 4 - sys/etc/recipes.db | 2108 -------------------------------- sys/etc/scripts/obsidian | 4 +- sys/extensions/tl3.lua | 96 +- 54 files changed, 175 insertions(+), 15800 deletions(-) delete mode 100644 sys/apis/base64.lua delete mode 100644 sys/apis/blocks.lua delete mode 100644 sys/apis/chestAdapter.lua delete mode 100644 sys/apis/chestAdapter18.lua delete mode 100644 sys/apis/deflatelua.lua delete mode 100644 sys/apis/input.lua delete mode 100644 sys/apis/itemDB.lua delete mode 100644 sys/apis/me.lua delete mode 100644 sys/apis/meAdapter.lua delete mode 100644 sys/apis/message.lua delete mode 100644 sys/apis/profile.lua delete mode 100644 sys/apis/refinedAdapter.lua delete mode 100644 sys/apis/schematic.lua delete mode 100644 sys/apis/tableDB.lua delete mode 100644 sys/apis/turtle/craft.lua delete mode 100644 sys/apis/turtle/level.lua rename sys/apis/{ => ui}/fileui.lua (100%) rename sys/apis/{ => ui}/glasses.lua (100%) rename sys/apis/{ => ui}/region.lua (100%) rename sys/apis/{ => ui}/tween.lua (100%) delete mode 100644 sys/apps/base64dl.lua delete mode 100644 sys/apps/builder.lua delete mode 100644 sys/apps/chestManager.lua delete mode 100644 sys/apps/logMonitor.lua delete mode 100644 sys/apps/mirror.lua delete mode 100644 sys/apps/mirrorClient.lua delete mode 100644 sys/apps/mirrorHost.lua delete mode 100644 sys/apps/pickup.lua delete mode 100644 sys/apps/pickupRemote.lua delete mode 100644 sys/apps/recorder.lua delete mode 100644 sys/apps/shapes.lua delete mode 100644 sys/apps/simpleMiner.lua delete mode 100644 sys/apps/storageActivity.lua delete mode 100644 sys/apps/storageManager.lua delete mode 100644 sys/apps/supplier.lua delete mode 100644 sys/apps/t.lua delete mode 100644 sys/apps/treefarm.lua delete mode 100644 sys/etc/blocks.json delete mode 100644 sys/etc/fstab delete mode 100644 sys/etc/recipes.db diff --git a/sys/apis/base64.lua b/sys/apis/base64.lua deleted file mode 100644 index 767b86d..0000000 --- a/sys/apis/base64.lua +++ /dev/null @@ -1,135 +0,0 @@ --- Base64 Encoder / Decoder --- By KillaVanilla --- see: http://www.computercraft.info/forums2/index.php?/topic/12450-killavanillas-various-apis/ - -Base64 = { } - -local alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - -local function sixBitToBase64(input) - return string.sub(alphabet, input+1, input+1) -end - -local function base64ToSixBit(input) - for i=1, 64 do - if input == string.sub(alphabet, i, i) then - return i-1 - end - end -end - -local function octetToBase64(o1, o2, o3) - local i1 = sixBitToBase64(bit.brshift(bit.band(o1, 0xFC), 2)) - local i2 = "A" - local i3 = "=" - local i4 = "=" - if o2 then - i2 = sixBitToBase64(bit.bor( bit.blshift(bit.band(o1, 3), 4), bit.brshift(bit.band(o2, 0xF0), 4) )) - if not o3 then - i3 = sixBitToBase64(bit.blshift(bit.band(o2, 0x0F), 2)) - else - i3 = sixBitToBase64(bit.bor( bit.blshift(bit.band(o2, 0x0F), 2), bit.brshift(bit.band(o3, 0xC0), 6) )) - end - else - i2 = sixBitToBase64(bit.blshift(bit.band(o1, 3), 4)) - end - if o3 then - i4 = sixBitToBase64(bit.band(o3, 0x3F)) - end - - return i1..i2..i3..i4 -end - --- octet 1 needs characters 1/2 --- octet 2 needs characters 2/3 --- octet 3 needs characters 3/4 - -local function base64ToThreeOctet(s1) - local c1 = base64ToSixBit(string.sub(s1, 1, 1)) - local c2 = base64ToSixBit(string.sub(s1, 2, 2)) - local c3 = 0 - local c4 = 0 - local o1 = 0 - local o2 = 0 - local o3 = 0 - if string.sub(s1, 3, 3) == "=" then - c3 = nil - c4 = nil - elseif string.sub(s1, 4, 4) == "=" then - c3 = base64ToSixBit(string.sub(s1, 3, 3)) - c4 = nil - else - c3 = base64ToSixBit(string.sub(s1, 3, 3)) - c4 = base64ToSixBit(string.sub(s1, 4, 4)) - end - o1 = bit.bor( bit.blshift(c1, 2), bit.brshift(bit.band( c2, 0x30 ), 4) ) - if c3 then - o2 = bit.bor( bit.blshift(bit.band(c2, 0x0F), 4), bit.brshift(bit.band( c3, 0x3C ), 2) ) - else - o2 = nil - end - if c4 then - o3 = bit.bor( bit.blshift(bit.band(c3, 3), 6), c4 ) - else - o3 = nil - end - return o1, o2, o3 -end - -local function splitIntoBlocks(bytes) - local blockNum = 1 - local blocks = {} - for i=1, #bytes, 3 do - blocks[blockNum] = {bytes[i], bytes[i+1], bytes[i+2]} - --[[ - if #blocks[blockNum] < 3 then - for j=#blocks[blockNum]+1, 3 do - table.insert(blocks[blockNum], 0) - end - end - ]] - blockNum = blockNum+1 - end - return blocks -end - -function Base64.encode(bytes) - local blocks = splitIntoBlocks(bytes) - local output = "" - for i=1, #blocks do - output = output..octetToBase64( unpack(blocks[i]) ) - end - return output -end - -function Base64.decode(str) - local bytes = {} - local blocks = {} - local blockNum = 1 - for i=1, #str, 4 do - blocks[blockNum] = string.sub(str, i, i+3) - blockNum = blockNum+1 - end - for i=1, #blocks do - local o1, o2, o3 = base64ToThreeOctet(blocks[i]) - table.insert(bytes, o1) - table.insert(bytes, o2) - table.insert(bytes, o3) -if (i % 1000) == 0 then - os.sleep(0) -end - end - -- Remove padding: - --[[ - for i=#bytes, 1, -1 do - if bytes[i] ~= 0 then - break - else - bytes[i] = nil - end - end - ]] - return bytes -end - -return Base64 diff --git a/sys/apis/blocks.lua b/sys/apis/blocks.lua deleted file mode 100644 index fb9942d..0000000 --- a/sys/apis/blocks.lua +++ /dev/null @@ -1,612 +0,0 @@ -local class = require('class') -local Util = require('util') -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 - ---[[-- nameDB --]]-- -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 - ---[[-- blockDB --]]-- -local blockDB = TableDB() - -function blockDB:load() - - 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, block.place) - else - for nid,name in pairs(block.name) do - self:add(block.id, nid - 1, name, strId, block.place) - end - end - end -end - -function blockDB:lookup(id, dmg) - if not id then - return - end - - return self.data[id .. ':' .. dmg] -end - -function blockDB:add(id, dmg, name, strId, place) - local key = id .. ':' .. dmg - - TableDB.add(self, key, { - id = id, - dmg = dmg, - name = name, - strId = strId, - place = place, - }) -end - ---[[-- placementDB --]]-- --- in memory table that expands the standardBlock and blockType tables for each item/dmg/placement combination -local placementDB = TableDB() - -function placementDB:load(sbDB, btDB) - - for k,blockType in pairs(sbDB.data) do - local bt = btDB.data[blockType] - if not bt then - error('missing block type: ' .. blockType) - end - local id, dmg = string.match(k, '(%d+):*(%d+)') - self:addSubsForBlockType(tonumber(id), tonumber(dmg), bt) - end -end - -function placementDB:load2(sbDB, btDB) - - for k,v in pairs(sbDB.data) do - if v.place then - local bt = btDB.data[v.place] - if not bt then - error('missing block type: ' .. v.place) - end - local id, dmg = string.match(k, '(%d+):*(%d+)') - self:addSubsForBlockType(tonumber(id), tonumber(dmg), bt) - end - end - - -- special case for quartz pillars - self:addSubsForBlockType(155, 2, btDB.data['quartz-pillar']) -end - - -function placementDB:addSubsForBlockType(id, dmg, bt) - for _,sub in pairs(bt) do - local odmg = sub.odmg - if type(sub.odmg) == 'string' then - odmg = dmg + tonumber(string.match(odmg, '+(%d+)')) - end - - local b = blockDB:lookup(id, dmg) - local strId = tostring(id) - if b then - strId = b.strId - end - - self:add( - id, - odmg, - sub.sid or strId, - sub.sdmg or dmg, - sub.dir, - sub.extra) - end -end - -function placementDB:add(id, dmg, sid, sdmg, direction, extra) - if direction and #direction == 0 then - direction = nil - end - - local entry = { - oid = id, -- numeric ID - odmg = dmg, -- dmg with placement info - id = sid, -- string ID - dmg = sdmg, -- dmg without placement info - direction = direction, - } - if extra then - Util.merge(entry, extra) - end - - self.data[id .. ':' .. dmg] = entry -end - ---[[-- BlockTypeDB --]]-- -local blockTypeDB = TableDB() - -function blockTypeDB:addTemp(blockType, subs) - local bt = self.data[blockType] - if not bt then - bt = { } - self.data[blockType] = bt - end - for _,sub in pairs(subs) do - table.insert(bt, { - odmg = sub[1], - sid = sub[2], - sdmg = sub[3], - dir = sub[4], - extra = sub[5] - }) - end - self.dirty = true -end - -function blockTypeDB:load() - - blockTypeDB:addTemp('stairs', { - { 0, nil, 0, 'east-up' }, - { 1, nil, 0, 'west-up' }, - { 2, nil, 0, 'south-up' }, - { 3, nil, 0, 'north-up' }, - { 4, nil, 0, 'east-down' }, - { 5, nil, 0, 'west-down' }, - { 6, nil, 0, 'south-down' }, - { 7, nil, 0, 'north-down' }, - }) - blockTypeDB:addTemp('gate', { - { 0, nil, 0, 'north' }, - { 1, nil, 0, 'east' }, - { 2, nil, 0, 'south' }, - { 3, nil, 0, 'west' }, - { 4, nil, 0, 'north' }, - { 5, nil, 0, 'east' }, - { 6, nil, 0, 'south' }, - { 7, nil, 0, 'west' }, - }) - blockTypeDB:addTemp('pumpkin', { - { 0, nil, 0, 'north-block' }, - { 1, nil, 0, 'east-block' }, - { 2, nil, 0, 'south-block' }, - { 3, nil, 0, 'west-block' }, - { 4, nil, 0, 'north-block' }, - { 5, nil, 0, 'east-block' }, - { 6, nil, 0, 'south-block' }, - { 7, nil, 0, 'west-block' }, - }) - blockTypeDB:addTemp('anvil', { - { 0, nil, 0, 'south' }, - { 1, nil, 0, 'east' }, - { 2, nil, 0, 'south'}, - { 3, nil, 0, 'east' }, - { 4, nil, 0, 'south' }, - { 5, nil, 0, 'east' }, - { 6, nil, 0, 'east' }, - { 7, nil, 0, 'south' }, - { 8, nil, 0, 'south' }, - { 9, nil, 0, 'east' }, - { 10, nil, 0, 'east' }, - { 11, nil, 0, 'south' }, - { 12, nil, 0 }, - { 13, nil, 0 }, - { 14, nil, 0 }, - { 15, nil, 0 }, - }) - blockTypeDB:addTemp('bed', { - { 0, nil, 0, 'south' }, - { 1, nil, 0, 'west' }, - { 2, nil, 0, 'north' }, - { 3, nil, 0, 'east' }, - { 4, nil, 0, 'south' }, - { 5, nil, 0, 'west' }, - { 6, nil, 0, 'north' }, - { 7, nil, 0, 'east' }, - { 8, 'minecraft:air', 0 }, - { 9, 'minecraft:air', 0 }, - { 10, 'minecraft:air', 0 }, - { 11, 'minecraft:air', 0 }, - { 12, 'minecraft:air', 0 }, - { 13, 'minecraft:air', 0 }, - { 14, 'minecraft:air', 0 }, - { 15, 'minecraft:air', 0 }, - }) - blockTypeDB:addTemp('comparator', { - { 0, nil, 0, 'south' }, - { 1, nil, 0, 'west' }, - { 2, nil, 0, 'north' }, - { 3, nil, 0, 'east' }, - { 4, nil, 0, 'south' }, - { 5, nil, 0, 'west' }, - { 6, nil, 0, 'north' }, - { 7, nil, 0, 'east' }, - { 8, nil, 0, 'south' }, - { 9, nil, 0, 'west' }, - { 10, nil, 0, 'north' }, - { 11, nil, 0, 'east' }, - { 12, nil, 0, 'south' }, - { 13, nil, 0, 'west' }, - { 14, nil, 0, 'north' }, - { 15, nil, 0, 'east' }, - }) - blockTypeDB:addTemp('quartz-pillar', { - { 2, nil, 2 }, - { 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' }, - { 3, nil, 0, 'north-block' }, - { 4, nil, 0, 'south-block' }, - { 5, nil, 0 }, -- block top - }) - blockTypeDB:addTemp('cauldron', { - { 0, nil, 0 }, - { 1, nil, 0 }, - { 2, nil, 0 }, - { 3, nil, 0 }, - }) - blockTypeDB:addTemp('dispenser', { - { 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 }, - { 2, nil, 0, 'south-block' }, - { 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' }, - { 12, nil, 0, 'north-block' }, - { 13, nil, 0, 'east-block' }, - { 14, nil, 0, 'west-block' }, - }) - blockTypeDB:addTemp('mobhead', { - { 0, nil, 0 }, - { 1, nil, 0 }, - { 2, nil, 0, 'south-block' }, - { 3, nil, 0, 'north-block' }, - { 4, nil, 0, 'west-block' }, - { 5, nil, 0, 'east-block' }, - }) - blockTypeDB:addTemp('rail', { - { 0, nil, 0, 'south' }, - { 1, nil, 0, 'east' }, - { 2, nil, 0, 'east' }, - { 3, nil, 0, 'east' }, - { 4, nil, 0, 'south' }, - { 5, nil, 0, 'south' }, - { 6, nil, 0, 'east' }, - { 7, nil, 0, 'south' }, - { 8, nil, 0, 'east' }, - { 9, nil, 0, 'south' }, - }) - blockTypeDB:addTemp('adp-rail', { - { 0, nil, 0, 'south' }, - { 1, nil, 0, 'east' }, - { 2, nil, 0, 'east' }, - { 3, nil, 0, 'east' }, - { 4, nil, 0, 'south' }, - { 5, nil, 0, 'south' }, - { 8, nil, 0, 'south' }, - { 9, nil, 0, 'east' }, - { 10, nil, 0, 'east' }, - { 11, nil, 0, 'east' }, - { 12, nil, 0, 'south' }, - { 13, nil, 0, 'south' }, - }) - blockTypeDB:addTemp('signpost', { - { 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 }, - { 1, nil, 0, 'south-block-vine' }, - { 2, nil, 0, 'west-block-vine' }, - { 3, nil, 0, 'south-block-vine' }, - { 4, nil, 0, 'north-block-vine' }, - { 5, nil, 0, 'south-block-vine' }, - { 6, nil, 0, 'north-block-vine' }, - { 7, nil, 0, 'south-block-vine' }, - { 8, nil, 0, 'east-block-vine' }, - { 9, nil, 0, 'south-block-vine' }, - { 10, nil, 0, 'east-block-vine' }, - { 11, nil, 0, 'east-block-vine' }, - { 12, nil, 0, 'east-block-vine' }, - { 13, nil, 0, 'east-block-vine' }, - { 14, nil, 0, 'east-block-vine' }, - { 15, nil, 0, 'east-block-vine' }, - }) - blockTypeDB:addTemp('torch', { - { 0, nil, 0 }, - { 1, nil, 0, 'west-block' }, - { 2, nil, 0, 'east-block' }, - { 3, nil, 0, 'north-block' }, - { 4, nil, 0, 'south-block' }, - { 5, nil, 0 }, - }) - blockTypeDB:addTemp('tripwire', { - { 0, nil, 0, 'north-block' }, - { 1, nil, 0, 'east-block' }, - { 2, nil, 0, 'south-block' }, - { 3, nil, 0, 'west-block' }, - }) - blockTypeDB:addTemp('trapdoor', { - { 0, nil, 0, 'south-block' }, - { 1, nil, 0, 'north-block' }, - { 2, nil, 0, 'east-block' }, - { 3, nil, 0, 'west-block' }, - { 4, nil, 0, 'south-block' }, - { 5, nil, 0, 'north-block' }, - { 6, nil, 0, 'east-block' }, - { 7, nil, 0, 'west-block' }, - { 8, nil, 0, 'south-block' }, - { 9, nil, 0, 'north-block' }, - { 10, nil, 0, 'east-block' }, - { 11, nil, 0, 'west-block' }, - { 12, nil, 0, 'south-block' }, - { 13, nil, 0, 'north-block' }, - { 14, nil, 0, 'east-block' }, - { 15, nil, 0, 'west-block' }, - }) - blockTypeDB:addTemp('piston', { -- piston placement is broken in 1.7 -- need to add work around - { 0, nil, 0, 'piston-down' }, - { 1, nil, 0, 'piston-up' }, - { 2, nil, 0, 'piston-north' }, - { 3, nil, 0, 'piston-south' }, - { 4, nil, 0, 'piston-west' }, - { 5, nil, 0, 'piston-east' }, - { 8, nil, 0, 'piston-down' }, - { 9, nil, 0, 'piston-up' }, - { 10, nil, 0, 'piston-north' }, - { 11, nil, 0, 'piston-south' }, - { 12, nil, 0, 'piston-west' }, - { 13, nil, 0, 'piston-east' }, - }) - blockTypeDB:addTemp('lever', { - { 0, nil, 0, 'up' }, - { 1, nil, 0, 'west-block' }, - { 2, nil, 0, 'east-block' }, - { 3, nil, 0, 'north-block' }, - { 4, nil, 0, 'south-block' }, - { 5, nil, 0, 'north' }, - { 6, nil, 0, 'west' }, - { 7, nil, 0, 'up' }, - { 8, nil, 0, 'up' }, - { 9, nil, 0, 'west-block' }, - { 10, nil, 0, 'east-block' }, - { 11, nil, 0, 'north-block' }, - { 12, nil, 0, 'south-block' }, - { 13, nil, 0, 'north' }, - { 14, nil, 0, 'west' }, - { 15, nil, 0, 'up' }, - }) - 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('chest-furnace', { - { 0, nil, 0 }, - { 2, nil, 0, 'south' }, - { 3, nil, 0, 'north' }, - { 4, nil, 0, 'east' }, - { 5, nil, 0, 'west' }, - }) - blockTypeDB:addTemp('repeater', { - { 0, nil, 0, 'north' }, - { 1, nil, 0, 'east' }, - { 2, nil, 0, 'south' }, - { 3, nil, 0, 'west' }, - { 4, nil, 0, 'north' }, - { 5, nil, 0, 'east' }, - { 6, nil, 0, 'south' }, - { 7, nil, 0, 'west' }, - { 8, nil, 0, 'north' }, - { 9, nil, 0, 'east' }, - { 10, nil, 0, 'south' }, - { 11, nil, 0, 'west' }, - { 12, nil, 0, 'north' }, - { 13, nil, 0, 'east' }, - { 14, nil, 0, 'south' }, - { 15, nil, 0, 'west' }, - }) - blockTypeDB:addTemp('flatten', { - { 0, nil, 0 }, - { 1, nil, 0 }, - { 2, nil, 0 }, - { 3, nil, 0 }, - { 4, nil, 0 }, - { 5, nil, 0 }, - { 6, nil, 0 }, - { 7, nil, 0 }, - { 8, nil, 0 }, - { 9, nil, 0 }, - { 10, nil, 0 }, - { 11, nil, 0 }, - { 12, nil, 0 }, - { 13, nil, 0 }, - { 14, nil, 0 }, - { 15, nil, 0 }, - }) - blockTypeDB:addTemp('sapling', { - { '+0', nil, nil }, - { '+8', nil, nil }, - }) - blockTypeDB:addTemp('leaves', { - { '+0', nil, nil }, - { '+4', nil, nil }, - { '+8', nil, nil }, - { '+12', nil, nil }, - }) - blockTypeDB:addTemp('slab', { - { '+0', nil, nil, 'bottom' }, - { '+8', nil, nil, 'top' }, - }) - blockTypeDB:addTemp('largeplant', { - { '+0', nil, nil, 'east-door', { twoHigh = true } }, -- should use a generic double tall keyword - { '+8', 'minecraft:air', 0 }, - }) - blockTypeDB:addTemp('wood', { - { '+0', nil, nil }, - { '+4', nil, nil, 'east-west-block' }, - { '+8', nil, nil, 'north-south-block' }, - { '+12', nil, nil }, - }) - blockTypeDB:addTemp('door', { - { 0, nil, 0, 'east-door', { twoHigh = true } }, - { 1, nil, 0, 'south-door', { twoHigh = true } }, - { 2, nil, 0, 'west-door', { twoHigh = true } }, - { 3, nil, 0, 'north-door', { twoHigh = true } }, - { 4, nil, 0, 'east-door', { twoHigh = true } }, - { 5, nil, 0, 'south-door', { twoHigh = true } }, - { 6, nil, 0, 'west-door', { twoHigh = true } }, - { 7, nil, 0, 'north-door', { twoHigh = true } }, - { 8,'minecraft:air', 0 }, - { 9,'minecraft:air', 0 }, - { 10,'minecraft:air', 0 }, - { 11,'minecraft:air', 0 }, - { 12,'minecraft:air', 0 }, - { 13,'minecraft:air', 0 }, - { 14,'minecraft:air', 0 }, - { 15,'minecraft:air', 0 }, - }) - blockTypeDB:addTemp('cocoa', { - { 0, nil, 0, 'south-block' }, - { 1, nil, 0, 'west-block' }, - { 2, nil, 0, 'north-block' }, - { 3, nil, 0, 'east-block' }, - { 4, nil, 0, 'south-block' }, - { 5, nil, 0, 'west-block' }, - { 6, nil, 0, 'north-block' }, - { 7, nil, 0, 'east-block' }, - { 8, nil, 0, 'south-block' }, - { 9, nil, 0, 'west-block' }, - { 10, nil, 0, 'north-block' }, - { 11, nil, 0, 'east-block' }, - }) -end - -local Blocks = class() -function Blocks:init(args) - - Util.merge(self, args) - self.blockDB = blockDB - self.nameDB = nameDB - - blockDB:load() --- standardBlockDB:load() - blockTypeDB:load() - nameDB:load(self.dir, blockDB) --- placementDB:load(standardBlockDB, blockTypeDB) - placementDB:load2(blockDB, blockTypeDB) - --- _G._b = blockDB --- _G._s = standardBlockDB --- _G._bt = blockTypeDB --- _G._p = placementDB - --- Util.writeTable('pb1.lua', placementDB.data) - --- placementDB.data = { } - --- Util.writeTable('pb2.lua', placementDB.data) -end - --- for an ID / dmg (with placement info) - return the correct block (without the placment info embedded in the dmg) -function Blocks:getPlaceableBlock(id, dmg) - - local p = placementDB:get({id, dmg}) - if p then - return Util.shallowCopy(p) - 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 - -return Blocks diff --git a/sys/apis/chestAdapter.lua b/sys/apis/chestAdapter.lua deleted file mode 100644 index 3688bd1..0000000 --- a/sys/apis/chestAdapter.lua +++ /dev/null @@ -1,111 +0,0 @@ -local class = require('class') -local Logger = require('logger') - -local ChestProvider = class() - -function ChestProvider:init(args) - - args = args or { } - - self.stacks = {} - self.name = 'chest' - self.direction = args.direction or 'up' - self.wrapSide = args.wrapSide or 'bottom' - self.p = peripheral.wrap(self.wrapSide) -end - -function ChestProvider:isValid() - return self.p and self.p.getAllStacks -end - -function ChestProvider:refresh() - if self.p then - self.p.condenseItems() - self.stacks = self.p.getAllStacks(false) - local t = { } - for _,s in ipairs(self.stacks) do - local key = s.id .. ':' .. s.dmg - if t[key] and t[key].qty < 64 then - t[key].max_size = t[key].qty - else - t[key] = { - qty = s.qty - } - end - end - for _,s in ipairs(self.stacks) do - local key = s.id .. ':' .. s.dmg - if t[key].max_size then - s.max_size = t[key].qty - else - s.max_size = 64 - end - end - end - return self.stacks -end - -function ChestProvider:getItemInfo(id, dmg) - local item = { id = id, dmg = dmg, qty = 0, max_size = 64 } - for _,stack in pairs(self.stacks) do - if stack.id == id and stack.dmg == dmg then - item.name = stack.display_name - item.qty = item.qty + stack.qty - item.max_size = stack.max_size - end - end - if item.name then - return item - end -end - -function ChestProvider:craft(id, dmg, qty) - return false -end - -function ChestProvider:craftItems(items) -end - -function ChestProvider:provide(item, qty, slot) - if self.p then - self.stacks = self.p.getAllStacks(false) - for key,stack in pairs(self.stacks) do - if stack.id == item.id and stack.dmg == item.dmg then - local amount = math.min(qty, stack.qty) - self.p.pushItemIntoSlot(self.direction, key, amount, slot) - qty = qty - amount - if qty <= 0 then - break - end - end - end - end -end - -function ChestProvider:extract(slot, qty) - if self.p then - self.p.pushItem(self.direction, slot, qty) - end -end - -function ChestProvider:insert(slot, qty) - if self.p then - local s, m = pcall(function() self.p.pullItem(self.direction, slot, qty) end) - if not s and m then - print('chestProvider:pullItem') - print(m) - Logger.log('chestProvider', 'Insert failed, trying again') - sleep(1) - s, m = pcall(function() self.p.pullItem(self.direction, slot, qty) end) - if not s and m then - print('chestProvider:pullItem') - print(m) - Logger.log('chestProvider', 'Insert failed again') - else - Logger.log('chestProvider', 'Insert successful') - end - end - end -end - -return ChestProvider diff --git a/sys/apis/chestAdapter18.lua b/sys/apis/chestAdapter18.lua deleted file mode 100644 index 4cc2d6b..0000000 --- a/sys/apis/chestAdapter18.lua +++ /dev/null @@ -1,140 +0,0 @@ -local class = require('class') -local Util = require('util') -local itemDB = require('itemDB') -local Peripheral = require('peripheral') - -local ChestAdapter = class() - -local keys = Util.transpose({ - 'damage', - 'displayName', - 'maxCount', - 'maxDamage', - 'name', - 'nbtHash', -}) - -function ChestAdapter:init(args) - local defaults = { - items = { }, - name = 'chest', - direction = 'up', - wrapSide = 'bottom', - } - Util.merge(self, defaults) - Util.merge(self, args) - - local chest = Peripheral.getBySide(self.wrapSide) - if not chest then - chest = Peripheral.getByMethod('list') - end - if chest then - Util.merge(self, chest) - end -end - -function ChestAdapter:isValid() - return not not self.list -end - -function ChestAdapter:getCachedItemDetails(item, k) - local key = { item.name, item.damage, item.nbtHash } - - local detail = itemDB:get(key) - if not detail then - pcall(function() detail = self.getItemMeta(k) end) - if not detail then - return - end --- NOT SUFFICIENT - if detail.name ~= item.name then - return - end - - for _,k in ipairs(Util.keys(detail)) do - if not keys[k] then - detail[k] = nil - end - end - - itemDB:add(key, detail) - end - if detail then - return Util.shallowCopy(detail) - end -end - -function ChestAdapter:refresh(throttle) - return self:listItems(throttle) -end - --- provide a consolidated list of items -function ChestAdapter: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.count = 0 - self.cache[key] = entry - table.insert(items, entry) - end - end - - if entry then - entry.count = entry.count + v.count - end - throttle() - end - - itemDB:flush() - - return items -end - -function ChestAdapter:getItemInfo(name, damage, nbtHash) - if not self.cache then - self:listItems() - end - local key = table.concat({ name, damage, nbtHash }, ':') - return self.cache[key] -end - -function ChestAdapter:craft(name, damage, qty) -end - -function ChestAdapter:craftItems(items) -end - -function ChestAdapter:provide(item, qty, slot, direction) - local stacks = self.list() - for key,stack in pairs(stacks) do - if stack.name == item.name and stack.damage == item.damage then - local amount = math.min(qty, stack.count) - if amount > 0 then - self.pushItems(direction or self.direction, key, amount, slot) - end - qty = qty - amount - if qty <= 0 then - break - end - end - end -end - -function ChestAdapter:extract(slot, qty, toSlot) - self.pushItems(self.direction, slot, qty, toSlot) -end - -function ChestAdapter:insert(slot, qty) - self.pullItems(self.direction, slot, qty) -end - -return ChestAdapter diff --git a/sys/apis/deflatelua.lua b/sys/apis/deflatelua.lua deleted file mode 100644 index 55bb7e9..0000000 --- a/sys/apis/deflatelua.lua +++ /dev/null @@ -1,870 +0,0 @@ ---[[ - -LUA MODULE - - compress.deflatelua - deflate (and gunzip/zlib) implemented in Lua. - -SYNOPSIS - - local DEFLATE = require 'compress.deflatelua' - -- uncompress gzip file - local fh = assert(io.open'foo.txt.gz', 'rb') - local ofh = assert(io.open'foo.txt', 'wb') - DEFLATE.gunzip {input=fh, output=ofh} - fh:close(); ofh:close() - -- can also uncompress from string including zlib and raw DEFLATE formats. - -DESCRIPTION - - This is a pure Lua implementation of decompressing the DEFLATE format, - including the related zlib and gzip formats. - - Note: This library only supports decompression. - Compression is not currently implemented. - -API - - Note: in the following functions, input stream `fh` may be - a file handle, string, or an iterator function that returns strings. - Output stream `ofh` may be a file handle or a function that - consumes one byte (number 0..255) per call. - - DEFLATE.inflate {input=fh, output=ofh} - - Decompresses input stream `fh` in the DEFLATE format - while writing to output stream `ofh`. - DEFLATE is detailed in http://tools.ietf.org/html/rfc1951 . - - DEFLATE.gunzip {input=fh, output=ofh, disable_crc=disable_crc} - - Decompresses input stream `fh` with the gzip format - while writing to output stream `ofh`. - `disable_crc` (defaults to `false`) will disable CRC-32 checking - to increase speed. - gzip is detailed in http://tools.ietf.org/html/rfc1952 . - - DEFLATE.inflate_zlib {input=fh, output=ofh, disable_crc=disable_crc} - - Decompresses input stream `fh` with the zlib format - while writing to output stream `ofh`. - `disable_crc` (defaults to `false`) will disable CRC-32 checking - to increase speed. - zlib is detailed in http://tools.ietf.org/html/rfc1950 . - - DEFLATE.adler32(byte, crc) --> rcrc - - Returns adler32 checksum of byte `byte` (number 0..255) appended - to string with adler32 checksum `crc`. This is internally used by - `inflate_zlib`. - ADLER32 in detailed in http://tools.ietf.org/html/rfc1950 . - -COMMAND LINE UTILITY - - A `gunziplua` command line utility (in folder `bin`) is also provided. - This mimicks the *nix `gunzip` utility but is a pure Lua implementation - that invokes this library. For help do - - gunziplua -h - -DEPENDENCIES - - Requires 'digest.crc32lua' (used for optional CRC-32 checksum checks). - https://github.com/davidm/lua-digest-crc32lua - - Will use a bit library ('bit', 'bit32', 'bit.numberlua') if available. This - is not that critical for this library but is required by digest.crc32lua. - - 'pythonic.optparse' is only required by the optional `gunziplua` - command-line utilty for command line parsing. - https://github.com/davidm/lua-pythonic-optparse - -INSTALLATION - - Copy the `compress` directory into your LUA_PATH. - -REFERENCES - - [1] DEFLATE Compressed Data Format Specification version 1.3 - http://tools.ietf.org/html/rfc1951 - [2] GZIP file format specification version 4.3 - http://tools.ietf.org/html/rfc1952 - [3] http://en.wikipedia.org/wiki/DEFLATE - [4] pyflate, by Paul Sladen - http://www.paul.sladen.org/projects/pyflate/ - [5] Compress::Zlib::Perl - partial pure Perl implementation of - Compress::Zlib - http://search.cpan.org/~nwclark/Compress-Zlib-Perl/Perl.pm - -LICENSE - - (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - (end license) ---]] - -local M = {_TYPE='module', _NAME='compress.deflatelua', _VERSION='0.3.20111128'} - -local assert = assert -local error = error -local ipairs = ipairs -local pairs = pairs -local print = print -local require = require -local tostring = tostring -local type = type -local setmetatable = setmetatable -local io = io -local math = math -local table_sort = table.sort -local math_max = math.max -local string_char = string.char - ---[[ - Requires the first module listed that exists, else raises like `require`. - If a non-string is encountered, it is returned. - Second return value is module name loaded (or ''). - --]] -local function requireany(...) - local errs = {} - for i = 1, select('#', ...) do local name = select(i, ...) - if type(name) ~= 'string' then return name, '' end - local ok, mod = pcall(require, name) - if ok then return mod, name end - errs[#errs+1] = mod - end - error(table.concat(errs, '\n'), 2) -end - - ---local crc32 = require "digest.crc32lua" . crc32_byte ---local bit, name_ = requireany('bit', 'bit32', 'bit.numberlua', nil) -local bit -local crc32 - -local DEBUG = false - --- Whether to use `bit` library functions in current module. --- Unlike the crc32 library, it doesn't make much difference in this module. -local NATIVE_BITOPS = (bit ~= nil) - -local band, lshift, rshift -if NATIVE_BITOPS then - band = bit.band - lshift = bit.lshift - rshift = bit.rshift -end - - -local function warn(s) - io.stderr:write(s, '\n') -end - - -local function debug(...) - print('DEBUG', ...) -end - - -local function runtime_error(s, level) - level = level or 1 - error({s}, level+1) -end - - -local function make_outstate(outbs) - local outstate = {} - outstate.outbs = outbs - outstate.window = {} - outstate.window_pos = 1 - return outstate -end - - -local function output(outstate, byte) - -- debug('OUTPUT:', s) - local window_pos = outstate.window_pos - outstate.outbs(byte) - outstate.window[window_pos] = byte - outstate.window_pos = window_pos % 32768 + 1 -- 32K -end - - -local function noeof(val) - return assert(val, 'unexpected end of file') -end - - -local function hasbit(bits, bit) - return bits % (bit + bit) >= bit -end - - -local function memoize(f) - local mt = {} - local t = setmetatable({}, mt) - function mt:__index(k) - local v = f(k) - t[k] = v - return v - end - return t -end - - --- small optimization (lookup table for powers of 2) -local pow2 = memoize(function(n) return 2^n end) - ---local tbits = memoize( --- function(bits) --- return memoize( function(bit) return getbit(bits, bit) end ) --- end ) - - --- weak metatable marking objects as bitstream type -local is_bitstream = setmetatable({}, {__mode='k'}) - - --- DEBUG --- prints LSB first ---[[ -local function bits_tostring(bits, nbits) - local s = '' - local tmp = bits - local function f() - local b = tmp % 2 == 1 and 1 or 0 - s = s .. b - tmp = (tmp - b) / 2 - end - if nbits then - for i=1,nbits do f() end - else - while tmp ~= 0 do f() end - end - - return s -end ---]] - -local function bytestream_from_file(fh) - local o = {} - function o:read() - local sb = fh:read(1) - if sb then return sb:byte() end - end - return o -end - - -local function bytestream_from_string(s) - local i = 1 - local o = {} - function o:read() - local by - if i <= #s then - by = s:byte(i) - i = i + 1 - end - return by - end - return o -end - - -local function bytestream_from_function(f) - local i = 0 - local buffer = '' - local o = {} - function o:read() - return f() --- i = i + 1 --- if i > #buffer then --- buffer = f() - -- if not buffer then return end - -- i = 1 --- end --- return buffer:byte(i,i) - end - return o -end - - -local function bitstream_from_bytestream(bys) - local buf_byte = 0 - local buf_nbit = 0 - local o = {} - - function o:nbits_left_in_byte() - return buf_nbit - end - - if NATIVE_BITOPS then - function o:read(nbits) - nbits = nbits or 1 - while buf_nbit < nbits do - local byte = bys:read() - if not byte then return end -- note: more calls also return nil - buf_byte = buf_byte + lshift(byte, buf_nbit) - buf_nbit = buf_nbit + 8 - end - local bits - if nbits == 0 then - bits = 0 - elseif nbits == 32 then - bits = buf_byte - buf_byte = 0 - else - bits = band(buf_byte, rshift(0xffffffff, 32 - nbits)) - buf_byte = rshift(buf_byte, nbits) - end - buf_nbit = buf_nbit - nbits - return bits - end - else - function o:read(nbits) - nbits = nbits or 1 - while buf_nbit < nbits do - local byte = bys:read() - if not byte then return end -- note: more calls also return nil - buf_byte = buf_byte + pow2[buf_nbit] * byte - buf_nbit = buf_nbit + 8 - end - local m = pow2[nbits] - local bits = buf_byte % m - buf_byte = (buf_byte - bits) / m - buf_nbit = buf_nbit - nbits - return bits - end - end - - is_bitstream[o] = true - - return o -end - - -local function get_bitstream(o) - local bs - if is_bitstream[o] then - return o - elseif io.type(o) == 'file' then - bs = bitstream_from_bytestream(bytestream_from_file(o)) - elseif type(o) == 'string' then - bs = bitstream_from_bytestream(bytestream_from_string(o)) - elseif type(o) == 'function' then - bs = bitstream_from_bytestream(bytestream_from_function(o)) - else - runtime_error 'unrecognized type' - end - return bs -end - - -local function get_obytestream(o) - local bs - if io.type(o) == 'file' then - bs = function(sbyte) o:write(string_char(sbyte)) end - elseif type(o) == 'function' then - bs = o - else - runtime_error('unrecognized type: ' .. tostring(o)) - end - return bs -end - - -local function HuffmanTable(init, is_full) - local t = {} - if is_full then - for val,nbits in pairs(init) do - if nbits ~= 0 then - t[#t+1] = {val=val, nbits=nbits} - --debug('*',val,nbits) - end - end - else - for i=1,#init-2,2 do - local firstval, nbits, nextval = init[i], init[i+1], init[i+2] - --debug(val, nextval, nbits) - if nbits ~= 0 then - for val=firstval,nextval-1 do - t[#t+1] = {val=val, nbits=nbits} - end - end - end - end - table_sort(t, function(a,b) - return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits - end) - - -- assign codes - local code = 1 -- leading 1 marker - local nbits = 0 - for i,s in ipairs(t) do - if s.nbits ~= nbits then - code = code * pow2[s.nbits - nbits] - nbits = s.nbits - end - s.code = code - --debug('huffman code:', i, s.nbits, s.val, code, bits_tostring(code)) - code = code + 1 - end - - local minbits = math.huge - local look = {} - for i,s in ipairs(t) do - minbits = math.min(minbits, s.nbits) - look[s.code] = s.val - end - - --for _,o in ipairs(t) do - -- debug(':', o.nbits, o.val) - --end - - -- function t:lookup(bits) return look[bits] end - - local msb = NATIVE_BITOPS and function(bits, nbits) - local res = 0 - for i=1,nbits do - res = lshift(res, 1) + band(bits, 1) - bits = rshift(bits, 1) - end - return res - end or function(bits, nbits) - local res = 0 - for i=1,nbits do - local b = bits % 2 - bits = (bits - b) / 2 - res = res * 2 + b - end - return res - end - - local tfirstcode = memoize( - function(bits) return pow2[minbits] + msb(bits, minbits) end) - - function t:read(bs) - local code = 1 -- leading 1 marker - local nbits = 0 - while 1 do - if nbits == 0 then -- small optimization (optional) - code = tfirstcode[noeof(bs:read(minbits))] - nbits = nbits + minbits - else - local b = noeof(bs:read()) - nbits = nbits + 1 - code = code * 2 + b -- MSB first - --[[NATIVE_BITOPS - code = lshift(code, 1) + b -- MSB first - --]] - end - --debug('code?', code, bits_tostring(code)) - local val = look[code] - if val then - --debug('FOUND', val) - return val - end - end - end - - return t -end - - -local function parse_gzip_header(bs) - -- local FLG_FTEXT = 2^0 - local FLG_FHCRC = 2^1 - local FLG_FEXTRA = 2^2 - local FLG_FNAME = 2^3 - local FLG_FCOMMENT = 2^4 - - local id1 = bs:read(8) - local id2 = bs:read(8) - if id1 ~= 31 or id2 ~= 139 then - runtime_error 'not in gzip format' - end - local cm = bs:read(8) -- compression method - local flg = bs:read(8) -- FLaGs - local mtime = bs:read(32) -- Modification TIME - local xfl = bs:read(8) -- eXtra FLags - local os = bs:read(8) -- Operating System - - if DEBUG then - debug("CM=", cm) - debug("FLG=", flg) - debug("MTIME=", mtime) - -- debug("MTIME_str=",os.date("%Y-%m-%d %H:%M:%S",mtime)) -- non-portable - debug("XFL=", xfl) - debug("OS=", os) - end - - if not os then runtime_error 'invalid header' end - - if hasbit(flg, FLG_FEXTRA) then - local xlen = bs:read(16) - local extra = 0 - for i=1,xlen do - extra = bs:read(8) - end - if not extra then runtime_error 'invalid header' end - end - - local function parse_zstring(bs) - repeat - local by = bs:read(8) - if not by then runtime_error 'invalid header' end - until by == 0 - end - - if hasbit(flg, FLG_FNAME) then - parse_zstring(bs) - end - - if hasbit(flg, FLG_FCOMMENT) then - parse_zstring(bs) - end - - if hasbit(flg, FLG_FHCRC) then - local crc16 = bs:read(16) - if not crc16 then runtime_error 'invalid header' end - -- IMPROVE: check CRC. where is an example .gz file that - -- has this set? - if DEBUG then - debug("CRC16=", crc16) - end - end -end - -local function parse_zlib_header(bs) - local cm = bs:read(4) -- Compression Method - local cinfo = bs:read(4) -- Compression info - local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG) - local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary) - local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level) - local cmf = cinfo * 16 + cm -- CMF (Compresion Method and flags) - local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs - - if cm ~= 8 then -- not "deflate" - runtime_error("unrecognized zlib compression method: " + cm) - end - if cinfo > 7 then - runtime_error("invalid zlib window size: cinfo=" + cinfo) - end - local window_size = 2^(cinfo + 8) - - if (cmf*256 + flg) % 31 ~= 0 then - runtime_error("invalid zlib header (bad fcheck sum)") - end - - if fdict == 1 then - runtime_error("FIX:TODO - FDICT not currently implemented") - local dictid_ = bs:read(32) - end - - return window_size -end - -local function parse_huffmantables(bs) - local hlit = bs:read(5) -- # of literal/length codes - 257 - local hdist = bs:read(5) -- # of distance codes - 1 - local hclen = noeof(bs:read(4)) -- # of code length codes - 4 - - local ncodelen_codes = hclen + 4 - local codelen_init = {} - local codelen_vals = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} - for i=1,ncodelen_codes do - local nbits = bs:read(3) - local val = codelen_vals[i] - codelen_init[val] = nbits - end - local codelentable = HuffmanTable(codelen_init, true) - - local function decode(ncodes) - local init = {} - local nbits - local val = 0 - while val < ncodes do - local codelen = codelentable:read(bs) - --FIX:check nil? - local nrepeat - if codelen <= 15 then - nrepeat = 1 - nbits = codelen - --debug('w', nbits) - elseif codelen == 16 then - nrepeat = 3 + noeof(bs:read(2)) - -- nbits unchanged - elseif codelen == 17 then - nrepeat = 3 + noeof(bs:read(3)) - nbits = 0 - elseif codelen == 18 then - nrepeat = 11 + noeof(bs:read(7)) - nbits = 0 - else - error 'ASSERT' - end - for i=1,nrepeat do - init[val] = nbits - val = val + 1 - end - end - local huffmantable = HuffmanTable(init, true) - return huffmantable - end - - local nlit_codes = hlit + 257 - local ndist_codes = hdist + 1 - - local littable = decode(nlit_codes) - local disttable = decode(ndist_codes) - - return littable, disttable -end - - -local tdecode_len_base -local tdecode_len_nextrabits -local tdecode_dist_base -local tdecode_dist_nextrabits -local function parse_compressed_item(bs, outstate, littable, disttable) - local val = littable:read(bs) - --debug(val, val < 256 and string_char(val)) - if val < 256 then -- literal - output(outstate, val) - elseif val == 256 then -- end of block - return true - else - if not tdecode_len_base then - local t = {[257]=3} - local skip = 1 - for i=258,285,4 do - for j=i,i+3 do t[j] = t[j-1] + skip end - if i ~= 258 then skip = skip * 2 end - end - t[285] = 258 - tdecode_len_base = t - --for i=257,285 do debug('T1',i,t[i]) end - end - if not tdecode_len_nextrabits then - local t = {} - if NATIVE_BITOPS then - for i=257,285 do - local j = math_max(i - 261, 0) - t[i] = rshift(j, 2) - end - else - for i=257,285 do - local j = math_max(i - 261, 0) - t[i] = (j - (j % 4)) / 4 - end - end - t[285] = 0 - tdecode_len_nextrabits = t - --for i=257,285 do debug('T2',i,t[i]) end - end - local len_base = tdecode_len_base[val] - local nextrabits = tdecode_len_nextrabits[val] - local extrabits = bs:read(nextrabits) - local len = len_base + extrabits - - if not tdecode_dist_base then - local t = {[0]=1} - local skip = 1 - for i=1,29,2 do - for j=i,i+1 do t[j] = t[j-1] + skip end - if i ~= 1 then skip = skip * 2 end - end - tdecode_dist_base = t - --for i=0,29 do debug('T3',i,t[i]) end - end - if not tdecode_dist_nextrabits then - local t = {} - if NATIVE_BITOPS then - for i=0,29 do - local j = math_max(i - 2, 0) - t[i] = rshift(j, 1) - end - else - for i=0,29 do - local j = math_max(i - 2, 0) - t[i] = (j - (j % 2)) / 2 - end - end - tdecode_dist_nextrabits = t - --for i=0,29 do debug('T4',i,t[i]) end - end - local dist_val = disttable:read(bs) - local dist_base = tdecode_dist_base[dist_val] - local dist_nextrabits = tdecode_dist_nextrabits[dist_val] - local dist_extrabits = bs:read(dist_nextrabits) - local dist = dist_base + dist_extrabits - - --debug('BACK', len, dist) - for i=1,len do - local pos = (outstate.window_pos - 1 - dist) % 32768 + 1 -- 32K - output(outstate, assert(outstate.window[pos], 'invalid distance')) - end - end - return false -end - - -local function parse_block(bs, outstate) - local bfinal = bs:read(1) - local btype = bs:read(2) - - local BTYPE_NO_COMPRESSION = 0 - local BTYPE_FIXED_HUFFMAN = 1 - local BTYPE_DYNAMIC_HUFFMAN = 2 - local BTYPE_RESERVED_ = 3 - - if DEBUG then - debug('bfinal=', bfinal) - debug('btype=', btype) - end - - if btype == BTYPE_NO_COMPRESSION then - bs:read(bs:nbits_left_in_byte()) - local len = bs:read(16) - local nlen_ = noeof(bs:read(16)) - - for i=1,len do - local by = noeof(bs:read(8)) - output(outstate, by) - end - elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then - local littable, disttable - if btype == BTYPE_DYNAMIC_HUFFMAN then - littable, disttable = parse_huffmantables(bs) - else - littable = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil} - disttable = HuffmanTable {0,5, 32,nil} - end - - repeat - local is_done = parse_compressed_item( - bs, outstate, littable, disttable) - until is_done - else - runtime_error 'unrecognized compression type' - end - - return bfinal ~= 0 -end - - -function M.inflate(t) - local bs = get_bitstream(t.input) - local outbs = get_obytestream(t.output) - local outstate = make_outstate(outbs) - - repeat - local is_final = parse_block(bs, outstate) - until is_final -end -local inflate = M.inflate - - -function M.gunzip(t) - local bs = get_bitstream(t.input) - local outbs = get_obytestream(t.output) - local disable_crc = t.disable_crc - if disable_crc == nil then disable_crc = false end - - parse_gzip_header(bs) - - local data_crc32 = 0 - - inflate{input=bs, output= - disable_crc and outbs or - function(byte) - data_crc32 = crc32(byte, data_crc32) - outbs(byte) - end - } - - bs:read(bs:nbits_left_in_byte()) - - local expected_crc32 = bs:read(32) - local isize = bs:read(32) -- ignored - if DEBUG then - debug('crc32=', expected_crc32) - debug('isize=', isize) - end - if not disable_crc and data_crc32 then - if data_crc32 ~= expected_crc32 then - runtime_error('invalid compressed data--crc error') - end - end - if bs:read() then - warn 'trailing garbage ignored' - end -end - - -function M.adler32(byte, crc) - local s1 = crc % 65536 - local s2 = (crc - s1) / 65536 - s1 = (s1 + byte) % 65521 - s2 = (s2 + s1) % 65521 - return s2*65536 + s1 -end -- 65521 is the largest prime smaller than 2^16 - - -function M.inflate_zlib(t) - local bs = get_bitstream(t.input) - local outbs = get_obytestream(t.output) - local disable_crc = t.disable_crc - if disable_crc == nil then disable_crc = false end - - local window_size_ = parse_zlib_header(bs) - - local data_adler32 = 1 - - inflate{input=bs, output= - disable_crc and outbs or - function(byte) - data_adler32 = M.adler32(byte, data_adler32) - outbs(byte) - end - } - - bs:read(bs:nbits_left_in_byte()) - - local b3 = bs:read(8) - local b2 = bs:read(8) - local b1 = bs:read(8) - local b0 = bs:read(8) - local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0 - if DEBUG then - debug('alder32=', expected_adler32) - end - if not disable_crc then - if data_adler32 ~= expected_adler32 then - runtime_error('invalid compressed data--crc error') - end - end - if bs:read() then - warn 'trailing garbage ignored' - end -end - - -return M \ No newline at end of file diff --git a/sys/apis/fs/gitfs.lua b/sys/apis/fs/gitfs.lua index 3b62613..2bd4aac 100644 --- a/sys/apis/fs/gitfs.lua +++ b/sys/apis/fs/gitfs.lua @@ -9,8 +9,10 @@ function gitfs.mount(dir, user, repo, branch) local list = git.list(user, repo, branch) for path, entry in pairs(list) do - local node = fs.mount(fs.combine(dir, path), 'urlfs', entry.url) - node.size = entry.size + if not fs.exists(fs.combine(dir, path)) then + local node = fs.mount(fs.combine(dir, path), 'urlfs', entry.url) + node.size = entry.size + end end end diff --git a/sys/apis/fs/urlfs.lua b/sys/apis/fs/urlfs.lua index fe87e5c..aecfd39 100644 --- a/sys/apis/fs/urlfs.lua +++ b/sys/apis/fs/urlfs.lua @@ -38,6 +38,11 @@ end function urlfs.open(node, fn, fl) + if fl == 'w' or fl == 'wb' then + fs.delete(fn) + return fs.open(fn, fl) + end + if fl ~= 'r' and fl ~= 'rb' then error('Unsupported mode') end diff --git a/sys/apis/input.lua b/sys/apis/input.lua deleted file mode 100644 index c821859..0000000 --- a/sys/apis/input.lua +++ /dev/null @@ -1,112 +0,0 @@ -local input = { } - -function input:translate(event, code) - - if event == 'key' then - local ch = keys.getName(code) - if ch then - - if code == keys.leftCtrl or code == keys.rightCtrl then - self.control = true - self.combo = false - return - end - - if code == keys.leftShift or code == keys.rightShift then - self.shift = true - self.combo = false - return - end - - if self.shift then - if #ch > 1 then - ch = 'shift-' .. ch - elseif self.control then - -- will create control-X - -- better than shift-control-x - ch = ch:upper() - end - self.combo = true - end - - if self.control then - ch = 'control-' .. ch - self.combo = true - -- even return numbers such as - -- control-seven - return ch - end - - -- filter out characters that will be processed in - -- the subsequent char event - if ch and #ch > 1 and (code < 2 or code > 11) then - return ch - end - end - - elseif event == 'key_up' then - - if code == keys.leftCtrl or code == keys.rightCtrl then - self.control = false - elseif code == keys.leftShift or code == keys.rightShift then - self.shift = false - else - return - end - - -- only send through the shift / control event if it wasn't - -- used in combination with another event - if not self.combo then - return keys.getName(code) - end - - elseif event == 'char' then - if not self.control then - self.combo = true - return event - end - - elseif event == 'mouse_click' then - - local buttons = { 'mouse_click', 'mouse_rightclick', 'mouse_doubleclick' } - - self.combo = true - if self.shift then - return 'shift-' .. buttons[code] - end - return buttons[code] - - elseif event == "mouse_scroll" then - local directions = { - [ -1 ] = 'scrollUp', - [ 1 ] = 'scrollDown' - } - return directions[code] - - elseif event == 'paste' then - self.combo = true - return event - - elseif event == 'mouse_drag' then - return event - end -end - --- can be useful for testing what keys are generated -function input:test() - print('press a key...') - while true do - local e, code = os.pullEvent() - - if e == 'char' and code == 'q' then - break - end - - local ch = input:translate(e, code) - if ch then - print(e .. ' ' .. code .. ' ' .. ch) - end - end -end - -return input diff --git a/sys/apis/itemDB.lua b/sys/apis/itemDB.lua deleted file mode 100644 index 5545cf0..0000000 --- a/sys/apis/itemDB.lua +++ /dev/null @@ -1,39 +0,0 @@ -local Util = require('util') -local TableDB = require('tableDB') - -local itemDB = TableDB({ fileName = 'usr/etc/items.db' }) - -function itemDB:get(key) - - local item = TableDB.get(self, key) - - if item then - return item - end - - if key[2] ~= 0 then - item = TableDB.get(self, { key[1], 0, key[3] }) - if item and item.maxDamage > 0 then - item = Util.shallowCopy(item) - item.damage = key[2] - item.displayName = string.format('%s (damage: %d)', item.displayName, item.damage) - return item - end - end -end - -function itemDB:add(key, item) - - if item.maxDamage > 0 then - key = { key[1], 0, key[3] } - end - TableDB.add(self, key, item) -end - -function itemDB:makeKey(item) - return { item.name, item.damage, item.nbtHash } -end - -itemDB:load() - -return itemDB diff --git a/sys/apis/me.lua b/sys/apis/me.lua deleted file mode 100644 index 88d573f..0000000 --- a/sys/apis/me.lua +++ /dev/null @@ -1,167 +0,0 @@ -local Util = require('util') - -local ME = { - jobList = { } -} - -function ME.setDevice(device) - ME.p = device - --Util.merge(ME, ME.p) - - if not device then - error('ME device not attached') - end - - for k,v in pairs(ME.p) do - if not ME[k] then - ME[k] = v - end - end -end - -function ME.isAvailable() - return not Util.empty(ME.getAvailableItems()) -end - --- Strip off color prefix -local function safeString(text) - - local val = text:byte(1) - - if val < 32 or val > 128 then - - local newText = {} - for i = 4, #text do - local val = text:byte(i) - newText[i - 3] = (val > 31 and val < 127) and val or 63 - end - return string.char(unpack(newText)) - end - - return text -end - -function ME.getAvailableItems() - local items - pcall(function() - items = ME.p.getAvailableItems('all') - for k,v in pairs(items) do - v.id = v.item.id - v.name = safeString(v.item.display_name) - v.qty = v.item.qty - v.dmg = v.item.dmg - v.max_dmg = v.item.max_dmg - v.nbt_hash = v.item.nbt_hash - end - end) - - return items or { } -end - -function ME.getItemCount(id, dmg, nbt_hash, ignore_dmg) - - local fingerprint = { - id = id, - nbt_hash = nbt_hash, - } - - if not ignore_dmg or ignore_dmg ~= 'yes' then - fingerprint.dmg = dmg or 0 - end - - local item = ME.getItemDetail(fingerprint, false) - - if item then - return item.qty - end - - return 0 -end - -function ME.extract(id, dmg, nbt_hash, qty, direction, slot) - dmg = dmg or 0 - qty = qty or 1 - direction = direction or 'up' - return pcall(function() - local fingerprint = { - dmg = dmg, - id = id, - nbt_hash = nbt_hash - } - return ME.exportItem(fingerprint, direction, qty, slot) - end) -end - -function ME.insert(slot, qty, direction) - direction = direction or 'up' - return ME.pullItem(direction, slot, qty) -end - -function ME.isCrafting() - local cpus = ME.p.getCraftingCPUs() or { } - for k,v in pairs(cpus) do - if v.busy then - return true - end - end -end - -function ME.isCPUAvailable() - local cpus = ME.p.getCraftingCPUs() or { } - local available = false - - for cpu,v in pairs(cpus) do - if not v.busy then - available = true - elseif not ME.jobList[cpu] then -- something else is crafting something (don't know what) - return false -- return false since we are in an unknown state - end - end - return available -end - -function ME.getJobList() - - local cpus = ME.p.getCraftingCPUs() or { } - for cpu,v in pairs(cpus) do - if not v.busy then - ME.jobList[cpu] = nil - end - end - - return ME.jobList -end - -function ME.craft(id, dmg, nbt_hash, qty) - local cpus = ME.p.getCraftingCPUs() or { } - for cpu,v in pairs(cpus) do - if not v.busy then - ME.p.requestCrafting({ - id = id, - dmg = dmg or 0, - nbt_hash = nbt_hash, - }, - qty or 1, - cpu - ) - - os.sleep(0) -- tell it to craft, yet it doesn't show busy - try waiting a cycle... - cpus = ME.p.getCraftingCPUs() or { } - if not cpus[cpu].busy then - -- print('sleeping again') - os.sleep(.1) -- sigh - cpus = ME.p.getCraftingCPUs() or { } - end - - -- not working :( - if cpus[cpu].busy then - ME.jobList[cpu] = { id = id, dmg = dmg, qty = qty, nbt_hash = nbt_hash } - return true - end - break -- only need to try the first available cpu - end - end - return false -end - -return ME \ No newline at end of file diff --git a/sys/apis/meAdapter.lua b/sys/apis/meAdapter.lua deleted file mode 100644 index e146196..0000000 --- a/sys/apis/meAdapter.lua +++ /dev/null @@ -1,157 +0,0 @@ -local class = require('class') -local Util = require('util') -local Peripheral = require('peripheral') - -local MEProvider = class() - -function MEProvider:init(args) - local defaults = { - items = { }, - name = 'ME', - } - Util.merge(self, defaults) - Util.merge(self, args) - - if self.side then - local mep = peripheral.wrap('bottom') - if mep then - Util.merge(self, mep) - end - else - local mep = Peripheral.getByMethod('getAvailableItems') - if mep then - Util.merge(self, mep) - end - end - - local sides = { - top = 'down', - bottom = 'up', - east = 'west', - west = 'east', - north = 'south', - south = 'north', - } - self.oside = sides[self.direction or self.side] -end - -function MEProvider:isValid() - return self.getAvailableItems and self.getAvailableItems() -end - --- Strip off color prefix -local function safeString(text) - - local val = text:byte(1) - - if val < 32 or val > 128 then - - local newText = {} - for i = 4, #text do - local val = text:byte(i) - newText[i - 3] = (val > 31 and val < 127) and val or 63 - end - return string.char(unpack(newText)) - end - - return text -end - -local convertNames = { - name = 'id', - damage = 'dmg', - maxCount = 'max_size', - count = 'qty', - displayName = 'display_name', - maxDamage = 'max_dmg', -} - -local function convertItem(item) - for k,v in pairs(convertNames) do - item[k] = item[v] - item[v] = nil - end - item.displayName = safeString(item.displayName) -end - -function MEProvider:refresh() - self.items = self.getAvailableItems('all') - for _,v in pairs(self.items) do - Util.merge(v, v.item) - convertItem(v) - end - return self.items -end - -function MEProvider:listItems() - self:refresh() - return self.items -end - -function MEProvider:getItemInfo(name, damage) - - for key,item in pairs(self.items) do - if item.name == name and item.damage == damage then - return item - end - end -end - -function MEProvider:craft(name, damage, count) - - self:refresh() - - local item = self:getItemInfo(name, damage) - - if item and item.is_craftable then - - self.requestCrafting({ id = name, dmg = damage }, count) - return true - end -end - -function MEProvider:craftItems(items) - local cpus = self.getCraftingCPUs() or { } - local count = 0 - - for _,cpu in pairs(cpus) do - if cpu.busy then - return - end - end - - for _,item in pairs(items) do - if count >= #cpus then - break - end - if self:craft(item.name, item.damage, item.count) then - count = count + 1 - end - end -end - -function MEProvider:provide(item, count, slot) - return pcall(function() - self.exportItem({ - id = item.name, - dmg = item.damage - }, self.oside, count, slot) - end) -end - -function MEProvider:insert(slot, count) - local s, m = pcall(function() self.pullItem(self.oside, slot, count) end) - if not s and m then - print('MEProvider:pullItem') - print(m) - sleep(1) - s, m = pcall(function() self.pullItem(self.oside, slot, count) end) - if not s and m then - print('MEProvider:pullItem') - print(m) - read() - end - end -end - -return MEProvider diff --git a/sys/apis/message.lua b/sys/apis/message.lua deleted file mode 100644 index fd38ed1..0000000 --- a/sys/apis/message.lua +++ /dev/null @@ -1,106 +0,0 @@ -local Event = require('event') -local Logger = require('logger') - -local Message = { } - -local messageHandlers = {} - -function Message.enable() - if not device.wireless_modem.isOpen(os.getComputerID()) then - device.wireless_modem.open(os.getComputerID()) - end - if not device.wireless_modem.isOpen(60000) then - device.wireless_modem.open(60000) - end -end - -if device and device.wireless_modem then - Message.enable() -end - -Event.on('device_attach', function(event, deviceName) - if deviceName == 'wireless_modem' then - Message.enable() - end -end) - -function Message.addHandler(type, f) - table.insert(messageHandlers, { - type = type, - f = f, - enabled = true - }) -end - -function Message.removeHandler(h) - for k,v in pairs(messageHandlers) do - if v == h then - messageHandlers[k] = nil - break - end - end -end - -Event.on('modem_message', - function(event, side, sendChannel, replyChannel, msg, distance) - if msg and msg.type then -- filter out messages from other systems - local id = replyChannel - Logger.log('modem_receive', { id, msg.type }) - --Logger.log('modem_receive', msg.contents) - for k,h in pairs(messageHandlers) do - if h.type == msg.type then --- should provide msg.contents instead of message - type is already known - h.f(h, id, msg, distance) - end - end - end - end -) - -function Message.send(id, msgType, contents) - if not device.wireless_modem then - error('No modem attached', 2) - end - - if id then - Logger.log('modem_send', { tostring(id), msgType }) - device.wireless_modem.transmit(id, os.getComputerID(), { - type = msgType, contents = contents - }) - else - Logger.log('modem_send', { 'broadcast', msgType }) - device.wireless_modem.transmit(60000, os.getComputerID(), { - type = msgType, contents = contents - }) - end -end - -function Message.broadcast(t, contents) - if not device.wireless_modem then - error('No modem attached', 2) - end - - Message.send(nil, t, contents) --- Logger.log('rednet_send', { 'broadcast', t }) --- rednet.broadcast({ type = t, contents = contents }) -end - -function Message.waitForMessage(msgType, timeout, fromId) - local timerId = os.startTimer(timeout) - repeat - local e, side, _id, id, msg, distance = os.pullEvent() - if e == 'modem_message' then - if msg and msg.type and msg.type == msgType then - if not fromId or id == fromId then - return e, id, msg, distance - end - end - end - until e == 'timer' and side == timerId -end - -function Message.enableWirelessLogging() - Logger.setWirelessLogging() -end - -return Message \ No newline at end of file diff --git a/sys/apis/point.lua b/sys/apis/point.lua index 3076d02..cbdf461 100644 --- a/sys/apis/point.lua +++ b/sys/apis/point.lua @@ -172,6 +172,7 @@ function Point.inBox(pt, box) pt.y >= box.y and pt.z >= box.z and pt.x <= box.ex and + pt.y <= box.ey and pt.z <= box.ez end diff --git a/sys/apis/profile.lua b/sys/apis/profile.lua deleted file mode 100644 index 6a4fbe9..0000000 --- a/sys/apis/profile.lua +++ /dev/null @@ -1,51 +0,0 @@ -local Util = require('util') -local Logger = require('logger') - -local Profile = { - start = function() end, - stop = function() end, - display = function() end, - methods = { }, -} - -local function Profile_display() - Logger.log('profile', 'Profiling results') - for k,v in pairs(Profile.methods) do - Logger.log('profile', '%s: %f %d %f', - k, Util.round(v.elapsed, 2), v.count, Util.round(v.elapsed/v.count, 2)) - end - Profile.methods = { } -end - -local function Profile_start(name) - local p = Profile.methods[name] - if not p then - p = { } - p.elapsed = 0 - p.count = 0 - Profile.methods[name] = p - end - p.clock = os.clock() - return p -end - -local function Profile_stop(name) - local p = Profile.methods[name] - p.elapsed = p.elapsed + (os.clock() - p.clock) - p.count = p.count + 1 -end - -function Profile.enable() - Logger.log('profile', 'Profiling enabled') - Profile.start = Profile_start - Profile.stop = Profile_stop - Profile.display = Profile_display -end - -function Profile.disable() - Profile.start = function() end - Profile.stop = function() end - Profile.display = function() end -end - -return Profile diff --git a/sys/apis/refinedAdapter.lua b/sys/apis/refinedAdapter.lua deleted file mode 100644 index f404fc5..0000000 --- a/sys/apis/refinedAdapter.lua +++ /dev/null @@ -1,143 +0,0 @@ -local class = require('class') -local Util = require('util') -local Peripheral = require('peripheral') -local itemDB = require('itemDB') - -local RefinedAdapter = class() - -local keys = { - 'damage', - 'displayName', - 'maxCount', - 'maxDamage', - 'name', - 'nbtHash', -} - -function RefinedAdapter:init(args) - local defaults = { - items = { }, - name = 'refinedStorage', - } - Util.merge(self, defaults) - Util.merge(self, args) - - local controller = Peripheral.getByType('refinedstorage:controller') - if controller then - Util.merge(self, controller) - end -end - -function RefinedAdapter:isValid() - return not not self.listAvailableItems -end - -function RefinedAdapter:isOnline() - return self.getNetworkEnergyStored() > 0 -end - -function RefinedAdapter:getCachedItemDetails(item) - local key = { item.name, item.damage, item.nbtHash } - - local detail = itemDB:get(key) - if not detail then - detail = self.findItem(item) - if detail then - local meta - pcall(function() meta = detail.getMetadata() end) - if not meta then - return - end - Util.merge(detail, meta) - - local t = { } - for _,k in pairs(keys) do - t[k] = detail[k] - end - - detail = t - itemDB:add(key, detail) - end - end - if detail then - return Util.shallowCopy(detail) - end -end - -function RefinedAdapter:listItems() - local items = { } - local list - - pcall(function() - list = self.listAvailableItems() - end) - - if list then - - local throttle = Util.throttle() - - for _,v in pairs(list) do - local item = self:getCachedItemDetails(v) - if item then - item.count = v.count - table.insert(items, item) - end - throttle() - end - itemDB:flush() - end - - return items -end - -function RefinedAdapter:getItemInfo(fingerprint) - - local key = { fingerprint.name, fingerprint.damage, fingerprint.nbtHash } - - local item = itemDB:get(key) - if not item then - return self:getCachedItemDetails(fingerprint) - end - - local detail = self.findItem(item) - if detail then - item.count = detail.count - return item - end -end - -function RefinedAdapter:isCrafting(item) - for _,task in pairs(self.getCraftingTasks()) do - local output = task.getPattern().outputs[1] - if output.name == item.name and - output.damage == item.damage and - output.nbtHash == item.nbtHash then - return true - end - end - return false -end - -function RefinedAdapter:craft(item, qty) - local detail = self.findItem(item) - if detail then - return detail.craft(qty) - end -end - -function RefinedAdapter:craftItems(items) - return false -end - -function RefinedAdapter:provide(item, qty, slot) -end - -function RefinedAdapter:extract(slot, qty) --- self.pushItems(self.direction, slot, qty) -end - -function RefinedAdapter:insert(slot, qty) --- self.pullItems(self.direction, slot, qty) -end - -return RefinedAdapter diff --git a/sys/apis/schematic.lua b/sys/apis/schematic.lua deleted file mode 100644 index f7d08d9..0000000 --- a/sys/apis/schematic.lua +++ /dev/null @@ -1,1175 +0,0 @@ -local class = require('class') -local Util = require('util') -local DEFLATE = require('deflatelua') -local UI = require('ui') -local Point = require('point') - ---[[ - Loading and manipulating a schematic ---]] - -local schematicMagic = 0x0a00 -local gzipMagic = 0x1f8b - -local Schematic = class() -function Schematic:init(args) - self.blocks = { } - self.damages = { } - self.originalBlocks = { } - self.x, self.y, self.z = 0, 0, 0 - self.height = 0 - self.index = 1 -end - ---[[ - Credit to Orwell for the schematic file reader code - http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/ - - Some parts of the file reader code was modified from the original ---]] - -function Schematic:discardBytes(h, n, spinner) - for i = 1,n do - h:readbyte() - if (i % 1000) == 0 then - spinner:spin() - end - end -end - -function Schematic:readname(h) - local n1 = h:readbyte(h) - local n2 = h:readbyte(h) - - if(n1 == nil or n2 == nil) then - return "" - end - - local n = n1*256 + n2 - - local str = "" - for i=1,n do - local c = h:readbyte(h) - if c == nil then - return - end - str = str .. string.char(c) - end - return str -end - -function Schematic:parse(a, h, containsName, spinner) - - if a==0 then - return - end - - local name - if containsName then - name = self:readname(h) - end - - if a==1 then - self:discardBytes(h, 1, spinner) - elseif a==2 then - local i1 = h:readbyte(h) - local i2 = h:readbyte(h) - local i = i1*256 + i2 - if(name=="Height") then - --self.height = i - elseif (name=="Length") then - self.length = i - elseif (name=="Width") then - self.width = i - end - return 2 - elseif a==3 then - self:discardBytes(h, 4, spinner) - return 4 - elseif a==4 then - self:discardBytes(h,8, spinner) - return 8 - elseif a==5 then - self:discardBytes(h,4, spinner) - return 4 - elseif a==6 then - self:discardBytes(h,8, spinner) - elseif a==7 then - local i1 = h:readbyte(h) - local i2 = h:readbyte(h) - local i3 = h:readbyte(h) - local i4 = h:readbyte(h) - local i = bit.blshift(i1, 24) + bit.blshift(i2, 16) + bit.blshift(i3, 8) + i4 - - if name == "Blocks" then - for i = 1, i do - local id = h:readbyte(h) - if id > 0 then - table.insert(self.blocks, { - id = id, - index = i, - }) - end - if (i % 1000) == 0 then - spinner:spin() - end - end - elseif name == "Data" then - for i = 1, i do - local dmg = h:readbyte(h) - if dmg > 0 then - self.damages[i] = dmg - end - if (i % 1000) == 0 then - spinner:spin() - end - end - else - self:discardBytes(h,i, spinner) - end - elseif a==8 then - local i1 = h:readbyte(h) - local i2 = h:readbyte(h) - local i = i1*256 + i2 - self:discardBytes(h,i, spinner) - elseif a==9 then - local type = h:readbyte(h) - local i1 = h:readbyte(h) - local i2 = h:readbyte(h) - local i3 = h:readbyte(h) - local i4 = h:readbyte(h) - local i = bit.blshift(i1, 24) + bit.blshift(i2, 16) + bit.blshift(i3, 8) + i4 - - for j=1,i do - self:parse(type, h, false, spinner) - end - elseif a > 11 then - error('invalid tag') - end -end --- end http://www.computercraft.info/forums2/index.php?/topic/1949-turtle-schematic-file-builder/ - -function Schematic:copyBlocks(iblocks, oblocks, throttle) - for k,b in ipairs(iblocks) do - oblocks[k] = Util.shallowCopy(b) - --if (k % 1000) == 0 then - throttle() - --end - end -end - -function Schematic:reload(throttle) - self.blocks = { } - self:copyBlocks(self.originalBlocks, self.blocks, throttle) - - for _,ri in pairs(self.rowIndex) do - ri.loaded = false - end -end - -function Schematic:getMagic(fh) - fh:open() - - local magic = fh:readbyte() * 256 + fh:readbyte() - - fh:close() - - return magic -end - -function Schematic:isCompressed(filename) - local h = fs.open(filename, "rb") - - if not h then - error('unable to open: ' .. filename) - end - - local magic = h.read() * 256 + h.read() - - h.close() - - return magic == gzipMagic -end - -function Schematic:checkFileType(fh) - - local magic = self:getMagic(fh) - if magic ~= schematicMagic then - error('Unknown file type') - end -end - -local DiskFile = class() -function DiskFile:init(args) - Util.merge(self, args) -end - -function DiskFile:open() - self.h = fs.open(self.filename, "rb") - if not self.h then - error('unable to open: ' .. self.filename) - end -end -function DiskFile:readbyte() - return self.h.read() -end -function DiskFile:close() - self.h.close() -end - -local MemoryFile = class() -function MemoryFile:init(args) - self.s = { } - self.i = 1 -end -function MemoryFile:open(filename) - self.i = 1 -end -function MemoryFile:close() end - -function MemoryFile:readbyte() - local b = self.s[self.i] - self.i = self.i + 1 - return b -end - -function MemoryFile:write(b) - self.s[#self.s + 1] = b -end - -function Schematic:decompress(ifname, spinner) - - local ifh = fs.open(ifname, "rb") - if not ifh then - error('Unable to open ' .. ifname) - end - - local mh = MemoryFile() - - DEFLATE.gunzip({ - input=function(...) spinner:spin() return ifh.read() end, - output=function(b) mh:write(b) end, - disable_crc=true - }) - - ifh.close() - - spinner:stop() - - return mh -end - -function Schematic:loadpass(fh, spinner) - - fh:open() - - while true do - local a = fh:readbyte() - - if not a then - break - end - self:parse(a, fh, true, spinner) - - spinner:spin() - end - - fh:close() - - print('Assigning coords ') - local index = 1 - for _, b in ipairs(self.blocks) do - while index < b.index do - self.x = self.x + 1 - if self.x >= self.width then - self.x = 0 - self.z = self.z + 1 - end - if self.z >= self.length then - self.z = 0 - self.y = self.y + 1 - end - if self.y >= self.height then - self.height = self.y + 1 - end - index = index + 1 - end - b.x = self.x - b.y = self.y - b.z = self.z - spinner:spin() - end - - self:assignDamages(spinner) - self.damages = nil - - self:copyBlocks(self.blocks, self.originalBlocks, function() spinner:spin() end) - - spinner:stop() -end - -function Schematic:load(filename) - - local cursorX, cursorY = term.getCursorPos() - local spinner = UI.Spinner({ - x = UI.term.width, - y = cursorY - 1 - }) - local f - - if self:isCompressed(filename) then - local originalFile = filename - filename = originalFile .. '.uncompressed' - - if not fs.exists(filename) then - print('Decompressing') - f = self:decompress(originalFile, spinner) - end - end - - self.filename = string.match(filename, '([^/]+)$') - - if not f then - f = DiskFile({ filename = filename }) - end - - self:checkFileType(f) - - print('Loading blocks ') - self:loadpass(f, spinner) - - self.rowIndex = { } - for k,b in ipairs(self.blocks) do - local ri = self.rowIndex[b.y] - if not ri then - self.rowIndex[b.y] = { s = k, e = k } - else - ri.e = k - end - end - - self.cache = Util.readTable('usr/builder/' .. self.filename .. '.cache') or { } -end - -function Schematic:assignDamages(spinner) - print('Assigning damages') - - for _,b in pairs(self.blocks) do - b.dmg = self.damages[b.index] or 0 - spinner:spin() - end -end - -function Schematic:findIndexAt(x, z, y, allBlocks) - if y < 0 then - return - end - - local ri = self.rowIndex[y] - if ri then - for i = ri.s, ri.e do - local b = self.blocks[i] - if b.x == x and b.z == z and b.y == y then - if b.id == 'minecraft:air' and not allBlocks then - -- this will possibly screw up placement order if a substition is made with air after starting - -- as blocks will be placed differently and could have a different heading - break - end - return i, b - end - end - end -end - -function Schematic:findBlockAtSide(b, side) - local hi = turtle.getHeadingInfo(side) - local index = self:findIndexAt(b.x + hi.xd, b.z + hi.zd, b.y + hi.yd) - if index then - return self.blocks[index] -- could be better - end -end - -function Schematic:addPlacementChain(chains, chain) - local t = { } - for _,v in ipairs(chain) do - local k = self:findIndexAt(v.x, v.z, v.y) - if k then - local b = self.blocks[k] -- could be better - b.index = v.y * self.width * self.length + v.z * self.width + v.x + 1 - table.insert(t, b) - end - end - if #t > 1 then - local keys = { } - for _,b in pairs(t) do - keys[b.index] = true - end - table.insert(chains, { - blocks = t, - keys = keys - }) - end -end - -function Schematic:bestSide(b, chains, ...) - local directions = { ... } - local blocks = { } - - for k,d in pairs(directions) do - local hi = turtle.getHeadingInfo(d) - local sb = self:findIndexAt(b.x - hi.xd, b.z - hi.zd, b.y) - if not sb then - b.heading = turtle.getHeadingInfo(d).heading - b.direction = d .. '-block' - return - end - blocks[k] = { - b = self.blocks[sb], - hi = hi, - d = d - } - end - - local bestBlock - for _,sb in ipairs(blocks) do - if not sb.b.direction then -- could be better - bestBlock = sb - break - end - end - - if not bestBlock then - local sideDirections = { - [ 'east-block' ] = 'east', - [ 'south-block' ] = 'south', - [ 'west-block' ] = 'west', - [ 'north-block' ] = 'north' - } - for _,sb in ipairs(blocks) do - if not bestBlock then - bestBlock = sb - end - if not sideDirections[sb.b.direction] then - bestBlock = sb - break - end - end - end - - local hi = bestBlock.hi - b.heading = hi.heading -- ????????????????????????????????? - b.direction = bestBlock.d .. '-block' - self:addPlacementChain(chains, { - { x = b.x, z = b.z, y = b.y }, - { x = b.x - hi.xd, z = b.z - hi.zd, y = b.y } - }) -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 - local fb = b -- first block - local lb = b -- last block - local od = b.direction -- original direction - - -- find the last block in the row with the same two-sided direction - while true do - sb = self:findBlockAtSide(lb, side2) - if not sb or sb.direction ~= b.direction then - break - end - lb = sb - end - - -- find the first block - while true do - sb = self:findBlockAtSide(fb, side1) - if not sb or sb.direction ~= b.direction then - break - end - fb = sb - end - - -- set the placement order to side1 -> side2 - if fb ~= lb then -- only 1 block - - local pc = { } -- placementChain - b = fb - - while true do - - table.insert(pc, { x = b.x, z = b.z, y = b.y }) - - b.direction = side1 .. '-block' - b.heading = turtle.getHeadingInfo(side1).heading - - if b == lb then - break - end - - b = self:findBlockAtSide(b, side2) - end - - self:addPlacementChain(chains, pc) - end - - -- can we place the first block from the side (instead of using piston) ? - sb = self:findBlockAtSide(fb, side1) - if not sb then - local ub = self:findBlockAtSide(fb, 'down') - if not ub then - fb.direction = side1 .. '-block' - fb.heading = turtle.getHeadingInfo(side1).heading - else - fb.direction = od - end - else -- really should use placement chain - fb.direction = od - end - - -- can we place the last block from the side (instead of using piston) ? - sb = self:findBlockAtSide(lb, side2) - if not sb then - local ub = self:findBlockAtSide(lb, 'down') - if not ub then - lb.direction = side1 .. '-block' - lb.heading = turtle.getHeadingInfo(side1).heading - else - fb.direction = od - end - else - lb.direction = od - end - -end - --- Determine the best way to place each block -function Schematic:determineBlockPlacement(y) - - -- NOTE: blocks are evaluated top to bottom - - print('Processing level ' .. y) - - local spinner = UI.Spinner({ - x = 1, - spinSymbols = { 'o.....', '.o....', '..o...', '...o..', '....o.', '.....o' } - }) - local stairDownDirections = { - [ 'north-down' ] = 'north', - [ 'south-down' ] = 'south', - [ 'east-down' ] = 'east', - [ 'west-down' ] = 'west' - } - local stairUpDirections = { - [ 'east-up' ] = { 'east', 'east-block', 1, 0, 'west-block' }, - [ 'west-up' ] = { 'west', 'west-block', -1, 0, 'east-block' }, - [ 'north-up' ] = { 'north', 'north-block', 0, -1, 'south-block' }, - [ 'south-up' ] = { 'south', 'south-block', 0, 1, 'north-block' } - } - local twoSideDirections = { - [ 'east-west-block' ] = true, - [ 'north-south-block' ] = true, - } - local directions = { - [ 'north' ] = 'north', - [ 'south' ] = 'south', - [ 'east' ] = 'east', - [ 'west' ] = 'west', - } - local blockDirections = { - [ 'east-block' ] = 'east', - [ 'south-block' ] = 'south', - [ 'west-block' ] = 'west', - [ 'north-block' ] = 'north', - } - local doorDirections = { - [ 'east-door' ] = 'east', - [ 'south-door' ] = 'south', - [ 'west-door' ] = 'west', - [ 'north-door' ] = 'north', - } - local vineDirections = { - [ 'east-block-vine' ] = 'east-block', - [ 'south-block-vine' ] = 'south-block', - [ '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 - - if d then - if vineDirections[d] then - local _, aboveBlock = self:findIndexAt(b.x, b.z, b.y+1) - - if aboveBlock and aboveBlock.id == b.id and aboveBlock.dmg == b.dmg and aboveBlock.direction == d then - -- only need to place top vine - b.id = 'minecraft:air' - b.dmg = 0 - b.direction = nil - else - b.direction = vineDirections[d] - table.insert(dirtyBlocks, b) - end - elseif twoSideDirections[d] then - table.insert(dirtyBlocks2, b) - else - table.insert(dirtyBlocks, b) - end - spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ') - end - end - --- Util.filterInplace(dirtyBlocks, function(b) return b.id ~= 'minecraft:air' end) - - -- remove directional info from slabs where possible - -- iterate backwards to process top planes first - for k = #dirtyBlocks, 1, -1 do - local b = dirtyBlocks[k] - local d = b.direction - - if d == 'top' then - -- slab occupying top of voxel - -- can be placed from the top if there is no block below - local belowBlock = self:findIndexAt(b.x, b.z, b.y-1) - if not belowBlock then - b.direction = nil - table.remove(dirtyBlocks, k) - end - elseif d == 'bottom' then - b.bottom = true -- flag this as a bottom block - local _,db = self:findIndexAt(b.x, b.z, b.y-1) - if db then - if not db.direction or db.direction ~= 'bottom' then - -- not a slab below, ok to place from above - if not db.bottom then - b.direction = nil - end - end - -- it is a slab below - must be pistoned - table.remove(dirtyBlocks, k) - end - end - spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ') - end - - -- iterate through the directional blocks setting the placement strategy - while #dirtyBlocks > 0 do - local b = table.remove(dirtyBlocks) - local d = b.direction or '' - - spinner:spin(#dirtyBlocks + #dirtyBlocks2 .. ' blocks remaining ') - - if directions[d] then - b.heading = turtle.getHeadingInfo(directions[d]).heading - end - - if doorDirections[d] then - - local hi = turtle.getHeadingInfo(doorDirections[d]) - b.heading = hi.heading - - self:addPlacementChain(chains, { - { x = b.x, z = b.z, y = b.y }, - { x = b.x - hi.xd, z = b.z - hi.zd, y = b.y }, - }) - end - - if stairDownDirections[d] then - if not self:findIndexAt(b.x, b.z, b.y-1) then - b.direction = stairDownDirections[b.direction] - b.heading = turtle.getHeadingInfo(b.direction).heading - else - b.heading = turtle.getHeadingInfo(stairDownDirections[b.direction]).heading - end - end - - if d == 'bottom' then - -- slab occupying bottom of voxel - -- can be placed from top if a block is below - -- otherwise, needs to be placed from side - - -- except... if the block below is a slab :( - --local _,db = self:findIndexAt(b.x, b.z, b.y-1) - --if not db then - -- no block below, place from side - - -- took care of all other cases above - self:bestSide(b, chains, 'east', 'south', 'west', 'north') - - -- elseif not db.direction or db.direction ~= 'bottom' then - -- not a slab below, ok to place from above - -- b.direction = nil - --end - -- otherwise, builder will piston it in from above - - elseif stairUpDirections[d] then - -- a directional stair - -- turtle can place correctly from above if there is a block below - -- otherwise, the turtle must place the block from the same plane - -- against another block - -- if no block to place against (from side) then the turtle must place from - -- the other side - -- - -- Stair bug in 1.7 - placing a stair southward doesn't respect the turtle's direction - -- all other directions are fine - -- any stair southwards that can't be placed against another block must be pistoned - local sd = stairUpDirections[d] - - if self:findIndexAt(b.x, b.z, b.y-1) then - -- there's a block below - b.direction = sd[1] - b.heading = turtle.getHeadingInfo(b.direction).heading - else - local _,pb = self:findIndexAt(b.x + sd[3], b.z + sd[4], b.y) - if pb and pb.direction ~= sd[5] then - -- place stair against another block (that's not relying on this block to be down first) - d = sd[2] -- fall through to the blockDirections code below - b.direction = sd[2] - else - b.heading = (turtle.getHeadingInfo(sd[1]).heading + 2) % 4 - end - end - elseif flipDirections[d] then - self:bestFlipSide(b, chains) - end - - if blockDirections[d] then - -- placing a block from the side - local hi = turtle.getHeadingInfo(blockDirections[d]) - b.heading = hi.heading - 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 - }) - end - end - - -- pass 3 - while #dirtyBlocks2 > 0 do - local b = table.remove(dirtyBlocks2) - local d = b.direction - - spinner:spin(#dirtyBlocks2 .. ' blocks remaining ') - - if d == 'east-west-block' then - self:bestOfTwoSides(b, chains, 'east', 'west') - elseif d == 'north-south-block' then - self:bestOfTwoSides(b, chains, 'north', 'south') - end - end - - term.clearLine() - - self:setPlacementOrder(spinner, chains) - local plane = self:optimizeRoute(spinner, y) - - term.clearLine() - spinner:stop() - - for k,b in ipairs(plane) do - self.blocks[ri.s + k - 1] = b - end -end - -function Schematic:getComputedBlock(i) - local b = self.blocks[i] - - -- has this level been computed ? - if not self.rowIndex[b.y].loaded then - -- compute each level up til this one (unless saved in cache) - - for y = 0, b.y - 1 do - if not self.cache[y] then - self:determineBlockPlacement(y) - end - end - self:determineBlockPlacement(b.y) - -- get the block now at the computed location - b = self.blocks[i] - end - return b -end - --- set the order for block dependencies -function Schematic:setPlacementOrder(spinner, placementChains) - - local cursorX, cursorY = term.getCursorPos() - - -- optimize for overlapping check - for _,chain in pairs(placementChains) do - for index,_ in pairs(chain.keys) do - if not chain.startRow or (index < chain.startRow) then - chain.startRow = index - end - if not chain.endRow or (index > chain.endRow) then - chain.endRow = index - end - end - end - - local function groupOverlappingChains(t, groupedChain, chain, spinner) - local found = true - - local function overlaps(chain1, chain2) - if chain1.startRow > chain2.endRow or - chain2.startRow > chain1.endRow then - return false - end - for k,_ in pairs(chain1.keys) do - if chain2.keys[k] then - return true - end - end - end - - while found do - found = false - for k, v in pairs(t) do - local o = overlaps(chain, v) - if o then - table.remove(t, k) - table.insert(groupedChain, v) - groupOverlappingChains(t, groupedChain, v, spinner) - spinner:spin() - found = true - break - end - end - end - end - - -- group together any placement chains with overlapping blocks - local groupedChains = {} - while #placementChains > 0 do - local groupedChain = {} - local chain = table.remove(placementChains) - table.insert(groupedChain, chain) - table.insert(groupedChains, groupedChain) - groupOverlappingChains(placementChains, groupedChain, chain, spinner) - spinner:spin('chains: ' .. #groupedChains .. ' ' .. #placementChains .. ' ') - end - - --Logger.log('schematic', 'groups: ' .. #groupedChains) - --Logger.setFileLogging('chains') - - local function mergeChains(chains) - - --[[ - Logger.debug('---------------') - Logger.log('schematic', 'mergeChains: ' .. #chains) - for _,chain in ipairs(chains) do - Logger.log('schematic', chain) - for _,e in ipairs(chain) do - Logger.log('schematic', string.format('%d:%d:%d %s %d:%d', - e.block.x, e.block.z, e.block.y, tostring(e.block.direction), e.block.id, e.block.dmg)) - end - end - ]]-- - - local masterChain = table.remove(chains) - - --[[ it's something like this: - - A chain B chain result - 1 1 - 2 -------- 2 2 - 3 3 - 4 4 - 5 5 - 6 -------- 6 6 - 7 7 - --]] - local function splice(chain1, chain2) - for k,v in ipairs(chain1) do - for k2,v2 in ipairs(chain2) do - if v == v2 then - local index = k - local dupe - for i = k2-1, 1, -1 do - dupe = false - -- traverse back through the first chain aligning on matches - for j = index-1, 1, -1 do - if chain1[j] == chain2[i] then - index = j - dupe = true - break - end - end - if not dupe then - table.insert(chain1, index, chain2[i]) - end - end - index = k+1 - for i = k2+1, #chain2, 1 do - dupe = false - for j = index, #chain1, 1 do - if chain1[j] == chain2[i] then - index = j - dupe = true - break - end - end - if not dupe then - table.insert(chain1, index, chain2[i]) - end - index = index + 1 - end - return true - end - end - end - end - - while #chains > 0 do - for k,chain in pairs(chains) do - if splice(masterChain.blocks, chain.blocks) then - table.remove(chains, k) - break - end - end - end - - --[[ - Logger.log('schematic', 'master chain: ') - Logger.log('schematic', masterChain) - Logger.log('schematic', '---------------') - for _,e in ipairs(masterChain.blocks) do - Logger.log('schematic', string.format('%d:%d:%d %s %s:%d', - e.x, e.z, e.y, tostring(e.direction), e.id, e.dmg)) - end - --]] - - return masterChain - end - - -- combine the individual overlapping placement chains into 1 long master chain - local masterChains = {} - for _,group in pairs(groupedChains) do - spinner:spin('chains: ' .. #masterChains) - table.insert(masterChains, mergeChains(group)) - end - - local function removeDuplicates(chain) - for k,v in ipairs(chain) do - for i = #chain, k+1, -1 do - if v == chain[i] then -v.info = 'Unplaceable' - table.remove(chain, i) - end - end - end - end - - -- any chains with duplicates cannot be placed correctly - -- there are some cases where a turtle cannot place blocks the same as a player - for _,chain in pairs(masterChains) do - removeDuplicates(chain.blocks) - spinner:spin('chains: ' .. #masterChains) - - --[[ - Logger.log('schematic', "MASTER CHAIN") - for _,e in ipairs(chain) do - Logger.log('schematic', string.format('%d:%d:%d %s %d:%d', - e.block.x, e.block.z, e.block.y, tostring(e.block.direction), e.block.id, e.block.dmg)) - end - --]] - - end - term.clearLine() - - -- set dependent blocks for optimize routine - for k,chain in pairs(masterChains) do - spinner:spin('chains: ' .. #masterChains - k) - - local prev - for k,b in ipairs(chain.blocks) do - b.prev = prev - b.next = chain.blocks[k + 1] - prev = b - end - end - - term.clearLine() - - return t -end - -function Schematic:optimizeRoute(spinner, y) - - local function getNearestNeighbor(p, pt, maxDistance) - 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) - if b.u then - return false - end - if b.prev and not b.prev.u then - return false - end - return true - 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 <= 1 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 <= 1 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 pt = Util.shallowCopy(self.cache[y - 1] or turtle.point) - local t = {} - local ri = self.rowIndex[y] - local blockCount = ri.e - ri.s + 1 - - local function extractPlane() - local t = {} - local dt = {} - for i = ri.s, ri.e do - local b = self.blocks[i] - if b.twoHigh then - b.last = true - while b.next do - b = b.next - b.last = true - end - end - end - for i = ri.s, ri.e do - local b = self.blocks[i] - if b.last then - table.insert(dt, b) - else - table.insert(t, b) - end - end - return t, dt - end - - local maxDistance = self.width*self.length - local plane, doors = extractPlane(y) - spinner:spin(percent) - pt.index = 0 - for i = 1, #plane do - local b = getNearestNeighbor(plane, pt, maxDistance) - table.insert(t, b) - local percent = math.floor(#t * 100 / blockCount) .. '%' - spinner:spin(percent .. ' ' .. blockCount - i .. ' ') - end - -- all two high blocks are placed last on each plane - pt.index = 0 - for i = 1, #doors do - local b = getNearestNeighbor(doors, pt, maxDistance) - table.insert(t, b) - local percent = math.floor(#t * 100 / blockCount) .. '%' - spinner:spin(percent .. ' ' .. blockCount - #plane - i .. ' ') - end - - self.rowIndex[y].loaded = true - if not self.cache[y] then - self.cache[y] = Util.shallowCopy(pt) - Util.writeTable('usr/builder/' .. self.filename .. '.cache', self.cache) - end - - return t -end - -return Schematic diff --git a/sys/apis/tableDB.lua b/sys/apis/tableDB.lua deleted file mode 100644 index 6299088..0000000 --- a/sys/apis/tableDB.lua +++ /dev/null @@ -1,54 +0,0 @@ -local class = require('class') -local Util = require('util') - -local TableDB = class() -function TableDB:init(args) - local defaults = { - fileName = '', - dirty = false, - data = { }, - tabledef = { }, - } - Util.merge(defaults, args) - Util.merge(self, defaults) -end - -function TableDB:load() - local table = Util.readTable(self.fileName) - if table then - self.data = table.data - self.tabledef = table.tabledef - end -end - -function TableDB:add(key, entry) - if type(key) == 'table' then - key = table.concat(key, ':') - end - self.data[key] = entry - self.dirty = true -end - -function TableDB:get(key) - if type(key) == 'table' then - key = table.concat(key, ':') - end - return self.data[key] -end - -function TableDB:remove(key) - self.data[key] = nil - self.dirty = true -end - -function TableDB:flush() - if self.dirty then - Util.writeTable(self.fileName, { - -- tabledef = self.tabledef, - data = self.data, - }) - self.dirty = false - end -end - -return TableDB diff --git a/sys/apis/turtle/craft.lua b/sys/apis/turtle/craft.lua deleted file mode 100644 index ae161bc..0000000 --- a/sys/apis/turtle/craft.lua +++ /dev/null @@ -1,166 +0,0 @@ -local itemDB = require('itemDB') -local Util = require('util') - -local Craft = { } - -local function clearGrid(chestAdapter) - for i = 1, 16 do - local count = turtle.getItemCount(i) - if count > 0 then - chestAdapter:insert(i, count) - if turtle.getItemCount(i) ~= 0 then - return false - end - end - end - return true -end - -local function splitKey(key) - local t = Util.split(key, '(.-):') - local item = { } - if #t[#t] > 2 then - item.nbtHash = table.remove(t) - end - item.damage = tonumber(table.remove(t)) - item.name = table.concat(t, ':') - return item -end - -local function getItemCount(items, key) - local item = splitKey(key) - for _,v in pairs(items) do - if v.name == item.name and - v.damage == item.damage and - v.nbtHash == item.nbtHash then - return v.count - end - end - return 0 -end - -local function turtleCraft(recipe, qty, chestAdapter) - - clearGrid(chestAdapter) - - for k,v in pairs(recipe.ingredients) do - local item = splitKey(v) - chestAdapter:provide(item, qty, k) - if turtle.getItemCount(k) == 0 then -- ~= qty then - -- FIX: ingredients cannot be stacked - return false - end - end - - return turtle.craft() -end - -function Craft.craftRecipe(recipe, count, chestAdapter) - - local items = chestAdapter:listItems() - - local function sumItems(items) - -- produces { ['minecraft:planks:0'] = 8 } - local t = {} - for _,item in pairs(items) do - t[item] = (t[item] or 0) + 1 - end - return t - end - - count = math.ceil(count / recipe.count) - - local maxCount = recipe.maxCount or math.floor(64 / recipe.count) - local summedItems = sumItems(recipe.ingredients) - - for key,icount in pairs(summedItems) do - local itemCount = getItemCount(items, key) - if itemCount < icount * count then - local irecipe = Craft.recipes[key] - if irecipe then -Util.print('Crafting %d %s', icount * count - itemCount, key) - if not Craft.craftRecipe(irecipe, - icount * count - itemCount, - chestAdapter) then - turtle.select(1) - return - end - end - end - end - repeat - if not turtleCraft(recipe, math.min(count, maxCount), chestAdapter) then - turtle.select(1) - return false - end - count = count - maxCount - until count <= 0 - - turtle.select(1) - return true -end - --- given a certain quantity, return how many of those can be crafted -function Craft.getCraftableAmount(recipe, count, items) - - local function sumItems(recipe, items, summedItems, count) - - local canCraft = 0 - - for i = 1, count do - for _,item in pairs(recipe.ingredients) do - local summedItem = summedItems[item] or getItemCount(items, item) - - local irecipe = Craft.recipes[item] - if irecipe and summedItem <= 0 then - summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) - end - if summedItem <= 0 then - return canCraft - end - summedItems[item] = summedItem - 1 - end - canCraft = canCraft + recipe.count - end - - return canCraft - end - - return sumItems(recipe, items, { }, math.ceil(count / recipe.count)) -end - -function Craft.canCraft(item, count, items) - return Craft.getCraftableAmount(Craft.recipes[item], count, items) == count -end - -function Craft.setRecipes(recipes) - Craft.recipes = recipes -end - -function Craft.getCraftableAmountTest() - local results = { } - Craft.setRecipes(Util.readTable('sys/etc/recipes.db')) - - local items = { - { name = 'minecraft:planks', damage = 0, count = 5 }, - { name = 'minecraft:log', damage = 0, count = 2 }, - } - results[1] = { item = 'chest', expected = 1, got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) } - - items = { - { name = 'minecraft:log', damage = 0, count = 1 }, - { name = 'minecraft:coal', damage = 1, count = 1 }, - } - results[2] = { item = 'torch', expected = 4, got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) } - - return results -end - -function Craft.craftRecipeTest(name, count) - local ChestAdapter = require('chestAdapter18') - local chestAdapter = ChestAdapter({ wrapSide = 'top', direction = 'down' }) - Craft.setRecipes(Util.readTable('usr/etc/recipes.db')) - return { Craft.craftRecipe(Craft.recipes[name], count, chestAdapter) } -end - -return Craft diff --git a/sys/apis/turtle/level.lua b/sys/apis/turtle/level.lua deleted file mode 100644 index bce7145..0000000 --- a/sys/apis/turtle/level.lua +++ /dev/null @@ -1,165 +0,0 @@ -local Point = require('point') -local Util = require('util') - -local checkedNodes = { } -local nodes = { } -local box = { } -local oldCallback - -local function toKey(pt) - return table.concat({ pt.x, pt.y, pt.z }, ':') -end - -local function addNode(node) - - for i = 0, 5 do - local hi = turtle.getHeadingInfo(i) - local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd } - - if Point.inBox(testNode, box) then - local key = toKey(testNode) - if not checkedNodes[key] then - nodes[key] = testNode - end - end - end -end - -local function dig(action) - - local directions = { - top = 'up', - bottom = 'down', - } - - -- convert to up, down, north, south, east, west - local direction = directions[action.side] or - turtle.getHeadingInfo(turtle.point.heading).direction - - local hi = turtle.getHeadingInfo(direction) - local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd } - - if Point.inBox(node, box) then - - local key = toKey(node) - checkedNodes[key] = true - nodes[key] = nil - - if action.dig() then - addNode(node) - repeat until not action.dig() -- sand, etc - return true - end - end -end - -local function move(action) - if action == 'turn' then - dig(turtle.getAction('forward')) - elseif action == 'up' then - dig(turtle.getAction('up')) - dig(turtle.getAction('forward')) - elseif action == 'down' then - dig(turtle.getAction('down')) - dig(turtle.getAction('forward')) - elseif action == 'back' then - dig(turtle.getAction('up')) - dig(turtle.getAction('down')) - end - - if oldCallback then - oldCallback(action) - end -end - --- find the closest block --- * favor same plane --- * going backwards only if the dest is above or below -function closestPoint(reference, pts) - local lpt, lm -- lowest - for _,pt in pairs(pts) do - local m = Point.turtleDistance(reference, pt) - local h = Point.calculateHeading(reference, pt) - local t = Point.calculateTurns(reference.heading, h) - if pt.y ~= reference.y then -- try and stay on same plane - m = m + .01 - end - if t ~= 2 or pt.y == reference.y then - m = m + t - if t > 0 then - m = m + .01 - end - end - if not lm or m < lm then - lpt = pt - lm = m - end - end - return lpt -end - -local function getAdjacentPoint(pt) - local t = { } - table.insert(t, pt) - for i = 0, 5 do - local hi = turtle.getHeadingInfo(i) - local heading - if i < 4 then - heading = (hi.heading + 2) % 4 - end - table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading }) - end - - return closestPoint(turtle.getPoint(), t) -end - -return function(startPt, endPt, firstPt, verbose) - - checkedNodes = { } - nodes = { } - box = { } - - box.x = math.min(startPt.x, endPt.x) - box.y = math.min(startPt.y, endPt.y) - box.z = math.min(startPt.z, endPt.z) - box.ex = math.max(startPt.x, endPt.x) - box.ey = math.max(startPt.y, endPt.y) - box.ez = math.max(startPt.z, endPt.z) - - if not turtle.pathfind(firstPt) then - error('failed to reach starting point') - end - - turtle.setPolicy("attack", { dig = dig }, "assuredMove") - - oldCallback = turtle.getMoveCallback() - turtle.setMoveCallback(move) - - repeat - local key = toKey(turtle.point) - - checkedNodes[key] = true - nodes[key] = nil - - dig(turtle.getAction('down')) - dig(turtle.getAction('up')) - dig(turtle.getAction('forward')) - - if verbose then - print(string.format('%d nodes remaining', Util.size(nodes))) - end - - if Util.size(nodes) == 0 then - break - end - - local node = closestPoint(turtle.point, nodes) - node = getAdjacentPoint(node) - if not turtle.gotoPoint(node) then - break - end - until turtle.abort - - turtle.resetState() - turtle.setMoveCallback(oldCallback) -end diff --git a/sys/apis/turtle/pathfind.lua b/sys/apis/turtle/pathfind.lua index 78307a8..93eb231 100644 --- a/sys/apis/turtle/pathfind.lua +++ b/sys/apis/turtle/pathfind.lua @@ -88,10 +88,6 @@ local function mapDimensions(dest, blocks, boundingBox) } end -local function nodeToString(n) - return string.format('%d:%d:%d:%d', n._x, n._y, n._z, n.__heading or 9) -end - -- shifting and coordinate flipping local function pointToMap(dim, pt) return { x = pt.x + dim.ox, z = pt.y + dim.oy, y = pt.z + dim.oz } @@ -144,15 +140,34 @@ local function addSensorBlocks(blocks, sblocks) end end +local function selectDestination(pts, box, map, dim) + + while #pts > 0 do + local pt = Point.closest(turtle.point, pts) + + if (box and not Point.inBox(pt, box)) or + map[pt.z + dim.oz][pt.x + dim.ox][pt.y + dim.oy] == 1 then + Util.removeByValue(pts, pt) + else + return pt + end + end +end + local function pathTo(dest, options) - local blocks = options.blocks or { } - local allDests = options.dest or { } -- support alternative destinations + local blocks = options.blocks or turtle.getState().blocks or { } + local dests = options.dest or { dest } -- support alternative destinations + local box = options.box or turtle.getState().box local lastDim = nil local map = nil local grid = nil + if box then + box = Point.normalizeBox(box) + end + -- Creates a pathfinder object local myFinder = Pathfinder(grid, 'ASTAR', walkable) @@ -162,7 +177,7 @@ local function pathTo(dest, options) while turtle.point.x ~= dest.x or turtle.point.z ~= dest.z or turtle.point.y ~= dest.y do -- map expands as we encounter obstacles - local dim = mapDimensions(dest, blocks, options.box) + local dim = mapDimensions(dest, blocks, box) -- reuse map if possible if not lastDim or not dimsAreEqual(dim, lastDim) then @@ -179,6 +194,15 @@ local function pathTo(dest, options) addBlock(map, dim, b) end + dest = selectDestination(dests, box, map, dim) + if not dest then + error('failed to reach destination') +-- return false, 'failed to reach destination' + end + if turtle.point.x == dest.x and turtle.point.z == dest.z and turtle.point.y == dest.y then + break + end + -- Define start and goal locations coordinates local startPt = pointToMap(dim, turtle.point) local endPt = pointToMap(dim, dest) @@ -187,14 +211,8 @@ local function pathTo(dest, options) local path = myFinder:getPath(startPt.x, startPt.y, startPt.z, turtle.point.heading, endPt.x, endPt.y, endPt.z, dest.heading) if not path then - Util.removeByValue(allDests, dest) - dest = Point.closest(turtle.point, allDests) - - if not dest then - return false, 'failed to recalculate' - end + Util.removeByValue(dests, dest) else - for node, count in path:nodes() do local pt = nodeToPoint(dim, node) @@ -206,9 +224,6 @@ local function pathTo(dest, options) -- when encountering obstacles -- IS THIS RIGHT ?? if not turtle.gotoSingleTurn(pt.x, pt.z, pt.y, node.heading) then table.insert(blocks, pt) - if #allDests > 0 then - dest = Point.closest(turtle.point, allDests) - end --if device.turtlesensorenvironment then -- addSensorBlocks(blocks, device.turtlesensorenvironment.sonicScan()) --end @@ -224,10 +239,27 @@ local function pathTo(dest, options) return dest end -return function(dest, options) - options = options or { } - if not options.blocks and turtle.gotoPoint(dest) then - return dest - end - return pathTo(dest, options) -end +return { + pathfind = function(dest, options) + options = options or { } + --if not options.blocks and turtle.gotoPoint(dest) then + -- return dest + --end + return pathTo(dest, options) + end, + + -- set a global bounding box + -- box can be overridden by passing box in pathfind options + setBox = function(box) + turtle.getState().box = box + end, + + setBlocks = function(blocks) + turtle.getState().blocks = blocks + end, + + reset = function() + turtle.getState().box = nil + turtle.getState().blocks = nil + end, +} diff --git a/sys/apis/ui.lua b/sys/apis/ui.lua index 8fe9571..81e117d 100644 --- a/sys/apis/ui.lua +++ b/sys/apis/ui.lua @@ -1,8 +1,8 @@ local Util = require('util') local class = require('class') local Event = require('event') -local Tween = require('tween') -local Region = require('region') +local Tween = require('ui.tween') +local Region = require('ui.region') local mapColorToGray = { [ colors.white ] = colors.white, diff --git a/sys/apis/fileui.lua b/sys/apis/ui/fileui.lua similarity index 100% rename from sys/apis/fileui.lua rename to sys/apis/ui/fileui.lua diff --git a/sys/apis/glasses.lua b/sys/apis/ui/glasses.lua similarity index 100% rename from sys/apis/glasses.lua rename to sys/apis/ui/glasses.lua diff --git a/sys/apis/region.lua b/sys/apis/ui/region.lua similarity index 100% rename from sys/apis/region.lua rename to sys/apis/ui/region.lua diff --git a/sys/apis/tween.lua b/sys/apis/ui/tween.lua similarity index 100% rename from sys/apis/tween.lua rename to sys/apis/ui/tween.lua diff --git a/sys/apis/util.lua b/sys/apis/util.lua index d282767..d14a779 100644 --- a/sys/apis/util.lua +++ b/sys/apis/util.lua @@ -426,6 +426,10 @@ function Util.matches(str, pattern) return t end +function Util.startsWidth(s, match) + return string.sub(s, 1, #match) == match +end + function Util.widthify(s, len) s = s or '' local slen = #s diff --git a/sys/apps/Overview.lua b/sys/apps/Overview.lua index 9e264d6..70af4ac 100644 --- a/sys/apps/Overview.lua +++ b/sys/apps/Overview.lua @@ -3,14 +3,26 @@ requireInjector(getfenv(1)) local class = require('class') local Config = require('config') local Event = require('event') -local FileUI = require('fileui') +local FileUI = require('ui.fileui') local NFT = require('nft') local SHA1 = require('sha1') -local Tween = require('tween') +local Tween = require('ui.tween') local UI = require('ui') local Util = require('util') local REGISTRY_DIR = 'usr/.registry' +local TEMPLATE = [[ +local env = { } +for k,v in pairs(getfenv(1)) do + env[k] = v +end +setmetatable(env, { __index = _G }) + +local s, m = os.run(env, 'sys/apps/appRun.lua', %s, ...) +if not s then + error(m) +end +]] multishell.setTitle(multishell.getCurrent(), 'Overview') UI:configure('Overview', ...) @@ -39,6 +51,11 @@ local function loadApplications() Util.each(applications, function(v, k) v.key = k end) applications = Util.filter(applications, function(_, a) return not a.disabled end) + + applications = Util.filter(applications, function(_, a) + return Util.startsWidth(a.run, 'http') or shell.resolveProgram(a.run) + end) + end loadApplications() @@ -285,6 +302,7 @@ function page:eventHandler(event) end Config.update('Overview', config) multishell.openTab({ + title = event.button.app.title, path = 'sys/apps/shell', args = { event.button.app.run }, focused = true, diff --git a/sys/apps/Script.lua b/sys/apps/Script.lua index 34ab631..c90545e 100644 --- a/sys/apps/Script.lua +++ b/sys/apps/Script.lua @@ -7,7 +7,7 @@ local UI = require('ui') local Util = require('util') local GROUPS_PATH = 'usr/groups' -local SCRIPTS_PATH = 'sys/etc/scripts' +local SCRIPTS_PATH = 'usr/etc/scripts' multishell.setTitle(multishell.getCurrent(), 'Script') UI:configure('script', ...) diff --git a/sys/apps/Turtles.lua b/sys/apps/Turtles.lua index c011b78..4a445ab 100644 --- a/sys/apps/Turtles.lua +++ b/sys/apps/Turtles.lua @@ -20,8 +20,7 @@ local options = { desc = 'Displays the options' }, } -local USR_SCRIPTS_PATH = 'usr/scripts' -local SYS_SCRIPTS_PATH = 'sys/etc/scripts' +local SCRIPTS_PATH = 'usr/etc/scripts' local nullTerm = Terminal.getNullTerm(term.current()) local turtles = { } @@ -228,21 +227,8 @@ end function page.tabs.scripts:draw() - local function combineDirs(...) - local list = { } - for _,path in pairs({...}) do - if fs.exists(path) then - local files = fs.list(path) - for _,f in pairs(files) do - list[f] = fs.combine(path, f) - end - end - end - return list - end - Util.clear(self.values) - local files = combineDirs(SYS_SCRIPTS_PATH, USR_SCRIPTS_PATH) + local files = fs.list(SCRIPTS_PATH) for f,path in pairs(files) do table.insert(self.values, { label = f, path = path }) end diff --git a/sys/apps/base64dl.lua b/sys/apps/base64dl.lua deleted file mode 100644 index 203b4a1..0000000 --- a/sys/apps/base64dl.lua +++ /dev/null @@ -1,36 +0,0 @@ -requireInjector(getfenv(1)) - -Base64 = require('base64') - -local args = { ... } - -if not args[2] then - error('Syntax: base64dl ') -end - -local c = http.get(args[2]) - -if not c then - error('unable to open url') -end - -local data = c.readAll() -c.close() - -print('size: ' .. #data) -local decoded = Base64.decode(data) -print('decoded: ' .. #decoded) - -local file = io.open(shell.resolve(args[1]), "wb") -if not file then - error('Unable to open ' .. args[1], 2) -end -for k,b in ipairs(decoded) do - if (k % 1000) == 0 then - os.sleep(0) - end - file:write(b) -end - -file:close() -print('done') diff --git a/sys/apps/builder.lua b/sys/apps/builder.lua deleted file mode 100644 index 06a0215..0000000 --- a/sys/apps/builder.lua +++ /dev/null @@ -1,2169 +0,0 @@ -if not turtle and not commands then - error('Must be run on a turtle or a command computer') -end - -requireInjector(getfenv(1)) - -local Blocks = require('blocks') -local class = require('class') -local Event = require('event') -local MEAdapter = require('meAdapter') -local Message = require('message') -local Point = require('point') -local Schematic = require('schematic') -local TableDB = require('tableDB') -local UI = require('ui') -local Util = require('util') - -local ChestAdapter = require('chestAdapter') -if Util.getVersion() == 1.8 then - ChestAdapter = require('chestAdapter18') -end - -if not _G.device then - local Opus = require('opus') - Opus.loadExtensions() -end - -local BUILDER_DIR = 'usr/builder' - -local schematic = Schematic() -local blocks = Blocks({ dir = BUILDER_DIR }) - -local Builder = { - version = '1.71', - isCommandComputer = not turtle, - slots = { }, - index = 1, - mode = 'build', - fuelItem = { id = 'minecraft:coal', dmg = 0 }, - resourceSlots = 14, - facing = 'south', - confirmFacing = false, - wrenchSucks = false, -} - -local pistonFacings - --- Temp functions until conversion to new adapters is complete -local function convertSingleForward(item) - item.name = item.id - item.damage = item.dmg - item.count = item.count - item.maxCount = item.max_size - return item -end - -local function convertForward(t) - for _,v in pairs(t) do - convertSingleForward(v) - end - return t -end - -local function convertSingleBack(item) - if item then - item.id = item.name - item.dmg = item.damage - item.qty = item.count - item.max_size = item.maxCount - item.display_name = item.displayName - end - return item -end - -local function convertBack(t) - for _,v in pairs(t) do - convertSingleBack(v) - end - return t -end - ---[[-- SubDB --]]-- -subDB = TableDB({ - fileName = fs.combine(BUILDER_DIR, 'sub.db'), -}) - -function subDB:load() - if fs.exists(self.fileName) then - TableDB.load(self) - elseif not Builder.isCommandComputer then - self:seedDB() - end -end - -function subDB:seedDB() - self.data = { - [ "minecraft:redstone_wire:0" ] = "minecraft:redstone:0", - [ "minecraft:wall_sign:0" ] = "minecraft:sign:0", - [ "minecraft:standing_sign:0" ] = "minecraft:sign:0", - [ "minecraft:potatoes:0" ] = "minecraft:potato:0", - [ "minecraft:unlit_redstone_torch:0" ] = "minecraft:redstone_torch:0", - [ "minecraft:powered_repeater:0" ] = "minecraft:repeater:0", - [ "minecraft:unpowered_repeater:0" ] = "minecraft:repeater:0", - [ "minecraft:carrots:0" ] = "minecraft:carrot:0", - [ "minecraft:cocoa:0" ] = "minecraft:dye:3", - [ "minecraft:unpowered_comparator:0" ] = "minecraft:comparator:0", - [ "minecraft:powered_comparator:0" ] = "minecraft:comparator:0", - [ "minecraft:piston_head:0" ] = "minecraft:air:0", - [ "minecraft:piston_extension:0" ] = "minecraft:air:0", - [ "minecraft:minecraft:portal:0" ] = "minecraft:air:0", - [ "minecraft:double_wooden_slab:0" ] = "minecraft:planks:0", - [ "minecraft:double_wooden_slab:1" ] = "minecraft:planks:1", - [ "minecraft:double_wooden_slab:2" ] = "minecraft:planks:2", - [ "minecraft:double_wooden_slab:3" ] = "minecraft:planks:3", - [ "minecraft:double_wooden_slab:4" ] = "minecraft:planks:4", - [ "minecraft:double_wooden_slab:5" ] = "minecraft:planks:5", - [ "minecraft:lit_redstone_lamp:0" ] = "minecraft:redstone_lamp:0", - [ "minecraft:double_stone_slab:1" ] = "minecraft:sandstone:0", - [ "minecraft:double_stone_slab:2" ] = "minecraft:planks:0", - [ "minecraft:double_stone_slab:3" ] = "minecraft:cobblestone:0", - [ "minecraft:double_stone_slab:4" ] = "minecraft:brick_block:0", - [ "minecraft:double_stone_slab:5" ] = "minecraft:stonebrick:0", - [ "minecraft:double_stone_slab:6" ] = "minecraft:nether_brick:0", - [ "minecraft:double_stone_slab:7" ] = "minecraft:quartz_block:0", - [ "minecraft:double_stone_slab:9" ] = "minecraft:sandstone:2", - [ "minecraft:double_stone_slab2:0" ] = "minecraft:sandstone:0", - [ "minecraft:stone_slab:2" ] = "minecraft:wooden_slab:0", - [ "minecraft:wheat:0" ] = "minecraft:wheat_seeds:0", - [ "minecraft:flowing_water:0" ] = "minecraft:air:0", - [ "minecraft:lit_furnace:0" ] = "minecraft:furnace:0", - [ "minecraft:wall_banner:0" ] = "minecraft:banner:0", - [ "minecraft:standing_banner:0" ] = "minecraft:banner:0", - [ "minecraft:tripwire:0" ] = "minecraft:string:0", - [ "minecraft:pumpkin_stem:0" ] = "minecraft:pumpkin_seeds:0", - } - self.dirty = true - self:flush() -end - -function subDB:add(s) - TableDB.add(self, { s.id, s.dmg }, table.concat({ s.sid, s.sdmg }, ':')) - self:flush() -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 - id, dmg = self:extract(sub) - end - return { id = id, dmg = dmg } -end - -function subDB:lookupBlocksForSub(sid, sdmg) - local t = { } - for k,v in pairs(self.data) do - local id, dmg = self:extract(v) - if id == sid and dmg == sdmg then - id, dmg = self:extract(k) - t[k] = { id = id, dmg = dmg, sid = sid, sdmg = sdmg } - end - end - return t -end - ---[[-- maxStackDB --]]-- -maxStackDB = TableDB({ - fileName = fs.combine(BUILDER_DIR, 'maxstack.db'), -}) - -function maxStackDB:get(id, dmg) - return self.data[id .. ':' .. dmg] or 64 -end - ---[[-- Spinner --]]-- -UI.Spinner = class() -function UI.Spinner:init(args) - local defaults = { - UIElement = 'Spinner', - timeout = .095, - x = 1, - y = 1, - c = os.clock(), - spinIndex = 0, - spinSymbols = { '-', '/', '|', '\\' } - } - defaults.x, defaults.y = term.getCursorPos() - defaults.startX = defaults.x - defaults.startY = defaults.y - - UI.setProperties(self, defaults) - UI.setProperties(self, args) -end - -function UI.Spinner:spin(text) - local cc = os.clock() - if cc > self.c + self.timeout then - term.setCursorPos(self.x, self.y) - local str = self.spinSymbols[self.spinIndex % #self.spinSymbols + 1] - if text then - str = str .. ' ' .. text - end - term.write(str) - self.spinIndex = self.spinIndex + 1 - os.sleep(0) - self.c = os.clock() - end -end - -function UI.Spinner:stop(text) - term.setCursorPos(self.x, self.y) - local str = string.rep(' ', #self.spinSymbols) - if text then - str = str .. ' ' .. text - end - term.write(str) - term.setCursorPos(self.startX, self.startY) -end - ---[[-- Builder --]]-- -function Builder:getBlockCounts() - local blocks = { } - - -- add a couple essential items to the supply list to allow replacements - if not self.isCommandComputer then - local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0) - wrench.qty = 0 - wrench.need = 1 - blocks[wrench.id .. ':' .. wrench.dmg] = wrench - - local fuel = subDB:getSubstitutedItem(Builder.fuelItem.id, Builder.fuelItem.dmg) - fuel.qty = 0 - fuel.need = 1 - blocks[fuel.id .. ':' .. fuel.dmg] = fuel - - blocks['minecraft:piston:0'] = { - id = 'minecraft:piston', - dmg = 0, - qty = 0, - need = 1, - } - end - - for k,b in ipairs(schematic.blocks) do - if k >= self.index then - local key = tostring(b.id) .. ':' .. b.dmg - local block = blocks[key] - if not block then - block = Util.shallowCopy(b) - block.qty = 0 - block.need = 0 - blocks[key] = block - end - block.need = block.need + 1 - end - end - - return blocks -end - -function Builder:selectItem(id, dmg) - - for k,s in ipairs(self.slots) do - if s.qty > 0 and s.id == id and s.dmg == dmg then - -- check to see if someone pulled items from inventory - -- or we passed over a hopper - if turtle.getItemCount(s.index) > 0 then - if k > 1 and s.qty > 1 then - table.remove(self.slots, k) - table.insert(self.slots, 1, s) - end - turtle.select(s.index) - return s - end - end - end -end - -function Builder:getAirResupplyList(blockIndex) - - local slots = { } - - if self.mode == 'destroy' then - for i = 1, self.resourceSlots do - slots[i] = { - qty = 0, - need = 0, - index = i - } - end - else - slots, _ = self:getGenericSupplyList(blockIndex) - end - - local fuel = subDB:getSubstitutedItem(Builder.fuelItem.id, Builder.fuelItem.dmg) - - slots[15] = { - id = 'minecraft:chest', --'ironchest:BlockIronChest', -- - dmg = 0, - qty = 0, - need = 1, - index = 15, - } - - slots[16] = { - id = fuel.id, - dmg = fuel.dmg, - wrench = true, - qty = 0, - need = 64, - index = 16, - } - - return slots -end - -function Builder:getSupplyList(blockIndex) - - local slots, lastBlock = self:getGenericSupplyList(blockIndex) - - slots[15] = { - id = 'minecraft:piston', - dmg = 0, - qty = 0, - need = 1, - index = 15, - } - - local wrench = subDB:getSubstitutedItem('SubstituteAWrench', 0) - slots[16] = { - id = wrench.id, - dmg = wrench.dmg, - wrench = true, - qty = 0, - need = 1, - index = 16, - } - - self.slots = slots - - return lastBlock -end - -function Builder:getGenericSupplyList(blockIndex) - - local slots = { } - - for i = 1, self.resourceSlots do - slots[i] = { - qty = 0, - need = 0, - index = i - } - end - - local function getSlot(id, dmg) - -- find matching slot - local maxStack = maxStackDB:get(id, dmg) - for _, s in ipairs(slots) do - if s.id == id and s.dmg == dmg and s.need < maxStack then - return s - end - end - -- return first available slot - for _, s in ipairs(slots) do - if not s.id then - s.key = id .. ':' .. dmg - s.id = id - s.dmg = dmg - return s - end - end - end - - local lastBlock = blockIndex - for k = blockIndex, #schematic.blocks do - lastBlock = k - local b = schematic:getComputedBlock(k) - - if b.id ~= 'minecraft:air' then - local slot = getSlot(b.id, b.dmg) - if not slot then - break - end - slot.need = slot.need + 1 - end - end - - for _,s in pairs(slots) do - if s.id then - s.name = blocks.nameDB:getName(s.id, s.dmg) - end - end - - return slots, lastBlock -end - -function Builder:substituteBlocks(throttle) - - for _,b in pairs(schematic.blocks) do - - -- replace schematic block type with substitution - local pb = blocks:getPlaceableBlock(b.id, b.dmg) - - Util.merge(b, pb) - - b.odmg = pb.odmg or pb.dmg - - local sub = subDB:get({ b.id, b.dmg }) - if sub then - b.id, b.dmg = subDB:extract(sub) - end - throttle() - end -end - -function Builder:dumpInventory() - - local success = true - - for i = 1, 16 do - local qty = turtle.getItemCount(i) - if qty > 0 then - self.itemAdapter:insert(i, qty) - end - if turtle.getItemCount(i) ~= 0 then - success = false - end - end - turtle.select(1) - - return success -end - -function Builder:dumpInventoryWithCheck() - - while not self:dumpInventory() do - print('Storage is full or missing - make space or replace') - print('Press enter to continue') - turtle.setHeading(0) - read() - end -end - -function Builder:autocraft(supplies) - local t = { } - - for i,s in pairs(supplies) do - local key = s.id .. ':' .. s.dmg - local item = t[key] - if not item then - item = { - id = s.id, - dmg = s.dmg, - qty = 0, - } - t[key] = item - end - item.qty = item.qty + (s.need - s.qty) - end - - Builder.itemAdapter:craftItems(convertForward(t)) -end - -function Builder:getSupplies() - - self.itemAdapter:refresh() - - local t = { } - for _,s in ipairs(self.slots) do - if s.need > 0 then - local item = convertSingleBack(self.itemAdapter:getItemInfo(s.id, s.dmg)) - if item then - s.name = item.display_name - - local qty = math.min(s.need - s.qty, item.qty) - - if qty + s.qty > item.max_size then - maxStackDB:add({ s.id, s.dmg }, item.max_size) - maxStackDB.dirty = true - maxStackDB:flush() - qty = item.max_size - s.need = qty - end - if qty > 0 then - self.itemAdapter:provide(convertSingleForward(item), qty, s.index) - s.qty = turtle.getItemCount(s.index) - end - else - s.name = blocks.nameDB:getName(s.id, s.dmg) - end - end - if s.qty < s.need then - table.insert(t, s) - end - end - - return t -end - -Event.on('build', function() - Builder:build() -end) - -function Builder:refuel() - while turtle.getFuelLevel() < 4000 and self.fuelItem do - print('Refueling') - turtle.select(1) - - local fuel = subDB:getSubstitutedItem(self.fuelItem.id, self.fuelItem.dmg) - - self.itemAdapter:provide(convertSingleForward(fuel), 64, 1) - if turtle.getItemCount(1) == 0 then - print('Out of fuel, add fuel to chest/ME system') - turtle.setHeading(0) - turtle.status = 'waiting' - os.sleep(5) - else - turtle.refuel(64) - end - end -end - -function Builder:inAirDropoff() - if not device.wireless_modem then - return false - end - - self:log('Requesting air supply drop for supply #: ' .. 1) - while true do - Message.broadcast('needSupplies', { point = turtle.getPoint(), uid = 1 }) - local _, id, msg, _ = Message.waitForMessage('gotSupplies', 1) - - if not msg or not msg.contents then - Message.broadcast('supplyList', { uid = 1, slots = self:getAirResupplyList() }) - return false - end - - turtle.status = 'waiting' - - if msg.contents.point then - local pt = msg.contents.point - - self:log('Received supply location') - os.sleep(0) - - turtle.goto(pt.x, pt.z, pt.y) - os.sleep(.1) -- random computer is not connected error - - local chestAdapter = ChestAdapter({ direction = 'down', wrapSide = 'top' }) - - if not chestAdapter:isValid() then - self:log('Chests above is not valid') - return false - end - - local oldAdapter = self.itemAdapter - self.itemAdapter = chestAdapter - - if not self:dumpInventory() then - self:log('Unable to dump inventory') - self.itemAdapter = oldAdapter - return false - end - - self.itemAdapter = oldAdapter - - Message.broadcast('thanks', { }) - - for i = 1,12 do -- wait til supplier is idle before sending next request - if turtle.detectUp() then - os.sleep(.25) - end - end - os.sleep(.1) - - Message.broadcast('supplyList', { uid = 1, slots = self:getAirResupplyList() }) - - return true - end - end -end - -function Builder:inAirResupply() - - if not device.wireless_modem then - return false - end - - local oldAdapter = self.itemAdapter - - self:log('Requesting air supply drop for supply #: ' .. self.slotUid) - while true do - Message.broadcast('needSupplies', { point = turtle.getPoint(), uid = Builder.slotUid }) - local _, id, msg, _ = Message.waitForMessage('gotSupplies', 1) - - if not msg or not msg.contents then - self.itemAdapter = oldAdapter - return false - end - - turtle.status = 'waiting' - - if msg.contents.point then - local pt = msg.contents.point - - self:log('Received supply location') - os.sleep(0) - - turtle.goto(pt.x, pt.z, pt.y) - os.sleep(.1) -- random computer is not connected error - - local chestAdapter = ChestAdapter({ direction = 'down', wrapSide = 'top' }) - - if not chestAdapter:isValid() then - Util.print('not valid') - read() - end - - self.itemAdapter = chestAdapter - - if not self:dumpInventory() then - self.itemAdapter = oldAdapter - return false - end - self:refuel() - - local lastBlock = self:getSupplyList(self.index) - local supplies = self:getSupplies() - - Message.broadcast('thanks', { }) - - self.itemAdapter = oldAdapter - - if #supplies == 0 then - - for i = 1,12 do -- wait til supplier is idle before sending next request - if turtle.detectUp() then - os.sleep(.25) - end - end - os.sleep(.1) - if lastBlock < #schematic.blocks then - self:sendSupplyRequest(lastBlock) - else - Message.broadcast('finished') - end - - return true - end - self:log('Missing supplies - manually resupplying') - return false - end - end -end - -function Builder:sendSupplyRequest(lastBlock) - - if device.wireless_modem then - local slots = self:getAirResupplyList(lastBlock) - self.slotUid = os.clock() - - Message.broadcast('supplyList', { uid = self.slotUid, slots = slots }) - end -end - -function Builder:resupply() - - if self.slotUid and self:inAirResupply() then - os.queueEvent('build') - return - end - - turtle.status = 'resupplying' - - self:log('Resupplying') - turtle.gotoYlast(turtle.getLocation('supplies')) - os.sleep(.1) -- random 'Computer is not connected' error... - self:dumpInventoryWithCheck() - self:refuel() - local lastBlock = self:getSupplyList(self.index) - if lastBlock < #schematic.blocks then - self:sendSupplyRequest(lastBlock) - elseif device.wireless_modem then - Message.broadcast('finished') - end - os.sleep(1) - local supplies = self:getSupplies() - - if #supplies == 0 then - os.queueEvent('build') - else - turtle.setHeading(0) - self:autocraft(supplies) - supplyPage:setSupplies(supplies) - UI:setPage('supply') - end -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 - -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 Util.getVersion() == 1.8 then - - local directions = { -- reversed directions - [5] = 'west', - [3] = 'north', - [4] = 'east', - [2] = 'south', - } - - if self:selectItem('minecraft:piston', 0) then - turtle.placeUp() - local _, bi = turtle.inspectUp() - turtle.digUp() - return directions[bi.metadata] - end - return - end - return Builder.facing -end - -function Builder:wrenchBlock(side, facing, cache) - - local s = Builder:getWrenchSlot() - - if not s then - b.needResupply = true - return false - end - - local key = turtle.point.heading .. '-' .. facing - if cache then - local count = cache[side][key] - - if count then - turtle.select(s.index) - for i = 1,count do - turtle.getAction(side).place() - end - return true - end - end - - local directions = { - [5] = 'east', - [3] = 'south', - [4] = 'west', - [2] = 'north', - [0] = 'down', - [1] = 'up', - } - - if turtle.getHeadingInfo(facing).heading < 4 then - local offsetDirection = (turtle.getHeadingInfo(Builder.facing).heading + - turtle.getHeadingInfo(facing).heading) % 4 - facing = turtle.getHeadingInfo(offsetDirection).direction - end - - count = 0 - print('determining wrench count') - for i = 1, 6 do - local _, bi = turtle.getAction(side).inspect() - - if facing == directions[bi.metadata] then - if cache then - cache[side][key] = count - end - return true - end - count = count + 1 - turtle.getAction(side).place() - end - - 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) - - local ps = Builder:selectItem('minecraft:piston', 0) - local ws = Builder:getWrenchSlot() - - if not ps or not ws then - b.needResupply = true - -- a hopper may have eaten the piston - return - end - - if not turtle.place(ps.index) then - return - end - - if self.wrenchSucks then - turtle.turnRight() - turtle.forward() - turtle.turnLeft() - turtle.forward() - turtle.turnLeft() - end - - local success = self:wrenchBlock('forward', 'down', pistonFacings) --wrench piston to point downwards - - rs.setOutput('front', true) - os.sleep(.25) - rs.setOutput('front', false) - os.sleep(.25) - turtle.select(ps.index) - turtle.dig() - - if not success and not self.wrenchSucks then - self.wrenchSucks = true - success = self:placePiston(b) - end - - return success -end - -function Builder:goto(x, z, y, heading) - if not turtle.goto(x, z, y, heading) then - print('stuck') - print('Press enter to continue') - os.sleep(1) - turtle.status = 'stuck' - read() - end -end - --- goto used when turtle could be below travel plane --- if the distance is no more than 1 block, there's no need to pop back to the travel plane -function Builder:gotoEx(x, z, y, h, travelPlane) - local distance = math.abs(turtle.getPoint().x - x) + math.abs(turtle.getPoint().z - z) - - -- following code could be better - if distance == 0 then - turtle.gotoY(y) - elseif distance == 1 then - if turtle.point.y < y then - turtle.gotoY(y) - end - elseif distance > 1 then - self:gotoTravelPlane(travelPlane) - end - self:goto(x, z, y, h) -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 } - end - - local directions = { - [ 'north' ] = 'north', - [ 'south' ] = 'south', - [ 'east' ] = 'east', - [ 'west' ] = 'west', - } - if directions[d] then - 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 - turtle.goback() - b.placed = self:placePiston(b) - end - end - - if d == 'bottom' then - local t = { - [1] = getAdjacentPoint(b, 'east'), - [2] = getAdjacentPoint(b, 'south'), - [3] = getAdjacentPoint(b, 'west'), - [4] = getAdjacentPoint(b, 'north'), - } - - local c = Point.closest(turtle.getPoint(), t) - self:gotoEx(c.x, c.z, c.y, c.heading, travelPlane) - - if self:place(slot) then - turtle.up() - b.placed = self:placePiston(b) - end - end - - local stairDownDirections = { - [ 'north-down' ] = 'north', - [ 'south-down' ] = 'south', - [ 'east-down' ] = 'east', - [ 'west-down' ] = 'west' - } - if stairDownDirections[d] then - self:gotoEx(b.x, b.z, b.y+1, turtle.getHeadingInfo(stairDownDirections[d]).heading, travelPlane) - if self:placeDown(slot) then - turtle.goback() - b.placed = self:placePiston(b) - end - end - - local stairUpDirections = { - [ 'north-up' ] = 'south', - [ 'south-up' ] = 'north', - [ 'east-up' ] = 'west', - [ 'west-up' ] = 'east' - } - if stairUpDirections[d] then - - local isSouth = (turtle.getHeadingInfo(Builder.facing).heading + - turtle.getHeadingInfo(stairUpDirections[d]).heading) % 4 == 1 - - if Util.getVersion() == 1.8 then - isSouth = false -- no stair bug in this version - end - - if isSouth then - - -- for some reason, the south facing stair doesn't place correctly - -- jump through some hoops to place it - self:gotoEx(b.x, b.z, b.y, (turtle.getHeadingInfo(stairUpDirections[d]).heading + 2) % 4, travelPlane) - if self:placeUp(slot) then - turtle.goback() - turtle.gotoY(turtle.point.y + 2) - b.placed = self:placePiston(b) - turtle.down() - b.placed = self:placePiston(b) - - b.heading = turtle.point.heading -- stop debug message below since we are pointing in wrong direction - end - else - local hi = turtle.getHeadingInfo(stairUpDirections[d]) - self:gotoEx(b.x - hi.xd, b.z - hi.zd, b.y, hi.heading, travelPlane) - if self:place(slot) then - turtle.up() - b.placed = self:placePiston(b) - end - end - end - - local horizontalDirections = { - [ 'east-west-block' ] = { 'east', 'west' }, - [ 'north-south-block' ] = { 'north', 'south' }, - } - if horizontalDirections[d] then - - local t = { - [1] = getAdjacentPoint(b, horizontalDirections[d][1]), - [2] = getAdjacentPoint(b, horizontalDirections[d][2]), - } - - local c = Point.closest(turtle.getPoint(), t) - self:gotoEx(c.x, c.z, c.y, c.heading, travelPlane) - - if self:place(slot) then - turtle.up() - b.placed = self:placePiston(b) - end - end - - local pistonDirections = { - [ 'piston-north' ] = 'north', - [ 'piston-south' ] = 'south', - [ 'piston-west' ] = 'west', - [ 'piston-east' ] = 'east', - [ 'piston-down' ] = 'down', - [ 'piston-up' ] = 'up', - } - - if pistonDirections[d] then - -- why are pistons so broke in cc 1.7 ?????????????????????? - - local ws = Builder:getWrenchSlot() - - if not ws then - b.needResupply = true - -- a hopper may have eaten the piston - return false - end - - -- piston turns relative to turtle position :) - local rotatedPistonDirections = { - [ 'piston-east' ] = 0, - [ 'piston-south' ] = 1, - [ 'piston-west' ] = 2, - [ 'piston-north' ] = 3, - } - - self:gotoEx(b.x, b.z, b.y, nil, travelPlane) - - local heading = rotatedPistonDirections[d] - if heading and turtle.point.heading % 2 ~= heading % 2 then - turtle.setHeading(heading) - end - - if self:placeDown(slot) then - 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', - [ 'west-door' ] = 'west', - [ 'north-door' ] = 'north', - } - if doorDirections[d] then - local hi = turtle.getHeadingInfo(doorDirections[d]) - 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', - [ 'east-block' ] = 'east', - [ 'west-block' ] = 'west', - } - if blockDirections[d] then - local hi = turtle.getHeadingInfo(blockDirections[d]) - self:gotoEx(b.x - hi.xd, b.z - hi.zd, b.y-1, hi.heading, travelPlane) - b.placed = self:place(slot) - end - - if b.facing then - self:rotateBlock('down', b.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 - self:log(d .. ' - ' .. turtle.getHeading() .. ' - ' .. (b.heading or 'nil')) - --read() - end -end - - return b.placed -end - -function Builder:reloadSchematic(throttle) - schematic:reload(throttle) - self:substituteBlocks(throttle) -end - -function Builder:log(...) - Util.print(...) -end - -function Builder:logBlock(index, b) - local bdir = b.direction or '' - local logText = string.format('%d %s:%d (x:%d,z:%d:y:%d) %s', - index, b.id, b.dmg, b.x, b.z, b.y, bdir) - self:log(logText) - -- self:log(b.index) -- unique identifier of block - - if device.wireless_modem then - Message.broadcast('builder', { x = b.x, y = b.y, z = b.z, heading = b.heading }) - end -end - -function Builder:saveProgress(index) - Util.writeTable( - fs.combine(BUILDER_DIR, schematic.filename .. '.progress'), - { index = index, facing = Builder.facing } - ) -end - -function Builder:loadProgress(filename) - local progress = Util.readTable(fs.combine(BUILDER_DIR, filename)) - if progress then - Builder.index = progress.index - if Builder.index > #schematic.blocks then - Builder.index = 1 - end - Builder.facing = progress.facing or 'south' - end -end - --- find the highest y in the last 2 planes -function Builder:findTravelPlane(index) - - local travelPlane - - for i = index, 1, -1 do - local b = schematic.blocks[i] - - local y = b.y - if b.twoHigh then - y = y + 1 - end - if not travelPlane or y > travelPlane then - travelPlane = y - elseif travelPlane and travelPlane - y > 2 then - break - end - end - - return travelPlane or 0 -end - -function Builder:gotoTravelPlane(travelPlane) - if travelPlane > turtle.point.y then - 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 - local throttle = Util.throttle() - - if self.mode == 'destroy' then - direction = -1 - last = 1 - turtle.status = 'destroying' - elseif not self.isCommandComputer then - travelPlane = self:findTravelPlane(self.index) - turtle.status = 'building' - if not self.confirmFacing then - local facing = self:getTurtleFacing() - if facing then - self.confirmFacing = true - self.facing = facing - 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.isCommandComputer then - self:logBlock(self.index, b) - - local id = b.id - if self.mode == 'destroy' then - id = 'minecraft:air' - end - - local function placeBlock(id, dmg, x, y, z) - - local cx, cy, cz = commands.getBlockPosition() - - local command = table.concat({ - "setblock", - cx + x + 1, - "~" .. y, - cz + z + 1, - id, - dmg, - }, ' ') - - commands.execAsync(command) - - local result = { os.pullEvent("task_complete") } - if not result[4] then - Util.print(result[5]) - if self.mode ~= 'destroy' then - read() - end - end - end - - placeBlock(id, b.odmg, b.x, b.y, b.z) - - if b.twoHigh then - local _, topBlock = schematic:findIndexAt(b.x, b.z, b.y + 1, true) - if topBlock then - placeBlock(id, topBlock.odmg, b.x, b.y + 1, b.z) - end - end - - elseif self.mode == 'destroy' then - - b.heading = nil -- don't make the supplier follow the block heading - self:logBlock(self.index, b) - if b.y ~= turtle.getPoint().y then - turtle.gotoY(b.y) - end - self:goto(b.x, b.z, b.y) - turtle.digDown() - - -- if no supplier, then should fill all slots - - if turtle.getItemCount(self.resourceSlots) > 0 or turtle.getFuelLevel() < minFuel then - if turtle.getFuelLevel() < minFuel or not self:inAirDropoff() then - turtle.gotoLocation('supplies') - os.sleep(.1) -- random 'Computer is not connected' error... - self:dumpInventoryWithCheck() - self:refuel() - end - turtle.status = 'destroying' - end - - else -- Build mode - - local slot = Builder:selectItem(b.id, b.dmg) - if not slot or turtle.getFuelLevel() < minFuel then - - if turtle.getPoint().x > -1 or turtle.getPoint().z > -1 then - self:gotoTravelPlane(travelPlane) - end - self:resupply() - return - end - local y = b.y - if b.twoHigh then - y = b.y + 1 - end - if y > travelPlane then - travelPlane = y - end - - self:logBlock(self.index, b) - - if b.direction then - b.needResupply = false - self:placeDirectionalBlock(b, slot, travelPlane) - if b.needResupply then -- lost our piston in a hopper probably - self:gotoTravelPlane(travelPlane) - self:resupply() - return - end - else - self:gotoTravelPlane(travelPlane) - self:goto(b.x, b.z, b.y) - b.placed = self:placeDown(slot) - end - - if b.placed then - slot.qty = slot.qty - 1 - else - print('failed to place block') - end - end - if self.mode == 'destroy' then - self:saveProgress(math.max(self.index, 1)) - else - self:saveProgress(self.index + 1) - end - else - throttle() -- sleep in case there are a large # of skipped blocks - end - - if turtle.abort then - turtle.status = 'aborting' - self:gotoTravelPlane(travelPlane) - turtle.gotoLocation('supplies') - turtle.setHeading(0) - Builder:dumpInventory() - Event.exitPullEvents() - UI.term:reset() - print('Aborted') - return - end - end - - if device.wireless_modem then - Message.broadcast('finished') - end - if not self.isCommandComputer then - self:gotoTravelPlane(travelPlane) - turtle.gotoLocation('supplies') - turtle.setHeading(0) - Builder:dumpInventory() - - for i = 1, 4 do - turtle.turnRight() - end - end - ---self.index = 1 ---os.queueEvent('build') - --UI.term:reset() - fs.delete(schematic.filename .. '.progress') - print('Finished') - Event.exitPullEvents() -end - ---[[-- blankPage --]]-- -blankPage = UI.Page() -function blankPage:draw() - self:clear() - self:setCursorPos(1, 1) -end - -function blankPage:enable() - self:sync() - UI.Page.enable(self) -end - ---[[-- selectSubstitutionPage --]]-- -selectSubstitutionPage = UI.Page({ - titleBar = UI.TitleBar({ - title = 'Select a substitution', - previousPage = 'listing' - }), - grid = UI.ScrollingGrid({ - columns = { - { heading = 'id', key = 'id' }, - { heading = 'dmg', key = 'dmg' }, - }, - sortColumn = 'id', - height = UI.term.height-1, - autospace = true, - y = 2, - }), -}) - -function selectSubstitutionPage:enable() - self.grid:adjustWidth() - self.grid:setIndex(1) - UI.Page.enable(self) -end - -function selectSubstitutionPage:eventHandler(event) - - if event.type == 'grid_select' then - substitutionPage.sub = event.selected - UI:setPage(substitutionPage) - elseif event.type == 'key' and event.key == 'q' then - UI:setPreviousPage() - else - return UI.Page.eventHandler(self, event) - end - return true -end - ---[[-- substitutionPage --]]-- -substitutionPage = UI.Page { - backgroundColor = colors.gray, - titleBar = UI.TitleBar { - previousPage = true, - title = 'Substitute a block' - }, - 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 { - columns = { - { 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, - }, - throttle = UI.Throttle { }, - statusBar = UI.StatusBar { } -} - -substitutionPage.menuBar:add({ - filterLabel = UI.Text({ - value = 'Search', - x = UI.term.width-14, - textColor = colors.black, - }), - filter = UI.TextEntry({ - x = UI.term.width-7, - width = 7, - }) -}) - -function substitutionPage.info:draw() - - local sub = self.parent.sub - local inName = blocks.nameDB:getName(sub.id, sub.dmg) - local outName = '' - if sub.sid then - outName = blocks.nameDB:getName(sub.sid, sub.sdmg) - end - - self:clear() - self:setCursorPos(1, 1) - self:print(' Replace ' .. inName .. '\n') - self:print(' ' .. sub.id .. ':' .. sub.dmg .. '\n', nil, colors.yellow) - self:print(' With ' .. outName) -end - -function substitutionPage:enable() - - self.allItems = convertBack(Builder.itemAdapter: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.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) - UI.Page.enable(self) -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.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 - self.grid.values = self.allItems - else - self.grid.values = { } - for _,item in pairs(self.allItems) do - if string.find(item.lname, text) then - table.insert(self.grid.values, item) - end - end - end - --self.grid:adjustWidth() - 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 - - if event.type == 'revert' then - subDB:remove(self.sub) - elseif not self.sub.sid then - self.statusBar:setStatus('Select a substition') - self.statusBar:draw() - return UI.Page.eventHandler(self, event) - else - subDB:add(self.sub) - end - - 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 { - title = 'Waiting for supplies', - previousPage = 'start' - }, - menuBar = UI.MenuBar { - y = 2, - buttons = { - --{ text = 'Refresh', event = 'refresh', help = 'Refresh inventory' }, - { text = 'Continue', event = 'build', help = 'Continue building' }, - { text = 'Menu', event = 'menu', help = 'Return to main menu' }, - { text = 'Force Craft', event = 'craft', help = 'Request crafting (again)' }, - } - }, - grid = UI.Grid { - columns = { - { heading = 'Name', key = 'name', width = UI.term.width - 7 }, - { heading = 'Need', key = 'need', width = 4 }, - }, - sortColumn = 'name', - y = 3, - width = UI.term.width, - height = UI.term.height - 3 - }, - 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.itemAdapter:craft(s.id, s.dmg, s.need-s.qty) then - local name = s.name or '' - self.statusBar:timedStatus('Requested ' .. s.need-s.qty .. ' ' .. name, 3) - 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() - - 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)) - - Event.addNamedTimer('supplyRefresh', 6, true, function() - if self.enabled then - Builder:autocraft(Builder:getSupplies()) - self:refresh() - self.statusBar:timedStatus('Refreshed ', 2) - self:sync() - end - end) - UI.Page.enable(self) -end - -function supplyPage:disable() - Event.cancelNamedTimer('supplyRefresh') -end - -function supplyPage:setSupplies(supplies) - local t = { } - for _,s in pairs(supplies) do - local key = s.id .. ':' .. s.dmg - local entry = t[key] - if not entry then - entry = Util.shallowCopy(s) - t[key] = entry - else - entry.need = entry.need + s.need - end - entry.need = entry.need - turtle.getItemCount(s.index) - end - - self.grid:setValues(t) -end - -function supplyPage:refresh() - self.statusBar:timedStatus('Refreshed ', 3) - local supplies = Builder:getSupplies() - if #supplies == 0 then - Builder:build() - else - self:setSupplies(supplies) - self.grid:draw() - end -end - ---[[-- ListingPage --]]-- -listingPage = UI.Page({ - titleBar = UI.TitleBar({ - title = 'Supply List', - previousPage = 'start' - }), - menuBar = UI.MenuBar({ - y = 2, - buttons = { - { text = 'Craft', event = 'craft', help = 'Request crafting' }, - { text = 'Refresh', event = 'refresh', help = 'Refresh inventory' }, - { text = 'Toggle', event = 'toggle', help = 'Toggles needed blocks' }, - { text = 'Substitute', event = 'edit', help = 'Substitute a block' }, - } - }), - grid = UI.ScrollingGrid({ - columns = { - { heading = 'Name', key = 'name', width = UI.term.width - 14 }, - { heading = 'Need', key = 'need', width = 5 }, - { heading = 'Have', key = 'qty', width = 5 }, - }, - sortColumn = 'name', - y = 3, - height = UI.term.height-3, - help = 'Set a block type or pick a substitute block' - }), - accelerators = { - q = 'menu', - c = 'craft', - r = 'refresh', - t = 'toggle', - }, - statusBar = UI.StatusBar(), - fullList = true -}) - -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 = convertSingleBack(Builder.itemAdapter:getItemInfo(s.id, s.dmg)) - if item and item.is_craftable then - local qty = math.max(0, s.need - item.qty) - - if item then - Builder.itemAdapter:craft(s.id, s.dmg, qty) - local name = s.name or s.key - self.statusBar:timedStatus('Requested ' .. qty .. ' ' .. name, 3) - end - else - self.statusBar:timedStatus('Unable to craft') - end - - elseif event.type == 'grid_focus_row' then - self.statusBar:setStatus(event.selected.id .. ':' .. event.selected.dmg) - self.statusBar:draw() - - elseif event.type == 'refresh' then - 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 - -function listingPage.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - row.need = Util.toBytes(row.need) - row.qty = Util.toBytes(row.qty) - return row -end - -function listingPage.grid:getRowTextColor(row, selected) - if row.is_craftable then - return colors.yellow - end - return UI.Grid:getRowTextColor(row, selected) -end - -function listingPage:refresh(throttle) - - local supplyList = Builder:getBlockCounts() - - Builder.itemAdapter:refresh(throttle) - - for _,b in pairs(supplyList) do - if b.need > 0 then - local item = convertSingleBack(Builder.itemAdapter:getItemInfo(b.id, b.dmg)) - - if item then - local block = blocks.blockDB:lookup(b.id, b.dmg) - if not block then - 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.display_name - b.qty = item.qty - b.is_craftable = item.is_craftable - else - b.name = blocks.nameDB:getName(b.id, b.dmg) - end - end - if throttle then - throttle() - end - end - blocks.nameDB:flush() - - if self.fullList then - self.grid:setValues(supplyList) - else - local t = {} - for _,b in pairs(supplyList) do - if self.fullList or b.qty < b.need then - table.insert(t, b) - end - end - self.grid:setValues(t) - end - self.grid:setIndex(1) -end - -function listingPage:manageBlock(selected) - - local substitutes = subDB:lookupBlocksForSub(selected.id, selected.dmg) - - if Util.empty(substitutes) then - substitutionPage.sub = { id = selected.id, dmg = selected.dmg } - UI:setPage(substitutionPage) - elseif Util.size(substitutes) == 1 then - local _,sub = next(substitutes) - substitutionPage.sub = sub - UI:setPage(substitutionPage) - else - selectSubstitutionPage.selected = selected - selectSubstitutionPage.grid:setValues(substitutes) - UI:setPage(selectSubstitutionPage) - end -end - ---[[-- startPage --]]-- - -local wy = 2 -local my = 4 - -if UI.term.width < 30 then - wy = 9 - my = 2 -end - -local startPage = UI.Page { - -- titleBar = UI.TitleBar({ title = 'Builder v' .. Builder.version }), - window = UI.Window { - x = UI.term.width-16, - y = wy, - width = 16, - height = 9, - backgroundColor = colors.gray, - grid = UI.Grid { - columns = { - { heading = 'Name', key = 'name', width = 6 }, - { heading = 'Value', key = 'value', width = 7 }, - }, - disableHeader = true, - --y = UI.term.height-1, - x = 1, - y = 2, - width = 16, - height = 9, - --autospace = true, - selectable = false, - backgroundColor = colors.gray - }, - }, - menu = UI.Menu { - x = 2, - y = my, - height = 7, - menuItems = { - { prompt = 'Set starting level', event = 'startLevel' }, - { prompt = 'Set starting block', event = 'startBlock' }, - { prompt = 'Supply list', event = 'assignBlocks' }, - { prompt = 'Toggle mode', event = 'toggleMode' }, - { prompt = 'Toggle facing', event = 'toggleFacing' }, - { 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 - fuel = string.format('%dk', math.floor(fuel/1024)) - end - local t = { - { name = 'mode', value = Builder.mode }, - { name = 'start', value = Builder.index }, - { name = 'blocks', value = #schematic.blocks }, - --{ name = 'fuel', value = fuel }, - { name = 'facing', value = Builder.facing }, - { name = 'length', value = schematic.length }, - { name = 'width', value = schematic.width }, - { name = 'height', value = schematic.height }, - } - - self.window.grid:setValues(t) - UI.Page.draw(self) -end - -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', - height = 7, - form = UI.Form { - y = 3, x = 2, height = 4, - text = UI.Text({ x = 5, y = 1, textColor = colors.gray, value = '0 - ' .. schematic.height }), - textEntry = UI.TextEntry({ x = 15, y = 1, '0 - 11', width = 7 }), - }, - statusBar = UI.StatusBar(), - }) - - dialog.eventHandler = function(self, event) - if event.type == 'form_complete' then - local l = tonumber(self.form.textEntry.value) - if l and l < schematic.height and l >= 0 then - for k,v in pairs(schematic.blocks) do - if v.y >= l then - Builder.index = k - Builder:saveProgress(Builder.index) - UI:setPreviousPage() - break - end - end - else - self.statusBar:timedStatus('Invalid Level', 3) - end - elseif event.type == 'form_cancel' or event.type == 'cancel' then - UI:setPreviousPage() - else - return UI.Dialog.eventHandler(self, 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', - height = 7, - form = UI.Form { - y = 3, x = 2, height = 4, - text = UI.Text { x = 2, y = 1, value = '1 - ' .. #schematic.blocks, textColor = colors.gray }, - textEntry = UI.TextEntry { x = 16, y = 1, value = tostring(Builder.index), width = 10, limit = 8 } - }, - statusBar = UI.StatusBar(), - } - - dialog.eventHandler = function(self, event) - if event.type == 'form_complete' then - local bn = tonumber(self.form.textEntry.value) - if bn and bn < #schematic.blocks and bn >= 0 then - Builder.index = bn - Builder:saveProgress(Builder.index) - UI:setPreviousPage() - else - self.statusBar:timedStatus('Invalid Block', 3) - end - elseif event.type == 'form_cancel' or event.type == 'cancel' then - UI:setPreviousPage() - else - return UI.Dialog.eventHandler(self, 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', function() self.throttle:update() end) - self.throttle:disable() - - elseif event.type == 'toggleMode' then - if Builder.mode == 'build' then - if Builder.index == 1 then - Builder.index = #schematic.blocks - end - Builder.mode = 'destroy' - else - if Builder.index == #schematic.blocks then - Builder.index = 1 - end - Builder.mode = 'build' - end - self:draw() - - elseif event.type == 'toggleFacing' then - local directions = { - [ 'north' ] = 'east', - [ 'east' ] = 'south', - [ 'south' ] = 'west', - [ 'west' ] = 'north', - } - - 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(Util.throttle()) - Builder:dumpInventory() - Builder:refuel() - - if Builder.mode == 'destroy' then - if device.wireless_modem then - Message.broadcast('supplyList', { uid = 1, slots = Builder:getAirResupplyList() }) - end - print('Beginning destruction') - else - print('Starting build') - end - - -- reset piston cache in case wrench was substituted - pistonFacings = { - down = { }, - forward = { }, - } - - Builder:build() - - elseif event.type == 'quit' then - UI.term:reset() - Event.exitPullEvents() - end - - return UI.Page.eventHandler(self, event) -end - ---[[-- startup logic --]]-- -local args = {...} -if #args < 1 then - error('supply file name') -end - -Builder.itemAdapter = MEAdapter() -if not Builder.itemAdapter:isValid() then - Builder.itemAdapter = ChestAdapter() - if not Builder.itemAdapter:isValid() then - error('A chest or ME interface must be below turtle') - end -end - -if commands then - turtle = { - policies = { }, - point = { x = -1, y = 0, z = -1, heading = 0 }, - getFuelLevel = function() return 20000 end, - select = function() end, - getItemCount = function() return 0 end, - getHeadingInfo = function(heading) - local headings = { - [ 0 ] = { xd = 1, zd = 0, yd = 0, heading = 0, direction = 'east' }, - [ 1 ] = { xd = 0, zd = 1, yd = 0, heading = 1, direction = 'south' }, - [ 2 ] = { xd = -1, zd = 0, yd = 0, heading = 2, direction = 'west' }, - [ 3 ] = { xd = 0, zd = -1, yd = 0, heading = 3, direction = 'north' }, - [ 4 ] = { xd = 0, zd = 0, yd = 1, heading = 4, direction = 'up' }, - [ 5 ] = { xd = 0, zd = 0, yd = -1, heading = 5, direction = 'down' } - } - local namedHeadings = { - east = headings[0], - south = headings[1], - west = headings[2], - north = headings[3], - up = headings[4], - down = headings[5] - } - if heading and type(heading) == 'string' then - return namedHeadings[heading] - end - heading = heading or 0 - return headings[heading] - end, - } -end - -multishell.setTitle(multishell.getCurrent(), 'Builder v' .. Builder.version) - -maxStackDB:load() -subDB:load() - -UI.term:reset() -turtle.status = 'reading' -print('Loading schematic') -schematic:load(args[1]) -print('Substituting blocks') - -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, - supply = supplyPage, - blank = blankPage -}) - -UI:setPage('start') - -if Builder.isCommandComputer then - Event.pullEvents() -else - local s, m = turtle.run(function() - turtle.setPolicy(turtle.policies.digAttack) - turtle.setPoint({ x = -1, z = -1, y = 0, heading = 0 }) - turtle.saveLocation('supplies') - Event.pullEvents() - end) -end diff --git a/sys/apps/chestManager.lua b/sys/apps/chestManager.lua deleted file mode 100644 index 03f2a38..0000000 --- a/sys/apps/chestManager.lua +++ /dev/null @@ -1,939 +0,0 @@ -requireInjector(getfenv(1)) - -local ChestAdapter = require('chestAdapter18') -local Config = require('config') -local Craft = require('turtle.craft') -local Event = require('event') -local itemDB = require('itemDB') -local Peripheral = require('peripheral') -local RefinedAdapter = require('refinedAdapter') -local Terminal = require('terminal') -local UI = require('ui') -local Util = require('util') - -multishell.setTitle(multishell.getCurrent(), 'Resource Manager') - --- 3 wide monitor (any side of turtle) - --- Config location is /sys/config/resourceManager --- adjust directions in that file if needed - -local config = { - trashDirection = 'up', -- trash /chest in relation to chest - turtleDirection = 'down', -- turtle in relation to chest -} - -Config.load('resourceManager', config) - -local controller = RefinedAdapter() -if not controller:isValid() then --- error('Refined storage controller not found') - controller = nil -end - -local chestAdapter = ChestAdapter({ direction = 'west', wrapSide = 'back' }) -local turtleChestAdapter = ChestAdapter({ direction = 'up', wrapSide = 'bottom' }) - -local RESOURCE_FILE = 'usr/etc/resources.db' -local RECIPES_FILE = 'sys/etc/recipes.db' - -local jobListGrid -local craftingPaused = false -local recipes = Util.readTable(RECIPES_FILE) or { } -local resources = Util.readTable(RESOURCE_FILE) or { } - -Craft.setRecipes(recipes) - -for _,r in pairs(resources) do - r.maxDamage = nil - r.displayName = nil - r.count = nil - r.lname = nil - r.has_recipe = nil - - if not r.ignoreDamage then - r.ignoreDamage = nil - end - - if not r.auto then - r.auto = nil - end -end -Util.writeTable(RESOURCE_FILE, resources) - -local function getItem(items, inItem, ignoreDamage) - for _,item in pairs(items) do - if item.name == inItem.name then - if ignoreDamage then - return item - elseif item.damage == inItem.damage and item.nbtHash == inItem.nbtHash then - return item - end - end - end -end - -local function splitKey(key) - local t = Util.split(key, '(.-):') - local item = { } - if #t[#t] > 2 then - item.nbtHash = table.remove(t) - end - item.damage = tonumber(table.remove(t)) - item.name = table.concat(t, ':') - return item -end - -local function getItemQuantity(items, item) - item = getItem(items, item) - if item then - return item.count - end - return 0 -end - -local function getItemDetails(items, item) - local cItem = getItem(items, item) - if cItem then - return cItem - end - cItem = itemDB:get(itemDB:makeKey(item)) - if cItem then - return { count = 0, maxCount = cItem.maxCount } - end - return { count = 0, maxCount = 64 } -end - -local function uniqueKey(item) - return table.concat({ item.name, item.damage, item.nbtHash }, ':') -end - -local function getName(item) - local detail = itemDB:get(itemDB:makeKey(item)) - if detail then - return detail.displayName - end - return item.name .. ':' .. item.damage -end - -local function mergeResources(t) - for _,v in pairs(resources) do - local item = getItem(t, v) - if item then - Util.merge(item, v) - else - item = Util.shallowCopy(v) - item.count = 0 - table.insert(t, item) - end - end - - for k in pairs(recipes) do - local v = splitKey(k) - local item = getItem(t, v) - if not item then - item = Util.shallowCopy(v) - item.count = 0 - table.insert(t, item) - end - item.has_recipe = true - end - - for _,v in pairs(t) do - if not v.displayName then - v.displayName = getName(v) - end - v.lname = v.displayName:lower() - end -end - -local function filterItems(t, filter) - if filter then - local r = {} - filter = filter:lower() - for k,v in pairs(t) do - if string.find(v.lname, filter) then - table.insert(r, v) - end - end - return r - end - return t -end - -local function sumItems3(ingredients, items, summedItems, count) - - local canCraft = 0 - for _,key in pairs(ingredients) do - local item = splitKey(key) - local summedItem = summedItems[key] - if not summedItem then - summedItem = Util.shallowCopy(item) - summedItem.recipe = recipes[key] - summedItem.count = getItemQuantity(items, summedItem) - summedItems[key] = summedItem - end - summedItem.count = summedItem.count - count - if summedItem.recipe and summedItem.count < 0 then - local need = math.ceil(-summedItem.count / summedItem.recipe.count) - summedItem.count = 0 - sumItems3(summedItem.recipe.ingredients, items, summedItems, need) - end - end -end - -local function isGridClear() - for i = 1, 16 do - if turtle.getItemCount(i) ~= 0 then - return false - end - end - return true -end - -local function clearGrid() - for i = 1, 16 do - local count = turtle.getItemCount(i) - if count > 0 then - chestAdapter:insert(i, count) - if turtle.getItemCount(i) ~= 0 then - return false - end - end - end - return true -end - -local function addCraftingRequest(item, craftList, count) - local key = uniqueKey(item) - local request = craftList[key] - if not craftList[key] then - request = { name = item.name, damage = item.damage, nbtHash = nbtHash, count = 0 } - request.displayName = getName(request) - craftList[key] = request - end - request.count = request.count + count -end - -local function craftItem(recipe, items, originalItem, craftList, count) - - if craftingPaused or not device.workbench or not isGridClear() then - return - end - - local toCraft = Craft.getCraftableAmount(recipe, count, items) - - if toCraft > 0 then - Craft.craftRecipe(recipe, toCraft, chestAdapter) - clearGrid() - items = chestAdapter:listItems() - end - - count = count - toCraft - - if count > 0 then - local summedItems = { } - sumItems3(recipe.ingredients, items, summedItems, math.ceil(count / recipe.count)) - - for key,ingredient in pairs(summedItems) do - if not ingredient.recipe and ingredient.count < 0 then - addCraftingRequest(ingredient, craftList, -ingredient.count) - end - end - end -end - -local function craftItems(craftList, allItems) - - for _,key in pairs(Util.keys(craftList)) do - local item = craftList[key] - local recipe = recipes[key] - if recipe then - craftItem(recipe, allItems, item, craftList, item.count) - allItems = chestAdapter:listItems() -- refresh counts - elseif item.rsControl then - item.status = 'Activated' - end - end - - for key,item in pairs(craftList) do - - if not recipes[key] then - if not controller then - item.status = '(no recipe)' - else - if controller:isCrafting(item) then - item.status = '(crafting)' - else - - local count = item.count - while count >= 1 do -- try to request smaller quantities until successful - local s, m = pcall(function() - item.status = '(no recipe)' - if not controller:craft(item, count) then - item.status = '(missing ingredients)' - error('failed') - end - item.status = '(crafting)' - end) - if s then - break -- successfully requested crafting - end - count = math.floor(count / 2) - end - end - end - end - end -end - -local function jobMonitor(jobList) - - local mon = Peripheral.getByType('monitor') - - if mon then - mon = UI.Device({ - device = mon, - textScale = .5, - }) - else - mon = UI.Device({ - device = Terminal.getNullTerm(term.current()) - }) - end - - jobListGrid = UI.Grid({ - parent = mon, - sortColumn = 'displayName', - columns = { - { heading = 'Qty', key = 'count', width = 6 }, - { heading = 'Crafting', key = 'displayName', width = mon.width / 2 - 10 }, - { heading = 'Status', key = 'status', width = mon.width - 10 }, - }, - }) -end - -local function getAutocraftItems() - local craftList = { } - - for _,res in pairs(resources) do - - if res.auto then - res.count = 4 -- this could be higher to increase autocrafting speed - local key = uniqueKey(res) - craftList[key] = res - end - end - return craftList -end - -local function getItemWithQty(items, res, ignoreDamage) - - local item = getItem(items, res, ignoreDamage) - - if item then - - if ignoreDamage then - local count = 0 - - for _,v in pairs(items) do - if item.name == v.name and item.nbtHash == v.nbtHash then - if item.maxDamage > 0 or item.damage == v.damage then - count = count + v.count - end - end - end - - item.count = count - end - end - - return item -end - -local function watchResources(items) - - local craftList = { } - - for k, res in pairs(resources) do - local item = getItemWithQty(items, res, res.ignoreDamage) - if not item then - item = { - damage = res.damage, - nbtHash = res.nbtHash, - name = res.name, - displayName = getName(res), - count = 0 - } - end - - if res.limit and item.count > res.limit then - chestAdapter:provide(res, item.count - res.limit, nil, config.trashDirection) - - elseif res.low and item.count < res.low then - if res.ignoreDamage then - item.damage = 0 - end - local key = uniqueKey(res) - craftList[key] = { - damage = item.damage, - nbtHash = item.nbtHash, - count = res.low - item.count, - name = item.name, - displayName = item.displayName, - status = '', - rsControl = res.rsControl, - } - end - - if res.rsControl and res.rsDevice and res.rsSide then - pcall(function() - device[res.rsDevice].setOutput(res.rsSide, item.count < res.low) - end) - end - end - - return craftList -end - -local itemPage = UI.Page { - backgroundColor = colors.lightGray, - titleBar = UI.TitleBar { - title = 'Limit Resource', - previousPage = true, - event = 'form_cancel', - backgroundColor = colors.green - }, - displayName = UI.Window { - x = 2, y = 2, width = UI.term.width - 4, height = 3, - }, - form = UI.Form { - x = 4, y = 5, height = 8, rex = -4, - [1] = UI.TextEntry { - width = 7, - backgroundColor = colors.gray, - backgroundFocusColor = colors.gray, - formLabel = 'Min', formKey = 'low', help = 'Craft if below min' - }, - [2] = UI.TextEntry { - width = 7, - backgroundColor = colors.gray, - backgroundFocusColor = colors.gray, - formLabel = 'Max', formKey = 'limit', help = 'Eject if above max' - }, - [3] = UI.Chooser { - width = 7, - formLabel = 'Autocraft', formKey = 'auto', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Craft until out of ingredients' - }, - [4] = UI.Chooser { - width = 7, - formLabel = 'Ignore Dmg', formKey = 'ignore_dmg', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Ignore damage of item' - }, - [5] = UI.Chooser { - width = 7, - formLabel = 'RS Control', formKey = 'rsControl', - nochoice = 'No', - choices = { - { name = 'Yes', value = true }, - { name = 'No', value = false }, - }, - help = 'Control via redstone' - }, - [6] = UI.Chooser { - width = 25, - formLabel = 'RS Device', formKey = 'rsDevice', - --choices = devices, - help = 'Redstone Device' - }, - [7] = UI.Chooser { - width = 10, - formLabel = 'RS Side', formKey = 'rsSide', - --nochoice = 'No', - choices = { - { name = 'up', value = 'up' }, - { name = 'down', value = 'down' }, - { name = 'east', value = 'east' }, - { name = 'north', value = 'north' }, - { name = 'west', value = 'west' }, - { name = 'south', value = 'south' }, - }, - help = 'Output side' - }, - }, - statusBar = UI.StatusBar { } -} - -function itemPage.displayName:draw() - local item = self.parent.item - local str = string.format('Name: %s\nDamage: %d', item.displayName, item.damage) - if item.nbtHash then - str = str .. string.format('\n%s', item.nbtHash) - end - self:setCursorPos(1, 1) - self:print(str) -end - -function itemPage:enable(item) - self.item = item - - self.form:setValues(item) - self.titleBar.title = item.name - - local devices = self.form[6].choices - Util.clear(devices) - for _,device in pairs(device) do - if device.setOutput then - table.insert(devices, { name = device.name, value = device.name }) - end - end - - if Util.size(devices) == 0 then - table.insert(devices, { name = 'None found', values = '' }) - end - - UI.Page.enable(self) - self:focusFirst() -end - -function itemPage:eventHandler(event) - if event.type == 'form_cancel' then - UI:setPreviousPage() - - elseif event.type == 'focus_change' then - self.statusBar:setStatus(event.focused.help) - self.statusBar:draw() - - elseif event.type == 'form_complete' then - local values = self.form.values - local keys = { 'name', 'auto', 'low', 'limit', 'damage', - 'nbtHash', 'ignoreDamage', - 'rsControl', 'rsDevice', 'rsSide', } - - local filtered = { } - for _,key in pairs(keys) do - filtered[key] = values[key] - end - filtered.low = tonumber(filtered.low) - filtered.limit = tonumber(filtered.limit) - - --filtered.ignoreDamage = filtered.ignoreDamage == true - --filtered.auto = filtered.auto == true - --filtered.rsControl = filtered.rsControl == true - - if filtered.auto ~= true then - filtered.auto = nil - end - - if filtered.rsControl ~= true then - filtered.rsControl = nil - filtered.rsSide = nil - filtered.rsDevice = nil - end - - if values.ignoreDamage == true then - filtered.damage = 0 - end - - resources[uniqueKey(filtered)] = filtered - Util.writeTable(RESOURCE_FILE, resources) - - UI:setPreviousPage() - - else - return UI.Page.eventHandler(self, event) - end - return true -end - -local listingPage = UI.Page { - menuBar = UI.MenuBar { - buttons = { - { text = 'Learn', event = 'learn' }, - { text = 'Forget', event = 'forget' }, - { text = 'Craft', event = 'craft' }, - }, - }, - grid = UI.Grid { - y = 2, height = UI.term.height - 2, - columns = { - { heading = 'Name', key = 'displayName' , width = 22 }, - { heading = 'Qty', key = 'count' , width = 5 }, - { heading = 'Min', key = 'low' , width = 4 }, - { heading = 'Max', key = 'limit' , width = 4 }, - }, - sortColumn = 'displayName', - }, - statusBar = UI.StatusBar { - backgroundColor = colors.gray, - width = UI.term.width, - filterText = UI.Text { - x = 2, width = 6, - value = 'Filter', - }, - filter = UI.TextEntry { - x = 9, width = 19, - limit = 50, - }, - refresh = UI.Button { - x = 31, width = 8, - text = 'Refresh', - event = 'refresh', - }, - }, - accelerators = { - r = 'refresh', - q = 'quit', - } -} - -function listingPage.grid:getRowTextColor(row, selected) - if row.is_craftable then - return colors.yellow - end - if row.has_recipe then - if selected then - return colors.blue - end - return colors.lightBlue - end - return UI.Grid:getRowTextColor(row, selected) -end - -function listingPage.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - row.count = Util.toBytes(row.count) - if row.low then - row.low = Util.toBytes(row.low) - end - if row.limit then - row.limit = Util.toBytes(row.limit) - end - return row -end - -function listingPage.statusBar:draw() - return UI.Window.draw(self) -end - -function listingPage.statusBar.filter:eventHandler(event) - if event.type == 'mouse_rightclick' then - self.value = '' - self:draw() - local page = UI:getCurrentPage() - page.filter = nil - page:applyFilter() - page.grid:draw() - page:setFocus(self) - end - return UI.TextEntry.eventHandler(self, event) -end - -function listingPage:eventHandler(event) - if event.type == 'quit' then - UI:exitPullEvents() - - elseif event.type == 'grid_select' then - local selected = event.selected - UI:setPage('item', selected) - - elseif event.type == 'refresh' then - self:refresh() - self.grid:draw() - self.statusBar.filter:focus() - - elseif event.type == 'learn' then - UI:setPage('learn') - - elseif event.type == 'craft' then - UI:setPage('craft') - - elseif event.type == 'forget' then - local item = self.grid:getSelected() - if item then - local key = uniqueKey(item) - - if recipes[key] then - recipes[key] = nil - Util.writeTable(RECIPES_FILE, recipes) - end - - if resources[key] then - resources[key] = nil - Util.writeTable(RESOURCE_FILE, resources) - end - - self.statusBar:timedStatus('Forgot: ' .. item.name, 3) - self:refresh() - self.grid:draw() - end - - elseif event.type == 'text_change' then - self.filter = event.text - if #self.filter == 0 then - self.filter = nil - end - self:applyFilter() - self.grid:draw() - self.statusBar.filter:focus() - - else - UI.Page.eventHandler(self, event) - end - return true -end - -function listingPage:enable() - self:refresh() - self:setFocus(self.statusBar.filter) - UI.Page.enable(self) -end - -function listingPage:refresh() - self.allItems = chestAdapter:listItems() - mergeResources(self.allItems) - self:applyFilter() -end - -function listingPage:applyFilter() - local t = filterItems(self.allItems, self.filter) - self.grid:setValues(t) -end - --- without duck antenna -local function getTurtleInventoryOld() - local inventory = { } - for i = 1,16 do - if turtle.getItemCount(i) > 0 then - turtle.select(i) - local item = turtle.getItemDetail() - inventory[i] = { - name = item.name, - damage = item.damage, - count = item.count, - } - end - end - return inventory -end - -local function getTurtleInventory() - local inventory = { } - for i = 1,16 do - local qty = turtle.getItemCount(i) - if qty > 0 then - turtleChestAdapter:insert(i, qty) - local items = turtleChestAdapter:listItems() - _, inventory[i] = next(items) - turtleChestAdapter:extract(1, qty, i) - end - end - return inventory -end - -local function filter(t, filter) - local keys = Util.keys(t) - for _,key in pairs(keys) do - if not Util.key(filter, key) then - t[key] = nil - end - end -end - -local function learnRecipe(page) - local recipe = { } - local ingredients = getTurtleInventory() - if ingredients then - turtle.select(1) - if device.workbench and turtle.craft() then - recipe = getTurtleInventory() - if recipe and recipe[1] then - clearGrid() - - local key = uniqueKey(recipe[1]) - local newRecipe = { - count = recipe[1].count, - ingredients = ingredients, - } - if recipe[1].maxCount ~= 64 then - newRecipe.maxCount = recipe[1].maxCount - end - - for k,ingredient in pairs(ingredients) do - ingredients[k] = uniqueKey(ingredient) - end - - recipes[key] = newRecipe - - Util.writeTable(RECIPES_FILE, recipes) - - local displayName = getName(recipe[1]) - - listingPage.statusBar.filter:setValue(displayName) - listingPage.statusBar:timedStatus('Learned: ' .. displayName, 3) - listingPage.filter = displayName - listingPage:refresh() - listingPage.grid:draw() - - return true - end - else - page.statusBar:timedStatus('Failed to craft', 3) - end - else - page.statusBar:timedStatus('No recipe defined', 3) - end -end - -local learnPage = UI.Dialog { - height = 7, width = UI.term.width - 6, - backgroundColor = colors.lightGray, - title = 'Learn Recipe', - idField = UI.Text { - x = 5, - y = 3, - width = UI.term.width - 10, - value = 'Place recipe in turtle' - }, - accept = UI.Button { - rx = -13, ry = -2, - text = 'Ok', event = 'accept', - }, - cancel = UI.Button { - rx = -8, ry = -2, - text = 'Cancel', event = 'cancel' - }, - statusBar = UI.StatusBar { - status = 'Crafting paused' - } -} - -function learnPage:enable() - craftingPaused = true - self:focusFirst() - UI.Dialog.enable(self) -end - -function learnPage:disable() - craftingPaused = false - UI.Dialog.disable(self) -end - -function learnPage:eventHandler(event) - if event.type == 'cancel' then - UI:setPreviousPage() - elseif event.type == 'accept' then - if learnRecipe(self) then - UI:setPreviousPage() - end - else - return UI.Dialog.eventHandler(self, event) - end - return true -end - -local craftPage = UI.Dialog { - height = 6, width = UI.term.width - 10, - backgroundColor = colors.lightGray, - title = 'Enter amount to craft', - idField = UI.TextEntry { - x = 15, - y = 3, - width = 10, - limit = 6, - value = '1', - backgroundColor = colors.black, - backgroundFocusColor = colors.black, - }, - accept = UI.Button { - rx = -7, ry = -1, - backgroundColor = colors.green, - text = '+', event = 'accept', - }, - cancel = UI.Button { - rx = -3, ry = -1, - backgroundColor = colors.red, - backgroundFocusColor = colors.red, - text = '\215', event = 'cancel' - }, -} - -function craftPage:draw() - UI.Dialog.draw(self) - self:write(6, 3, 'Quantity') -end - -function craftPage:enable() - craftingPaused = true - self:focusFirst() - UI.Dialog.enable(self) -end - -function craftPage:disable() - craftingPaused = false - UI.Dialog.disable(self) -end - -function craftPage:eventHandler(event) - if event.type == 'cancel' then - UI:setPreviousPage() - elseif event.type == 'accept' then - - else - return UI.Dialog.eventHandler(self, event) - end - return true -end - -UI:setPages({ - listing = listingPage, - item = itemPage, - learn = learnPage, - craft = craftPage, -}) - -UI:setPage(listingPage) -listingPage:setFocus(listingPage.statusBar.filter) - -clearGrid() -jobMonitor() -jobListGrid:draw() -jobListGrid:sync() - -Event.onInterval(5, function() - - if not craftingPaused then - local items = chestAdapter:listItems() - if Util.size(items) == 0 then - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system') - jobListGrid:sync() - - else - local craftList = watchResources(items) - jobListGrid:setValues(craftList) - --jobListGrid:draw() - --jobListGrid:sync() - craftItems(craftList, items) - jobListGrid:update() - jobListGrid:draw() - jobListGrid:sync() - craftList = getAutocraftItems(items) -- autocrafted items don't show on job monitor - craftItems(craftList, items) - end - end -end) - -UI:pullEvents() -jobListGrid.parent:reset() diff --git a/sys/apps/logMonitor.lua b/sys/apps/logMonitor.lua deleted file mode 100644 index d54c2b1..0000000 --- a/sys/apps/logMonitor.lua +++ /dev/null @@ -1,101 +0,0 @@ -requireInjector(getfenv(1)) - -local Event = require('event') -local Message = require('message') -local UI = require('ui') -local Util = require('util') - -multishell.setTitle(multishell.getCurrent(), 'Log Monitor') - -if not device.wireless_modem then - error('Wireless modem is required') -end -device.wireless_modem.open(59998) - -local ids = { } -local messages = { } -local terminal = UI.term - -if device.openperipheral_bridge then - - UI.Glasses = require('glasses') - - terminal = UI.Glasses({ - x = 4, - y = 175, - height = 40, - width = 64, - textScale = .5, - backgroundOpacity = .65, - - }) -elseif device.monitor then - terminal = UI.Device({ - deviceType = 'monitor', - textScale = .5 - }) -end - -terminal:clear() - -function getClient(id) - if not ids[id] then - ids[id] = { - titleBar = UI.TitleBar({ title = 'ID: ' .. id, parent = terminal }), - scrollingText = UI.ScrollingText({ parent = terminal }) - } - local clientCount = Util.size(ids) - local clientHeight = math.floor((terminal.height - clientCount) / clientCount) - terminal:clear() - local y = 1 - for k,v in pairs(ids) do - v.titleBar.y = y - y = y + 1 - v.scrollingText.height = clientHeight - v.scrollingText.y = y - y = y + clientHeight - v.scrollingText:clear() - - v.titleBar:draw() - v.scrollingText:draw() - end - end - return ids[id] -end - -Event.on('logMessage', function() - local t = { } - while #messages > 0 do - local msg = messages[1] - table.remove(messages, 1) - local client = getClient(msg.id) - client.scrollingText:appendLine(string.format('%d %s', math.floor(os.clock()), msg.text)) - t[msg.id] = client - end - for _,client in pairs(t) do - client.scrollingText:draw() - end - terminal:sync() -end) - -Message.addHandler('log', function(h, id, msg) - table.insert(messages, { id = id, text = msg.contents }) - os.queueEvent('logMessage') -end) - -Event.on('monitor_touch', function() - terminal:reset() - ids = { } -end) - -Event.on('mouse_click', function() - terminal:reset() - ids = { } -end) - -Event.on('char', function() - Event.exitPullEvents() -end) - -Event.pullEvents(logWriter) -terminal:reset() diff --git a/sys/apps/mirror.lua b/sys/apps/mirror.lua deleted file mode 100644 index ab3c8c1..0000000 --- a/sys/apps/mirror.lua +++ /dev/null @@ -1,25 +0,0 @@ -requireInjector(getfenv(1)) - -local Terminal = require('terminal') - -local args = { ... } -local mon = device[table.remove(args, 1) or 'monitor'] -if not mon then - error('mirror: Invalid device') -end - -mon.clear() -mon.setTextScale(.5) -mon.setCursorPos(1, 1) - -local oterm = Terminal.copy(term.current()) -Terminal.mirror(term.current(), mon) - -term.current().getSize = mon.getSize - -if #args > 0 then - shell.run(unpack(args)) - Terminal.copy(oterm, term.current()) - - mon.setCursorBlink(false) -end diff --git a/sys/apps/mirrorClient.lua b/sys/apps/mirrorClient.lua deleted file mode 100644 index 7152ee6..0000000 --- a/sys/apps/mirrorClient.lua +++ /dev/null @@ -1,86 +0,0 @@ -requireInjector(getfenv(1)) - -local Event = require('event') -local Logger = require('logger') -local Socket = require('socket') -local Terminal = require('terminal') -local Util = require('util') - -Logger.setScreenLogging() - -local remoteId -local args = { ... } -if #args == 1 then - remoteId = tonumber(args[1]) -else - print('Enter host ID') - remoteId = tonumber(read()) -end - -if not remoteId then - error('Syntax: mirrorClient ') -end - -local function wrapTerm(socket) - local methods = { 'blit', 'clear', 'clearLine', 'setCursorPos', 'write', - 'setTextColor', 'setTextColour', 'setBackgroundColor', - 'setBackgroundColour', 'scroll', 'setCursorBlink', } - - socket.term = multishell.term - socket.oldTerm = Util.shallowCopy(socket.term) - - for _,k in pairs(methods) do - socket.term[k] = function(...) - if not socket.queue then - socket.queue = { } - Event.onTimeout(0, function() - if socket.queue then - socket:write(socket.queue) - socket.queue = nil - end - end) - end - table.insert(socket.queue, { - f = k, - args = { ... }, - }) - socket.oldTerm[k](...) - end - end -end - -while true do - print('connecting...') - local socket - - while true do - socket = Socket.connect(remoteId, 5901) - if socket then - break - end - os.sleep(3) - end - - print('connected') - - wrapTerm(socket) - - os.queueEvent('term_resize') - - while true do - local e = Event.pullEvent() - if e[1] == 'terminate' then - break - end - if not socket.connected then - break - end - end - - for k,v in pairs(socket.oldTerm) do - socket.term[k] = v - end - - socket:close() - -end diff --git a/sys/apps/mirrorHost.lua b/sys/apps/mirrorHost.lua deleted file mode 100644 index 4ece283..0000000 --- a/sys/apps/mirrorHost.lua +++ /dev/null @@ -1,53 +0,0 @@ -requireInjector(getfenv(1)) - -local Event = require('event') -local Logger = require('logger') -local Socket = require('socket') - -Logger.setScreenLogging() - -local args = { ... } -local mon = device[args[1] or 'monitor'] - -if not mon then - error('Monitor not attached') -end - -mon.setBackgroundColor(colors.black) -mon.clear() - -while true do - local socket = Socket.server(5901) - - print('mirror: connection from ' .. socket.dhost) - - Event.addRoutine(function() - while true do - local data = socket:read() - if not data then - break - end - for _,v in ipairs(data) do - mon[v.f](unpack(v.args)) - end - end - end) - - -- ensure socket is connected - Event.onInterval(3, function(h) - if not socket:ping() then - Event.off(h) - end - end) - - while true do - Event.pullEvent() - if not socket.connected then - break - end - end - - print('connection lost') - - socket:close() -end diff --git a/sys/apps/pickup.lua b/sys/apps/pickup.lua deleted file mode 100644 index 8285647..0000000 --- a/sys/apps/pickup.lua +++ /dev/null @@ -1,335 +0,0 @@ -requireInjector(getfenv(1)) - -local Event = require('event') -local GPS = require('gps') -local Logger = require('logger') -local MEProvider = require('meProvider') -local Point = require('point') -local Socket = require('socket') -local Util = require('util') - -if not device.wireless_modem then - error('Modem is required') -end - -Logger.setWirelessLogging() - -if not turtle then - error('Can only be run on a turtle') -end - -local blocks = { } -local meProvider = MEProvider() -local items = { } - -local pickups = Util.readTable('pickup.tbl') or { } -local cells = Util.readTable('cells.tbl') or { } -local refills = Util.readTable('refills.tbl') or { } -local fluids = Util.readTable('fluids.tbl') or { } -local chestPt = turtle.loadLocation('chest') -local chargePt = turtle.loadLocation('charge') - -local fuel = { - item = { - id = 'minecraft:coal', - dmg = 0, - }, - qty = 64 -} - -local slots - -turtle.setMoveCallback(function(action, pt) - if slots then - for _,slot in pairs(slots) do - if turtle.getItemCount(slot.index) ~= slot.qty then - printError('Slots changed') - Event.exitPullEvents() - end - end - end -end) - -function refuel() - if turtle.getFuelLevel() < 5000 then - print('refueling') - turtle.status = 'refueling' - gotoPoint(chestPt, true) - dropOff(chestPt) - while turtle.getFuelLevel() < 5000 do - turtle.select(1) - meProvider:provide(fuel.item, fuel.qty, 1) - turtle.refuel(64) - print(turtle.getFuelLevel()) - os.sleep(1) - end - end -end - -function pickUp(pt) - turtle.status = 'picking up' - gotoPoint(pt, true) - while true do - if not turtle.selectOpenSlot() then - dropOff(chestPt) - gotoPoint(pt, true) - end - turtle.select(1) - if not turtle.suckDown(64) then - return - end - end -end - -function dropOff(pt) - if turtle.selectSlotWithItems() then - gotoPoint(pt, true) - turtle.emptyInventory(turtle.dropDown) - if pt == chestPt then - print('refreshing items') - items = meProvider:refresh() - end - end -end - -function gotoPoint(pt, doDetect) - slots = turtle.getInventory() - while not turtle.pathfind(pt, blocks) do - if turtle.abort then - error('aborted') - end - turtle.status = 'blocked' - os.sleep(5) - end - - if doDetect and not turtle.detectDown() then - printError('Missing target') - Event.exitPullEvents() - end -end - -function checkCell(pt) - if not turtle.selectOpenSlot() then - dropOff(chestPt) - end - - print('checking cell') - turtle.status = 'recharging' - gotoPoint(pt, true) - local c = peripheral.wrap('bottom') - local energy = c.getMaxEnergyStored() - - c.getEnergyStored() - if energy > 20000 then - print('charging cell') - turtle.selectOpenSlot() - turtle.digDown() - gotoPoint(chargePt, true) - turtle.dropDown() - os.sleep(energy / 20000) - turtle.suckDown() - print('replacing cell') - gotoPoint(pt) - if not turtle.placeDown() then - error('could not place down cell') - end - end -end - -function fluid(points) - print('checking fluid') - turtle.status = 'fluiding' - gotoPoint(points.source, true) - turtle.select(1) - turtle.digDown() - gotoPoint(points.target) - if not turtle.placeDown() then - error('could not place fluid container') - end - os.sleep(5) - turtle.digDown() - gotoPoint(points.source) - turtle.placeDown() -end - -function refill(entry) - dropOff(chestPt) - - turtle.status = 'refilling' - gotoPoint(chestPt) - for _,item in pairs(entry.items) do - meProvider:provide(item, tonumber(item.qty), turtle.selectOpenSlot()) - end - - if turtle.selectSlotWithItems() then - if entry.point then - dropOff(entry.point) - end - end -end - -function oldRefill(points) - gotoPoint(points.source) - repeat until not turtle.suckDown(64) - if points.target then - dropOff(points.target) - end - if points.targets then - for k,target in pairs(points.targets) do - dropOff(target) - end - end - dropOff(points.source) - dropOff(chestPt) -end - -local function makeKey(pt) - return string.format('%d:%d:%d', pt.x, pt.y, pt.z) -end - -local function pickupHost(socket) - - while true do - local data = socket:read() - if not data then - print('pickup: closing connection to ' .. socket.dhost) - return - end - - print('command: ' .. data.type) - - if data.type == 'pickup' then - local key = makeKey(data.point) - pickups[key] = data.point - Util.writeTable('pickup.tbl', pickups) - socket:write( { type = "response", response = 'added' }) - - elseif data.type == 'items' then - socket:write( { type = "response", response = items }) - - elseif data.type == 'refill' then - local key = makeKey(data.entry.point) - refills[key] = data.entry - Util.writeTable('refills.tbl', refills) - socket:write( { type = "response", response = 'added' }) - - elseif data.type == 'setPickup' then - chestPt = data.point - turtle.storeLocation('chest', chestPt) - socket:write( { type = "response", response = 'Location set' }) - - elseif data.type == 'setRecharge' then - chargePt = data.point - turtle.storeLocation('charge', chargePt) - socket:write( { type = "response", response = 'Location set' }) - - elseif data.type == 'charge' then - local key = makeKey(data.point) - cells[key] = data.point - Util.writeTable('cells.tbl', cells) - socket:write( { type = "response", response = 'added' }) - - elseif data.type == 'fluid' then - - elseif data.type == 'clear' then - local key = makeKey(data.point) - refills[key] = nil - cells[key] = nil - fluids[key] = nil - pickups[key] = nil - - Util.writeTable('refills.tbl', refills) - Util.writeTable('cells.tbl', cells) - Util.writeTable('fluids.tbl', fluids) - Util.writeTable('pickup.tbl', pickups) - - socket:write( { type = "response", response = 'cleared' }) - else - print('unknown command') - end - end -end - -Event.addRoutine(function() - while true do - print('waiting for connection on port 5222') - local socket = Socket.server(5222) - - print('pickup: connection from ' .. socket.dhost) - - Event.addRoutine(function() pickupHost(socket) end) - end -end) - -local function eachEntry(t, fn) - - local keys = Util.keys(t) - for _,key in pairs(keys) do - if t[key] then - if turtle.abort then - return - end - fn(t[key]) - end - end -end - -local function eachClosestEntry(t, fn) - - local points = { } - for k,v in pairs(t) do - v = Util.shallowCopy(v) - v.key = k - table.insert(points, v) - end - - while not Util.empty(points) do - local closest = Point.closest(turtle.point, points) - if turtle.abort then - return - end - if t[closest.key] then - fn(closest) - end - for k,v in pairs(points) do - if v.key == closest.key then - table.remove(points, k) - break - end - end - end -end - -Event.addRoutine(function() - - while true do - if chestPt then - eachClosestEntry(pickups, pickUp) - eachEntry(refills, refill) - refuel() - end - eachEntry(fluids, fluid) - if chargePt then - eachEntry(cells, checkCell) - end - print('sleeping') - turtle.status = 'sleeping' - if turtle.abort then - printError('aborted') - break - end - os.sleep(60) - end - - Event.exitPullEvents() -end) - -turtle.run(function() - - if not turtle.enableGPS() then - error('turtle: No GPS found') - end - - refuel() - Event.pullEvents() - -end) diff --git a/sys/apps/pickupRemote.lua b/sys/apps/pickupRemote.lua deleted file mode 100644 index a42d9e4..0000000 --- a/sys/apps/pickupRemote.lua +++ /dev/null @@ -1,231 +0,0 @@ -if not device.wireless_modem then - error('Wireless modem is required') -end - -requireInjector(getfenv(1)) - -local Event = require('event') -local GPS = require('gps') -local Socket = require('socket') -local UI = require('ui') -local Util = require('util') - -multishell.setTitle(multishell.getCurrent(), 'Pickup Remote') - -local id - -local mainPage = UI.Page({ - menu = UI.Menu({ - centered = true, - y = 2, - menuItems = { - { prompt = 'Pickup', event = 'pickup', help = 'Pickup items from this location' }, - { prompt = 'Charge cell', event = 'charge', help = 'Recharge this cell' }, - { prompt = 'Refill', event = 'refill', help = 'Recharge this cell' }, - { prompt = 'Set pickup location', event = 'setPickup', help = 'Recharge this cell' }, - { prompt = 'Set recharge location', event = 'setRecharge', help = 'Recharge this cell' }, - { prompt = 'Clear', event = 'clear', help = 'Remove this location' }, - }, - }), - statusBar = UI.StatusBar(), - accelerators = { - q = 'quit', - }, -}) - -local refillPage = UI.Page({ - menuBar = UI.MenuBar({ - y = 1, - buttons = { - { text = 'Done', event = 'done', help = 'Pickup items from this location' }, - { text = 'Back', event = 'back', help = 'Recharge this cell' }, - }, - }), - grid1 = UI.ScrollingGrid({ - columns = { - { heading = 'Name', key = 'name', width = UI.term.width-9 }, - { heading = 'Qty', key = 'fQty', width = 5 }, - }, - sortColumn = 'name', - height = 8, - y = 3, - }), - grid2 = UI.ScrollingGrid({ - columns = { - { heading = 'Name', key = 'name', width = UI.term.width-9 }, - { heading = 'Qty', key = 'qty', width = 5 }, - }, - sortColumn = 'name', - height = 4, - y = 12, - }), - statusBar = UI.StatusBar(), - accelerators = { - q = 'quit', - }, -}) - -refillPage.menuBar:add({ - filter = UI.TextEntry({ - x = UI.term.width-10, - width = 10, - }) -}) - -local function sendCommand(cmd) - local socket = Socket.connect(id, 5222) - if not socket then - mainPage.statusBar:timedStatus('Unable to connect', 3) - return - end - - socket:write(cmd) - local m = socket:read(3) - socket:close() - if m then - return m.response - end - mainPage.statusBar:timedStatus('No response', 3) -end - -local function getPoint() - local gpt = GPS.getPoint() - if not gpt then - mainPage.statusBar:timedStatus('Unable to get location', 3) - end - return gpt -end - -function refillPage:eventHandler(event) - - if event.type == 'grid_select' then - - local item = { - name = event.selected.name, - id = event.selected.id, - dmg = event.selected.dmg, - qty = 0, - } - - local dialog = UI.Dialog({ - x = 1, - width = UI.term.width, - text = UI.Text({ x = 3, y = 3, value = 'Quantity' }), - textEntry = UI.TextEntry({ x = 14, y = 3 }) - }) - - dialog.eventHandler = function(self, event) - if event.type == 'accept' then - local l = tonumber(self.textEntry.value) - if l and l <= 1024 and l > 0 then - item.qty = self.textEntry.value - table.insert(refillPage.grid2.values, item) - refillPage.grid2:update() - UI:setPreviousPage() - else - self.statusBar:timedStatus('Invalid Quantity', 3) - end - return true - end - - return UI.Dialog.eventHandler(self, event) - end - - dialog.titleBar.title = item.name - dialog:setFocus(dialog.textEntry) - UI:setPage(dialog) - - elseif event.type == 'text_change' then - local text = event.text - if #text == 0 then - self.grid1.values = self.allItems - else - self.grid1.values = { } - for _,item in pairs(self.allItems) do - if string.find(item.lname, text) then - table.insert(self.grid1.values, item) - end - end - end - --self.grid:adjustWidth() - self.grid1:update() - self.grid1:setIndex(1) - self.grid1:draw() - - elseif event.type == 'back' then - UI:setPreviousPage() - - elseif event.type == 'done' then - UI:setPage(mainPage) - local pt = getPoint() - if pt then - local response = sendCommand({ type = 'refill', entry = { point = pt, items = self.grid2.values } }) - if response then - mainPage.statusBar:timedStatus(response, 3) - end - end - - elseif event.type == 'grid_focus_row' then - self.statusBar:setStatus(event.selected.id .. ':' .. event.selected.dmg) - self.statusBar:draw() - end - - return UI.Page.eventHandler(self, event) -end - -function refillPage:enable() - for _,item in pairs(self.allItems) do - item.lname = string.lower(item.name) - item.fQty = Util.toBytes(item.qty) - end - - self.grid1:setValues(self.allItems) - - self.menuBar.filter.value = '' - self.menuBar.filter.pos = 1 - self:setFocus(self.menuBar.filter) - UI.Page.enable(self) -end - -function mainPage:eventHandler(event) - - if event.type == 'quit' then - Event.exitPullEvents() - - elseif event.type == 'refill' then - local response = sendCommand({ type = 'items' }) - if response then - refillPage.allItems = response - refillPage.grid2:setValues({ }) - UI:setPage(refillPage) - end - - elseif event.type == 'pickup' or event.type == 'setPickup' or - event.type == 'setRecharge' or event.type == 'charge' or - event.type == 'clear' then - local pt = getPoint() - if pt then - local response = sendCommand({ type = event.type, point = pt }) - if response then - self.statusBar:timedStatus(response, 3) - end - end - - end - - return UI.Page.eventHandler(self, event) -end - -local args = { ... } -if #args == 1 then - id = tonumber(args[1]) -end - -if not id then - error('Syntax: pickupRemote ') -end - -UI:setPage(mainPage) - -Event.pullEvents() -UI.term:reset() diff --git a/sys/apps/recorder.lua b/sys/apps/recorder.lua deleted file mode 100644 index b889475..0000000 --- a/sys/apps/recorder.lua +++ /dev/null @@ -1,538 +0,0 @@ --- +---------------------+------------+---------------------+ --- | | | | --- | | RecGif | | --- | | | | --- +---------------------+------------+---------------------+ - -local version = "Version 1.1.6" - --- Records your terminal and saves the result as an animating GIF. --- http://www.computercraft.info/forums2/index.php?/topic/24840-recgif/ - --- ---------------------------------------------------------- - --- Original code by Bomb Bloke --- Modified to integrate with opus os - -requireInjector(getfenv(1)) - -local Util = require('util') - -local recTerm, oldTerm, arg, showInput, skipLast, lastDelay, curInput = {}, Util.shallowCopy(multishell.term), {...}, false, false, 2, "" -local curBlink, oldBlink, tTerm, buffer, colourNum, xPos, yPos, oldXPos, oldYPos, tCol, bCol, xSize, ySize = false, false, {}, {}, {}, 1, 1, 1, 1, colours.white, colours.black, oldTerm.getSize() -local greys, buttons = {["0"] = true, ["7"] = true, ["8"] = true, ["f"] = true}, {"l", "r", "m"} -local charW, charH, chars, resp -local filename - -local calls = { } -local curCalls = { delay = 0 } -local callListCount = 0 -local callCount = 0 - -local function showSyntax() - print('Gif Recorder by Bomb Bloke\n') - print('Syntax: recGif [-i] [-s] [-ld:] filename') - print(' -i : show input') - print(' -s : skip last') - print(' -ld : last delay') -end - -for i = #arg, 1, -1 do - local curArg = arg[i]:lower() - - if curArg == "-i" then - showInput, ySize = true, ySize + 1 - table.remove(arg, i) - elseif curArg == "-s" then - skipLast = true - table.remove(arg, i) - elseif curArg:sub(1, 4) == "-ld:" then - curArg = tonumber(curArg:sub(5)) - if curArg then lastDelay = curArg end - table.remove(arg, i) - elseif curArg == '-?' then - showSyntax() - return - elseif i ~= #arg then - showSyntax() - printError('\nInvalid argument') - return - end -end - -print('Press control-p to stop recording') - -local filename = arg[#arg] -if not filename then - print('Enter file name:') - filename = read() -end - -if #filename == 0 then - showSyntax() - print() - error('Invalid file name') -end - -print('Initializing...') - --- don't pollute global env --- convert these to require style apis -local function loadAPI(url, env) - local apiEnv = Util.shallowCopy(env) - apiEnv.shell = nil - apiEnv.multishell = nil - setmetatable(apiEnv, { __index = _G }) - local fn = Util.loadUrl(url, apiEnv) - fn() - return apiEnv -end - -bbpack = loadAPI('http://pastebin.com/raw/PdrJjb5S', getfenv(1)) -GIF = loadAPI('http://pastebin.com/raw/5uk9uRjC', getfenv(1)) - -Util.runUrl(getfenv(1), 'http://pastebin.com/raw/cUYTGbpb', 'get', 'Y0eLUPtr') - -local function snooze() - local myEvent = tostring({}) - os.queueEvent(myEvent) - os.pullEvent(myEvent) -end - -local function safeString(text) - local newText = {} - - for i = 1, #text do - local val = text:byte(i) - newText[i] = (val > 31 and val < 127) and val or 63 - end - - return string.char(unpack(newText)) -end - -local function safeCol(text, subst) - local newText = {} - - for i = 1, #text do - local val = text:sub(i, i) - newText[i] = greys[val] and val or subst - end - - return table.concat(newText) -end - --- Build a terminal that records stuff: - -recTerm = multishell.term - -for key, func in pairs(oldTerm) do - recTerm[key] = function(...) - local result = { func(...) } - - if callCount == 0 then - os.queueEvent('capture_frame') - end - callCount = callCount + 1 - curCalls[callCount] = { key, ... } - return unpack(result) - end -end - -local tabId = multishell.getCurrent() - -multishell.addHotkey(25, function() - os.queueEvent('recorder_stop') -end) - -local tabs = multishell.getTabs() -for _,tab in pairs(tabs) do - if tab.isOverview then - multishell.hideTab(tabId) - multishell.setFocus(tab.tabId) - os.queueEvent('term_resize') - break - end -end - -local curTime = os.clock() - 1 - -while true do - local event = { os.pullEventRaw() } - - if event[1] == 'recorder_stop' or event[1] == 'terminate' then - break - end - - if event[1] == 'capture_frame' then - local newTime = os.clock() - - if callListCount > 0 then - calls[callListCount].delay = (newTime - curTime) - end - - curTime = newTime - callListCount = callListCount + 1 - calls[callListCount] = curCalls - - curCalls, callCount = { delay = 0 }, 0 - end -end - -multishell.removeHotkey(25) - -for k,fn in pairs(oldTerm) do - multishell.term[k] = fn -end - -multishell.unhideTab(tabId) -multishell.setFocus(tabId) - -if #calls[#calls] == 0 then calls[#calls] = nil end -if skipLast and #calls > 1 then calls[#calls] = nil end - -calls[#calls].delay = lastDelay - -print(string.format("Encoding %d frames...", #calls)) ---Util.writeTable('tmp/raw.txt', calls) - --- Perform a quick re-parse of the recorded data (adding frames for when the cursor blinks): - -do - local callListCount, tempCalls, blink, oldBlink, curBlink, blinkDelay = 1, {}, false, false, true, 0 - - for i = 1, #calls - 1 do - curCalls = calls[i] - tempCalls[callListCount] = curCalls - for j = 1, #curCalls do if curCalls[j][1] == "setCursorBlink" then blink = curCalls[j][2] end end - - if blink then - if blinkDelay == 0 then - curCalls[#curCalls + 1] = {"toggleCur", curBlink} - blinkDelay, curBlink = 0.4, not curBlink - end - - while tempCalls[callListCount].delay > blinkDelay do - local remainder = tempCalls[callListCount].delay - blinkDelay - tempCalls[callListCount].delay = blinkDelay - callListCount = callListCount + 1 - tempCalls[callListCount] = {{"toggleCur", curBlink}, ["delay"] = remainder} - blinkDelay, curBlink = 0.4, not curBlink - end - - blinkDelay = blinkDelay - tempCalls[callListCount].delay - else - if oldBlink then curCalls[#curCalls + 1] = {"toggleCur", false} end - blinkDelay = (curCalls.delay - blinkDelay) % 0.4 - end - - callListCount, oldBlink = callListCount + 1, blink - end - - tempCalls[callListCount] = calls[#calls] - tempCalls[callListCount][#tempCalls[callListCount] + 1] = {"toggleCur", false} - - calls, curCalls = tempCalls, nil -end - -snooze() - --- Load font data: -do - local ascii, counter = GIF.toPaintutils(GIF.flattenGIF(GIF.loadGIF("ascii.gif"))), 0 - local newFont, ybump, xbump = #ascii ~= #ascii[1], 0, 0 - charW, charH, chars = newFont and #ascii[1] / 16 or #ascii[1] * 3 / 64, #ascii / 16, {} - - for yy = 0, newFont and 15 or 7 do - for xx = 0, 15 do - local newChar, length = {}, 0 - - -- Place in 2d grid of bools: - for y = 1, charH do - local newRow = {} - - for x = 1, charW do - local set = ascii[y + ybump][x + xbump] == 1 - if set and x > length then length = x end - newRow[x] = set - end - - newChar[y] = newRow - end - - -- Center: - if not newFont then for y = 1, charH do for x = 1, math.floor((charW - length) / 2) do table.insert(newChar[y], 1, false) end end end - - chars[counter] = newChar - counter, xbump = counter + 1, xbump + (newFont and charW or charH) - end - xbump, ybump = 0, ybump + charH - end -end - -snooze() - --- Terminal data translation: - -do - local hex, counter = "0123456789abcdef", 1 - - for i = 1, 16 do - colourNum[counter] = hex:sub(i, i) - counter = counter * 2 - end -end - -for y = 1, ySize do - buffer[y] = {} - for x = 1, xSize do buffer[y][x] = {" ", colourNum[tCol], colourNum[bCol]} end -end - -if showInput then for x = 1, xSize do buffer[ySize][x][3] = colourNum[colours.lightGrey] end end - -tTerm.blit = function(text, fgCol, bgCol) - if xPos > xSize or xPos + #text - 1 < 1 or yPos < 1 or yPos > ySize then return end - - if not _HOST then text = safeString(text) end - - if not term.isColour() then - fgCol = safeCol(fgCol, "0") - bgCol = safeCol(bgCol, "f") - end - - if xPos < 1 then - text = text:sub(2 - xPos) - fgCol = fgCol:sub(2 - xPos) - bgCol = bgCol:sub(2 - xPos) - xPos = 1 - end - - if xPos + #text - 1 > xSize then - text = text:sub(1, xSize - xPos + 1) - fgCol = fgCol:sub(1, xSize - xPos + 1) - bgCol = bgCol:sub(1, xSize - xPos + 1) - end - - for x = 1, #text do - buffer[yPos][xPos + x - 1][1] = text:sub(x, x) - buffer[yPos][xPos + x - 1][2] = fgCol:sub(x, x) - buffer[yPos][xPos + x - 1][3] = bgCol:sub(x, x) - end - - xPos = xPos + #text -end - -tTerm.write = function(text) - text = tostring(text) - tTerm.blit(text, string.rep(colourNum[tCol], #text), string.rep(colourNum[bCol], #text)) -end - -tTerm.clearLine = function() - local oldXPos = xPos - - xPos = 1 - tTerm.write(string.rep(" ", xSize)) - - xPos = oldXPos -end - -tTerm.clear = function() - local oldXPos, oldYPos = xPos, yPos - - for y = 1, ySize do - xPos, yPos = 1, y - tTerm.write(string.rep(" ", xSize)) - end - - xPos, yPos = oldXPos, oldYPos -end - -tTerm.setCursorPos = function(x, y) - xPos, yPos = math.floor(x), math.floor(y) -end - -tTerm.setTextColour = function(col) - tCol = col -end - -tTerm.setTextColor = function(col) - tCol = col -end - -tTerm.setBackgroundColour = function(col) - bCol = col -end - -tTerm.setBackgroundColor = function(col) - bCol = col -end - -tTerm.scroll = function(lines) - if math.abs(lines) < ySize then - local oldXPos, oldYPos = xPos, yPos - - for y = 1, ySize do - if y + lines > 0 and y + lines <= ySize then - for x = 1, xSize do - xPos, yPos = x, y - tTerm.blit(buffer[y + lines][x][1], buffer[y + lines][x][2], buffer[y + lines][x][3]) - end - else - yPos = y - tTerm.clearLine() - end - end - - xPos, yPos = oldXPos, oldYPos - else tTerm.clear() end -end - -tTerm.toggleCur = function(newBlink) - curBlink = newBlink -end - -tTerm.newInput = function(input) - local oldTC, oldBC, oldX, oldY = tCol, bCol, xPos, yPos - tCol, bCol, xPos, yPos, ySize, input = colours.grey, colours.lightGrey, 1, ySize + 1, ySize + 1, input .. " " - - while #curInput + #input + 1 > xSize do curInput = curInput:sub(curInput:find(" ") + 1) end - curInput = curInput .. input .. " " - tTerm.clearLine() - tTerm.write(curInput) - - tCol, bCol, xPos, yPos, ySize = oldTC, oldBC, oldX, oldY, ySize - 1 -end - -tTerm.key = function(key) - tTerm.newInput((not keys.getName(key)) and "unknownKey" or keys.getName(key)) -end - -tTerm.mouse_click = function(button, x, y) - tTerm.newInput(buttons[button] .. "C@" .. tostring(x) .. "x" .. tostring(y)) -end - -local image = {["width"] = xSize * charW, ["height"] = ySize * charH} - -for i = 1, #calls do - local xMin, yMin, xMax, yMax, oldBuffer, curCalls, changed = xSize + 1, ySize + 1, 0, 0, {}, calls[i], false - calls[i] = nil - - for y = 1, ySize do - oldBuffer[y] = {} - for x = 1, xSize do oldBuffer[y][x] = {buffer[y][x][1], buffer[y][x][2], buffer[y][x][3], buffer[y][x][4]} end - end - - snooze() - - if showInput then ySize = ySize - 1 end - for j = 1, #curCalls do if tTerm[curCalls[j][1]] then tTerm[curCalls[j][1]](unpack(curCalls[j], 2)) end end - if showInput then ySize = ySize + 1 end - - if i > 1 then - for yy = 1, ySize do for xx = 1, xSize do if buffer[yy][xx][1] ~= oldBuffer[yy][xx][1] or (buffer[yy][xx][2] ~= oldBuffer[yy][xx][2] and buffer[yy][xx][1] ~= " ") or buffer[yy][xx][3] ~= oldBuffer[yy][xx][3] then - changed = true - if xx < xMin then xMin = xx end - if xx > xMax then xMax = xx end - if yy < yMin then yMin = yy end - if yy > yMax then yMax = yy end - end end end - else xMin, yMin, xMax, yMax, changed = 1, 1, xSize, ySize, true end - - if oldBlink and (xPos ~= oldXPos or yPos ~= oldYPos or not curBlink) and oldXPos > 0 and oldYPos > 0 and oldXPos <= xSize and oldYPos <= ySize then - changed = true - if oldXPos < xMin then xMin = oldXPos end - if oldXPos > xMax then xMax = oldXPos end - if oldYPos < yMin then yMin = oldYPos end - if oldYPos > yMax then yMax = oldYPos end - buffer[oldYPos][oldXPos][4] = false - end - - if curBlink and (xPos ~= oldXPos or yPos ~= oldYPos or not oldBlink) and xPos > 0 and yPos > 0 and xPos <= xSize and yPos <= ySize then - changed = true - if xPos < xMin then xMin = xPos end - if xPos > xMax then xMax = xPos end - if yPos < yMin then yMin = yPos end - if yPos > yMax then yMax = yPos end - buffer[yPos][xPos][4] = true - end - - oldBlink, oldXPos, oldYPos = curBlink, xPos, yPos - - local thisFrame = { - ["xstart"] = (xMin - 1) * charW, - ["ystart"] = (yMin - 1) * charH, - ["xend"] = (xMax - xMin + 1) * charW, - ["yend"] = (yMax - yMin + 1) * charH, - ["delay"] = curCalls.delay, - ["disposal"] = 1 - } - - for y = 1, (yMax - yMin + 1) * charH do - local row = {} - for x = 1, (xMax - xMin + 1) * charW do row[x] = " " end - thisFrame[y] = row - end - - snooze() - - for yy = yMin, yMax do - local yBump = (yy - yMin) * charH - - for xx = xMin, xMax do if buffer[yy][xx][1] ~= oldBuffer[yy][xx][1] or (buffer[yy][xx][2] ~= oldBuffer[yy][xx][2] and buffer[yy][xx][1] ~= " ") or buffer[yy][xx][3] ~= oldBuffer[yy][xx][3] or buffer[yy][xx][4] ~= oldBuffer[yy][xx][4] or i == 1 then - local thisChar, thisT, thisB, xBump = chars[buffer[yy][xx][1]:byte()], buffer[yy][xx][2], buffer[yy][xx][3], (xx - xMin) * charW -if thisChar then - for y = 1, charH do - for x = 1, charW do - local ch = thisChar[y][x] and thisT or thisB - thisFrame[y + yBump][x + xBump] = ch - end - end -end - - if buffer[yy][xx][4] then - thisT, thisChar = colourNum[tCol], chars[95] - for y = 1, charH do for x = 1, charW do if thisChar[y][x] then thisFrame[y + yBump][x + xBump] = thisT end end end - end - end end - - for y = yBump + 1, yBump + charH do - local skip, chars, row = 0, {}, {} - - for x = 1, #thisFrame[y] do - if thisFrame[y][x] == " " then - if #chars > 0 then - row[#row + 1] = table.concat(chars) - chars = {} - end - - skip = skip + 1 - else - if skip > 0 then - row[#row + 1] = skip - skip = 0 - end - - chars[#chars + 1] = thisFrame[y][x] - end - end - - if #chars > 0 then row[#row + 1] = table.concat(chars) end - thisFrame[y] = row - end - - snooze() - end - - if changed then - image[#image + 1] = thisFrame - else - image[#image].delay = image[#image].delay + curCalls.delay - end -end - -buffer = nil - -GIF.saveGIF(image, filename) - -fs.delete('ascii.gif') - -print("Encode complete") diff --git a/sys/apps/shapes.lua b/sys/apps/shapes.lua deleted file mode 100644 index 5b694df..0000000 --- a/sys/apps/shapes.lua +++ /dev/null @@ -1,517 +0,0 @@ -requireInjector(getfenv(1)) - -local GPS = require('gps') -local Socket = require('socket') -local UI = require('ui') -local Util = require('util') - -multishell.setTitle(multishell.getCurrent(), 'Shapes') - -local args = { ... } -local turtleId = args[1] or error('Supply turtle ID') -turtleId = tonumber(turtleId) - -local script = [[ - -requireInjector(getfenv(1)) - -local GPS = require('gps') -local ChestAdapter = require('chestAdapter18') -local Point = require('point') -local Util = require('util') - -local itemAdapter - -function dumpInventory() - - for i = 1, 16 do - local qty = turtle.getItemCount(i) - if qty > 0 then - itemAdapter:insert(i, qty) - end - if turtle.getItemCount(i) ~= 0 then - print('Adapter 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) - - itemAdapter:provide({ name = 'minecraft:coal', damage = 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) - - itemAdapter = ChestAdapter({ 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 levelScript = [[ - -requireInjector(getfenv(1)) - -local Point = require('point') -local Util = require('util') - -local checkedNodes = { } -local nodes = { } -local box = { } - -local function inBox(pt, box) - return pt.x >= box.x and - pt.y >= box.y and - pt.z >= box.z and - pt.x <= box.ex and - pt.y <= box.ey and - pt.z <= box.ez -end - -local function toKey(pt) - return table.concat({ pt.x, pt.y, pt.z }, ':') -end - -local function addNode(node) - - for i = 0, 5 do - local hi = turtle.getHeadingInfo(i) - local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd } - - if inBox(testNode, box) then - local key = toKey(testNode) - if not checkedNodes[key] then - nodes[key] = testNode - end - end - end -end - -local function dig(action) - - local directions = { - top = 'up', - bottom = 'down', - } - - -- convert to up, down, north, south, east, west - local direction = directions[action.side] or - turtle.getHeadingInfo(turtle.point.heading).direction - - local hi = turtle.getHeadingInfo(direction) - local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd } - if inBox(node, box) then - - local key = toKey(node) - checkedNodes[key] = true - nodes[key] = nil - - if action.dig() then - addNode(node) - repeat until not action.dig() -- sand, etc - return true - end - end -end - -local function move(action) - if action == 'turn' then - dig(turtle.getAction('forward')) - elseif action == 'up' then - dig(turtle.getAction('up')) - elseif action == 'down' then - dig(turtle.getAction('down')) - elseif action == 'back' then - dig(turtle.getAction('up')) - dig(turtle.getAction('down')) - end -end - -local function getAdjacentPoint(pt) - local t = { } - table.insert(t, pt) - for i = 0, 5 do - local hi = turtle.getHeadingInfo(i) - local heading - if i < 4 then - heading = (hi.heading + 2) % 4 - end - table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading }) - end - - return Point.closest2(turtle.getPoint(), t) -end - -local function level() - - box.x = math.min(data.startPt.x, data.endPt.x) - box.y = math.min(data.startPt.y, data.endPt.y) - box.z = math.min(data.startPt.z, data.endPt.z) - box.ex = math.max(data.startPt.x, data.endPt.x) - box.ey = math.max(data.startPt.y, data.endPt.y) - box.ez = math.max(data.startPt.z, data.endPt.z) - - turtle.pathfind(data.firstPt) - - turtle.setPolicy("attack", { dig = dig }, "assuredMove") - turtle.setMoveCallback(move) - - repeat - local key = toKey(turtle.point) - - checkedNodes[key] = true - nodes[key] = nil - - dig(turtle.getAction('down')) - dig(turtle.getAction('up')) - dig(turtle.getAction('forward')) - - print(string.format('%d nodes remaining', Util.size(nodes))) - - if Util.size(nodes) == 0 then - break - end - - local node = Point.closest2(turtle.point, nodes) - node = getAdjacentPoint(node) - if not turtle.gotoPoint(node) then - break - end - until turtle.abort - - turtle.resetState() -end - -local s, m = turtle.run(function() - turtle.status = 'Leveling' - - if turtle.enableGPS() then - - local pt = Util.shallowCopy(turtle.point) - local s, m = pcall(level) - turtle.pathfind(pt) - - if not s and m then - error(m) - end - end -end) - -if not s then - error(m) -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' }, - first = UI.Button { x = 2, y = 11, text = 'First', event = 'firstCoord' }, - 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) - -Util.writeFile('script.tmp', 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 == 'firstCoord' then - data.firstPt = self:getPoint() - if data.firstPt then - self.statusBar:setStatus('first point 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) .. levelScript - 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/shell b/sys/apps/shell index 9d7278d..cd832f2 100644 --- a/sys/apps/shell +++ b/sys/apps/shell @@ -41,7 +41,12 @@ end function shell.run(...) local path, args = parseCommandLine(...) - path = shell.resolveProgram(path) + local isUrl = not not path:match("^(https?:)//(([^/:]+):?([0-9]*))(/?.*)$") + + if not isUrl then + path = shell.resolveProgram(path) + end + if path then tProgramStack[#tProgramStack + 1] = path local oldTitle @@ -51,7 +56,15 @@ function shell.run(...) multishell.setTitle(multishell.getCurrent(), fs.getName(path)) end - local result, err = os.run(Util.shallowCopy(sandboxEnv), path, unpack(args)) + local result, err + + if isUrl then + local env = Util.shallowCopy(sandboxEnv) + setmetatable(env, { __index = _G }) + result, err = Util.runUrl(env, path, unpack(args)) + else + result, err = os.run(Util.shallowCopy(sandboxEnv), path, unpack(args)) + end if multishell then local title = 'shell' diff --git a/sys/apps/simpleMiner.lua b/sys/apps/simpleMiner.lua deleted file mode 100644 index fb34c41..0000000 --- a/sys/apps/simpleMiner.lua +++ /dev/null @@ -1,633 +0,0 @@ -requireInjector(getfenv(1)) - -local Logger = require('logger') -local Point = require('point') -local Util = require('util') - -if device and device.wireless_modem then - Logger.setWirelessLogging() -end - -local args = { ... } -local options = { - chunks = { arg = 'c', type = 'number', value = -1, - desc = 'Number of chunks to mine' }, - depth = { arg = 'd', type = 'number', value = 9000, - desc = 'Mining depth' }, --- enderChest = { arg = 'e', type = 'flag', value = false, --- desc = 'Use ender chest' }, - resume = { arg = 'r', type = 'flag', value = false, - desc = 'Resume mining' }, - fortunePick = { arg = 'p', type = 'string', value = nil, - desc = 'Pick to use with CCTweaks toolhost' }, - setTrash = { arg = 's', type = 'flag', value = false, - desc = 'Set trash items' }, - help = { arg = 'h', type = 'flag', value = false, - desc = 'Displays the options' }, -} - -local fortuneBlocks = { - [ 'minecraft:redstone_ore' ] = true, - [ 'minecraft:lapis_ore' ] = true, - [ 'minecraft:coal_ore' ] = true, - [ 'minecraft:diamond_ore' ] = true, - [ 'minecraft:emerald_ore' ] = true, -} - -local MIN_FUEL = 7500 -local LOW_FUEL = 1500 -local MAX_FUEL = 100000 - -if not term.isColor() then - MAX_FUEL = 20000 -end - -local mining = { - diameter = 1, - chunkIndex = 0, - chunks = -1, -} - -local trash -local boreDirection - -function getChunkCoordinates(diameter, index, x, z) - local dirs = { -- circumference of grid - { xd = 0, zd = 1, heading = 1 }, -- south - { xd = -1, zd = 0, heading = 2 }, - { xd = 0, zd = -1, heading = 3 }, - { xd = 1, zd = 0, heading = 0 } -- east - } - -- always move east when entering the next diameter - if index == 0 then - dirs[4].x = x + 16 - dirs[4].z = z - return dirs[4] - end - dir = dirs[math.floor(index / (diameter - 1)) + 1] - dir.x = x + dir.xd * 16 - dir.z = z + dir.zd * 16 - return dir -end - -function getBoreLocations(x, z) - - local locations = {} - - while true do - local a = math.abs(z) - local b = math.abs(x) - - if x > 0 and z > 0 or - x < 0 and z < 0 then - -- rotate coords - a = math.abs(x) - b = math.abs(z) - end - if (a % 5 == 0 and b % 5 == 0) or - (a % 5 == 2 and b % 5 == 1) or - (a % 5 == 4 and b % 5 == 2) or - (a % 5 == 1 and b % 5 == 3) or - (a % 5 == 3 and b % 5 == 4) then - table.insert(locations, { x = x, z = z, y = 0 }) - end - if z % 2 == 0 then -- forward dir - if (x + 1) % 16 == 0 then - z = z + 1 - else - x = x + 1 - end - else - if (x - 1) % 16 == 15 then - if (z + 1) % 16 == 0 then - break - end - z = z + 1 - else - x = x - 1 - end - end - end - return locations -end - --- get the bore location closest to the miner -local function getClosestLocation(points, b) - local key = 1 - local leastMoves = 9000 - for k,pt in pairs(points) do - - local moves = Point.calculateMoves(turtle.point, pt) - - if moves < leastMoves then - key = k - leastMoves = moves - if leastMoves == 0 then - break - end - end - end - return table.remove(points, key) -end - -function getCornerOf(c) - return math.floor(c.x / 16) * 16, math.floor(c.z / 16) * 16 -end - -function nextChunk() - - local x, z = getCornerOf({ x = mining.x, z = mining.z }) - local points = math.pow(mining.diameter, 2) - math.pow(mining.diameter-2, 2) - mining.chunkIndex = mining.chunkIndex + 1 - - if mining.chunkIndex >= points then - mining.diameter = mining.diameter + 2 - mining.chunkIndex = 0 - end - - if mining.chunks ~= -1 then - local chunks = math.pow(mining.diameter-2, 2) + mining.chunkIndex - if chunks >= mining.chunks then - return false - end - end - - local nc = getChunkCoordinates(mining.diameter, mining.chunkIndex, x, z) - mining.locations = getBoreLocations(nc.x, nc.z) - - -- enter next chunk - mining.x = nc.x - mining.z = nc.z - - Util.writeTable('mining.progress', mining) - - return true -end - -function addTrash() - - if not trash then - trash = { } - end - - local slots = turtle.getFilledSlots() - - for k,slot in pairs(slots) do - trash[slot.iddmg] = true - end - - trash['minecraft:bucket:0'] = nil - Util.writeTable('mining.trash', trash) -end - -function log(text) - print(text) - Logger.log('mineWorker', text) -end - -function status(status) - turtle.status = status - log(status) -end - -function refuel() - if turtle.getFuelLevel() < MIN_FUEL then - local oldStatus = turtle.status - status('refueling') - - if turtle.selectSlot('minecraft:coal:0') then - local qty = turtle.getItemCount() - print('refueling ' .. qty) - turtle.refuel(qty) - end - if turtle.getFuelLevel() < MIN_FUEL then - log('desperate fueling') - - turtle.eachFilledSlot(function(slot) - if turtle.getFuelLevel() < MIN_FUEL then - turtle.select(slot.index) - turtle.refuel(64) - end - end) - end - log('Fuel: ' .. turtle.getFuelLevel()) - status(oldStatus) - end - - turtle.select(1) -end - -function enderChestUnload() - log('unloading') - turtle.select(1) - if not Util.tryTimed(5, function() - turtle.digDown() - return turtle.placeDown() - end) then - log('placedown failed') - else - turtle.reconcileInventory(slots, turtle.dropDown) - - turtle.select(1) - turtle.drop(64) - turtle.digDown() - end -end - -function safeGoto(x, z, y, h) - local oldStatus = turtle.status - while not turtle.pathfind({ x = x, z = z, y = y, heading = h }) do - --status('stuck') - if turtle.abort then - return false - end - --os.sleep(1) - end - turtle.status = oldStatus - return true -end - -function safeGotoY(y) - local oldStatus = turtle.status - while not turtle.gotoY(y) do - status('stuck') - if turtle.abort then - return false - end - os.sleep(1) - end - turtle.status = oldStatus - return true -end - -function makeWalkableTunnel(action, tpt, pt) - if action ~= 'turn' and not Point.compare(tpt, { x = 0, z = 0 }) then -- not at source - if not Point.compare(tpt, pt) then -- not at dest - local r, block = turtle.inspectUp() - if r and not turtle.isTurtleAtSide('top') then - if block.name ~= 'minecraft:cobblestone' and - block.name ~= 'minecraft:chest' then - turtle.digUp() - end - end - end - end -end - -function normalChestUnload() - local oldStatus = turtle.status - status('unloading') - local pt = Util.shallowCopy(turtle.point) - safeGotoY(0) - - turtle.setMoveCallback(function(action, tpt) - makeWalkableTunnel(action, tpt, { x = pt.x, z = pt.z }) - end) - - safeGoto(0, 0) - if not turtle.detectUp() then - error('no chest') - end - local slots = turtle.getFilledSlots() - for _,slot in pairs(slots) do - if not trash[slot.iddmg] and - slot.iddmg ~= 'minecraft:bucket:0' and - slot.id ~= 'minecraft:diamond_pickaxe' and - slot.id ~= 'cctweaks:toolHost' then - if slot.id ~= options.fortunePick.value then - turtle.select(slot.index) - turtle.dropUp(64) - end - end - end - turtle.select(1) - safeGoto(pt.x, pt.z, 0, pt.heading) - - turtle.clearMoveCallback() - - safeGotoY(pt.y) - status(oldStatus) -end - -function ejectTrash() - - local cobbleSlotCount = 0 - - turtle.eachFilledSlot(function(slot) - if slot.iddmg == 'minecraft:cobblestone:0' then - cobbleSlotCount = cobbleSlotCount + 1 - end - - if trash[slot.iddmg] then - -- retain 1 slot with cobble in order to indicate active mining - if slot.iddmg ~= 'minecraft:cobblestone:0' or cobbleSlotCount > 1 then - turtle.select(slot.index) - turtle.dropDown(64) - end - end - end) -end - -function mineable(action) - local r, block = action.inspect() - if not r then - return false - end - - if block.name == 'minecraft:chest' then - collectDrops(action.suck) - end - - if turtle.getFuelLevel() < (MAX_FUEL - 1000) then - if block.name == 'minecraft:lava' or block.name == 'minecraft:flowing_lava' then - if turtle.selectSlot('minecraft:bucket:0') then - if action.place() then - log('Lava! ' .. turtle.getFuelLevel()) - turtle.refuel() - log(turtle.getFuelLevel()) - end - turtle.select(1) - end - return false - end - end - - if action.side == 'bottom' then - return block.name - end - - if trash[block.name .. ':0'] then - return false - end - - return block.name -end - -function fortuneDig(action, blockName) - if options.fortunePick.value and fortuneBlocks[blockName] then - turtle.selectSlot('cctweaks:toolHost') - turtle.equipRight() - turtle.selectSlot(options.fortunePick.value) - repeat until not turtle.dig() - turtle.selectSlot('minecraft:diamond_pickaxe') - turtle.equipRight() - turtle.select(1) - return true - end -end - -function mine(action) - local blockName = mineable(action) - if blockName then - checkSpace() - --collectDrops(action.suck) - if not fortuneDig(action, blockName) then - action.dig() - end - end -end - -function bore() - - local loc = turtle.point - local level = loc.y - - turtle.select(1) - status('boring down') - boreDirection = 'down' - - while true do - if turtle.abort then - status('aborting') - return false - end - if loc.y <= -mining.depth then - break - end - - if turtle.point.y < -2 then --- turtle.setDigPolicy(turtle.digPolicies.turtleSafe) - end - - mine(turtle.getAction('down')) - if not Util.tryTimed(3, turtle.down) then - break - end - - if loc.y < level - 1 then - mine(turtle.getAction('forward')) - turtle.turnRight() - mine(turtle.getAction('forward')) - end - end - - boreDirection = 'up' - status('boring up') - - turtle.turnRight() - mine(turtle.getAction('forward')) - - turtle.turnRight() - mine(turtle.getAction('forward')) - - turtle.turnLeft() - - while true do - if turtle.abort then - status('aborting') - return false - end - - if turtle.point.y > -2 then --- turtle.setDigPolicy(turtle.digPolicies.turtleSafe) - end - - while not Util.tryTimed(3, turtle.up) do - status('stuck') - end - if turtle.status == 'stuck' then - status('boring up') - end - - if loc.y >= level - 1 then - break - end - - mine(turtle.getAction('forward')) - turtle.turnLeft() - mine(turtle.getAction('forward')) - end - - if turtle.getFuelLevel() < LOW_FUEL then - refuel() - local veryMinFuel = Point.turtleDistance(turtle.point, { x = 0, y = 0, z = 0}) + 512 - if turtle.getFuelLevel() < veryMinFuel then - log('Not enough fuel to continue') - return false - end - end - - return true -end - -function checkSpace() - if turtle.getItemCount(16) > 0 then - refuel() - local oldStatus = turtle.status - status('condensing') - ejectTrash() - turtle.condense() - local lastSlot = 16 - if boreDirection == 'down' then - lastSlot = 15 - end - if turtle.getItemCount(lastSlot) > 0 then - unload() - end - status(oldStatus) - turtle.select(1) - end -end - -function collectDrops(suckAction) - for i = 1, 50 do - if not suckAction() then - break - end - checkSpace() - end -end - -function Point.compare(pta, ptb) - if pta.x == ptb.x and pta.z == ptb.z then - if pta.y and ptb.y then - return pta.y == ptb.y - end - return true - end - return false -end - -function inspect(action, name) - local r, block = action.inspect() - if r and block.name == name then - return true - end -end - -function boreCommand() - local pt = getClosestLocation(mining.locations, turtle.point) - - turtle.setMoveCallback(function(action, tpt) - makeWalkableTunnel(action, tpt, pt) - end) - - safeGotoY(0) - safeGoto(pt.x, pt.z, 0) - - turtle.clearMoveCallback() - - -- location is either mined, currently being mined or is the - -- dropoff point for a turtle - if inspect(turtle.getAction('up'), 'minecraft:cobblestone') or - inspect(turtle.getAction('up'), 'minecraft:chest') or - inspect(turtle.getAction('down'), 'minecraft:cobblestone') then - return true - end - - turtle.digUp() - turtle.placeUp('minecraft:cobblestone:0') - - local success = bore() - - safeGotoY(0) -- may have aborted - turtle.digUp() - - if success then - turtle.placeDown('minecraft:cobblestone:0') -- cap with cobblestone to indicate this spot was mined out - end - - return success -end - -if not Util.getOptions(options, args) then - return -end - -mining.depth = options.depth.value -mining.chunks = options.chunks.value - -unload = normalChestUnload ---if options.enderChest.value then --- unload = enderChestUnload ---end - -mining.x = 0 -mining.z = 0 -mining.locations = getBoreLocations(0, 0) -trash = Util.readTable('mining.trash') - -if options.resume.value then - mining = Util.readTable('mining.progress') -elseif fs.exists('mining.progress') then - print('use -r to resume') - read() -end - -if not trash or options.setTrash.value then - print('Add trash blocks, press enter when ready') - read() - addTrash() -end - -if not turtle.getSlot('minecraft:bucket:0') or - not turtle.getSlot('minecraft:cobblestone:0') then - print('Add bucket and cobblestone, press enter when ready') - read() -end - -if options.fortunePick.value then - local s = turtle.getSlot(options.fortunePick.value) - if not s then - error('fortunePick not found: ' .. options.fortunePick.value) - end - if not turtle.getSlot('cctweaks:toolHost:0') then - error('CCTweaks tool host not found') - end - trash[s.iddmg] = nil - trash['minecraft:diamond_pickaxe:0'] = nil - trash['cctweaks:toolHost:0'] = nil -end - -_G._p = trash - -local function main() - repeat - while #mining.locations > 0 do - status('searching') - if not boreCommand() then - return - end - Util.writeTable('mining.progress', mining) - end - until not nextChunk() -end - -turtle.run(function() - turtle.reset() - turtle.setPolicy(turtle.policies.digAttack) - turtle.setDigPolicy(turtle.digPolicies.turtleSafe) - - unload() - status('mining') - - local s, m = pcall(function() main() end) - if not s and m then - printError(m) - end - - safeGotoY(0) - safeGoto(0, 0, 0, 0) - unload() - turtle.reset() -end) diff --git a/sys/apps/storageActivity.lua b/sys/apps/storageActivity.lua deleted file mode 100644 index 135ee13..0000000 --- a/sys/apps/storageActivity.lua +++ /dev/null @@ -1,174 +0,0 @@ -requireInjector(getfenv(1)) - -local ChestAdapter = require('chestAdapter18') -local Event = require('event') -local MEAdapter = require('meAdapter') -local RefinedAdapter = require('refinedAdapter') -local UI = require('ui') -local Util = require('util') - -local storage = RefinedAdapter() -if not storage:isValid() then - storage = MEAdapter() - if not storage:isValid() then - storage = ChestAdapter() - end -end - -if not storage:isValid() then - error('Not connected to a storage device') -end - -multishell.setTitle(multishell.getCurrent(), 'Storage Activity') -UI:configure('StorageActivity', ...) - -local changedPage = UI.Page({ - grid = UI.Grid({ - columns = { - { heading = 'Qty', key = 'count', width = 5 }, - { heading = 'Change', key = 'change', width = 6 }, - { heading = 'Name', key = 'displayName', width = UI.term.width - 15 }, - }, - sortColumn = 'displayName', - rey = -6, - }), - buttons = UI.Window({ - ry = -4, - height = 5, - backgroundColor = colors.gray, - prevButton = UI.Button({ - event = 'previous', - backgroundColor = colors.lightGray, - x = 2, - y = 2, - height = 3, - width = 5, - text = ' < ' - }), - resetButton = UI.Button({ - event = 'reset', - backgroundColor = colors.lightGray, - x = 8, - y = 2, - height = 3, - rex = -8, - text = 'Reset' - }), - nextButton = UI.Button({ - event = 'next', - backgroundColor = colors.lightGray, - rx = -5, - y = 2, - height = 3, - width = 5, - text = ' > ' - }) - }), - accelerators = { - q = 'quit', - } -}) - -function changedPage.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - - local ind = '+' - if row.change < 0 then - ind = '' - end - row.change = ind .. Util.toBytes(row.change) - row.count = Util.toBytes(row.count) - - return row -end - -function changedPage:eventHandler(event) - - if event.type == 'reset' then - self.lastItems = nil - self.grid:setValues({ }) - self.grid:clear() - self.grid:draw() - - elseif event.type == 'next' then - self.grid:nextPage() - - elseif event.type == 'previous' then - self.grid:previousPage() - - elseif event.type == 'quit' then - Event.exitPullEvents() - - else - return UI.Page.eventHandler(self, event) - end - - return true -end - -local function uniqueKey(item) - return table.concat({ item.name, item.damage, item.nbtHash }, ':') -end - -function changedPage:refresh() - local t = storage:listItems() - - if not t or Util.empty(t) then - self:clear() - self:centeredWrite(math.ceil(self.height/2), 'Communication failure') - return - end - - for k,v in pairs(t) do - t[k] = Util.shallowCopy(v) - end - - if not self.lastItems then - self.lastItems = t - self.grid:setValues({ }) - else - local changedItems = {} - for _,v in pairs(self.lastItems) do - found = false - for k2,v2 in pairs(t) do - if uniqueKey(v) == uniqueKey(v2) then - if v.count ~= v2.count then - local c = Util.shallowCopy(v2) - c.lastCount = v.count - table.insert(changedItems, c) - end - table.remove(t, k2) - found = true - break - end - end - -- New item - if not found then - local c = Util.shallowCopy(v) - c.lastCount = v.count - c.count = 0 - table.insert(changedItems, c) - end - end - -- No items left - for k,v in pairs(t) do - v.lastCount = 0 - table.insert(changedItems, v) - end - - for k,v in pairs(changedItems) do - v.change = v.count - v.lastCount - end - - self.grid:setValues(changedItems) - end - self.grid:draw() -end - -Event.onInterval(5, function() - changedPage:refresh() - changedPage:sync() -end) - -UI:setPage(changedPage) -UI:pullEvents() diff --git a/sys/apps/storageManager.lua b/sys/apps/storageManager.lua deleted file mode 100644 index 62ef357..0000000 --- a/sys/apps/storageManager.lua +++ /dev/null @@ -1,901 +0,0 @@ -requireInjector(getfenv(1)) - -local Config = require('config') -local Event = require('event') -local Logger = require('logger') -local ME = require('me') -local UI = require('ui') -local Util = require('util') - --- Must be a crafty turtle with duck antenna ! --- 3 wide monitor (any side of turtle) - --- Config location is /sys/config/storageMonitor --- adjust directions in that file if needed - -local config = { - trashDirection = 'up', -- trash /chest in relation to interface - turtleDirection = 'down', -- turtle in relation to interface - noCraftingStorage = 'false' -- no ME crafting (or ability to tell if powered - use with caution) -} - -Config.load('storageMonitor', config) - -if not device.tileinterface then - error('ME interface not found') -end - -local duckAntenna - -if device.workbench then - - local oppositeSide = { - [ 'left' ] = 'right', - [ 'right' ] = 'left' - } - - local duckAntennaSide = oppositeSide[device.workbench.side] - duckAntenna = peripheral.wrap(duckAntennaSide) -end ---if not device.monitor then --- error('Monitor not found') ---end - -ME.setDevice(device.tileinterface) - -local jobListGrid -local craftingPaused = false - -multishell.setTitle(multishell.getCurrent(), 'Storage Manager') - -Logger.disable() - -function getItem(items, inItem, ignore_dmg) - for _,item in pairs(items) do - if item.id == inItem.id then - if ignore_dmg and ignore_dmg == 'yes' then - return item - elseif item.dmg == inItem.dmg and item.nbt_hash == inItem.nbt_hash then - return item - end - end - end -end - -local function uniqueKey(item) - local key = item.id .. ':' .. item.dmg - if item.nbt_hash then - key = key .. ':' .. item.nbt_hash - end - return key -end - -function mergeResources(t) - local resources = Util.readTable('resource.limits') - resources = resources or { } - - for _,item in pairs(t) do - item.has_recipe = false - end - - for _,v in pairs(resources) do - local item = getItem(t, v) - if item then - item.limit = tonumber(v.limit) - item.low = tonumber(v.low) - item.auto = v.auto - item.ignore_dmg = v.ignore_dmg - else - v.qty = 0 - v.limit = tonumber(v.limit) - v.low = tonumber(v.low) - v.auto = v.auto - v.ignore_dmg = v.ignore_dmg - table.insert(t, v) - end - end - - recipes = Util.readTable('recipes') or { } - - for _,v in pairs(recipes) do - local item = getItem(t, v) - if item then - item.has_recipe = true - else - v.qty = 0 - v.limit = nil - v.low = nil - v.has_recipe = true - v.auto = 'no' - v.ignore_dmg = 'no' - v.has_recipe = 'true' - table.insert(t, v) - end - end -end - -function filterItems(t, filter) - local r = {} - if filter then - filter = filter:lower() - for k,v in pairs(t) do - if string.find(v.lname, filter) then - table.insert(r, v) - end - end - else - return t - end - return r -end - -function sumItems(items) - local t = {} - - for _,item in pairs(items) do - local key = uniqueKey(item) - local summedItem = t[key] - if summedItem then - summedItem.qty = summedItem.qty + item.qty - else - summedItem = Util.shallowCopy(item) - t[key] = summedItem - end - end - - return t -end - -function isGridClear() - for i = 1, 16 do - if turtle.getItemCount(i) ~= 0 then - return false - end - end - return true -end - -local function clearGrid() - for i = 1, 16 do - local count = turtle.getItemCount(i) - if count > 0 then - ME.insert(i, count, config.turtleDirection) - if turtle.getItemCount(i) ~= 0 then - return false - end - end - end - return true -end - -function turtleCraft(recipe, originalItem) - - for k,v in pairs(recipe.ingredients) do - - -- ugh - local dmg = v.dmg - - if v.max_dmg and v.max_dmg > 0 then - local item = ME.getItemDetail({ id = v.id, nbt_hash = v.nbt_hash }, false) - if item then - dmg = item.dmg - end - end - - if not ME.extract(v.id, dmg, v.nbt_hash, v.qty, config.turtleDirection, k) then - clearGrid() - originalItem.status = v.name .. ' (extract failed)' - return false - end - end - - if not turtle.craft() then - clearGrid() - return false - end - - clearGrid() - return true -end - -function craftItem(items, recipes, item, originalItem, itemList) - - local key = uniqueKey(item) - local recipe = recipes[key] - - if recipe then - - if not isGridClear() then - return - end - - local summedItems = sumItems(recipe.ingredients) - - for i = 1, math.ceil(item.qty / recipe.qty) do - - local failed = false -- try to craft all components (use all CPUs available) - - for _,ingredient in pairs(summedItems) do - local ignore_dmg = 'no' - if ingredient.max_dmg and ingredient.max_dmg > 0 then - ignore_dmg = 'yes' - end - local qty = ME.getItemCount(ingredient.id, ingredient.dmg, ingredient.nbt_hash, ignore_dmg) - if qty < ingredient.qty then - originalItem.status = ingredient.name .. ' (crafting)' - ingredient.qty = ingredient.qty - qty - if not craftItem(items, recipes, ingredient, originalItem, itemList) then - failed = true - end - end - end - - if failed then - return false - end - - if not failed and not turtleCraft(recipe, originalItem) then - Logger.debug('turtle failed to craft ' .. item.name) - return false - end - end - - return true - - else - - local meItem = getItem(items, item) - if not meItem or not meItem.is_craftable then - - if item.id == originalItem.id and item.dmg == originalItem.dmg then - originalItem.status = '(not craftable)' - else - originalItem.status = item.name .. ' (missing)' - end - - else - - if item.id == originalItem.id and item.dmg == originalItem.dmg then - item.meCraft = true - return false - end - - -- find it in the list of items to be crafted - for _,v in pairs(itemList) do - if v.id == item.id and v.dmg == item.dmg and v.nbt_hash == item.nbt_hash then - v.qty = item.qty + v.qty - return false - end - end - -- add to the item list - table.insert(itemList, { - id = item.id, - dmg = item.dmg, - nbt_hash = item.nbt_hash, - qty = item.qty, - name = item.name, - meCraft = true, - status = '' - }) - end - end - - return false -end - -function craftItems(itemList) - - local recipes = Util.readTable('recipes') or { } - local items = ME.getAvailableItems() - - -- turtle craft anything we can, build up list for ME items - local keys = Util.keys(itemList) - for _,key in pairs(keys) do - local item = itemList[key] - craftItem(items, recipes, item, item, itemList) - end - - -- second pass is to request crafting from ME with aggregated items - for _,item in pairs(itemList) do - if item.meCraft then - - local alreadyCrafting = false - local jobList = ME.getJobList() - - for _,v in pairs(jobList) do - if v.id == item.id and v.dmg == item.dmg and v.nbt_hash == item.nbt_hash then - alreadyCrafting = true - end - end - - if alreadyCrafting then - item.status = '(crafting)' - elseif not ME.isCPUAvailable() then - item.status = '(waiting)' - else - item.status = '(failed)' - - local qty = item.qty - while qty >= 1 do -- try to request smaller quantities until successful - if ME.craft(item.id, item.dmg, item.nbt_hash, qty) then - item.status = '(crafting)' - break -- successfully requested crafting - end - qty = math.floor(qty / 2) - end - end - end - end -end - --- AE 1 (obsolete) -function isCrafting(jobList, id, dmg) - for _, job in pairs(jobList) do - if job.id == id and job.dmg == dmg then - return job - end - end -end - -local nullDevice = { - setCursorPos = function(...) end, - write = function(...) end, - getSize = function() return 13, 20 end, - isColor = function() return false end, - setBackgroundColor = function(...) end, - setTextColor = function(...) end, - clear = function(...) end, -} - -local function jobMonitor(jobList) - - local mon - - if device.monitor then - mon = UI.Device({ - deviceType = 'monitor', - textScale = .5, - }) - else - mon = UI.Device({ - device = nullDevice - }) - end - - jobListGrid = UI.Grid({ - parent = mon, - sortColumn = 'name', - columns = { - { heading = 'Qty', key = 'qty', width = 6 }, - { heading = 'Crafting', key = 'name', width = mon.width / 2 - 10 }, - { heading = 'Status', key = 'status', width = mon.width - 10 }, - }, - }) -end - -function getAutocraftItems(items) - local t = Util.readTable('resource.limits') or { } - local itemList = { } - - for _,res in pairs(t) do - - if res.auto and res.auto == 'yes' then - res.qty = 4 -- this could be higher to increase autocrafting speed - table.insert(itemList, res) - end - end - return itemList -end - -local function getItemWithQty(items, res, ignore_dmg) - - local item = getItem(items, res, ignore_dmg) - - if item then - - if ignore_dmg and ignore_dmg == 'yes' then - local qty = 0 - - for _,v in pairs(items) do - if item.id == v.id and item.nbt_hash == v.nbt_hash then - if item.max_dmg > 0 or item.dmg == v.dmg then - qty = qty + v.qty - end - end - end - - item.qty = qty - end - end - - return item -end - -function watchResources(items) - - local itemList = { } - - local t = Util.readTable('resource.limits') or { } - for k, res in pairs(t) do - local item = getItemWithQty(items, res, res.ignore_dmg) - res.limit = tonumber(res.limit) - res.low = tonumber(res.low) - if not item then - item = { - id = res.id, - dmg = res.dmg, - nbt_hash = res.nbt_hash, - name = res.name, - qty = 0 - } - end - - if res.limit and item.qty > res.limit then - Logger.debug("Purging " .. item.qty-res.limit .. " " .. res.name) - if not ME.extract(item.id, item.dmg, item.nbt_hash, item.qty - res.limit, config.trashDirection) then - Logger.debug('Failed to purge ' .. res.name) - end - - elseif res.low and item.qty < res.low then - if res.ignore_dmg and res.ignore_dmg == 'yes' then - item.dmg = 0 - end - table.insert(itemList, { - id = item.id, - dmg = item.dmg, - nbt_hash = item.nbt_hash, - qty = res.low - item.qty, - name = item.name, - status = '' - }) - end - end - - return itemList -end - -itemPage = UI.Page { - backgroundColor = colors.lightGray, - titleBar = UI.TitleBar { - title = 'Limit Resource', - previousPage = true, - event = 'form_cancel', - backgroundColor = colors.green - }, - idField = UI.Text { - x = 5, y = 3, width = UI.term.width - 10, - }, - form = UI.Form { - x = 4, y = 4, height = 8, rex = -4, - [1] = UI.TextEntry { - width = 7, - backgroundColor = colors.gray, - backgroundFocusColor = colors.gray, - formLabel = 'Min', formKey = 'low', help = 'Craft if below min' - }, - [2] = UI.TextEntry { - width = 7, - backgroundColor = colors.gray, - backgroundFocusColor = colors.gray, - formLabel = 'Max', formKey = 'limit', help = 'Eject if above max' - }, - [3] = UI.Chooser { - width = 7, - formLabel = 'Autocraft', formKey = 'auto', - nochoice = 'No', - choices = { - { name = 'Yes', value = 'yes' }, - { name = 'No', value = 'no' }, - }, - help = 'Craft until out of ingredients' - }, - [4] = UI.Chooser { - width = 7, - formLabel = 'Ignore Dmg', formKey = 'ignore_dmg', - nochoice = 'No', - choices = { - { name = 'Yes', value = 'yes' }, - { name = 'No', value = 'no' }, - }, - help = 'Ignore damage of item' - }, - }, - statusBar = UI.StatusBar { } -} - -function itemPage:enable() - UI.Page.enable(self) - self:focusFirst() -end - -function itemPage:eventHandler(event) - if event.type == 'form_cancel' then - UI:setPreviousPage() - - elseif event.type == 'focus_change' then - self.statusBar:setStatus(event.focused.help) - self.statusBar:draw() - - elseif event.type == 'form_complete' then - local values = self.form.values - local t = Util.readTable('resource.limits') or { } - for k,v in pairs(t) do - if v.id == values.id and v.dmg == values.dmg then - table.remove(t, k) - break - end - end - local keys = { 'name', 'auto', 'id', 'low', 'dmg', 'max_dmg', 'nbt_hash', 'limit', 'ignore_dmg' } - local filtered = { } - for _,key in pairs(keys) do - filtered[key] = values[key] - end - - table.insert(t, filtered) - Util.writeTable('resource.limits', t) - UI:setPreviousPage() - - else - return UI.Page.eventHandler(self, event) - end - return true -end - -listingPage = UI.Page { - menuBar = UI.MenuBar { - buttons = { - { text = 'Learn', event = 'learn' }, - { text = 'Forget', event = 'forget' }, - }, - }, - grid = UI.Grid { - y = 2, height = UI.term.height - 2, - columns = { - { heading = 'Name', key = 'name' , width = 22 }, - { heading = 'Qty', key = 'qty' , width = 5 }, - { heading = 'Min', key = 'low' , width = 4 }, - { heading = 'Max', key = 'limit', width = 4 }, - }, - sortColumn = 'name', - }, - statusBar = UI.StatusBar { - backgroundColor = colors.gray, - width = UI.term.width, - filterText = UI.Text { - x = 2, width = 6, - value = 'Filter', - }, - filter = UI.TextEntry { - x = 9, width = 19, - limit = 50, - }, - refresh = UI.Button { - x = 31, width = 8, - text = 'Refresh', - event = 'refresh', - }, - }, - accelerators = { - r = 'refresh', - q = 'quit', - } -} - -function listingPage.grid:getRowTextColor(row, selected) - if row.is_craftable then - return colors.yellow - end - if row.has_recipe then - if selected then - return colors.blue - end - return colors.lightBlue - end - return UI.Grid:getRowTextColor(row, selected) -end - -function listingPage.grid:getDisplayValues(row) - row = Util.shallowCopy(row) - row.qty = Util.toBytes(row.qty) - if row.low then - row.low = Util.toBytes(row.low) - end - if row.limit then - row.limit = Util.toBytes(row.limit) - end - return row -end - -function listingPage.statusBar:draw() - return UI.Window.draw(self) -end - -function listingPage.statusBar.filter:eventHandler(event) - if event.type == 'mouse_rightclick' then - self.value = '' - self:draw() - local page = UI:getCurrentPage() - page.filter = nil - page:applyFilter() - page.grid:draw() - page:setFocus(self) - end - return UI.TextEntry.eventHandler(self, event) -end - -function listingPage:eventHandler(event) - if event.type == 'quit' then - Event.exitPullEvents() - - elseif event.type == 'grid_select' then - local selected = event.selected - itemPage.form:setValues(selected) - itemPage.titleBar.title = selected.name - itemPage.idField.value = selected.id - UI:setPage('item') - - elseif event.type == 'refresh' then - self:refresh() - self.grid:draw() - - elseif event.type == 'learn' then - if not duckAntenna then - self.statusBar:timedStatus('Missing peripherals', 3) - else - UI:setPage('craft') - end - - elseif event.type == 'forget' then - local item = self.grid:getSelected() - if item then - local recipes = Util.readTable('recipes') or { } - local key = uniqueKey(item) - local recipe = recipes[key] - - if recipe then - recipes[key] = nil - Util.writeTable('recipes', recipes) - end - - local resources = Util.readTable('resource.limits') or { } - for k,v in pairs(resources) do - if v.id == item.id and v.dmg == item.dmg then - table.remove(resources, k) - Util.writeTable('resource.limits', resources) - break - end - end - - self.statusBar:timedStatus('Forgot: ' .. item.name, 3) - self:refresh() - self.grid:draw() - end - - elseif event.type == 'text_change' then - self.filter = event.text - if #self.filter == 0 then - self.filter = nil - end - self:applyFilter() - self.grid:draw() - self.statusBar.filter:focus() - - else - UI.Page.eventHandler(self, event) - end - return true -end - -function listingPage:enable() - self:refresh() - self:setFocus(self.statusBar.filter) - UI.Page.enable(self) -end - -function listingPage:refresh() - self.allItems = ME.getAvailableItems('all') - - mergeResources(self.allItems) - - Util.each(self.allItems, function(item) - item.lname = item.name:lower() - end) - - self:applyFilter() -end - -function listingPage:applyFilter() - local t = filterItems(self.allItems, self.filter) - self.grid:setValues(t) -end - --- without duck antenna -local function getTurtleInventory() - local inventory = { } - for i = 1,16 do - if turtle.getItemCount(i) > 0 then - turtle.select(i) - local item = turtle.getItemDetail() - inventory[i] = { - id = item.name, - dmg = item.damage, - qty = item.count, - name = item.name, - } - end - end - return inventory -end - --- Strip off color prefix -local function safeString(text) - - local val = text:byte(1) - - if val < 32 or val > 128 then - - local newText = {} - for i = 4, #text do - local val = text:byte(i) - newText[i - 3] = (val > 31 and val < 127) and val or 63 - end - return string.char(unpack(newText)) - end - - return text -end - -local function filter(t, filter) - local keys = Util.keys(t) - for _,key in pairs(keys) do - if not Util.key(filter, key) then - t[key] = nil - end - end -end - -local function learnRecipe(page) - local t = Util.readTable('recipes') or { } - local recipe = { } - local ingredients = duckAntenna.getAllStacks(false) -- getTurtleInventory() - if ingredients then - turtle.select(1) - if turtle.craft() then - recipe = duckAntenna.getAllStacks(false) -- getTurtleInventory() - if recipe and recipe[1] then - recipe = recipe[1] - local key = uniqueKey(recipe) - - clearGrid() - - recipe.name = safeString(recipe.display_name) - filter(recipe, { 'name', 'id', 'dmg', 'nbt_hash', 'qty', 'max_size' }) - - for _,ingredient in pairs(ingredients) do - ingredient.name = safeString(ingredient.display_name) - filter(ingredient, { 'name', 'id', 'dmg', 'nbt_hash', 'qty', 'max_size', 'max_dmg' }) - - if ingredient.max_dmg > 0 then -- let's try this... - ingredient.dmg = 0 - end - end - recipe.ingredients = ingredients - recipe.ignore_dmg = 'no' - - t[key] = recipe - - Util.writeTable('recipes', t) - listingPage.statusBar.filter:setValue(recipe.name) - listingPage.statusBar:timedStatus('Learned: ' .. recipe.name, 3) - listingPage.filter = recipe.name - listingPage:refresh() - listingPage.grid:draw() - - return true - end - else - page.statusBar:timedStatus('Failed to craft', 3) - end - else - page.statusBar:timedStatus('No recipe defined', 3) - end -end - -craftPage = UI.Dialog { - height = 7, width = UI.term.width - 6, - backgroundColor = colors.lightGray, - titleBar = UI.TitleBar { - title = 'Learn Recipe', - previousPage = true, - }, - idField = UI.Text { - x = 5, - y = 3, - width = UI.term.width - 10, - value = 'Place recipe in turtle' - }, - accept = UI.Button { - rx = -13, ry = -2, - text = 'Ok', event = 'accept', - }, - cancel = UI.Button { - rx = -8, ry = -2, - text = 'Cancel', event = 'cancel' - }, - statusBar = UI.StatusBar { - status = 'Crafting paused' - } -} - -function craftPage:enable() - craftingPaused = true - self:focusFirst() - UI.Dialog.enable(self) -end - -function craftPage:disable() - craftingPaused = false - UI.Dialog.disable(self) -end - -function craftPage:eventHandler(event) - if event.type == 'cancel' then - UI:setPreviousPage() - elseif event.type == 'accept' then - if learnRecipe(self) then - UI:setPreviousPage() - end - else - return UI.Dialog.eventHandler(self, event) - end - return true -end - -UI:setPages({ - listing = listingPage, - item = itemPage, - craft = craftPage, -}) - -UI:setPage(listingPage) -listingPage:setFocus(listingPage.statusBar.filter) - -clearGrid() -jobMonitor() -jobListGrid:draw() -jobListGrid:sync() - -Event.onInterval(5, function() - - if not craftingPaused then - - local items = ME.getAvailableItems() - - if Util.size(items) == 0 then - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'No items in system') - jobListGrid:sync() - - elseif config.noCraftingStorage ~= 'true' and #ME.getCraftingCPUs() <= 0 then -- only way to determine if AE is online - jobListGrid.parent:clear() - jobListGrid.parent:centeredWrite(math.ceil(jobListGrid.parent.height/2), 'Power failure') - jobListGrid:sync() - - else - local itemList = watchResources(items) - jobListGrid:setValues(itemList) - jobListGrid:draw() - jobListGrid:sync() - craftItems(itemList) - jobListGrid:update() - jobListGrid:draw() - jobListGrid:sync() - - itemList = getAutocraftItems(items) -- autocrafted items don't show on job monitor - craftItems(itemList) - end - end -end) - -UI:pullEvents() -jobListGrid.parent:reset() diff --git a/sys/apps/supplier.lua b/sys/apps/supplier.lua deleted file mode 100644 index 042de28..0000000 --- a/sys/apps/supplier.lua +++ /dev/null @@ -1,438 +0,0 @@ -requireInjector(getfenv(1)) - -local Event = require('event') -local Logger = require('logger') -local MEProvider = require('meProvider') -local Message = require('message') -local Point = require('point') -local TableDB = require('tableDB') -local Util = require('util') - ---[[ - A supplier turtle for the builder turtle. For larger builds, use - ender modems. - - Setup: - - 1. chest or ME interface at level 0 (bottom of build area) - 2. builder turtle on top facing the build area - 3. If facing the build turtle, the supplier turtle is to the right - pointing at the chest/interface -]]-- - -local ChestProvider = require('chestProvider') -if Util.getVersion() == 1.8 then - ChestProvider = require('chestProvider18') -end - -if not device.wireless_modem then - error('No wireless modem detected') -end - -Logger.filter('modem_send', 'event', 'ui') -Logger.setWirelessLogging() - -local __BUILDER_ID = 6 -local itemInfoDB - -local Builder = { - version = '1.70', - ccVersion = nil, - slots = { }, - index = 1, - fuelItem = { id = 'minecraft:coal', dmg = 0 }, - resupplying = true, - ready = true, -} - ---[[-- maxStackDB --]]-- -local maxStackDB = TableDB({ - fileName = 'maxstack.db', - tabledef = { - autokeys = false, - type = 'simple', - columns = { - { label = 'Key', type = 'key', length = 8 }, - { label = 'Quantity', type = 'number', length = 2 } - } - } -}) - -function maxStackDB:get(id, dmg) - return self.data[id .. ':' .. dmg] or 64 -end - -function Builder:dumpInventory() - - local success = true - - for i = 1, 16 do - local qty = turtle.getItemCount(i) - if qty > 0 then - self.itemProvider:insert(i, qty) - end - if turtle.getItemCount(i) ~= 0 then - success = false - end - end - turtle.select(1) - - return success -end - -function Builder:dumpInventoryWithCheck() - while not self:dumpInventory() do - Builder:log('Unable to dump inventory') - print('Provider is full or missing - make space or replace') - print('Press enter to continue') - --turtle.setHeading(0) - self.ready = false - read() - end - self.ready = true -end - -function Builder:autocraft(supplies) - local t = { } - - for i,s in pairs(supplies) do - local key = s.id .. ':' .. s.dmg - local item = t[key] - if not item then - item = { - id = s.id, - dmg = s.dmg, - qty = 0, - } - t[key] = item - end - item.qty = item.qty + (s.need-s.qty) - end - - Builder.itemProvider:craftItems(t) -end - -function Builder:refuel() - while turtle.getFuelLevel() < 4000 and self.fuelItem do - Builder:log('Refueling') - turtle.select(1) - self.itemProvider:provide(self.fuelItem, 64, 1) - if turtle.getItemCount(1) == 0 then - Builder:log('Out of fuel, add coal to chest/ME system') - --turtle.setHeading(0) - os.sleep(5) - else - turtle.refuel(64) - end - end -end - -function Builder:log(...) - Logger.log('supplier', ...) - Util.print(...) -end - -function Builder:getSupplies() - - Builder.itemProvider:refresh() - - local t = { } - for _,s in ipairs(self.slots) do - if s.need > 0 then - local item = Builder.itemProvider:getItemInfo(s.id, s.dmg) - if item then - if item.name then - s.name = item.name - end - - local qty = math.min(s.need-s.qty, item.qty) - - if qty + s.qty > item.max_size then - maxStackDB:add({ s.id, s.dmg }, item.max_size) - maxStackDB.dirty = true - maxStackDB:flush() - qty = item.max_size - s.need = qty - end - if qty > 0 then - self.itemProvider:provide(item, qty, s.index) - s.qty = turtle.getItemCount(s.index) - end - end - end - if s.qty < s.need then - table.insert(t, s) - local name = s.name or s.id .. ':' .. s.dmg - local item = itemInfoDB:get({ s.id, s.dmg }) - if item then - name = item.displayName - end - - Builder:log('Need %d %s', s.need - s.qty, name) - end - end - - return t -end - -local function moveTowardsX(dx) - - local direction = dx - turtle.point.x - local move - - if direction == 0 then - return false - end - - if direction > 0 and turtle.point.heading == 0 or - direction < 0 and turtle.point.heading == 2 then - move = turtle.forward - else - move = turtle.back - end - - return move() -end - -local function moveTowardsZ(dz) - - local direction = dz - turtle.point.z - local move - - if direction == 0 then - return false - end - - if direction > 0 and turtle.point.heading == 1 or - direction < 0 and turtle.point.heading == 3 then - move = turtle.forward - else - move = turtle.back - end - - return move() -end - -function Builder:finish() - - Builder.resupplying = true - Builder.ready = false - if turtle.gotoLocation('supplies') then - turtle.setHeading(1) - os.sleep(.1) -- random 'Computer is not connected' error... - Builder:dumpInventory() - Event.exitPullEvents() - print('Finished') - end -end - -function Builder:gotoBuilder() - - if Builder.lastPoint then - turtle.status = 'tracking' - while true do - local pt = Point.copy(Builder.lastPoint) - pt.y = pt.y + 3 - if turtle.point.y ~= pt.y then - turtle.gotoY(pt.y) - else - local distance = Point.turtleDistance(turtle.point, pt) - if distance <= 3 then - Builder:log('Synchronized') - break - end - - if turtle.point.heading % 2 == 0 then - if turtle.point.x == pt.x then - turtle.headTowardsZ(pt.z) - moveTowardsZ(pt.z) - else - moveTowardsX(pt.x) - end - elseif turtle.point.z ~= pt.z then - moveTowardsZ(pt.z) - else - turtle.headTowardsX(pt.x) - moveTowardsX(pt.x) - end - end - end - end -end - -Message.addHandler('builder', - function(h, id, msg, distance) - if not id or id ~= __BUILDER_ID then - return - end - - if not Builder.resupplying then - local pt = msg.contents - pt.y = pt.y + 3 - - turtle.status = 'supervising' - turtle.gotoYfirst(pt) - end - end) - -Message.addHandler('supplyList', - function(h, id, msg, distance) - if not id or id ~= __BUILDER_ID then - return - end - - turtle.status = 'resupplying' - Builder.resupplying = true - Builder.slots = msg.contents.slots - Builder.slotUid = msg.contents.uid - - Builder:log('Received supply list ' .. Builder.slotUid) - - os.sleep(0) - if not turtle.gotoLocation('supplies') then - Builder:log('Failed to go to supply location') - self.ready = false - Event.exitPullEvents() - end - turtle.setHeading(1) - os.sleep(.2) -- random 'Computer is not connected' error... - Builder:dumpInventoryWithCheck() - Builder:refuel() - - while true do - local supplies = Builder:getSupplies() - if #supplies == 0 then - break - end - Builder:autocraft(supplies) - turtle.status = 'waiting' - os.sleep(5) - end - Builder:log('Got all supplies') - os.sleep(0) - Builder:gotoBuilder() - Builder.resupplying = false - end) - -Message.addHandler('needSupplies', - function(h, id, msg, distance) - if not id or id ~= __BUILDER_ID then - return - end - - if Builder.resupplying or msg.contents.uid ~= Builder.slotUid then - - Builder:log('No supplies ready') - - Message.send(__BUILDER_ID, 'gotSupplies') - else - turtle.status = 'supplying' - Builder:log('Supplying') - os.sleep(0) - - local pt = msg.contents.point - pt.y = turtle.getPoint().y - pt.heading = nil - if not turtle.gotoYfirst(pt) then -- location of builder - Builder.resupplying = true - Message.send(__BUILDER_ID, 'gotSupplies') - os.sleep(0) - if not turtle.gotoLocation('supplies') then - Builder:log('failed to go to supply location') - --self.ready = false - Event.exitPullEvents() - end - turtle.setHeading(1) - return - end - pt.y = pt.y - 2 -- location where builder should go for the chest to be above - - turtle.select(15) - turtle.placeDown() - os.sleep(.1) -- random computer not connected error - local p = ChestProvider({ direction = 'up', wrapSide = 'bottom' }) - for i = 1, 16 do - p:insert(i, 64) - end - - Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true, point = pt }) - - Message.waitForMessage('thanks', 5, __BUILDER_ID) - --os.sleep(0) - - --p.condenseItems() - for i = 1, 16 do - p:extract(i, 64) - end - turtle.digDown() - turtle.status = 'waiting' - end - end) - -Message.addHandler('finished', - function(h, id) - if not id or id ~= __BUILDER_ID then - return - end - Builder:finish() - end) - -Event.on('turtle_abort', - function() - turtle.abort = false - turtle.status = 'aborting' - Builder:finish() - end) - -local function onTheWay() -- parallel routine - while true do - local e, side, _id, id, msg, distance = os.pullEvent('modem_message') - if Builder.ready then - if id == __BUILDER_ID and msg and msg.type then - if msg.type == 'needSupplies' then - Message.send(__BUILDER_ID, 'gotSupplies', { supplies = true }) - elseif msg.type == 'builder' then - Builder.lastPoint = msg.contents - end - end - end - end -end - -local args = {...} -if #args < 2 then - error('syntax: ') -end - -__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 = { - east = 'west', - west = 'east', - north = 'south', - south = 'north', - } - - Builder.itemProvider = ChestProvider({ direction = sides[args[2]], wrapSide = 'front' }) - if not Builder.itemProvider:isValid() then - error('A chest or ME interface must be in front of turtle') - end -end - -turtle.run(function() - turtle.setPoint({ x = -1, z = -2, y = -1, heading = 1 }) - - turtle.saveLocation('supplies') - - Event.pullEvents(onTheWay) -end) diff --git a/sys/apps/t.lua b/sys/apps/t.lua deleted file mode 100644 index 6ecfd2b..0000000 --- a/sys/apps/t.lua +++ /dev/null @@ -1,98 +0,0 @@ -function doCommand(command, moves) - --[[ - if command == 'sl' then - local pt = GPS.getPoint() - if pt then - turtle.storeLocation(moves, pt) - end - return - end - --]] - - local function format(value) - if type(value) == 'boolean' then - if value then return 'true' end - return 'false' - end - if type(value) ~= 'table' then - return value - end - local str - for k,v in pairs(value) do - if not str then - str = '{ ' - else - str = str .. ', ' - end - str = str .. k .. '=' .. tostring(v) - end - if str then - str = str .. ' }' - else - str = '{ }' - end - - return str - end - - local function runCommand(fn, arg) - local r = { fn(arg) } - if r[2] then - print(format(r[1]) .. ': ' .. format(r[2])) - elseif r[1] then - print(format(r[1])) - end - return r[1] - end - - local cmds = { - [ 's' ] = turtle.select, - [ 'rf' ] = turtle.refuel, - [ 'gh' ] = function() turtle.pathfind({ x = 0, y = 0, z = 0, heading = 0}) end, - } - - local repCmds = { - [ 'u' ] = turtle.up, - [ 'd' ] = turtle.down, - [ 'f' ] = turtle.forward, - [ 'r' ] = turtle.turnRight, - [ 'l' ] = turtle.turnLeft, - [ 'ta' ] = turtle.turnAround, - [ 'DD' ] = turtle.digDown, - [ 'DU' ] = turtle.digUp, - [ 'D' ] = turtle.dig, - [ 'p' ] = turtle.place, - [ 'pu' ] = turtle.placeUp, - [ 'pd' ] = turtle.placeDown, - [ 'b' ] = turtle.back, - [ 'gfl' ] = turtle.getFuelLevel, - [ 'gp' ] = turtle.getPoint, - [ 'R' ] = function() turtle.setPoint({x = 0, y = 0, z = 0, heading = 0}) return turtle.point end - } - - if cmds[command] then - runCommand(cmds[command], moves) - elseif repCmds[command] then - for i = 1, moves do - if not runCommand(repCmds[command]) then - break - end - end - end -end - -local args = {...} - -if #args > 0 then - doCommand(args[1], args[2] or 1) -else - print('Enter command (q to quit):') - while true do - local cmd = read() - if cmd == 'q' then break - end - args = { } - cmd:gsub('%w+', function(w) table.insert(args, w) end) - doCommand(args[1], args[2] or 1) - end -end diff --git a/sys/apps/treefarm.lua b/sys/apps/treefarm.lua deleted file mode 100644 index 7d1fdbb..0000000 --- a/sys/apps/treefarm.lua +++ /dev/null @@ -1,709 +0,0 @@ -requireInjector(getfenv(1)) - ---[[ - Requirements: - Place turtle against an oak tree or oak sapling - Area around turtle must be flat and can only be dirt or grass - (10 blocks in each direction from turtle) - Turtle must have: crafting table, chest - Turtle must have a pick equipped on the left side - - Optional: - Add additional sapling types that can grow with a single sapling - - Notes: - If the turtle does not get any saplings from the initial tree, place - down another sapling in front of the turtle. - - The program will be able to survive server restarts as long as it has - created the cobblestone line. If the program is stopped before that time, - place the turtle in the original position before restarting the program. -]]-- - -local ChestAdapter = require('chestAdapter18') -local Craft = require('turtle.craft') -local Level = require('turtle.level') -local Point = require('point') -local Util = require('util') - -local FUEL_BASE = 0 -local FUEL_DIRE = FUEL_BASE + 10 -local FUEL_GOOD = FUEL_BASE + 2000 - -local MIN_CHARCOAL = 24 -local MAX_SAPLINGS = 32 - -local GRID_WIDTH = 8 -local GRID_LENGTH = 10 -local GRID = { - TL = { x = 8, y = 0, z = -8 }, - TR = { x = 8, y = 0, z = 8 }, - BL = { x = -10, y = 0, z = -8 }, - BR = { x = -10, y = 0, z = 8 }, -} - -local HOME_PT = { x = 0, y = 0, z = 0, heading = 0 } - -local DIG_BLACKLIST = { - [ 'minecraft:furnace' ] = true, - [ 'minecraft:lit_furnace' ] = true, - [ 'minecraft:chest' ] = true, -} - -local COBBLESTONE = 'minecraft:cobblestone:0' -local CHARCOAL = 'minecraft:coal:1' -local OAK_LOG = 'minecraft:log:0' -local OAK_PLANK = 'minecraft:planks:0' -local CHEST = 'minecraft:chest:0' -local FURNACE = 'minecraft:furnace:0' -local SAPLING = 'minecraft:sapling:0' -local STONE = 'minecraft:stone:0' -local TORCH = 'minecraft:torch:0' -local DIRT = 'minecraft:dirt:0' -local APPLE = 'minecraft:apple:0' -local STICK = 'minecraft:stick:0' - -local ALL_SAPLINGS = { - SAPLING -} - -local state = Util.readTable('usr/config/treefarm') or { - trees = { - { x = 1, y = 0, z = 0 } - } -} - -local clock = os.clock() -local recipes = Util.readTable('sys/etc/recipes.db') or { } - -Craft.setRecipes(recipes) - -local function inspect(fn) - local s, item = fn() - if s and item then - return item.name .. ':' .. item.metadata - end - return 'minecraft:air:0' -end - -local function setState(key, value) - state[key] = value - Util.writeTable('usr/config/treefarm', state) -end - -local function refuel() - if turtle.getFuelLevel() < FUEL_GOOD then - local charcoal = turtle.getItemCount(CHARCOAL) - if charcoal > 1 then - turtle.refuel(CHARCOAL, math.min(charcoal - 1, MIN_CHARCOAL / 2)) - print('fuel: ' .. turtle.getFuelLevel()) - end - end - return true -end - -local function safePlaceBlock(item) - - if turtle.placeUp(item) then - return true - end - - local s, m = turtle.inspectUp() - if s and not DIG_BLACKLIST[m.name] then - turtle.digUp() - return turtle.placeUp(item) - end - - turtle.forward() - return turtle.placeUp(item) -end - -local function craftItem(item, qty) - - local success - - if safePlaceBlock(CHEST) then - - if turtle.equip('left', 'minecraft:crafting_table') then - - local chestAdapter = ChestAdapter({ - wrapSide = 'top', - direction = 'down', - }) - if not chestAdapter:isValid() then - print('invalid chestAdapter') - read() - end - -- turtle.emptyInventory(turtle.dropUp) - - Util.print('Crafting %d %s', (qty or 1), item) - success = Craft.craftRecipe(recipes[item], qty or 1, chestAdapter) - - repeat until not turtle.suckUp() - end - turtle.equip('left', 'minecraft:diamond_pickaxe') - turtle.digUp() - end - - return success -end - -local function cook(item, count, result, fuel, fuelCount) - - setState('cooking', true) - - fuel = fuel or CHARCOAL - fuelCount = fuelCount or math.ceil(count / 8) - Util.print('Making %d %s', count, result) - - turtle.dropForwardAt(state.furnace, fuel, fuelCount) - turtle.dropDownAt(state.furnace, item, count) - - count = count + turtle.getItemCount(result) - turtle.select(1) - turtle.pathfind(Point.below(state.furnace)) - repeat - os.sleep(1) - turtle.suckUp() - until turtle.getItemCount(result) >= count - - setState('cooking') -end - -local function makeSingleCharcoal() - - local slots = turtle.getSummedInventory() - - if not state.furnace or - slots[CHARCOAL] or - not slots[OAK_LOG] or - slots[OAK_LOG].count < 2 then - return true - end - - turtle.faceAgainst(state.furnace) - if craftItem(OAK_PLANK) then - cook(OAK_LOG, 1, CHARCOAL, OAK_PLANK, 1) - turtle.refuel(OAK_PLANK) - end - - return true -end - -local function makeCharcoal() - - local slots = turtle.getSummedInventory() - - if not state.furnace or - not slots[CHARCOAL] or - slots[CHARCOAL].count >= MIN_CHARCOAL then - return true - end - - local function getLogSlot(slots) - local maxslot = { count = 0 } - for k,slot in pairs(slots) do - if string.match(k, 'minecraft:log') then - if slot.count > maxslot.count then - maxslot = slot - end - end - end - return maxslot - end - - repeat - local slots = turtle.getSummedInventory() - local charcoal = slots[CHARCOAL].count - local slot = getLogSlot(slots) - - if slot.count < 8 then - break - end - - local toCook = math.min(charcoal, math.floor(slot.count / 8)) - toCook = math.min(toCook, math.floor((MIN_CHARCOAL + 8 - charcoal) / 8)) - toCook = toCook * 8 - - cook(slot.key, toCook, CHARCOAL) - - until charcoal + toCook >= MIN_CHARCOAL - - return true -end - -local function emptyFurnace() - if state.cooking then - - print('Emptying furnace') - - turtle.suckDownAt(state.furnace) - turtle.suckForwardAt(state.furnace) - turtle.suckUpAt(state.furnace) - setState('cooking') - end -end - -local function getCobblestone(count) - - local slots = turtle.getSummedInventory() - - if not slots[COBBLESTONE] or slots[COBBLESTONE].count < count then - - print('Collecting cobblestone') - - slots[COBBLESTONE] = true - slots[DIRT] = true - - local pt = Point.copy(GRID.BR) - pt.x = GRID.BR.x + 2 - pt.z = GRID.BR.z - 2 - - turtle.pathfind(pt) - - repeat - turtle.select(1) - turtle.digDown() - turtle.down() - for i = 1, 4 do - if inspect(turtle.inspect) == STONE then - turtle.dig() - end - turtle.turnRight() - end - - for item in pairs(turtle.getSummedInventory()) do - if not slots[item] then - turtle.drop(item) - end - end - - until turtle.getItemCount(COBBLESTONE) >= count - - turtle.gotoPoint(pt) - turtle.placeDown(DIRT) - - turtle.drop(DIRT) - end -end - -local function createFurnace() - - if not state.furnace then - if turtle.getFuelLevel() < FUEL_BASE + 100 then - return true -- try again later - end - print('Adding a furnace') - getCobblestone(8) - - if craftItem(FURNACE) then - turtle.drop(COBBLESTONE) - local furnacePt = { x = GRID.BL.x + 2, y = 1, z = GRID.BL.z + 2 } - turtle.placeAt(furnacePt, FURNACE) - setState('furnace', furnacePt) - end - end -end - -local function createPerimeter() - - if not state.perimeter then - if not state.furnace or - turtle.getFuelLevel() < FUEL_BASE + 500 or - turtle.getItemCount(OAK_LOG) == 0 or - not craftItem(OAK_PLANK, 2) then - return true - end - - print('Creating a perimeter') - - getCobblestone(GRID_WIDTH * 2 + 1) - cook(COBBLESTONE, 2, STONE, OAK_PLANK, 2) - turtle.refuel(OAK_PLANK) - - turtle.pathfind(GRID.BL) - turtle.digDown() - turtle.placeDown(STONE) - - turtle.setMoveCallback(function() - local target = COBBLESTONE - if math.abs(turtle.point.x) == GRID_LENGTH and - math.abs(turtle.point.z) == GRID_WIDTH then - target = STONE - end - - if inspect(turtle.inspectDown) ~= target then - turtle.digDown() - turtle.placeDown(target) - end - end) - - turtle.pathfind(GRID.BR) - - turtle.clearMoveCallback() - turtle.drop(COBBLESTONE) - turtle.drop(DIRT) - - setState('perimeter', true) - end -end - -local function createChests() - if state.chest_1 then - return false - end - if state.perimeter and - turtle.getFuelLevel() > FUEL_GOOD and - Craft.canCraft(CHEST, 4, turtle.getSummedInventory()) then - - print('Adding storage') - if craftItem(CHEST, 4) then - - local pt = Point.copy(GRID.BL) - pt.x = pt.x + 1 - pt.y = pt.y - 1 - - for i = 1, 2 do - pt.z = pt.z + 1 - - turtle.digDownAt(pt) - turtle.placeDown(CHEST) - - pt.z = pt.z + 1 - - turtle.digDownAt(pt) - turtle.placeDown(CHEST) - - setState('chest_' .. i, Util.shallowCopy(pt)) - - pt.z = pt.z + 1 - end - turtle.drop(DIRT) - turtle.refuel(OAK_PLANK) - end - end - return true -end - -local function dropOffItems() - - if state.chest_1 then - local slots = turtle.getSummedInventory() - - if state.chest_1 and - slots[CHARCOAL] and - slots[CHARCOAL].count >= MIN_CHARCOAL and - (turtle.getItemCount('minecraft:log') > 0 or - turtle.getItemCount('minecraft:log2') > 0) then - - print('Storing logs') - turtle.pathfind(state.chest_1) - turtle.dropDown('minecraft:log') - turtle.dropDown('minecraft:log2') - end - - if slots[APPLE] then - print('Storing apples') - turtle.dropDownAt(state.chest_2, APPLE) - end - end - - return true -end - -local function eatSaplings() - - local slots = turtle.getSummedInventory() - - for _, sapling in pairs(ALL_SAPLINGS) do - if slots[sapling] and slots[sapling].count > MAX_SAPLINGS then - turtle.refuel(sapling, slots[sapling].count - MAX_SAPLINGS) - end - end - return true -end - -local function placeTorches() - if state.torches then - return - end - - if turtle.getFuelLevel() > 100 and - Craft.canCraft(TORCH, 4, turtle.getSummedInventory()) then - - print('Placing torches') - - if craftItem(TORCH, 4) then - local pts = { } - for x = -4, 4, 8 do - for z = -4, 4, 8 do - table.insert(pts, { x = x, y = 0, z = z }) - end - end - Point.eachClosest(turtle.point, pts, function(pt) - turtle.placeAt(pt, TORCH) - end) - turtle.refuel(STICK) - turtle.refuel(OAK_PLANK) - setState('torches', true) - end - end - - return true -end - -local function randomSapling() - - local sapling = SAPLING - - if #state.trees > 1 then - ALL_SAPLINGS = { } - - local slots = turtle.getFilledSlots() - for _, slot in pairs(slots) do - if slot.name == 'minecraft:sapling' then - table.insert(ALL_SAPLINGS, slot.key) - end - end - sapling = ALL_SAPLINGS[math.random(1, #ALL_SAPLINGS)] - end - - return sapling -end - -local function fellTree(pt) - - local function desparateRefuel(min) - if turtle.getFuelLevel() < min then - local logs = turtle.getItemCount(OAK_LOG) - if logs > 0 then - if craftItem(OAK_PLANK, math.min(8, logs * 4)) then - turtle.refuel(OAK_PLANK) - print('fuel: ' .. turtle.getFuelLevel()) - end - end - end - end - - turtle.setMoveCallback(function() desparateRefuel(FUEL_DIRE) end) - - desparateRefuel(FUEL_DIRE) - - if turtle.digUpAt(Point.above(pt)) then - Level( - { x = GRID_WIDTH-1, y = 1, z = GRID_WIDTH-1 }, - { x = -(GRID_WIDTH-1), y = 50, z = -(GRID_WIDTH-1) }, - Point.above(pt)) - end - - desparateRefuel(FUEL_BASE + 100) - turtle.clearMoveCallback() - turtle.setPolicy("attack") - - return true -end - -local function fell() - - local pts = Util.shallowCopy(state.trees) - - local pt = table.remove(pts, math.random(1, #pts)) - if not turtle.faceAgainst(pt) or - not string.match(inspect(turtle.inspect), 'minecraft:log') then - return true - end - - print('Chopping') - - local fuel = turtle.getFuelLevel() - table.insert(pts, 1, pt) - - Point.eachClosest(turtle.point, pts, function(pt) - if turtle.faceAgainst(pt) and - string.match(inspect(turtle.inspect), 'minecraft:log') then - turtle.dig() - fellTree(pt) - end - turtle.placeAt(pt, randomSapling()) - turtle.select(1) - end) - - print('Used ' .. (fuel - turtle.getFuelLevel()) .. ' fuel') - return true -end - -local function moreTrees() - - if #state.trees > 1 then - return - end - - if not state.chest_1 or turtle.getItemCount(SAPLING) < 9 then - return true - end - - print('Adding more trees') - - local singleTree = state.trees[1] - - state.trees = { } - for x = -2, 2, 2 do - for z = -2, 2, 2 do - table.insert(state.trees, { x = x, y = 0, z = z }) - end - end - - turtle.digAt(singleTree) - fellTree(singleTree) - - setState('trees', state.trees) - - Point.eachClosest(turtle.point, state.trees, function(pt) - turtle.placeDownAt(pt, randomSapling()) - end) -end - -function getTurtleFacing(block) - local directions = { - [5] = 2, - [3] = 3, - [4] = 0, - [2] = 1, - } - - if not safePlaceBlock(block) then - error('unable to place chest above') - end - local _, bi = turtle.inspectUp() - turtle.digUp() - return directions[bi.metadata] -end - -function saveTurtleFacing() - if not state.facing then - setState('facing', getTurtleFacing(CHEST)) - end -end - -local function findGround() - print('Locating ground level') - turtle.setPoint(HOME_PT) - - while true do - local s, block = turtle.inspectDown() - - if not s then block = { name = 'minecraft:air', metadata = 0 } end - b = block.name .. ':' .. block.metadata - - if b == 'minecraft:dirt:0' or - b == 'minecraft:grass:0' or - block.name == 'minecraft:chest' then - break - end - - if b == COBBLESTONE or b == STONE then - error('lost') - end - - if b == TORCH or b == FURNACE then - turtle.forward() - else - turtle.digDown() - turtle.down() - end - - if turtle.point.y < -20 then - error('lost') - end - end - turtle.setPoint(HOME_PT) -end - -local function findHome() - - if not state.perimeter then - return - end - - print('Determining location') - - turtle.point.heading = getTurtleFacing(CHEST) - turtle.setHeading(state.facing) - turtle.point.heading = 0 - - local pt = Point.copy(turtle.point) - - while inspect(turtle.inspectDown) ~= COBBLESTONE do - pt.x = pt.x - 1 - turtle.pathfind(pt) - if pt.x < -20 then - error('lost') - end - end - while inspect(turtle.inspectDown) == COBBLESTONE do - pt.z = pt.z - 1 - turtle.pathfind(pt) - if pt.z < -20 then - error('lost') - end - end - - turtle.setPoint({ - x = -(GRID_LENGTH), - y = 0, - z = -GRID_WIDTH, - heading = turtle.point.heading - }) -end - -local function updateClock() - - local ONE_HOUR = 50 - - if os.clock() - clock > ONE_HOUR then - clock = os.clock() - else - print('sleeping for ' .. math.floor(ONE_HOUR - (os.clock() - clock))) - os.sleep(ONE_HOUR - (os.clock() - clock)) - clock = os.clock() - end - - return true -end - -local tasks = { - { desc = 'Finding ground', fn = findGround }, - { desc = 'Determine facing', fn = saveTurtleFacing }, - { desc = 'Finding home', fn = findHome }, - { desc = 'Adding trees', fn = moreTrees }, - { desc = 'Chopping', fn = fell }, - { desc = 'Snacking', fn = eatSaplings }, - { desc = 'Creating chest', fn = createChests }, - { desc = 'Creating furnace', fn = createFurnace }, - { desc = 'Emptying furnace', fn = emptyFurnace }, - { desc = 'Making charcoal', fn = makeSingleCharcoal }, - { desc = 'Making charcoal', fn = makeCharcoal }, - { desc = 'Creating perimeter', fn = createPerimeter }, - { desc = 'Placing torches', fn = placeTorches }, - { desc = 'Refueling', fn = refuel }, - { desc = 'Dropping off items', fn = dropOffItems }, - { desc = 'Condensing', fn = turtle.condense }, - { desc = 'Sleeping', fn = updateClock }, -} - -turtle.run(function() - - turtle.setPolicy("attack") - - while not turtle.abort do - print('fuel: ' .. turtle.getFuelLevel()) - for _,task in ipairs(Util.shallowCopy(tasks)) do - --print(task.desc) - turtle.status = task.desc - turtle.select(1) - if not task.fn() then - Util.filterInplace(tasks, function(v) return v.fn ~= task.fn end) - end - end - end -end) diff --git a/sys/boot/multishell.boot b/sys/boot/multishell.boot index 0d3c40d..e63a58d 100644 --- a/sys/boot/multishell.boot +++ b/sys/boot/multishell.boot @@ -1,6 +1,6 @@ print('\nStarting Opus..') -LUA_PATH = '/sys/apis' +LUA_PATH = '/sys/apis:/usr/apis' local Util = dofile('sys/apis/util.lua') _G.debug = function(...) Util.print(...) end @@ -15,7 +15,7 @@ if not s then end -- process fstab -local mounts = Util.readFile('sys/etc/fstab') +local mounts = Util.readFile('usr/etc/fstab') if mounts then for _,l in ipairs(Util.split(mounts)) do if l:sub(1, 1) ~= '#' then @@ -25,6 +25,8 @@ if mounts then end end +fs.mount('usr', 'gitfs', 'kepler155c', 'opus-apps', 'develop') + -- user environment if not fs.exists('usr/apps') then fs.makeDir('usr/apps') diff --git a/sys/etc/app.db b/sys/etc/app.db index 9ee9df8..5ac07d5 100644 --- a/sys/etc/app.db +++ b/sys/etc/app.db @@ -103,7 +103,7 @@ icon = "\030f \ \030f\0310lua>\031 \ \030f ", - run = "Lua.lua", + run = "sys/apps/Lua.lua", }, [ "89307d419a2fe4fbb69af92b3d3af27b6ec14d3e" ] = { title = "Telnet", @@ -177,14 +177,6 @@ \031e\\/\031 \0319c", run = "vnc.lua", }, - [ "4759bf14d7a511508e86c343c934894b6e8db533" ] = { - title = "Builder", - category = "Apps", - icon = "\0317_____\ -\030e\031c###\0308\0317=\030e\031c#\ -\030e\031c#\0307\031f.\030e\031c###", - run = "builder.lua", - }, [ "6ce6c512ea433a7fc5c8841628e7696cd0ff7f2b" ] = { title = "Files", category = "Apps", @@ -217,4 +209,36 @@ \0304 \030f \030 ", run = "shell", }, + [ "131f0b008f44298812221d120d982940609be781" ] = { + title = "Builder", + category = "Apps", + icon = "\0317_____\ +\030e\031c###\0308\0317=\030e\031c#\ +\030e\031c#\0307\031f.\030e\031c###", + run = "usr/apps/builder.lua", + }, + [ "d8c298dd41e4a4ec20e8307901797b64688b3b77" ] = { + title = "GPS Deploy", + category = "Apps", + run = "http://pastebin.com/raw/qLthLak5", + requires = "turtle", + }, + [ "53a5d150062b1e03206b9e15854b81060e3c7552" ] = { + apptype = "url", + title = "Minesweeper", + category = "Games", + run = "http://pastebin.com/raw/nsKrHTbN", + }, + [ "8d59207c8a84153b3e9f035cc3b6ec7a23671323" ] = { + apptype = "url", + title = "Micropaint", + category = "Apps", + run = "http://pastebin.com/raw/tMRzJXx2", + }, + [ "d78f28759f255a0db76604ee560b87c4715a0da5" ] = { + apptype = "url", + title = "Sketch", + category = "Apps", + run = "http://pastebin.com/raw/Mm5hd97E", + }, } diff --git a/sys/etc/blocks.json b/sys/etc/blocks.json deleted file mode 100644 index 99b7ef3..0000000 --- a/sys/etc/blocks.json +++ /dev/null @@ -1,1370 +0,0 @@ -{ - "air": { - "id": 0, - "name": "Air", - }, - "stone": { - "id": 1, - "name": ["Stone", - "Granite", - "Polished Granite", - "Diorite", - "Polished Diorite", - "Andesite", - "Polished Andesite"], - }, - "grass": { - "id": 2, - "name": "Grass Block", - }, - "dirt": { - "id": 3, - "name": ["Dirt", - "Coarse Dirt", - "Podzol"], - }, - "cobblestone": { - "id": 4, - "name": "Cobblestone", - }, - "planks": { - "id": 5, - "name": ["Oak Wood Planks", - "Spruce Wood Planks", - "Birch Wood Planks", - "Jungle Wood Planks", - "Acacia Wood Planks", - "Dark Oak Wood Planks"], - }, - "sapling": { - "id": 6, - "name": ["Oak Sapling", - "Spruce Sapling", - "Birch Sapling", - "Jungle Sapling", - "Acacia Sapling", - "Dark Oak Sapling"], - "place": "sapling", - }, - "bedrock": { - "id": 7, - "name": "Bedrock", - }, - "flowing_water": { - "id": 8, - "name": "Water", - "place": "flatten", - }, - "water": { - "id": 9, - "name": "Water", - "place": "flatten", - }, - "flowing_lava": { - "id": 10, - "name": "Lava", - }, - "lava": { - "id": 11, - "name": "Lava", - }, - "sand": { - "id": 12, - "name": ["Sand", - "Red Sand"], - }, - "gravel": { - "id": 13, - "name": "Gravel", - }, - "gold_ore": { - "id": 14, - "name": "Gold Ore", - }, - "iron_ore": { - "id": 15, - "name": "Iron Ore", - }, - "coal_ore": { - "id": 16, - "name": "Coal Ore", - }, - "log": { - "id": 17, - "name": ["Oak Wood", - "Spruce Wood", - "Birch Wood", - "Jungle Wood"], - "place": "wood", - }, - "leaves": { - "id": 18, - "name": ["Oak Leaves", - "Spruce Leaves", - "Birch Leaves", - "Jungle Leaves"], - "place": "leaves", - }, - "sponge": { - "id": 19, - "name": ["Sponge", - "Wet Sponge"], - }, - "glass": { - "id": 20, - "name": "Glass", - }, - "lapis_ore": { - "id": 21, - "name": "Lapis Lazuli Ore", - }, - "lapis_block": { - "id": 22, - "name": "Lapis Lazuli Block", - }, - "dispenser": { - "id": 23, - "name": "Dispenser", - "place": "dispenser", - }, - "sandstone": { - "id": 24, - "name": ["Sandstone", - "Chiseled Sandstone", - "Smooth Sandstone"], - }, - "noteblock": { - "id": 25, - "name": "Note Block", - }, - "bed": { - "id": 26, - "name": "Bed", - "place": "bed", - }, - "golden_rail": { - "id": 27, - "name": "Powered Rail", - "place": "adp-rail", - }, - "detector_rail": { - "id": 28, - "name": "Detector Rail", - "place": "adp-rail", - }, - "sticky_piston": { - "id": 29, - "name": "Sticky Piston", - "place": "piston", - }, - "web": { - "id": 30, - "name": "Cobweb", - }, - "tallgrass": { - "id": 31, - "name": ["Shrub", - "Grass", - "Fern"], - }, - "deadbush": { - "id": 32, - "name": "Dead Bush", - }, - "piston": { - "id": 33, - "name": "Piston", - "place": "piston", - }, - "piston_head": { - "id": 34, - "name": "Piston Extension", - "place": "flatten", - }, - "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"], - }, - "piston_extension": { - "id": 36, - "name": "Block moved by Piston", - "place": "flatten", - }, - "yellow_flower": { - "id": 37, - "name": "Dandelion", - }, - "red_flower": { - "id": 38, - "name": ["Poppy", - "Blue Orchid", - "Allium", - "Azure Bluet", - "Red Tulip", - "Orange Tulip", - "White Tulip", - "Pink Tulip", - "Oxeye Daisy"], - }, - "brown_mushroom": { - "id": 39, - "name": "Brown Mushroom", - }, - "red_mushroom": { - "id": 40, - "name": "Red Mushroom", - }, - "gold_block": { - "id": 41, - "name": "Block of Gold", - }, - "iron_block": { - "id": 42, - "name": "Block of Iron", - }, - "double_stone_slab": { - "id": 43, - "name": "Double Stone Slab", - }, - "stone_slab": { - "id": 44, - "name": ["Stone Slab", - "Sandstone Slab", - "Wooden Slab", - "Cobblestone Slab", - "Bricks Slab", - "Stone Bricks Slab", - "Nether Brick Slab", - "Quartz Slab"], - "place": "slab", - }, - "brick_block": { - "id": 45, - "name": "Bricks", - }, - "tnt": { - "id": 46, - "name": "TNT", - }, - "bookshelf": { - "id": 47, - "name": "Bookshelf", - }, - "mossy_cobblestone": { - "id": 48, - "name": "Moss Stone", - }, - "obsidian": { - "id": 49, - "name": "Obsidian", - }, - "torch": { - "id": 50, - "name": "Torch", - "place": "torch", - }, - "fire": { - "id": 51, - "name": "Fire", - "place": "flatten", - }, - "mob_spawner": { - "id": 52, - "name": "Monster Spawner", - }, - "oak_stairs": { - "id": 53, - "name": "Oak Wood Stairs", - "place": "stairs", - }, - "chest": { - "id": 54, - "name": "Chest", - "place": "chest-furnace", - }, - "redstone_wire": { - "id": 55, - "name": "Redstone Wire", - "place": "flatten", - }, - "diamond_ore": { - "id": 56, - "name": "Diamond Ore", - }, - "diamond_block": { - "id": 57, - "name": "Block of Diamond", - }, - "crafting_table": { - "id": 58, - "name": "Crafting Table", - }, - "wheat": { - "id": 59, - "name": "Wheat", - "place": "flatten", - }, - "farmland": { - "id": 60, - "name": "Farmland", - "place": "flatten", - }, - "furnace": { - "id": 61, - "name": "Furnace", - "place": "chest-furnace", - }, - "lit_furnace": { - "id": 62, - "name": "Burning Furnace", - "place": "chest-furnace", - }, - "standing_sign": { - "id": 63, - "name": "Sign", - "place": "signpost", - }, - "wooden_door": { - "id": 64, - "name": "Oak Door", - "place": "door", - }, - "ladder": { - "id": 65, - "name": "Ladder", - "place": "wallsign-ladder", - }, - "rail": { - "id": 66, - "name": "Rail", - "place": "rail", - }, - "stone_stairs": { - "id": 67, - "name": "Cobblestone Stairs", - "place": "stairs", - }, - "wall_sign": { - "id": 68, - "name": "Sign", - "place": "wallsign-ladder", - }, - "lever": { - "id": 69, - "name": "Lever", - "place": "lever", - }, - "stone_pressure_plate": { - "id": 70, - "name": "Stone Pressure Plate", - }, - "iron_door": { - "id": 71, - "name": "Iron Door", - "place": "door", - }, - "wooden_pressure_plate": { - "id": 72, - "name": "Wooden Pressure Plate", - }, - "redstone_ore": { - "id": 73, - "name": "Redstone Ore", - }, - "lit_redstone_ore": { - "id": 74, - "name": "Redstone Ore", - }, - "unlit_redstone_torch": { - "id": 75, - "name": "Redstone Torch (inactive)", - "place": "torch", - }, - "redstone_torch": { - "id": 76, - "name": "Redstone Torch (active)", - "place": "torch", - }, - "stone_button": { - "id": 77, - "name": "Stone Button", - "place": "button", - }, - "snow_layer": { - "id": 78, - "name": "Snow", - "place": "flatten", - }, - "ice": { - "id": 79, - "name": "Ice", - }, - "snow": { - "id": 80, - "name": "Snow", - }, - "cactus": { - "id": 81, - "name": "Cactus", - "place": "flatten", - }, - "clay": { - "id": 82, - "name": "Clay", - }, - "reeds": { - "id": 83, - "name": "Sugar Cane", - "place": "flatten", - }, - "jukebox": { - "id": 84, - "name": "Jukebox", - "place": "flatten", - }, - "fence": { - "id": 85, - "name": "Fence", - }, - "pumpkin": { - "id": 86, - "name": "Pumpkin", - "place": "pumpkin", - }, - "netherrack": { - "id": 87, - "name": "Netherrack", - }, - "soul_sand": { - "id": 88, - "name": "Soul Sand", - }, - "glowstone": { - "id": 89, - "name": "Glowstone", - }, - "portal": { - "id": 90, - "name": "Portal", - "place": "flatten", - }, - "lit_pumpkin": { - "id": 91, - "name": "Jack o'Lantern", - "place": "pumpkin", - }, - "cake": { - "id": 92, - "name": "Cake", - "place": "flatten", - }, - "unpowered_repeater": { - "id": 93, - "name": "Redstone Repeater (inactive)", - "place": "repeater", - }, - "powered_repeater": { - "id": 94, - "name": "Redstone Repeater (active)", - "place": "repeater", - }, - "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"], - }, - "trapdoor": { - "id": 96, - "name": "Trapdoor", - "place": "trapdoor", - }, - "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"], - }, - "stonebrick": { - "id": 98, - "name": ["Stone Bricks", - "Mossy Stone Bricks", - "Cracked Stone Bricks", - "Chiseled Stone Bricks"], - }, - "brown_mushroom_block": { - "id": 99, - "name": "Brown Mushroom (block)", - "place": "flatten", - }, - "red_mushroom_block": { - "id": 100, - "name": "Red Mushroom (block)", - "place": "flatten", - }, - "iron_bars": { - "id": 101, - "name": "Iron Bars", - }, - "glass_pane": { - "id": 102, - "name": "Glass Pane", - }, - "melon_block": { - "id": 103, - "name": "Melon", - }, - "pumpkin_stem": { - "id": 104, - "name": "Pumpkin Stem", - }, - "melon_stem": { - "id": 105, - "name": "Melon Stem", - }, - "vine": { - "id": 106, - "name": "Vines", - "place": "vine", - }, - "fence_gate": { - "id": 107, - "name": "Fence Gate", - "place": "gate", - }, - "brick_stairs": { - "id": 108, - "name": "Brick Stairs", - "place": "stairs", - }, - "stone_brick_stairs": { - "id": 109, - "name": "Stone Brick Stairs", - "place": "stairs", - }, - "mycelium": { - "id": 110, - "name": "Mycelium", - }, - "waterlily": { - "id": 111, - "name": "Lily Pad", - }, - "nether_brick": { - "id": 112, - "name": "Nether Brick", - }, - "nether_brick_fence": { - "id": 113, - "name": "Nether Brick Fence", - }, - "nether_brick_stairs": { - "id": 114, - "name": "Nether Brick Stairs", - "place": "stairs", - }, - "nether_wart": { - "id": 115, - "name": "Nether Wart", - "place": "flatten", - }, - "enchanting_table": { - "id": 116, - "name": "Enchantment Table", - }, - "brewing_stand": { - "id": 117, - "name": "Brewing Stand", - "place": "flatten", - }, - "cauldron": { - "id": 118, - "name": "Cauldron", - "place": "cauldron", - }, - "end_portal": { - "id": 119, - "name": "End Portal", - }, - "end_portal_frame": { - "id": 120, - "name": "End Portal Block", - "place": "flatten", - }, - "end_stone": { - "id": 121, - "name": "End Stone", - }, - "dragon_egg": { - "id": 122, - "name": "Dragon Egg", - }, - "redstone_lamp": { - "id": 123, - "name": "Redstone Lamp (inactive)", - }, - "lit_redstone_lamp": { - "id": 124, - "name": "Redstone Lamp (active)", - }, - "double_wooden_slab": { - "id": 125, - "name": "Double Wooden Slab", - }, - "wooden_slab": { - "id": 126, - "name": ["Oak Wood Slab", - "Spruce Wood Slab", - "Birch Wood Slab", - "Jungle Wood Slab", - "Acacia Wood Slab", - "Dark Oak Wood Slab"], - "place": "slab", - }, - "cocoa": { - "id": 127, - "name": "Cocoa", - "place": "cocoa", - }, - "sandstone_stairs": { - "id": 128, - "name": "Sandstone Stairs", - "place": "stairs", - }, - "emerald_ore": { - "id": 129, - "name": "Emerald Ore", - }, - "ender_chest": { - "id": 130, - "name": "Ender Chest", - "place": "chest-furnace", - }, - "tripwire_hook": { - "id": 131, - "name": "Tripwire Hook", - "place": "tripwire", - }, - "tripwire": { - "id": 132, - "name": "Tripwire", - "place": "flatten", - }, - "emerald_block": { - "id": 133, - "name": "Block of Emerald", - }, - "spruce_stairs": { - "id": 134, - "name": "Spruce Wood Stairs", - "place": "stairs", - }, - "birch_stairs": { - "id": 135, - "name": "Birch Wood Stairs", - "place": "stairs", - }, - "jungle_stairs": { - "id": 136, - "name": "Jungle Wood Stairs", - "place": "stairs", - }, - "command_block": { - "id": 137, - "name": "Command Block", - }, - "beacon": { - "id": 138, - "name": "Beacon", - }, - "cobblestone_wall": { - "id": 139, - "name": ["Cobblestone Wall", - "Mossy Cobblestone Wall"], - }, - "flower_pot": { - "id": 140, - "name": "Flower Pot", - "place": "flatten", - }, - "carrots": { - "id": 141, - "name": "Carrot", - "place": "flatten", - }, - "potatoes": { - "id": 142, - "name": "Potato", - "place": "flatten", - }, - "wooden_button": { - "id": 143, - "name": "Wooden Button", - "place": "button", - }, - "skull": { - "id": 144, - "name": "Mob Head", - "place": "mobhead", - }, - "anvil": { - "id": 145, - "name": ["Anvil", - "Slightly Damaged Anvil", - "Very Damaged Anvil"], - "place": "anvil", - }, - "trapped_chest": { - "id": 146, - "name": "Trapped Chest", - "place": "chest-furnace", - }, - "light_weighted_pressure_plate": { - "id": 147, - "name": "Weighted Pressure Plate", - }, - "heavy_weighted_pressure_plate": { - "id": 148, - "name": "Weighted Pressure Plate", - }, - "unpowered_comparator": { - "id": 149, - "name": "Redstone Comparator", - "place": "comparator", - }, - "powered_comparator": { - "id": 150, - "name": "Redstone Comparator", - }, - "daylight_detector": { - "id": 151, - "name": "Daylight Sensor", - "place": "flatten", - }, - "redstone_block": { - "id": 152, - "name": "Block of Redstone", - }, - "quartz_ore": { - "id": 153, - "name": "Nether Quartz Ore", - }, - "hopper": { - "id": 154, - "name": "Hopper", - "place": "hopper", - }, - "quartz_block": { - "id": 155, - "name": ["Block of Quartz", - "Chiseled Quartz Block", - "Pillar Quartz Block"], - }, - "quartz_stairs": { - "id": 156, - "name": "Quartz Stairs", - "place": "stairs", - }, - "activator_rail": { - "id": 157, - "name": "Activator Rail", - "place": "adp-rail", - }, - "dropper": { - "id": 158, - "name": "Dropper", - "place": "dispenser", - }, - "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"], - }, - "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"], - }, - "leaves2": { - "id": 161, - "name": ["Acacia Leaves", - "Dark Oak Leaves"], - "place": "leaves", - }, - "log2": { - "id": 162, - "name": ["Acacia Wood", - "Dark Oak Wood"], - "place": "wood", - }, - "acacia_stairs": { - "id": 163, - "name": "Acacia Wood Stairs", - "place": "stairs", - }, - "dark_oak_stairs": { - "id": 164, - "name": "Dark Oak Wood Stairs", - "place": "stairs", - }, - "slime": { - "id": 165, - "name": "Slime Block", - }, - "barrier": { - "id": 166, - "name": "Barrier", - }, - "iron_trapdoor": { - "id": 167, - "name": "Iron Trapdoor", - "place": "trapdoor", - }, - "prismarine": { - "id": 168, - "name": ["Prismarine", - "Prismarine Bricks", - "Dark Prismarine"], - }, - "sea_lantern": { - "id": 169, - "name": "Sea Lantern", - }, - "hay_block": { - "id": 170, - "name": "Hay Block", - "place": "hay-bale", - }, - "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"], - }, - "hardened_clay": { - "id": 172, - "name": "Hardened Clay", - }, - "coal_block": { - "id": 173, - "name": "Block of Coal", - }, - "packed_ice": { - "id": 174, - "name": "Packed Ice", - }, - "double_plant": { - "id": 175, - "name": ["Sunflower", - "Lilac", - "Double Tallgrass", - "Large Fern", - "Rose Bush", - "Peony"], - "place": "largeplant", - }, - "standing_banner": { - "id": 176, - "name": "Banner", - "place": "signpost", - }, - "wall_banner": { - "id": 177, - "name": "Banner", - "place": "wallsign-ladder", - }, - "daylight_detector_inverted": { - "id": 178, - "name": "Inverted Daylight Sensor", - "place": "flatten", - }, - "red_sandstone": { - "id": 179, - "name": ["Red Sandstone", - "Chiseled Red Sandstone", - "Smooth Red Sandstone"], - }, - "red_sandstone_stairs": { - "id": 180, - "name": "Red Sandstone Stairs", - "place": "stairs", - }, - "double_stone_slab2": { - "id": 181, - "name": "Double Red Sandstone Slab", - }, - "stone_slab2": { - "id": 182, - "name": "Red Sandstone Slab", - "place": "slab", - }, - "spruce_fence_gate": { - "id": 183, - "name": "Spruce Fence Gate", - "place": "gate", - }, - "birch_fence_gate": { - "id": 184, - "name": "Birch Fence Gate", - "place": "gate", - }, - "jungle_fence_gate": { - "id": 185, - "name": "Jungle Fence Gate", - "place": "gate", - }, - "dark_oak_fence_gate": { - "id": 186, - "name": "Dark Oak Fence Gate", - "place": "gate", - }, - "acacia_fence_gate": { - "id": 187, - "name": "Acacia Fence Gate", - "place": "gate", - }, - "spruce_fence": { - "id": 188, - "name": "Spruce Fence", - }, - "birch_fence": { - "id": 189, - "name": "Birch Fence", - }, - "jungle_fence": { - "id": 190, - "name": "Jungle Fence", - }, - "dark_oak_fence": { - "id": 191, - "name": "Dark Oak Fence", - }, - "acacia_fence": { - "id": 192, - "name": "Acacia Fence", - }, - "spruce_door": { - "id": 193, - "name": "Spruce Door", - "place": "door", - }, - "birch_door": { - "id": 194, - "name": "Birch Door", - "place": "door", - }, - "jungle_door": { - "id": 195, - "name": "Jungle Door", - "place": "door", - }, - "acacia_door": { - "id": 196, - "name": "Acacia Door", - "place": "door", - }, - "dark_oak_door": { - "id": 197, - "name": "Dark Oak Door", - "place": "door", - }, - "end_rod": { - "id": 198 - "name": "End Rod", - "place": "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, - "place": "slab", - }, - "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, - "place": "flatten", - }, - "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", - "place": "bed", - }, - "repeater": { - "id": 356, - "name": "Redstone Repeater", - "place": "repeater", - }, - "carrot": { - "id": 391, - "name": "Carrot", - }, - "potato": { - "id": 392, - "name": "Potato", - }, - "comparator": { - "id": 404, - "name": "Redstone Comparator", - "place": "comparator", - }, - "banner": { - "id": 425, - "name": "Banner", - } -} diff --git a/sys/etc/fstab b/sys/etc/fstab deleted file mode 100644 index f65dd34..0000000 --- a/sys/etc/fstab +++ /dev/null @@ -1,4 +0,0 @@ -sys/apps/gpsdeploy urlfs http://pastebin.com/raw/qLthLak5 -sys/apps/Minesweeper urlfs http://pastebin.com/raw/nsKrHTbN -sys/apps/Micropaint urlfs http://pastebin.com/raw/tMRzJXx2 -sys/apps/sketch urlfs http://pastebin.com/raw/Mm5hd97E \ No newline at end of file diff --git a/sys/etc/recipes.db b/sys/etc/recipes.db deleted file mode 100644 index 61611db..0000000 --- a/sys/etc/recipes.db +++ /dev/null @@ -1,2108 +0,0 @@ -{ - [ "minecraft:wool:4" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:11", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:stained_glass:9" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:6", - }, - }, - [ "minecraft:trapdoor:0" ] = { - count = 2, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:dark_oak_fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:5", - "minecraft:stick:0", - "minecraft:planks:5", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:5", - [ 5 ] = "minecraft:planks:5", - }, - }, - [ "minecraft:dirt:1" ] = { - count = 4, - ingredients = { - "minecraft:dirt:0", - "minecraft:gravel:0", - [ 5 ] = "minecraft:gravel:0", - [ 6 ] = "minecraft:dirt:0", - }, - }, - [ "minecraft:carpet:4" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:4", - [ 6 ] = "minecraft:wool:4", - }, - }, - [ "minecraft:stained_glass:1" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:14", - }, - }, - [ "minecraft:wooden_pressure_plate:0" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:stained_hardened_clay:1" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:14", - }, - }, - [ "minecraft:stained_hardened_clay:13" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:2", - }, - }, - [ "minecraft:stained_glass_pane:11" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:11", - "minecraft:stained_glass:11", - "minecraft:stained_glass:11", - [ 6 ] = "minecraft:stained_glass:11", - [ 7 ] = "minecraft:stained_glass:11", - [ 5 ] = "minecraft:stained_glass:11", - }, - }, - [ "minecraft:dye:10" ] = { - count = 2, - ingredients = { - "minecraft:dye:15", - "minecraft:dye:2", - }, - }, - [ "minecraft:quartz_block:1" ] = { - count = 1, - ingredients = { - [ 2 ] = "minecraft:stone_slab:7", - [ 6 ] = "minecraft:stone_slab:7", - }, - }, - [ "minecraft:carpet:12" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:12", - [ 6 ] = "minecraft:wool:12", - }, - }, - [ "minecraft:birch_fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:2", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:2", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:acacia_fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:4", - "minecraft:stick:0", - "minecraft:planks:4", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:4", - [ 5 ] = "minecraft:planks:4", - }, - }, - [ "minecraft:diamond_block:0" ] = { - count = 1, - ingredients = { - "minecraft:diamond:0", - "minecraft:diamond:0", - "minecraft:diamond:0", - [ 7 ] = "minecraft:diamond:0", - [ 9 ] = "minecraft:diamond:0", - [ 10 ] = "minecraft:diamond:0", - [ 11 ] = "minecraft:diamond:0", - [ 5 ] = "minecraft:diamond:0", - [ 6 ] = "minecraft:diamond:0", - }, - }, - [ "minecraft:stone:1" ] = { - count = 1, - ingredients = { - "minecraft:stone:3", - "minecraft:quartz:0", - }, - }, - [ "minecraft:wooden_slab:2" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:planks:2", - [ 7 ] = "minecraft:planks:2", - [ 5 ] = "minecraft:planks:2", - }, - }, - [ "minecraft:stained_hardened_clay:14" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:1", - }, - }, - [ "minecraft:stained_glass_pane:6" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:6", - "minecraft:stained_glass:6", - "minecraft:stained_glass:6", - [ 6 ] = "minecraft:stained_glass:6", - [ 7 ] = "minecraft:stained_glass:6", - [ 5 ] = "minecraft:stained_glass:6", - }, - }, - [ "minecraft:carpet:9" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:9", - [ 6 ] = "minecraft:wool:9", - }, - }, - [ "minecraft:carpet:0" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:quartz_block:0" ] = { - count = 1, - ingredients = { - "minecraft:quartz:0", - "minecraft:quartz:0", - [ 5 ] = "minecraft:quartz:0", - [ 6 ] = "minecraft:quartz:0", - }, - }, - [ "minecraft:pumpkin_seeds:0" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:pumpkin:0", - }, - }, - [ "minecraft:stone_slab:4" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:brick_block:0", - [ 7 ] = "minecraft:brick_block:0", - [ 5 ] = "minecraft:brick_block:0", - }, - }, - [ "minecraft:carpet:10" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:10", - [ 6 ] = "minecraft:wool:10", - }, - }, - [ "minecraft:carpet:8" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:8", - [ 6 ] = "minecraft:wool:8", - }, - }, - [ "minecraft:stained_glass_pane:1" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:1", - "minecraft:stained_glass:1", - "minecraft:stained_glass:1", - [ 6 ] = "minecraft:stained_glass:1", - [ 7 ] = "minecraft:stained_glass:1", - [ 5 ] = "minecraft:stained_glass:1", - }, - }, - [ "minecraft:cobblestone_wall:0" ] = { - count = 6, - ingredients = { - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - [ 6 ] = "minecraft:cobblestone:0", - [ 7 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:wooden_button:0" ] = { - count = 1, - ingredients = { - [ 6 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:book:0" ] = { - count = 1, - ingredients = { - "minecraft:paper:0", - "minecraft:paper:0", - "minecraft:paper:0", - [ 5 ] = "minecraft:leather:0", - }, - }, - [ "minecraft:stone_pressure_plate:0" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:stone:0", - [ 6 ] = "minecraft:stone:0", - }, - }, - [ "minecraft:planks:4" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log2:0", - }, - }, - [ "minecraft:stone_slab:7" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:quartz_block:0", - [ 7 ] = "minecraft:quartz_block:0", - [ 5 ] = "minecraft:quartz_block:0", - }, - }, - [ "minecraft:sandstone:1" ] = { - count = 1, - ingredients = { - [ 2 ] = "minecraft:stone_slab:1", - [ 6 ] = "minecraft:stone_slab:1", - }, - }, - [ "minecraft:jungle_fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:3", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:3", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:furnace:0" ] = { - count = 1, - ingredients = { - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - [ 7 ] = "minecraft:cobblestone:0", - [ 9 ] = "minecraft:cobblestone:0", - [ 10 ] = "minecraft:cobblestone:0", - [ 11 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:dye:5" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:1", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:stone_brick_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:stonebrick:0", - [ 9 ] = "minecraft:stonebrick:0", - [ 10 ] = "minecraft:stonebrick:0", - [ 11 ] = "minecraft:stonebrick:0", - [ 5 ] = "minecraft:stonebrick:0", - [ 6 ] = "minecraft:stonebrick:0", - }, - }, - [ "minecraft:nether_brick_fence:0" ] = { - count = 6, - ingredients = { - "minecraft:nether_brick:0", - "minecraft:nether_brick:0", - "minecraft:nether_brick:0", - [ 6 ] = "minecraft:nether_brick:0", - [ 7 ] = "minecraft:nether_brick:0", - [ 5 ] = "minecraft:nether_brick:0", - }, - }, - [ "minecraft:wool:11" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:sign:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:light_weighted_pressure_plate:0" ] = { - count = 1, - ingredients = { - "minecraft:gold_ingot:0", - "minecraft:gold_ingot:0", - }, - }, - [ "minecraft:flower_pot:0" ] = { - count = 1, - ingredients = { - "minecraft:brick:0", - [ 6 ] = "minecraft:brick:0", - [ 3 ] = "minecraft:brick:0", - }, - }, - [ "minecraft:wooden_door:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - [ 9 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:wool:0" ] = { - count = 1, - ingredients = { - "minecraft:string:0", - "minecraft:string:0", - [ 5 ] = "minecraft:string:0", - [ 6 ] = "minecraft:string:0", - }, - }, - [ "minecraft:carpet:2" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:2", - [ 6 ] = "minecraft:wool:2", - }, - }, - [ "minecraft:comparator:0" ] = { - count = 1, - ingredients = { - [ 7 ] = "minecraft:redstone_torch:0", - [ 2 ] = "minecraft:redstone_torch:0", - [ 10 ] = "minecraft:stone:0", - [ 11 ] = "minecraft:stone:0", - [ 5 ] = "minecraft:redstone_torch:0", - [ 6 ] = "minecraft:quartz:0", - [ 9 ] = "minecraft:stone:0", - }, - }, - [ "minecraft:crafting_table:0" ] = { - count = 1, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:stained_glass_pane:3" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:3", - "minecraft:stained_glass:3", - "minecraft:stained_glass:3", - [ 6 ] = "minecraft:stained_glass:3", - [ 7 ] = "minecraft:stained_glass:3", - [ 5 ] = "minecraft:stained_glass:3", - }, - }, - [ "minecraft:stick:0" ] = { - count = 4, - ingredients = { - [ 2 ] = "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:stained_glass_pane:0" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:0", - "minecraft:stained_glass:0", - "minecraft:stained_glass:0", - [ 6 ] = "minecraft:stained_glass:0", - [ 7 ] = "minecraft:stained_glass:0", - [ 5 ] = "minecraft:stained_glass:0", - }, - }, - [ "minecraft:wool:6" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:9", - }, - }, - [ "minecraft:stonebrick:3" ] = { - count = 1, - ingredients = { - [ 2 ] = "minecraft:stone_slab:5", - [ 6 ] = "minecraft:stone_slab:5", - }, - }, - [ "minecraft:emerald_block:0" ] = { - count = 1, - ingredients = { - "minecraft:emerald:0", - "minecraft:emerald:0", - "minecraft:emerald:0", - [ 7 ] = "minecraft:emerald:0", - [ 9 ] = "minecraft:emerald:0", - [ 10 ] = "minecraft:emerald:0", - [ 11 ] = "minecraft:emerald:0", - [ 5 ] = "minecraft:emerald:0", - [ 6 ] = "minecraft:emerald:0", - }, - }, - [ "minecraft:wool:13" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:2", - }, - }, - [ "minecraft:noteblock:0" ] = { - count = 1, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 9 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:planks:0", - [ 11 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - [ 6 ] = "minecraft:redstone:0", - }, - }, - [ "minecraft:spruce_door:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:1", - "minecraft:planks:1", - [ 9 ] = "minecraft:planks:1", - [ 10 ] = "minecraft:planks:1", - [ 5 ] = "minecraft:planks:1", - [ 6 ] = "minecraft:planks:1", - }, - }, - [ "minecraft:dye:9" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:1", - [ 6 ] = "minecraft:dye:15", - }, - }, - [ "minecraft:stained_glass:15" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:0", - }, - }, - [ "minecraft:stained_hardened_clay:5" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:10", - }, - }, - [ "minecraft:fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:0", - "minecraft:stick:0", - "minecraft:planks:0", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:dispenser:0" ] = { - count = 1, - ingredients = { - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - [ 7 ] = "minecraft:cobblestone:0", - [ 9 ] = "minecraft:cobblestone:0", - [ 10 ] = "minecraft:redstone:0", - [ 11 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - [ 6 ] = "minecraft:bow:0", - }, - }, - [ "minecraft:beacon:0" ] = { - count = 1, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:obsidian:0", - [ 10 ] = "minecraft:obsidian:0", - [ 11 ] = "minecraft:obsidian:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:nether_star:0", - }, - }, - [ "minecraft:redstone_torch:0" ] = { - count = 1, - ingredients = { - [ 2 ] = "minecraft:redstone:0", - [ 6 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:snow_layer:0" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:snow:0", - [ 7 ] = "minecraft:snow:0", - [ 5 ] = "minecraft:snow:0", - }, - }, - [ "minecraft:stained_glass:2" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:13", - }, - }, - [ "minecraft:mossy_cobblestone:0" ] = { - count = 1, - ingredients = { - "minecraft:cobblestone:0", - "minecraft:vine:0", - }, - }, - [ "minecraft:stained_glass_pane:14" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:14", - "minecraft:stained_glass:14", - "minecraft:stained_glass:14", - [ 6 ] = "minecraft:stained_glass:14", - [ 7 ] = "minecraft:stained_glass:14", - [ 5 ] = "minecraft:stained_glass:14", - }, - }, - [ "minecraft:glowstone:0" ] = { - count = 1, - ingredients = { - "minecraft:glowstone_dust:0", - "minecraft:glowstone_dust:0", - [ 5 ] = "minecraft:glowstone_dust:0", - [ 6 ] = "minecraft:glowstone_dust:0", - }, - }, - [ "minecraft:bone_block:0" ] = { - count = 1, - ingredients = { - "minecraft:dye:15", - "minecraft:dye:15", - "minecraft:dye:15", - [ 7 ] = "minecraft:dye:15", - [ 9 ] = "minecraft:dye:15", - [ 10 ] = "minecraft:dye:15", - [ 11 ] = "minecraft:dye:15", - [ 5 ] = "minecraft:dye:15", - [ 6 ] = "minecraft:dye:15", - }, - }, - [ "minecraft:stained_hardened_clay:3" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:12", - }, - }, - [ "minecraft:spruce_fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:1", - "minecraft:stick:0", - "minecraft:planks:1", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:1", - [ 5 ] = "minecraft:planks:1", - }, - }, - [ "minecraft:paper:0" ] = { - count = 3, - ingredients = { - "minecraft:reeds:0", - "minecraft:reeds:0", - "minecraft:reeds:0", - }, - }, - [ "minecraft:stained_glass:3" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:12", - }, - }, - [ "minecraft:redstone_lamp:0" ] = { - count = 1, - ingredients = { - [ 7 ] = "minecraft:redstone:0", - [ 2 ] = "minecraft:redstone:0", - [ 10 ] = "minecraft:redstone:0", - [ 5 ] = "minecraft:redstone:0", - [ 6 ] = "minecraft:glowstone:0", - }, - }, - [ "minecraft:heavy_weighted_pressure_plate:0" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:wool:15" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:0", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:stained_glass:10" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:5", - }, - }, - [ "minecraft:tnt:0" ] = { - count = 1, - ingredients = { - "minecraft:gunpowder:0", - "minecraft:sand:0", - "minecraft:gunpowder:0", - [ 7 ] = "minecraft:sand:0", - [ 9 ] = "minecraft:gunpowder:0", - [ 10 ] = "minecraft:sand:0", - [ 11 ] = "minecraft:gunpowder:0", - [ 5 ] = "minecraft:sand:0", - [ 6 ] = "minecraft:gunpowder:0", - }, - }, - [ "minecraft:dye:7" ] = { - count = 3, - ingredients = { - "minecraft:dye:15", - "minecraft:dye:15", - [ 5 ] = "minecraft:dye:0", - }, - }, - [ "minecraft:stained_glass:14" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:1", - }, - }, - [ "minecraft:banner:0" ] = { - count = 1, - ingredients = { - "minecraft:wool:15", - "minecraft:wool:15", - "minecraft:wool:15", - [ 6 ] = "minecraft:wool:15", - [ 7 ] = "minecraft:wool:15", - [ 5 ] = "minecraft:wool:15", - [ 10 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:wooden_slab:5" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:planks:5", - [ 7 ] = "minecraft:planks:5", - [ 5 ] = "minecraft:planks:5", - }, - }, - [ "minecraft:anvil:0" ] = { - count = 1, - ingredients = { - "minecraft:iron_block:0", - "minecraft:iron_block:0", - "minecraft:iron_block:0", - [ 9 ] = "minecraft:iron_ingot:0", - [ 10 ] = "minecraft:iron_ingot:0", - [ 11 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:stained_glass_pane:4" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:4", - "minecraft:stained_glass:4", - "minecraft:stained_glass:4", - [ 6 ] = "minecraft:stained_glass:4", - [ 7 ] = "minecraft:stained_glass:4", - [ 5 ] = "minecraft:stained_glass:4", - }, - }, - [ "minecraft:stained_hardened_clay:4" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:11", - }, - }, - [ "minecraft:wooden_slab:1" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:planks:1", - [ 7 ] = "minecraft:planks:1", - [ 5 ] = "minecraft:planks:1", - }, - }, - [ "minecraft:bookshelf:0" ] = { - count = 1, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - "minecraft:planks:0", - [ 7 ] = "minecraft:book:0", - [ 9 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:planks:0", - [ 11 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:book:0", - [ 6 ] = "minecraft:book:0", - }, - }, - [ "minecraft:stonebrick:0" ] = { - count = 4, - ingredients = { - "minecraft:stone:0", - "minecraft:stone:0", - [ 5 ] = "minecraft:stone:0", - [ 6 ] = "minecraft:stone:0", - }, - }, - [ "minecraft:ladder:0" ] = { - count = 3, - ingredients = { - "minecraft:stick:0", - [ 7 ] = "minecraft:stick:0", - [ 9 ] = "minecraft:stick:0", - [ 3 ] = "minecraft:stick:0", - [ 11 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - [ 6 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:trapped_chest:0" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:chest:0", - [ 6 ] = "minecraft:tripwire_hook:0", - }, - }, - [ "minecraft:wool:3" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:12", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:dropper:0" ] = { - count = 1, - ingredients = { - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - "minecraft:cobblestone:0", - [ 7 ] = "minecraft:cobblestone:0", - [ 9 ] = "minecraft:cobblestone:0", - [ 10 ] = "minecraft:redstone:0", - [ 11 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:stained_hardened_clay:7" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:8", - }, - }, - [ "minecraft:stained_hardened_clay:9" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:6", - }, - }, - [ "minecraft:stone:3" ] = { - count = 2, - ingredients = { - "minecraft:quartz:0", - "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - [ 6 ] = "minecraft:quartz:0", - }, - }, - [ "minecraft:wooden_slab:0" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:prismarine:1" ] = { - count = 1, - ingredients = { - "minecraft:prismarine_shard:0", - "minecraft:prismarine_shard:0", - "minecraft:prismarine_shard:0", - [ 7 ] = "minecraft:prismarine_shard:0", - [ 9 ] = "minecraft:prismarine_shard:0", - [ 10 ] = "minecraft:prismarine_shard:0", - [ 11 ] = "minecraft:prismarine_shard:0", - [ 5 ] = "minecraft:prismarine_shard:0", - [ 6 ] = "minecraft:prismarine_shard:0", - }, - }, - [ "minecraft:acacia_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:planks:4", - [ 9 ] = "minecraft:planks:4", - [ 10 ] = "minecraft:planks:4", - [ 11 ] = "minecraft:planks:4", - [ 5 ] = "minecraft:planks:4", - [ 6 ] = "minecraft:planks:4", - }, - }, - [ "minecraft:iron_bars:0" ] = { - count = 16, - ingredients = { - "minecraft:iron_ingot:0", - "minecraft:iron_ingot:0", - "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:iron_ingot:0", - [ 7 ] = "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:birch_fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:2", - "minecraft:stick:0", - "minecraft:planks:2", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:2", - [ 5 ] = "minecraft:planks:2", - }, - }, - [ "minecraft:dark_oak_door:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:5", - "minecraft:planks:5", - [ 6 ] = "minecraft:planks:5", - [ 10 ] = "minecraft:planks:5", - [ 5 ] = "minecraft:planks:5", - [ 9 ] = "minecraft:planks:5", - }, - }, - [ "minecraft:stone:4" ] = { - count = 4, - ingredients = { - "minecraft:stone:3", - "minecraft:stone:3", - [ 5 ] = "minecraft:stone:3", - [ 6 ] = "minecraft:stone:3", - }, - }, - [ "minecraft:chest:0" ] = { - count = 1, - ingredients = { - "minecraft:planks:0", - "minecraft:planks:0", - "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 9 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:planks:0", - [ 11 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:bow:0" ] = { - count = 1, - ingredients = { - "minecraft:string:0", - "minecraft:stick:0", - [ 9 ] = "minecraft:string:0", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:string:0", - [ 10 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:stained_glass_pane:15" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:15", - "minecraft:stained_glass:15", - "minecraft:stained_glass:15", - [ 6 ] = "minecraft:stained_glass:15", - [ 7 ] = "minecraft:stained_glass:15", - [ 5 ] = "minecraft:stained_glass:15", - }, - }, - [ "minecraft:red_sandstone:2" ] = { - count = 4, - ingredients = { - "minecraft:red_sandstone:0", - "minecraft:red_sandstone:0", - [ 5 ] = "minecraft:red_sandstone:0", - [ 6 ] = "minecraft:red_sandstone:0", - }, - }, - [ "minecraft:detector_rail:0" ] = { - count = 6, - ingredients = { - "minecraft:iron_ingot:0", - [ 7 ] = "minecraft:iron_ingot:0", - [ 9 ] = "minecraft:iron_ingot:0", - [ 10 ] = "minecraft:redstone:0", - [ 11 ] = "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:stone_pressure_plate:0", - [ 3 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:birch_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:planks:2", - [ 9 ] = "minecraft:planks:2", - [ 10 ] = "minecraft:planks:2", - [ 11 ] = "minecraft:planks:2", - [ 5 ] = "minecraft:planks:2", - [ 6 ] = "minecraft:planks:2", - }, - }, - [ "minecraft:redstone_block:0" ] = { - count = 1, - ingredients = { - "minecraft:redstone:0", - "minecraft:redstone:0", - "minecraft:redstone:0", - [ 7 ] = "minecraft:redstone:0", - [ 9 ] = "minecraft:redstone:0", - [ 10 ] = "minecraft:redstone:0", - [ 11 ] = "minecraft:redstone:0", - [ 5 ] = "minecraft:redstone:0", - [ 6 ] = "minecraft:redstone:0", - }, - }, - [ "minecraft:wool:8" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:7", - }, - }, - [ "minecraft:coal_block:0" ] = { - count = 1, - ingredients = { - "minecraft:coal:0", - "minecraft:coal:0", - "minecraft:coal:0", - [ 7 ] = "minecraft:coal:0", - [ 9 ] = "minecraft:coal:0", - [ 10 ] = "minecraft:coal:0", - [ 11 ] = "minecraft:coal:0", - [ 5 ] = "minecraft:coal:0", - [ 6 ] = "minecraft:coal:0", - }, - }, - [ "minecraft:stained_hardened_clay:15" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:0", - }, - }, - [ "minecraft:dye:14" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:1", - [ 6 ] = "minecraft:dye:11", - }, - }, - [ "minecraft:dye:8" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:15", - [ 6 ] = "minecraft:dye:0", - }, - }, - [ "minecraft:ender_eye:0" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:blaze_powder:0", - [ 6 ] = "minecraft:ender_pearl:0", - }, - }, - [ "minecraft:end_bricks:0" ] = { - count = 4, - ingredients = { - "minecraft:end_stone:0", - "minecraft:end_stone:0", - [ 5 ] = "minecraft:end_stone:0", - [ 6 ] = "minecraft:end_stone:0", - }, - }, - [ "minecraft:carpet:5" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:5", - [ 6 ] = "minecraft:wool:5", - }, - }, - [ "minecraft:jungle_fence:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:3", - "minecraft:stick:0", - "minecraft:planks:3", - [ 6 ] = "minecraft:stick:0", - [ 7 ] = "minecraft:planks:3", - [ 5 ] = "minecraft:planks:3", - }, - }, - [ "minecraft:stone_slab:1" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:sandstone:0", - [ 7 ] = "minecraft:sandstone:0", - [ 5 ] = "minecraft:sandstone:0", - }, - }, - [ "minecraft:stained_glass_pane:9" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:9", - "minecraft:stained_glass:9", - "minecraft:stained_glass:9", - [ 6 ] = "minecraft:stained_glass:9", - [ 7 ] = "minecraft:stained_glass:9", - [ 5 ] = "minecraft:stained_glass:9", - }, - }, - [ "minecraft:stained_glass_pane:7" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:7", - "minecraft:stained_glass:7", - "minecraft:stained_glass:7", - [ 6 ] = "minecraft:stained_glass:7", - [ 7 ] = "minecraft:stained_glass:7", - [ 5 ] = "minecraft:stained_glass:7", - }, - }, - [ "minecraft:spruce_fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:1", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:1", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:stained_glass:7" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:8", - }, - }, - [ "minecraft:stained_glass_pane:10" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:10", - "minecraft:stained_glass:10", - "minecraft:stained_glass:10", - [ 6 ] = "minecraft:stained_glass:10", - [ 7 ] = "minecraft:stained_glass:10", - [ 5 ] = "minecraft:stained_glass:10", - }, - }, - [ "minecraft:wool:10" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:5", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:dye:6" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:2", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:planks:5" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log2:1", - }, - }, - [ "minecraft:stone_button:0" ] = { - count = 1, - ingredients = { - [ 6 ] = "minecraft:stone:0", - }, - }, - [ "minecraft:sugar:0" ] = { - count = 1, - ingredients = { - [ 6 ] = "minecraft:reeds:0", - }, - }, - [ "minecraft:stone_slab:5" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:stonebrick:0", - [ 7 ] = "minecraft:stonebrick:0", - [ 5 ] = "minecraft:stonebrick:0", - }, - }, - [ "minecraft:stone_slab:3" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:cobblestone:0", - [ 7 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:stone_slab:6" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:nether_brick:0", - [ 7 ] = "minecraft:nether_brick:0", - [ 5 ] = "minecraft:nether_brick:0", - }, - }, - [ "minecraft:stone:6" ] = { - count = 4, - ingredients = { - "minecraft:stone:5", - "minecraft:stone:5", - [ 5 ] = "minecraft:stone:5", - [ 6 ] = "minecraft:stone:5", - }, - }, - [ "minecraft:dye:13" ] = { - count = 3, - ingredients = { - "minecraft:dye:4", - "minecraft:dye:1", - [ 5 ] = "minecraft:dye:9", - }, - }, - [ "minecraft:stained_glass:5" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:10", - }, - }, - [ "minecraft:carpet:6" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:6", - [ 6 ] = "minecraft:wool:6", - }, - }, - [ "minecraft:stained_glass:6" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:9", - }, - }, - [ "minecraft:stained_glass:13" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:2", - }, - }, - [ "minecraft:sandstone:0" ] = { - count = 1, - ingredients = { - "minecraft:sand:0", - "minecraft:sand:0", - [ 5 ] = "minecraft:sand:0", - [ 6 ] = "minecraft:sand:0", - }, - }, - [ "minecraft:gold_block:0" ] = { - count = 1, - ingredients = { - "minecraft:gold_ingot:0", - "minecraft:gold_ingot:0", - "minecraft:gold_ingot:0", - [ 7 ] = "minecraft:gold_ingot:0", - [ 9 ] = "minecraft:gold_ingot:0", - [ 10 ] = "minecraft:gold_ingot:0", - [ 11 ] = "minecraft:gold_ingot:0", - [ 5 ] = "minecraft:gold_ingot:0", - [ 6 ] = "minecraft:gold_ingot:0", - }, - }, - [ "minecraft:stained_glass:0" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:15", - }, - }, - [ "minecraft:stained_glass_pane:8" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:8", - "minecraft:stained_glass:8", - "minecraft:stained_glass:8", - [ 6 ] = "minecraft:stained_glass:8", - [ 7 ] = "minecraft:stained_glass:8", - [ 5 ] = "minecraft:stained_glass:8", - }, - }, - [ "minecraft:wool:9" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:6", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:carpet:11" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:11", - [ 6 ] = "minecraft:wool:11", - }, - }, - [ "minecraft:stained_glass:11" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:carpet:7" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:7", - [ 6 ] = "minecraft:wool:7", - }, - }, - [ "minecraft:wool:2" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:13", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:end_rod:0" ] = { - count = 4, - ingredients = { - [ 2 ] = "minecraft:blaze_rod:0", - [ 6 ] = "minecraft:chorus_fruit_popped:0", - }, - }, - [ "minecraft:sandstone_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:sandstone:0", - [ 9 ] = "minecraft:sandstone:0", - [ 10 ] = "minecraft:sandstone:0", - [ 11 ] = "minecraft:sandstone:0", - [ 5 ] = "minecraft:sandstone:0", - [ 6 ] = "minecraft:sandstone:0", - }, - }, - [ "minecraft:stained_hardened_clay:11" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:stone_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:cobblestone:0", - [ 9 ] = "minecraft:cobblestone:0", - [ 10 ] = "minecraft:cobblestone:0", - [ 11 ] = "minecraft:cobblestone:0", - [ 5 ] = "minecraft:cobblestone:0", - [ 6 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:stained_glass_pane:2" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:2", - "minecraft:stained_glass:2", - "minecraft:stained_glass:2", - [ 6 ] = "minecraft:stained_glass:2", - [ 7 ] = "minecraft:stained_glass:2", - [ 5 ] = "minecraft:stained_glass:2", - }, - }, - [ "minecraft:hopper:0" ] = { - count = 1, - ingredients = { - "minecraft:iron_ingot:0", - [ 7 ] = "minecraft:iron_ingot:0", - [ 3 ] = "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:chest:0", - [ 10 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:nether_brick_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:nether_brick:0", - [ 9 ] = "minecraft:nether_brick:0", - [ 10 ] = "minecraft:nether_brick:0", - [ 11 ] = "minecraft:nether_brick:0", - [ 5 ] = "minecraft:nether_brick:0", - [ 6 ] = "minecraft:nether_brick:0", - }, - }, - [ "minecraft:stained_glass_pane:13" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:13", - "minecraft:stained_glass:13", - "minecraft:stained_glass:13", - [ 6 ] = "minecraft:stained_glass:13", - [ 7 ] = "minecraft:stained_glass:13", - [ 5 ] = "minecraft:stained_glass:13", - }, - }, - [ "minecraft:wool:12" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:3", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:birch_door:0" ] = { - count = 3, - ingredients = { - "minecraft:planks:2", - "minecraft:planks:2", - [ 9 ] = "minecraft:planks:2", - [ 10 ] = "minecraft:planks:2", - [ 5 ] = "minecraft:planks:2", - [ 6 ] = "minecraft:planks:2", - }, - }, - [ "minecraft:ender_chest:0" ] = { - count = 1, - ingredients = { - "minecraft:obsidian:0", - "minecraft:obsidian:0", - "minecraft:obsidian:0", - [ 7 ] = "minecraft:obsidian:0", - [ 9 ] = "minecraft:obsidian:0", - [ 10 ] = "minecraft:obsidian:0", - [ 11 ] = "minecraft:obsidian:0", - [ 5 ] = "minecraft:obsidian:0", - [ 6 ] = "minecraft:ender_eye:0", - }, - }, - [ "minecraft:brick_block:0" ] = { - count = 1, - ingredients = { - "minecraft:brick:0", - "minecraft:brick:0", - [ 5 ] = "minecraft:brick:0", - [ 6 ] = "minecraft:brick:0", - }, - }, - [ "minecraft:prismarine:0" ] = { - count = 1, - ingredients = { - "minecraft:prismarine_shard:0", - "minecraft:prismarine_shard:0", - [ 5 ] = "minecraft:prismarine_shard:0", - [ 6 ] = "minecraft:prismarine_shard:0", - }, - }, - [ "minecraft:stone:5" ] = { - count = 2, - ingredients = { - "minecraft:stone:3", - "minecraft:cobblestone:0", - }, - }, - [ "minecraft:torch:0" ] = { - count = 4, - ingredients = { - [ 2 ] = "minecraft:coal:1", - [ 6 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:iron_block:0" ] = { - count = 1, - ingredients = { - "minecraft:iron_ingot:0", - "minecraft:iron_ingot:0", - "minecraft:iron_ingot:0", - [ 7 ] = "minecraft:iron_ingot:0", - [ 9 ] = "minecraft:iron_ingot:0", - [ 10 ] = "minecraft:iron_ingot:0", - [ 11 ] = "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:stained_hardened_clay:12" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:3", - }, - }, - [ "minecraft:stained_glass:8" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:7", - }, - }, - [ "minecraft:stained_hardened_clay:0" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:15", - }, - }, - [ "minecraft:wooden_slab:4" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:planks:4", - [ 7 ] = "minecraft:planks:4", - [ 5 ] = "minecraft:planks:4", - }, - }, - [ "minecraft:carpet:3" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:3", - [ 6 ] = "minecraft:wool:3", - }, - }, - [ "minecraft:carpet:14" ] = { - count = 3, - ingredients = { - "minecraft:wool:14", - "minecraft:wool:14", - }, - }, - [ "minecraft:stained_glass_pane:12" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:12", - "minecraft:stained_glass:12", - "minecraft:stained_glass:12", - [ 6 ] = "minecraft:stained_glass:12", - [ 7 ] = "minecraft:stained_glass:12", - [ 5 ] = "minecraft:stained_glass:12", - }, - }, - [ "minecraft:planks:1" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log:1", - }, - }, - [ "minecraft:spruce_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:planks:1", - [ 9 ] = "minecraft:planks:1", - [ 10 ] = "minecraft:planks:1", - [ 11 ] = "minecraft:planks:1", - [ 5 ] = "minecraft:planks:1", - [ 6 ] = "minecraft:planks:1", - }, - }, - [ "minecraft:quartz_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:quartz_block:0", - [ 9 ] = "minecraft:quartz_block:0", - [ 10 ] = "minecraft:quartz_block:0", - [ 11 ] = "minecraft:quartz_block:0", - [ 5 ] = "minecraft:quartz_block:0", - [ 6 ] = "minecraft:quartz_block:0", - }, - }, - [ "minecraft:cauldron:0" ] = { - count = 1, - ingredients = { - "minecraft:iron_ingot:0", - [ 7 ] = "minecraft:iron_ingot:0", - [ 9 ] = "minecraft:iron_ingot:0", - [ 10 ] = "minecraft:iron_ingot:0", - [ 11 ] = "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - [ 3 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:0", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:0", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:hay_block:0" ] = { - count = 1, - ingredients = { - "minecraft:wheat:0", - "minecraft:wheat:0", - "minecraft:wheat:0", - [ 7 ] = "minecraft:wheat:0", - [ 9 ] = "minecraft:wheat:0", - [ 10 ] = "minecraft:wheat:0", - [ 11 ] = "minecraft:wheat:0", - [ 5 ] = "minecraft:wheat:0", - [ 6 ] = "minecraft:wheat:0", - }, - }, - [ "minecraft:red_sandstone:0" ] = { - count = 1, - ingredients = { - "minecraft:sand:1", - "minecraft:sand:1", - [ 5 ] = "minecraft:sand:1", - [ 6 ] = "minecraft:sand:1", - }, - }, - [ "minecraft:enchanting_table:0" ] = { - count = 1, - ingredients = { - [ 7 ] = "minecraft:diamond:0", - [ 2 ] = "minecraft:book:0", - [ 10 ] = "minecraft:obsidian:0", - [ 11 ] = "minecraft:obsidian:0", - [ 5 ] = "minecraft:diamond:0", - [ 6 ] = "minecraft:obsidian:0", - [ 9 ] = "minecraft:obsidian:0", - }, - }, - [ "minecraft:lapis_block:0" ] = { - count = 1, - ingredients = { - "minecraft:dye:4", - "minecraft:dye:4", - "minecraft:dye:4", - [ 7 ] = "minecraft:dye:4", - [ 9 ] = "minecraft:dye:4", - [ 10 ] = "minecraft:dye:4", - [ 11 ] = "minecraft:dye:4", - [ 5 ] = "minecraft:dye:4", - [ 6 ] = "minecraft:dye:4", - }, - }, - [ "minecraft:quartz_block:2" ] = { - count = 2, - ingredients = { - [ 2 ] = "minecraft:quartz_block:0", - [ 6 ] = "minecraft:quartz_block:0", - }, - }, - [ "minecraft:wool:5" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:10", - }, - }, - [ "minecraft:dye:12" ] = { - count = 2, - ingredients = { - [ 5 ] = "minecraft:dye:4", - [ 6 ] = "minecraft:dye:15", - }, - }, - [ "minecraft:dark_oak_fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:5", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:5", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:dark_oak_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:planks:5", - [ 9 ] = "minecraft:planks:5", - [ 10 ] = "minecraft:planks:5", - [ 11 ] = "minecraft:planks:5", - [ 5 ] = "minecraft:planks:5", - [ 6 ] = "minecraft:planks:5", - }, - }, - [ "minecraft:stone_slab:0" ] = { - count = 6, - ingredients = { - [ 6 ] = "minecraft:stone:0", - [ 7 ] = "minecraft:stone:0", - [ 5 ] = "minecraft:stone:0", - }, - }, - [ "minecraft:glass_pane:0" ] = { - count = 16, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 6 ] = "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - }, - }, - [ "minecraft:bed:0" ] = { - count = 1, - ingredients = { - "minecraft:wool:14", - "minecraft:wool:14", - "minecraft:wool:14", - [ 6 ] = "minecraft:planks:0", - [ 7 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:stained_glass:4" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:11", - }, - }, - [ "minecraft:prismarine:2" ] = { - count = 1, - ingredients = { - "minecraft:prismarine_shard:0", - "minecraft:prismarine_shard:0", - "minecraft:prismarine_shard:0", - [ 7 ] = "minecraft:prismarine_shard:0", - [ 9 ] = "minecraft:prismarine_shard:0", - [ 10 ] = "minecraft:prismarine_shard:0", - [ 11 ] = "minecraft:prismarine_shard:0", - [ 5 ] = "minecraft:prismarine_shard:0", - [ 6 ] = "minecraft:dye:0", - }, - }, - [ "minecraft:carpet:15" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:15", - [ 6 ] = "minecraft:wool:15", - }, - }, - [ "minecraft:wool:7" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:8", - }, - }, - [ "minecraft:iron_trapdoor:0" ] = { - count = 1, - ingredients = { - "minecraft:iron_ingot:0", - "minecraft:iron_ingot:0", - [ 5 ] = "minecraft:iron_ingot:0", - [ 6 ] = "minecraft:iron_ingot:0", - }, - }, - [ "minecraft:planks:2" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log:2", - }, - }, - [ "minecraft:stained_glass:12" ] = { - count = 8, - ingredients = { - "minecraft:glass:0", - "minecraft:glass:0", - "minecraft:glass:0", - [ 7 ] = "minecraft:glass:0", - [ 9 ] = "minecraft:glass:0", - [ 10 ] = "minecraft:glass:0", - [ 11 ] = "minecraft:glass:0", - [ 5 ] = "minecraft:glass:0", - [ 6 ] = "minecraft:dye:3", - }, - }, - [ "minecraft:stained_glass_pane:5" ] = { - count = 16, - ingredients = { - "minecraft:stained_glass:5", - "minecraft:stained_glass:5", - "minecraft:stained_glass:5", - [ 6 ] = "minecraft:stained_glass:5", - [ 7 ] = "minecraft:stained_glass:5", - [ 5 ] = "minecraft:stained_glass:5", - }, - }, - [ "minecraft:wool:14" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:wool:0", - [ 6 ] = "minecraft:dye:1", - }, - }, - [ "minecraft:lever:0" ] = { - count = 1, - ingredients = { - [ 2 ] = "minecraft:stick:0", - [ 6 ] = "minecraft:cobblestone:0", - }, - }, - [ "minecraft:nether_brick:0" ] = { - count = 1, - ingredients = { - "minecraft:netherbrick:0", - "minecraft:netherbrick:0", - [ 5 ] = "minecraft:netherbrick:0", - [ 6 ] = "minecraft:netherbrick:0", - }, - }, - [ "minecraft:acacia_fence_gate:0" ] = { - count = 1, - ingredients = { - "minecraft:stick:0", - "minecraft:planks:4", - "minecraft:stick:0", - [ 6 ] = "minecraft:planks:4", - [ 7 ] = "minecraft:stick:0", - [ 5 ] = "minecraft:stick:0", - }, - }, - [ "minecraft:stained_hardened_clay:8" ] = { - count = 8, - ingredients = { - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - "minecraft:hardened_clay:0", - [ 7 ] = "minecraft:hardened_clay:0", - [ 9 ] = "minecraft:hardened_clay:0", - [ 10 ] = "minecraft:hardened_clay:0", - [ 11 ] = "minecraft:hardened_clay:0", - [ 5 ] = "minecraft:hardened_clay:0", - [ 6 ] = "minecraft:dye:7", - }, - }, - [ "minecraft:carpet:13" ] = { - count = 3, - ingredients = { - [ 5 ] = "minecraft:wool:13", - [ 6 ] = "minecraft:wool:13", - }, - }, - [ "minecraft:sea_lantern:0" ] = { - count = 1, - ingredients = { - "minecraft:prismarine_shard:0", - "minecraft:prismarine_crystals:0", - "minecraft:prismarine_shard:0", - [ 7 ] = "minecraft:prismarine_crystals:0", - [ 9 ] = "minecraft:prismarine_shard:0", - [ 10 ] = "minecraft:prismarine_crystals:0", - [ 11 ] = "minecraft:prismarine_shard:0", - [ 5 ] = "minecraft:prismarine_crystals:0", - [ 6 ] = "minecraft:prismarine_crystals:0", - }, - }, - [ "minecraft:oak_stairs:0" ] = { - count = 8, - ingredients = { - "minecraft:planks:0", - [ 9 ] = "minecraft:planks:0", - [ 10 ] = "minecraft:planks:0", - [ 11 ] = "minecraft:planks:0", - [ 5 ] = "minecraft:planks:0", - [ 6 ] = "minecraft:planks:0", - }, - }, - [ "minecraft:wool:1" ] = { - count = 1, - ingredients = { - [ 5 ] = "minecraft:dye:14", - [ 6 ] = "minecraft:wool:0", - }, - }, - [ "minecraft:planks:3" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log:3", - }, - }, - [ "minecraft:sandstone:2" ] = { - count = 4, - ingredients = { - "minecraft:sandstone:0", - "minecraft:sandstone:0", - [ 5 ] = "minecraft:sandstone:0", - [ 6 ] = "minecraft:sandstone:0", - }, - }, - [ "minecraft:planks:0" ] = { - count = 4, - ingredients = { - [ 6 ] = "minecraft:log:0", - }, - }, -} \ No newline at end of file diff --git a/sys/etc/scripts/obsidian b/sys/etc/scripts/obsidian index 355f106..2695af1 100644 --- a/sys/etc/scripts/obsidian +++ b/sys/etc/scripts/obsidian @@ -28,7 +28,7 @@ local function findObsidian() local _,b = turtle.inspectDown() if b and (b.name == 'minecraft:lava' or b.name == 'minecraft:flowing_lava') then - if turtle.selectSlot('minecraft:water_bucket') then + if turtle.select('minecraft:water_bucket') then while true do if turtle.up() then break @@ -84,7 +84,7 @@ local s, m = turtle.run(function() end findObsidian() - if not turtle.selectSlot('minecraft:water_bucket') then + if not turtle.select('minecraft:water_bucket') then break end turtle.goto(0, 0) diff --git a/sys/extensions/tl3.lua b/sys/extensions/tl3.lua index 3b01783..f06287e 100644 --- a/sys/extensions/tl3.lua +++ b/sys/extensions/tl3.lua @@ -7,10 +7,11 @@ requireInjector(getfenv(1)) local Point = require('point') local synchronized = require('sync') local Util = require('util') -turtle.pathfind = require('turtle.pathfind') +local Pathing = require('turtle.pathfind') local function noop() end +turtle.pathfind = Pathing.pathfind turtle.point = { x = 0, y = 0, z = 0, heading = 0 } turtle.status = 'idle' turtle.abort = false @@ -46,7 +47,7 @@ function turtle.resetState() state.digPolicy = noop state.movePolicy = _defaultMove state.moveCallback = noop - state.locations = { } + Pathing.reset() return true end @@ -355,40 +356,6 @@ function turtle.setMoveCallback(cb) state.moveCallback = cb end function turtle.clearMoveCallback() state.moveCallback = noop end function turtle.getMoveCallback() return state.moveCallback end --- [[ Locations ]] -- -function turtle.getLocation(name) - return state.locations[name] -end - -function turtle.saveLocation(name, pt) - pt = pt or turtle.point - state.locations[name] = { x = pt.x, y = pt.y, z = pt.z } -end - -function turtle.gotoLocation(name) - local pt = turtle.getLocation(name) - if pt then - return turtle.goto(pt.x, pt.z, pt.y, pt.heading) - end -end - -function turtle.storeLocation(name, pt) - pt = pt or turtle.point - Util.writeTable(name .. '.pt', pt) - return true -end - -function turtle.loadLocation(name) - return Util.readTable(name .. '.pt') -end - -function turtle.gotoStoredLocation(name) - local pt = turtle.loadLocation(name) - if pt then - return turtle.gotoPoint(pt) - end -end - -- [[ Heading ]] -- function turtle.getHeading() return turtle.point.heading @@ -813,10 +780,6 @@ function turtle.select(indexOrId) return false, 'Inventory does not contain item' end -function turtle.selectSlot(indexOrId) -- deprecated - return turtle.select(indexOrId) -end - function turtle.getInventory(slots) slots = slots or { } for i = 1, 16 do @@ -851,24 +814,6 @@ function turtle.getSummedInventory() return t end -function turtle.emptyInventory(dropAction) - dropAction = dropAction or turtle.drop - for i = 1, 16 do - turtle.emptySlot(i, dropAction) - end - turtle.select(1) -end - -function turtle.emptySlot(slot, dropAction) - dropAction = dropAction or turtle.drop - local count = turtle.getItemCount(slot) - if count > 0 then - turtle.select(slot) - return dropAction(count) - end - return false, 'No items to drop' -end - function turtle.getFilledSlots(startSlot) startSlot = startSlot or 1 @@ -889,6 +834,15 @@ function turtle.eachFilledSlot(fn) end end +function turtle.emptyInventory(dropAction) + dropAction = dropAction or turtle.native.drop + turtle.eachFilledSlot(function(slot) + turtle.select(slot.index) + dropAction() + end) + turtle.select(1) +end + function turtle.reconcileInventory(slots, dropAction) dropAction = dropAction or turtle.native.drop for _,s in pairs(slots) do @@ -910,10 +864,6 @@ function turtle.selectSlotWithItems(startSlot) end end -function turtle.selectOpenSlot(startSlot) - return turtle.selectSlotWithQuantity(0, startSlot) -end - function turtle.selectSlotWithQuantity(qty, startSlot) startSlot = startSlot or 1 @@ -925,6 +875,10 @@ function turtle.selectSlotWithQuantity(qty, startSlot) end end +function turtle.selectOpenSlot(startSlot) + return turtle.selectSlotWithQuantity(0, startSlot) +end + function turtle.condense() local slots = turtle.getInventory() @@ -1007,14 +961,15 @@ function turtle.abortAction() end -- [[ Pathing ]] -- -function turtle.faceAgainst(pt) -- 4 sided +function turtle.faceAgainst(pt, options) -- 4 sided - local pts = { } + options = options or { } + options.dest = { } for i = 0, 3 do local hi = turtle.getHeadingInfo(i) - table.insert(pts, { + table.insert(options.dest, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, @@ -1022,12 +977,13 @@ function turtle.faceAgainst(pt) -- 4 sided }) end - return turtle.pathfind(Point.closest(turtle.point, pts), { dest = pts }) + return turtle.pathfind(Point.closest(turtle.point, options.dest), options) end -function turtle.moveAgainst(pt) -- 6 sided +function turtle.moveAgainst(pt, options) -- 6 sided - local pts = { } + options = options or { } + options.dest = { } for i = 0, 5 do local hi = turtle.getHeadingInfo(i) @@ -1041,7 +997,7 @@ function turtle.moveAgainst(pt) -- 6 sided direction = 'up' end - table.insert(pts, { + table.insert(options.dest, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, @@ -1050,7 +1006,7 @@ function turtle.moveAgainst(pt) -- 6 sided }) end - return turtle.pathfind(Point.closest(turtle.point, pts), { dest = pts }) + return turtle.pathfind(Point.closest(turtle.point, options.dest), options) end local actionsAt = {