1
0
mirror of https://github.com/kepler155c/opus synced 2025-10-21 02:37:48 +00:00

reorganization

This commit is contained in:
kepler155c@gmail.com
2017-09-15 01:08:04 -04:00
parent b5ee5db16b
commit 64c68f2662
54 changed files with 175 additions and 15800 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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,

View File

@@ -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