spaces->tab, equipper improvements, supertreefarm rewrite, follow improvements, sensor cleanup, milo multiple items allowed in recipes, remote canvas access

This commit is contained in:
kepler155c@gmail.com
2019-06-18 15:23:20 -04:00
parent 3b9b509429
commit 045b32884f
162 changed files with 20448 additions and 20286 deletions

View File

@@ -8,154 +8,154 @@ local os = _G.os
local ChestAdapter = class()
local convertNames = {
name = 'id',
damage = 'dmg',
maxCount = 'max_size',
count = 'qty',
displayName = 'display_name',
maxDamage = 'max_dmg',
nbtHash = 'nbt_hash',
name = 'id',
damage = 'dmg',
maxCount = 'max_size',
count = 'qty',
displayName = 'display_name',
maxDamage = 'max_dmg',
nbtHash = 'nbt_hash',
}
-- Strip off color prefix
local function safeString(text)
local val = text:byte(1)
local val = text:byte(1)
if val < 32 or val > 128 then
if val < 32 or val > 128 then
local newText = {}
for i = 4, #text do
val = text:byte(i)
newText[i - 3] = (val > 31 and val < 127) and val or 63
end
return string.char(unpack(newText))
end
local newText = {}
for i = 4, #text do
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
return text
end
local function convertItem(item)
for k,v in pairs(convertNames) do
item[k] = item[v]
item[v] = nil
end
item.displayName = safeString(item.displayName)
for k,v in pairs(convertNames) do
item[k] = item[v]
item[v] = nil
end
item.displayName = safeString(item.displayName)
end
function ChestAdapter:init(args)
local defaults = {
name = 'chest',
}
Util.merge(self, defaults)
Util.merge(self, args)
local defaults = {
name = 'chest',
}
Util.merge(self, defaults)
Util.merge(self, args)
local chest
if not self.side then
chest = Peripheral.getByMethod('getAllStacks')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.getAllStacks then
chest = nil
end
end
local chest
if not self.side then
chest = Peripheral.getByMethod('getAllStacks')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.getAllStacks then
chest = nil
end
end
if chest then
Util.merge(self, chest)
if chest then
Util.merge(self, chest)
if chest.listAvailableItems then
self.list = chest.listAvailableItems
end
end
if chest.listAvailableItems then
self.list = chest.listAvailableItems
end
end
end
function ChestAdapter:isValid()
return not not self.getAllStacks
return not not self.getAllStacks
end
function ChestAdapter:refresh(throttle)
return self:listItems(throttle)
return self:listItems(throttle)
end
-- provide a consolidated list of items
function ChestAdapter:listItems(throttle)
local cache = { }
local items = { }
throttle = throttle or Util.throttle()
local cache = { }
local items = { }
throttle = throttle or Util.throttle()
-- getAllStacks sometimes fails
local s, m = pcall(function()
for _,v in pairs(self.getAllStacks(false)) do
if v.qty > 0 then
convertItem(v)
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':')
-- getAllStacks sometimes fails
local s, m = pcall(function()
for _,v in pairs(self.getAllStacks(false)) do
if v.qty > 0 then
convertItem(v)
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':')
local entry = cache[key]
if not entry then
entry = itemDB:get(v) or itemDB:add(v)
entry = Util.shallowCopy(entry)
entry.count = 0
cache[key] = entry
table.insert(items, entry)
end
entry.count = entry.count + v.count
throttle()
end
itemDB:flush()
end
end)
if s then
if not Util.empty(items) then
self.cache = cache
return items
end
else
_G._syslog(m)
end
local entry = cache[key]
if not entry then
entry = itemDB:get(v) or itemDB:add(v)
entry = Util.shallowCopy(entry)
entry.count = 0
cache[key] = entry
table.insert(items, entry)
end
entry.count = entry.count + v.count
throttle()
end
itemDB:flush()
end
end)
if s then
if not Util.empty(items) then
self.cache = cache
return items
end
else
_G._syslog(m)
end
end
function ChestAdapter:getItemInfo(item)
if not self.cache then
self:listItems()
end
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
return self.cache[key]
if not self.cache then
self:listItems()
end
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
return self.cache[key]
end
function ChestAdapter:provide(item, qty, slot, direction)
pcall(function()
for key,stack in Util.rpairs(self.getAllStacks(false)) do
if stack.id == item.name and
(not item.damage or stack.dmg == item.damage) and
(not item.nbtHash or stack.nbt_hash == item.nbtHash) then
local amount = math.min(qty, stack.qty)
if amount > 0 then
self.pushItemIntoSlot(direction or self.direction, key, amount, slot)
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
pcall(function()
for key,stack in Util.rpairs(self.getAllStacks(false)) do
if stack.id == item.name and
(not item.damage or stack.dmg == item.damage) and
(not item.nbtHash or stack.nbt_hash == item.nbtHash) then
local amount = math.min(qty, stack.qty)
if amount > 0 then
self.pushItemIntoSlot(direction or self.direction, key, amount, slot)
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
end
function ChestAdapter:extract(slot, qty, toSlot)
if toSlot then
self.pushItemIntoSlot(self.direction, slot, qty, toSlot)
else
self.pushItem(self.direction, slot, qty)
end
if toSlot then
self.pushItemIntoSlot(self.direction, slot, qty, toSlot)
else
self.pushItem(self.direction, slot, qty)
end
end
function ChestAdapter:insert(slot, qty, toSlot)
-- toSlot not tested ...
local s, m = pcall(self.pullItem, self.direction, slot, qty, toSlot)
if not s and m then
os.sleep(1)
pcall(self.pullItem, self.direction, slot, qty, toSlot)
end
-- toSlot not tested ...
local s, m = pcall(self.pullItem, self.direction, slot, qty, toSlot)
if not s and m then
os.sleep(1)
pcall(self.pullItem, self.direction, slot, qty, toSlot)
end
end
return ChestAdapter

View File

@@ -6,159 +6,159 @@ local Peripheral = require('peripheral')
local ChestAdapter = class()
function ChestAdapter:init(args)
local defaults = {
name = 'chest',
adapter = 'ChestAdapter18'
}
Util.merge(self, defaults)
Util.merge(self, args)
local defaults = {
name = 'chest',
adapter = 'ChestAdapter18'
}
Util.merge(self, defaults)
Util.merge(self, args)
local chest
if not self.side then
chest = Peripheral.getByMethod('list') or
Peripheral.getByMethod('listAvailableItems')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.list and not chest.listAvailableItems then
chest = nil
end
end
local chest
if not self.side then
chest = Peripheral.getByMethod('list') or
Peripheral.getByMethod('listAvailableItems')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.list and not chest.listAvailableItems then
chest = nil
end
end
if chest then
Util.merge(self, chest)
if chest then
Util.merge(self, chest)
if chest.listAvailableItems then
self.list = chest.listAvailableItems
end
end
if chest.listAvailableItems then
self.list = chest.listAvailableItems
end
end
end
function ChestAdapter:isValid()
return not not self.list
return not not self.list
end
-- handle both AE/RS and generic inventory
function ChestAdapter:getItemDetails(index, item)
if self.getItemMeta then
local s, detail = pcall(self.getItemMeta, index)
if not s or not detail or detail.name ~= item.name then
return
end
return detail
else
local detail = self.findItems(item)
if detail and #detail > 0 then
return detail[1].getMetadata()
end
end
if self.getItemMeta then
local s, detail = pcall(self.getItemMeta, index)
if not s or not detail or detail.name ~= item.name then
return
end
return detail
else
local detail = self.findItems(item)
if detail and #detail > 0 then
return detail[1].getMetadata()
end
end
end
function ChestAdapter:getCachedItemDetails(item, k)
local cached = itemDB:get(item)
if cached then
return cached
end
local cached = itemDB:get(item)
if cached then
return cached
end
local detail = self:getItemDetails(k, item)
if detail then
return itemDB:add(detail)
end
local detail = self:getItemDetails(k, item)
if detail then
return itemDB:add(detail)
end
end
function ChestAdapter:refresh(throttle)
return self:listItems(throttle)
return self:listItems(throttle)
end
-- provide a consolidated list of items
function ChestAdapter:listItems(throttle)
for _ = 1, 5 do
local list = self:listItemsInternal(throttle)
if list then
return list
end
end
error('Error accessing inventory: ' .. self.direction)
for _ = 1, 5 do
local list = self:listItemsInternal(throttle)
if list then
return list
end
end
error('Error accessing inventory: ' .. self.direction)
end
function ChestAdapter:listItemsInternal(throttle)
local cache = { }
local items = { }
throttle = throttle or Util.throttle()
local cache = { }
local items = { }
throttle = throttle or Util.throttle()
for k,v in pairs(self.list()) do
if v.count > 0 then
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':')
for k,v in pairs(self.list()) do
if v.count > 0 then
local key = table.concat({ v.name, v.damage, v.nbtHash }, ':')
local entry = cache[key]
if not entry then
entry = self:getCachedItemDetails(v, k)
if not entry then
return -- Inventory has changed
end
entry = Util.shallowCopy(entry)
entry.count = 0
cache[key] = entry
table.insert(items, entry)
end
local entry = cache[key]
if not entry then
entry = self:getCachedItemDetails(v, k)
if not entry then
return -- Inventory has changed
end
entry = Util.shallowCopy(entry)
entry.count = 0
cache[key] = entry
table.insert(items, entry)
end
if entry then
entry.count = entry.count + v.count
end
throttle()
end
end
itemDB:flush()
if entry then
entry.count = entry.count + v.count
end
throttle()
end
end
itemDB:flush()
self.cache = cache
return items
self.cache = cache
return items
end
function ChestAdapter:getItemInfo(item)
if not self.cache then
self:listItems()
end
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
local items = self.cache or { }
return items[key]
if not self.cache then
self:listItems()
end
local key = table.concat({ item.name, item.damage, item.nbtHash }, ':')
local items = self.cache or { }
return items[key]
end
function ChestAdapter:getPercentUsed()
if self.cache and self.getDrawerCount then
return math.floor(Util.size(self.cache) / self.getDrawerCount() * 100)
end
return 0
if self.cache and self.getDrawerCount then
return math.floor(Util.size(self.cache) / self.getDrawerCount() * 100)
end
return 0
end
function ChestAdapter:provide(item, qty, slot, direction)
local total = 0
local total = 0
local _, m = pcall(function()
local stacks = self.list()
for key,stack in Util.rpairs(stacks) do
if stack.name == item.name and
stack.damage == item.damage and
stack.nbtHash == item.nbtHash then
local amount = math.min(qty, stack.count)
if amount > 0 then
amount = self.pushItems(direction or self.direction, key, amount, slot)
end
qty = qty - amount
total = total + amount
if qty <= 0 then
break
end
end
end
end)
return total, m
local _, m = pcall(function()
local stacks = self.list()
for key,stack in Util.rpairs(stacks) do
if stack.name == item.name and
stack.damage == item.damage and
stack.nbtHash == item.nbtHash then
local amount = math.min(qty, stack.count)
if amount > 0 then
amount = self.pushItems(direction or self.direction, key, amount, slot)
end
qty = qty - amount
total = total + amount
if qty <= 0 then
break
end
end
end
end)
return total, m
end
function ChestAdapter:extract(slot, qty, toSlot, direction)
return self.pushItems(direction or self.direction, slot, qty, toSlot)
return self.pushItems(direction or self.direction, slot, qty, toSlot)
end
function ChestAdapter:insert(slot, qty, toSlot, direction)
return self.pullItems(direction or self.direction, slot, qty, toSlot)
return self.pullItems(direction or self.direction, slot, qty, toSlot)
end
return ChestAdapter

View File

@@ -6,277 +6,277 @@ local Util = require('util')
local itemDB = TableDB({ fileName = 'usr/config/items.db' })
local function safeString(text)
local val = text:byte(1)
local val = text:byte(1)
if val < 32 or val > 128 then
if val < 32 or val > 128 then
local newText = { }
local skip = 0
for i = 1, #text do
val = text:byte(i)
if val == 167 then
skip = 2
end
if skip > 0 then
skip = skip - 1
else
if val >= 32 and val <= 128 then
newText[#newText + 1] = val
end
end
end
return string.char(unpack(newText))
end
local newText = { }
local skip = 0
for i = 1, #text do
val = text:byte(i)
if val == 167 then
skip = 2
end
if skip > 0 then
skip = skip - 1
else
if val >= 32 and val <= 128 then
newText[#newText + 1] = val
end
end
end
return string.char(unpack(newText))
end
return text
return text
end
function itemDB:makeKey(item)
if not item then error('itemDB:makeKey: item is required', 2) end
return table.concat({ item.name, item.damage or '*', item.nbtHash }, ':')
if not item then error('itemDB:makeKey: item is required', 2) end
return table.concat({ item.name, item.damage or '*', item.nbtHash }, ':')
end
function itemDB:splitKey(key, item)
item = item or { }
item = item or { }
local t = Util.split(key, '(.-):')
if #t[#t] > 8 then
item.nbtHash = table.remove(t)
end
local damage = table.remove(t)
if damage ~= '*' then
item.damage = tonumber(damage)
end
item.name = table.concat(t, ':')
local t = Util.split(key, '(.-):')
if #t[#t] > 8 then
item.nbtHash = table.remove(t)
end
local damage = table.remove(t)
if damage ~= '*' then
item.damage = tonumber(damage)
end
item.name = table.concat(t, ':')
return item
return item
end
function itemDB:get(key, populateFn)
if not key then error('itemDB:get: key is required', 2) end
if type(key) == 'string' then
key = self:splitKey(key)
else
key = Util.shallowCopy(key)
end
if not key then error('itemDB:get: key is required', 2) end
if type(key) == 'string' then
key = self:splitKey(key)
else
key = Util.shallowCopy(key)
end
local item = self:_get(key)
if not item and populateFn then
item = populateFn()
if item then
item = self:add(item)
end
end
local item = self:_get(key)
if not item and populateFn then
item = populateFn()
if item then
item = self:add(item)
end
end
return item and Util.merge(key, item)
return item and Util.merge(key, item)
end
function itemDB:_get(key)
if not key then error('itemDB:get: key is required', 2) end
if type(key) == 'string' then
key = self:splitKey(key)
end
if not key then error('itemDB:get: key is required', 2) end
if type(key) == 'string' then
key = self:splitKey(key)
end
local item = TableDB.get(self, self:makeKey(key))
if item then
return item
end
local item = TableDB.get(self, self:makeKey(key))
if item then
return item
end
-- try finding an item that has damage values
if type(key.damage) == 'number' then
item = TableDB.get(self, self:makeKey({ name = key.name, nbtHash = key.nbtHash }))
if item and item.maxDamage then
item = Util.shallowCopy(item)
item.damage = key.damage
if item.maxDamage > 0 and type(item.damage) == 'number' and item.damage > 0 then
item.displayName = string.format('%s (damage: %s)', item.displayName, item.damage)
end
return item
end
else
for k,item in pairs(self.data) do
if key.name == item.name and
key.nbtHash == key.nbtHash and
item.maxDamage > 0 then
item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash
return item
end
end
end
-- try finding an item that has damage values
if type(key.damage) == 'number' then
item = TableDB.get(self, self:makeKey({ name = key.name, nbtHash = key.nbtHash }))
if item and item.maxDamage then
item = Util.shallowCopy(item)
item.damage = key.damage
if item.maxDamage > 0 and type(item.damage) == 'number' and item.damage > 0 then
item.displayName = string.format('%s (damage: %s)', item.displayName, item.damage)
end
return item
end
else
for k,item in pairs(self.data) do
if key.name == item.name and
key.nbtHash == key.nbtHash and
item.maxDamage > 0 then
item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash
return item
end
end
end
if key.nbtHash then
item = self:get({ name = key.name, damage = key.damage })
if key.nbtHash then
item = self:get({ name = key.name, damage = key.damage })
if item and item.ignoreNBT then
item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash
item.damage = key.damage
return item
end
end
if item and item.ignoreNBT then
item = Util.shallowCopy(item)
item.nbtHash = key.nbtHash
item.damage = key.damage
return item
end
end
end
local function formatTime(t)
local m = math.floor(t/60)
local s = t % 60
if s < 10 then
s = '0' .. s
end
local m = math.floor(t/60)
local s = t % 60
if s < 10 then
s = '0' .. s
end
return m .. ':' .. s
return m .. ':' .. s
end
--[[
If the base item contains an NBT hash, then the NBT hash uniquely
identifies this item.
If the base item contains an NBT hash, then the NBT hash uniquely
identifies this item.
]]--
function itemDB:add(baseItem)
local nItem = {
name = baseItem.name,
damage = baseItem.damage,
nbtHash = baseItem.nbtHash,
}
local nItem = {
name = baseItem.name,
damage = baseItem.damage,
nbtHash = baseItem.nbtHash,
}
-- if detail.maxDamage > 0 then
-- nItem.damage = '*'
-- end
nItem.displayName = safeString(baseItem.displayName)
nItem.maxCount = baseItem.maxCount
nItem.maxDamage = baseItem.maxDamage
nItem.displayName = safeString(baseItem.displayName)
nItem.maxCount = baseItem.maxCount
nItem.maxDamage = baseItem.maxDamage
-- enchanted items
if baseItem.enchantments then
if nItem.name == 'minecraft:enchanted_book' then
nItem.displayName = 'Book: '
else
nItem.displayName = nItem.displayName .. ': '
end
for k, v in ipairs(baseItem.enchantments) do
if k > 1 then
nItem.displayName = nItem.displayName .. ', '
end
nItem.displayName = nItem.displayName .. v.fullName
end
-- enchanted items
if baseItem.enchantments then
if nItem.name == 'minecraft:enchanted_book' then
nItem.displayName = 'Book: '
else
nItem.displayName = nItem.displayName .. ': '
end
for k, v in ipairs(baseItem.enchantments) do
if k > 1 then
nItem.displayName = nItem.displayName .. ', '
end
nItem.displayName = nItem.displayName .. v.fullName
end
-- turtles / computers / etc
elseif baseItem.computer then
-- a turtle's NBT is updated constantly
-- update the cache with the new NBT
if baseItem.computer.id then
Map.removeMatches(self.data, { name = nItem.name, displayName = nItem.displayName })
end
nItem.displayName = baseItem.computer.label or baseItem.displayName
-- turtles / computers / etc
elseif baseItem.computer then
-- a turtle's NBT is updated constantly
-- update the cache with the new NBT
if baseItem.computer.id then
Map.removeMatches(self.data, { name = nItem.name, displayName = nItem.displayName })
end
nItem.displayName = baseItem.computer.label or baseItem.displayName
-- disks
elseif baseItem.media then
-- don't ignore nbt... as disks can be labeled
if baseItem.media.recordTitle then
nItem.displayName = nItem.displayName .. ': ' .. baseItem.media.recordTitle
end
-- disks
elseif baseItem.media then
-- don't ignore nbt... as disks can be labeled
if baseItem.media.recordTitle then
nItem.displayName = nItem.displayName .. ': ' .. baseItem.media.recordTitle
end
-- potions
elseif nItem.name == 'minecraft:potion' or nItem.name == 'minecraft:lingering_potion' then
if baseItem.effects then
local effect = baseItem.effects[1]
if effect.amplifier == 1 then
nItem.displayName = nItem.displayName .. ' II'
end
if effect.duration and effect.duration > 0 then
nItem.displayName = string.format('%s (%s)', nItem.displayName, formatTime(effect.duration))
end
end
-- potions
elseif nItem.name == 'minecraft:potion' or nItem.name == 'minecraft:lingering_potion' then
if baseItem.effects then
local effect = baseItem.effects[1]
if effect.amplifier == 1 then
nItem.displayName = nItem.displayName .. ' II'
end
if effect.duration and effect.duration > 0 then
nItem.displayName = string.format('%s (%s)', nItem.displayName, formatTime(effect.duration))
end
end
else
for k,item in pairs(self.data) do
if nItem.name == item.name and
nItem.displayName == item.displayName then
else
for k,item in pairs(self.data) do
if nItem.name == item.name and
nItem.displayName == item.displayName then
if nItem.nbtHash ~= item.nbtHash and nItem.damage ~= item.damage then
nItem.damage = '*'
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
elseif nItem.damage ~= item.damage then
nItem.damage = '*'
self.data[k] = nil
break
elseif nItem.nbtHash ~= item.nbtHash then
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
end
end
end
end
if nItem.nbtHash ~= item.nbtHash and nItem.damage ~= item.damage then
nItem.damage = '*'
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
elseif nItem.damage ~= item.damage then
nItem.damage = '*'
self.data[k] = nil
break
elseif nItem.nbtHash ~= item.nbtHash then
nItem.nbtHash = nil
nItem.ignoreNBT = true
self.data[k] = nil
break
end
end
end
end
TableDB.add(self, self:makeKey(nItem), nItem)
nItem = Util.shallowCopy(nItem)
nItem.damage = baseItem.damage
nItem.nbtHash = baseItem.nbtHash
TableDB.add(self, self:makeKey(nItem), nItem)
nItem = Util.shallowCopy(nItem)
nItem.damage = baseItem.damage
nItem.nbtHash = baseItem.nbtHash
return nItem
return nItem
end
-- Accepts: "minecraft:stick:0" or { name = 'minecraft:stick', damage = 0 }
function itemDB:getName(item)
if type(item) == 'string' then
item = self:splitKey(item)
end
if type(item) == 'string' then
item = self:splitKey(item)
end
local detail = self:get(item)
if detail then
return detail.displayName
end
local detail = self:get(item)
if detail then
return detail.displayName
end
-- fallback to nameDB
local strId = self:makeKey(item)
local name = nameDB.data[strId]
if not name and not item.damage then
name = nameDB.data[self:makeKey({ name = item.name, damage = 0, nbtHash = item.nbtHash })]
end
return name or strId
-- fallback to nameDB
local strId = self:makeKey(item)
local name = nameDB.data[strId]
if not name and not item.damage then
name = nameDB.data[self:makeKey({ name = item.name, damage = 0, nbtHash = item.nbtHash })]
end
return name or strId
end
function itemDB:getMaxCount(item)
local detail = self:get(item)
return detail and detail.maxCount or 64
local detail = self:get(item)
return detail and detail.maxCount or 64
end
function itemDB:load()
TableDB.load(self)
TableDB.load(self)
for key,item in pairs(self.data) do
self:splitKey(key, item)
item.maxDamage = item.maxDamage or 0
item.maxCount = item.maxCount or 64
end
for key,item in pairs(self.data) do
self:splitKey(key, item)
item.maxDamage = item.maxDamage or 0
item.maxCount = item.maxCount or 64
end
end
function itemDB:flush()
if self.dirty then
if self.dirty then
local t = { }
for k,v in pairs(self.data) do
v = Util.shallowCopy(v)
v.name = nil
v.damage = nil
v.nbtHash = nil
local t = { }
for k,v in pairs(self.data) do
v = Util.shallowCopy(v)
v.name = nil
v.damage = nil
v.nbtHash = nil
v.count = nil -- wipe out previously saved counts - temporary
if v.maxDamage == 0 then
v.maxDamage = nil
end
if v.maxCount == 64 then
v.maxCount = nil
end
t[k] = v
end
if v.maxDamage == 0 then
v.maxDamage = nil
end
if v.maxCount == 64 then
v.maxCount = nil
end
t[k] = v
end
Util.writeTable(self.fileName, t)
self.dirty = false
end
Util.writeTable(self.fileName, t)
self.dirty = false
end
end
itemDB:load()

View File

@@ -6,249 +6,249 @@ local Util = require('util')
local os = _G.os
local convertNames = {
name = 'id',
damage = 'dmg',
maxCount = 'max_size',
count = 'qty',
displayName = 'display_name',
maxDamage = 'max_dmg',
nbtHash = 'nbt_hash',
name = 'id',
damage = 'dmg',
maxCount = 'max_size',
count = 'qty',
displayName = 'display_name',
maxDamage = 'max_dmg',
nbtHash = 'nbt_hash',
}
-- Strip off color prefix
local function safeString(text)
local val = text:byte(1)
local val = text:byte(1)
if val < 32 or val > 128 then
if val < 32 or val > 128 then
local newText = {}
for i = 4, #text do
val = text:byte(i)
newText[i - 3] = (val > 31 and val < 127) and val or 63
end
return string.char(unpack(newText))
end
local newText = {}
for i = 4, #text do
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
return text
end
local function convertItem(item)
for k,v in pairs(convertNames) do
item[k] = item[v]
item[v] = nil
end
item.displayName = safeString(item.displayName)
for k,v in pairs(convertNames) do
item[k] = item[v]
item[v] = nil
end
item.displayName = safeString(item.displayName)
end
local MEAdapter = class()
function MEAdapter:init(args)
local defaults = {
items = { },
name = 'ME',
jobList = { },
}
Util.merge(self, defaults)
Util.merge(self, args)
local defaults = {
items = { },
name = 'ME',
jobList = { },
}
Util.merge(self, defaults)
Util.merge(self, args)
local chest
local chest
if not self.side then
chest = Peripheral.getByMethod('getAvailableItems')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.getAvailableItems then
chest = nil
end
end
if not self.side then
chest = Peripheral.getByMethod('getAvailableItems')
else
chest = Peripheral.getBySide(self.side)
if chest and not chest.getAvailableItems then
chest = nil
end
end
if chest then
Util.merge(self, chest)
end
if chest then
Util.merge(self, chest)
end
end
function MEAdapter:isValid()
return self.getAvailableItems and self.getAvailableItems()
return self.getAvailableItems and self.getAvailableItems()
end
function MEAdapter:refresh()
self.items = nil
local hasItems, failed
self.items = nil
local hasItems, failed
local s, m = pcall(function()
self.items = self.getAvailableItems('all')
for _,v in pairs(self.items) do
Util.merge(v, v.item)
convertItem(v)
local s, m = pcall(function()
self.items = self.getAvailableItems('all')
for _,v in pairs(self.items) do
Util.merge(v, v.item)
convertItem(v)
-- if power has been interrupted, the list will still be returned
-- but all items will have a 0 quantity
-- ensure that the list is valid
if not hasItems then
hasItems = v.count > 0
end
-- if power has been interrupted, the list will still be returned
-- but all items will have a 0 quantity
-- ensure that the list is valid
if not hasItems then
hasItems = v.count > 0
end
if not v.fingerprint then
failed = true
break
end
if not v.fingerprint then
failed = true
break
end
if not itemDB:get(v) then
itemDB:add(v, v)
end
end
end)
itemDB:flush()
if not itemDB:get(v) then
itemDB:add(v, v)
end
end
end)
itemDB:flush()
if not s and m then
_G._syslog(m)
end
if not s and m then
_G._syslog(m)
end
if s and not failed and hasItems and self.items and not Util.empty(self.items) then
return self.items
end
self.items = nil
if s and not failed and hasItems and self.items and not Util.empty(self.items) then
return self.items
end
self.items = nil
end
function MEAdapter:listItems()
self:refresh()
return self.items
self:refresh()
return self.items
end
function MEAdapter:getItemInfo(item)
for _,i in pairs(self.items) do
if item.name == i.name and
item.damage == i.damage and
item.nbtHash == i.nbtHash then
return i
end
end
for _,i in pairs(self.items) do
if item.name == i.name and
item.damage == i.damage and
item.nbtHash == i.nbtHash then
return i
end
end
end
function MEAdapter:isCPUAvailable()
local cpus = self.getCraftingCPUs() or { }
local available = false
local cpus = self.getCraftingCPUs() or { }
local available = false
for cpu,v in pairs(cpus) do
if not v.busy then
available = true
elseif not self.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
for cpu,v in pairs(cpus) do
if not v.busy then
available = true
elseif not self.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 MEAdapter:craft(item, count)
if not self:isCPUAvailable() then
return false
end
if not self:isCPUAvailable() then
return false
end
self:refresh()
self:refresh()
item = self:getItemInfo(item)
if item and item.is_craftable then
item = self:getItemInfo(item)
if item and item.is_craftable then
local cpus = self.getCraftingCPUs() or { }
for cpu,v in pairs(cpus) do
if not v.busy then
self.requestCrafting({
id = item.name,
dmg = item.damage,
nbt_hash = item.nbtHash,
},
count or 1,
v.name -- CPUs must be named ! use anvil
)
local cpus = self.getCraftingCPUs() or { }
for cpu,v in pairs(cpus) do
if not v.busy then
self.requestCrafting({
id = item.name,
dmg = item.damage,
nbt_hash = item.nbtHash,
},
count or 1,
v.name -- CPUs must be named ! use anvil
)
os.sleep(0) -- needed ?
cpus = self.getCraftingCPUs() or { }
os.sleep(0) -- needed ?
cpus = self.getCraftingCPUs() or { }
if cpus[cpu].busy then
self.jobList[cpu] = {
name = item.name,
damage = item.damage,
nbtHash = item.nbtHash,
count = count,
}
return true
end
break -- only need to try the first available cpu
end
end
return false
end
if cpus[cpu].busy then
self.jobList[cpu] = {
name = item.name,
damage = item.damage,
nbtHash = item.nbtHash,
count = count,
}
return true
end
break -- only need to try the first available cpu
end
end
return false
end
end
function MEAdapter:getJobList()
local cpus = self.getCraftingCPUs() or { }
for cpu,v in pairs(cpus) do
if not v.busy then
self.jobList[cpu] = nil
end
end
local cpus = self.getCraftingCPUs() or { }
for cpu,v in pairs(cpus) do
if not v.busy then
self.jobList[cpu] = nil
end
end
return self.jobList
return self.jobList
end
function MEAdapter:isCrafting(item)
for _,v in pairs(self:getJobList()) do
if v.name == item.name and
v.damage == item.damage and
v.nbtHash == item.nbtHash then
return true
end
end
for _,v in pairs(self:getJobList()) do
if v.name == item.name and
v.damage == item.damage and
v.nbtHash == item.nbtHash then
return true
end
end
end
function MEAdapter:craftItems(items)
local cpus = self.getCraftingCPUs() or { }
local count = 0
local cpus = self.getCraftingCPUs() or { }
local count = 0
for _,cpu in pairs(cpus) do
if cpu.busy then
return
end
end
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 not self:isCrafting(item) then
if self:craft(item, item.count) then
count = count + 1
end
end
end
for _,item in pairs(items) do
if count >= #cpus then
break
end
if not self:isCrafting(item) then
if self:craft(item, item.count) then
count = count + 1
end
end
end
end
function MEAdapter:provide(item, qty, slot, direction)
return pcall(function()
for _,stack in pairs(self.getAvailableItems('all')) do
if stack.item.id == item.name and
(not item.damage or stack.item.dmg == item.damage) and
(not item.nbtHash or stack.item.nbt_hash == item.nbtHash) then
local amount = math.min(qty, stack.item.qty)
if amount > 0 then
self.exportItem(stack.item, direction or self.direction, amount, slot)
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
return pcall(function()
for _,stack in pairs(self.getAvailableItems('all')) do
if stack.item.id == item.name and
(not item.damage or stack.item.dmg == item.damage) and
(not item.nbtHash or stack.item.nbt_hash == item.nbtHash) then
local amount = math.min(qty, stack.item.qty)
if amount > 0 then
self.exportItem(stack.item, direction or self.direction, amount, slot)
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
end
function MEAdapter:insert(slot, qty, toSlot)
local s, m = pcall(self.pullItem, self.direction, slot, qty, toSlot)
if not s and m then
os.sleep(1)
pcall(self.pullItem, self.direction, slot, qty, toSlot)
end
local s, m = pcall(self.pullItem, self.direction, slot, qty, toSlot)
if not s and m then
os.sleep(1)
pcall(self.pullItem, self.direction, slot, qty, toSlot)
end
end
return MEAdapter

View File

@@ -8,83 +8,83 @@ local MEAdapter = class(RSAdapter)
local DEVICE_TYPE = 'appliedenergistics2:interface'
function MEAdapter:init(args)
local defaults = {
name = 'appliedEnergistics',
jobList = { },
}
Util.merge(self, defaults)
Util.merge(self, args)
local defaults = {
name = 'appliedEnergistics',
jobList = { },
}
Util.merge(self, defaults)
Util.merge(self, args)
local controller
if not self.side then
controller = Peripheral.getByType(DEVICE_TYPE)
else
controller = Peripheral.getBySide(self.side)
end
local controller
if not self.side then
controller = Peripheral.getByType(DEVICE_TYPE)
else
controller = Peripheral.getBySide(self.side)
end
if controller then
Util.merge(self, controller)
end
if controller then
Util.merge(self, controller)
end
end
function MEAdapter:isValid()
return self.type == DEVICE_TYPE and not not self.findItems
return self.type == DEVICE_TYPE and not not self.findItems
end
function MEAdapter:clearFinished()
for _,key in pairs(Util.keys(self.jobList)) do
local job = self.jobList[key]
if job.info.status() == 'finished' then
self.jobList[key] = nil
end
end
for _,key in pairs(Util.keys(self.jobList)) do
local job = self.jobList[key]
if job.info.status() == 'finished' then
self.jobList[key] = nil
end
end
end
function MEAdapter:isCPUAvailable()
local cpus = self.getCraftingCPUs() or { }
local busy = 0
local cpus = self.getCraftingCPUs() or { }
local busy = 0
for _,cpu in pairs(cpus) do
if cpu.busy then
busy = busy + 1
end
end
self:clearFinished()
return busy == Util.size(self.jobList) and busy < #cpus
for _,cpu in pairs(cpus) do
if cpu.busy then
busy = busy + 1
end
end
self:clearFinished()
return busy == Util.size(self.jobList) and busy < #cpus
end
function MEAdapter:craft(item, count)
if not self:isCPUAvailable() then
return false
end
if not self:isCPUAvailable() then
return false
end
local detail = self.findItem(item)
if detail and detail.craft then
local info = detail.craft(count or 1)
if info.status() == 'unknown' then
self.jobList[info.getId()] = {
name = item.name,
damage = item.damage,
nbtHash = item.nbtHash,
info = info,
}
return true
end
return false
end
local detail = self.findItem(item)
if detail and detail.craft then
local info = detail.craft(count or 1)
if info.status() == 'unknown' then
self.jobList[info.getId()] = {
name = item.name,
damage = item.damage,
nbtHash = item.nbtHash,
info = info,
}
return true
end
return false
end
end
function MEAdapter:isCrafting(item)
self:clearFinished()
self:clearFinished()
_G._p = self.jobList
for _,job in pairs(self.jobList) do
if job.name == item.name and
job.damage == item.damage and
job.nbtHash == item.nbtHash then
return true
end
end
return false
for _,job in pairs(self.jobList) do
if job.name == item.name and
job.damage == item.damage and
job.nbtHash == item.nbtHash then
return true
end
end
return false
end
return MEAdapter

View File

@@ -5,91 +5,91 @@ 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
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()
Message.enable()
end
Event.on('device_attach', function(event, deviceName)
if deviceName == 'wireless_modem' then
Message.enable()
end
if deviceName == 'wireless_modem' then
Message.enable()
end
end)
function Message.addHandler(type, f)
table.insert(messageHandlers, {
type = type,
f = f,
enabled = true
})
table.insert(messageHandlers, {
type = type,
f = f,
enabled = true
})
end
function Message.removeHandler(h)
for k,v in pairs(messageHandlers) do
for k,v in pairs(messageHandlers) do
if v == h then
messageHandlers[k] = nil
break
end
end
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
for k,h in pairs(messageHandlers) do
if h.type == msg.type then
function(event, side, sendChannel, replyChannel, msg, distance)
if msg and msg.type then -- filter out messages from other systems
local id = replyChannel
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
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 not device.wireless_modem then
error('No modem attached', 2)
end
if id then
device.wireless_modem.transmit(id, os.getComputerID(), {
type = msgType, contents = contents
})
else
device.wireless_modem.transmit(60000, os.getComputerID(), {
type = msgType, contents = contents
})
end
if id then
device.wireless_modem.transmit(id, os.getComputerID(), {
type = msgType, contents = contents
})
else
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
if not device.wireless_modem then
error('No modem attached', 2)
end
Message.send(nil, t, contents)
Message.send(nil, t, 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
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
return Message

View File

@@ -10,50 +10,50 @@ local USER_DIR = '/usr/etc/names'
local nameDB = TableDB()
function nameDB:loadDirectory(directory)
if fs.exists(directory) then
local files = fs.list(directory)
table.sort(files)
if fs.exists(directory) then
local files = fs.list(directory)
table.sort(files)
for _,file in ipairs(files) do
local mod = file:match('(%S+).json')
if mod then
local blocks = JSON.decodeFromFile(fs.combine(directory, file))
for _,file in ipairs(files) do
local mod = file:match('(%S+).json')
if mod then
local blocks = JSON.decodeFromFile(fs.combine(directory, file))
if not blocks then
error('Unable to read ' .. fs.combine(directory, file))
end
if not blocks then
error('Unable to read ' .. fs.combine(directory, file))
end
for strId, block in pairs(blocks) do
strId = string.format('%s:%s', mod, strId)
if type(block.name) == 'string' then
self.data[strId .. ':0'] = block.name
else
for nid,name in pairs(block.name) do
self.data[strId .. ':' .. (nid-1)] = name
end
end
end
for strId, block in pairs(blocks) do
strId = string.format('%s:%s', mod, strId)
if type(block.name) == 'string' then
self.data[strId .. ':0'] = block.name
else
for nid,name in pairs(block.name) do
self.data[strId .. ':' .. (nid-1)] = name
end
end
end
elseif file:match('(%S+).db') then
local names = Util.readTable(fs.combine(directory, file))
if not names then
error('Unable to read ' .. fs.combine(directory, file))
end
for key,name in pairs(names) do
self.data[key] = name
end
end
end
end
elseif file:match('(%S+).db') then
local names = Util.readTable(fs.combine(directory, file))
if not names then
error('Unable to read ' .. fs.combine(directory, file))
end
for key,name in pairs(names) do
self.data[key] = name
end
end
end
end
end
function nameDB:load()
self:loadDirectory(CORE_DIR)
self:loadDirectory(USER_DIR)
self:loadDirectory(CORE_DIR)
self:loadDirectory(USER_DIR)
end
function nameDB:getName(strId)
return self.data[strId] or strId
return self.data[strId] or strId
end
nameDB:load()

32
core/apis/proxy.lua Normal file
View File

@@ -0,0 +1,32 @@
local Socket = require('socket')
local Proxy = { }
function Proxy.create(remoteId, uri)
local socket, msg = Socket.connect(remoteId, 188)
if not socket then
error(msg)
end
socket.co = coroutine.running()
socket:write(uri)
local methods = socket:read(2) or error('Timed out')
local hijack = { }
for _,method in pairs(methods) do
hijack[method] = function(...)
socket:write({ method, ... })
local resp = socket:read()
if not resp then
error('timed out: ' .. method)
end
return table.unpack(resp)
end
end
return hijack, socket
end
return Proxy

View File

@@ -6,134 +6,134 @@ local Util = require('util')
local RefinedAdapter = class()
function RefinedAdapter:init(args)
local defaults = {
name = 'refinedStorage',
}
Util.merge(self, defaults)
Util.merge(self, args)
local defaults = {
name = 'refinedStorage',
}
Util.merge(self, defaults)
Util.merge(self, args)
local controller
if not self.side then
controller = Peripheral.getByMethod('getCraftingTasks')
else
controller = Peripheral.getBySide(self.side)
end
local controller
if not self.side then
controller = Peripheral.getByMethod('getCraftingTasks')
else
controller = Peripheral.getBySide(self.side)
end
if controller then
Util.merge(self, controller)
end
if controller then
Util.merge(self, controller)
end
end
function RefinedAdapter:isValid()
return not not self.getCraftingTasks
return not not self.getCraftingTasks
end
function RefinedAdapter:getItemDetails(item)
local detail = self.findItems(item)
if detail and #detail > 0 then
return detail[1].getMetadata()
end
local detail = self.findItems(item)
if detail and #detail > 0 then
return detail[1].getMetadata()
end
end
function RefinedAdapter:getCachedItemDetails(item)
local cached = itemDB:get(item)
if cached then
return cached
end
local cached = itemDB:get(item)
if cached then
return cached
end
local detail = self:getItemDetails(item)
if detail then
return itemDB:add(detail)
end
local detail = self:getItemDetails(item)
if detail then
return itemDB:add(detail)
end
end
function RefinedAdapter:refresh(throttle)
return self:listItems(throttle)
return self:listItems(throttle)
end
function RefinedAdapter:listItems(throttle)
local items = { }
throttle = throttle or Util.throttle()
local items = { }
throttle = throttle or Util.throttle()
local s, m = pcall(function()
for _,v in pairs(self.listAvailableItems()) do
--if v.count > 0 then
local item = self:getCachedItemDetails(v)
if item then
item = Util.shallowCopy(item)
item.count = v.count
table.insert(items, item)
end
--end
throttle()
end
end)
local s, m = pcall(function()
for _,v in pairs(self.listAvailableItems()) do
--if v.count > 0 then
local item = self:getCachedItemDetails(v)
if item then
item = Util.shallowCopy(item)
item.count = v.count
table.insert(items, item)
end
--end
throttle()
end
end)
if not s and m then
_G._syslog(m)
end
if not s and m then
_G._syslog(m)
end
itemDB:flush()
if not Util.empty(items) then
return items
end
itemDB:flush()
if not Util.empty(items) then
return items
end
end
function RefinedAdapter:getItemInfo(item)
return self:getItemDetails(item)
return self:getItemDetails(item)
end
function RefinedAdapter:isCPUAvailable()
return true
return true
end
function RefinedAdapter:craft(item, qty)
local detail = self.findItem(item)
if detail then
return detail.craft(qty)
end
local detail = self.findItem(item)
if detail then
return detail.craft(qty)
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
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:provide(item, qty, slot, direction)
return pcall(function()
for _,stack in pairs(self.listAvailableItems()) do
if stack.name == item.name and
(not item.damage or stack.damage == item.damage) and
(not item.nbtHash or stack.nbtHash == item.nbtHash) then
local amount = math.min(qty, stack.count)
if amount > 0 then
local detail = self.findItem(item)
if detail then
return detail.export(direction or self.direction, amount, slot)
end
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
return pcall(function()
for _,stack in pairs(self.listAvailableItems()) do
if stack.name == item.name and
(not item.damage or stack.damage == item.damage) and
(not item.nbtHash or stack.nbtHash == item.nbtHash) then
local amount = math.min(qty, stack.count)
if amount > 0 then
local detail = self.findItem(item)
if detail then
return detail.export(direction or self.direction, amount, slot)
end
end
qty = qty - amount
if qty <= 0 then
break
end
end
end
end)
end
function RefinedAdapter:extract(slot, qty, toSlot)
self.pushItems(self.direction, slot, qty, toSlot)
self.pushItems(self.direction, slot, qty, toSlot)
end
function RefinedAdapter:insert(slot, qty, toSlot)
self.pullItems(self.direction, slot, qty, toSlot)
self.pullItems(self.direction, slot, qty, toSlot)
end
return RefinedAdapter

View File

@@ -1,66 +1,66 @@
local class = require('class')
local Event = require('event')
local Map = require('map')
local Proxy = require('proxy')
local Proxy = require('core.proxy')
local Swarm = class()
function Swarm:init(args)
self.pool = { }
Map.merge(self, args)
self.pool = { }
Map.merge(self, args)
end
function Swarm:add(id, args)
local member = Map.shallowCopy(args or { })
member.id = id
self.pool[id] = member
local member = Map.shallowCopy(args or { })
member.id = id
self.pool[id] = member
end
function Swarm:remove(id, s, m)
local member = self.pool[id]
if member then
self.pool[id] = nil
self:onRemove(member, s, m)
if member.socket then
member.socket:close()
member.socket = nil
end
if member.handler then
member.handler:terminate()
member.handler = nil
end
end
local member = self.pool[id]
if member then
self.pool[id] = nil
self:onRemove(member, s, m)
if member.socket then
member.socket:close()
member.socket = nil
end
if member.handler then
member.handler:terminate()
member.handler = nil
end
end
end
function Swarm:run(fn)
for id, member in pairs(self.pool) do
if not member.socket then
member.handler = Event.addRoutine(function()
local s, m = pcall(function()
member.turtle, member.socket = Proxy.create(id, 'turtle')
for id, member in pairs(self.pool) do
if not member.socket then
member.handler = Event.addRoutine(function()
local s, m = pcall(function()
member.turtle, member.socket = Proxy.create(id, 'turtle')
fn(member)
end)
self:remove(id, s, m)
end)
end
end
fn(member)
end)
self:remove(id, s, m)
end)
end
end
end
function Swarm:stop()
for _, member in pairs(self.pool) do
if member.socket then
member.socket:close()
member.socket = nil
end
end
for _, member in pairs(self.pool) do
if member.socket then
member.socket:close()
member.socket = nil
end
end
end
-- Override
function Swarm:onRemove(member, success, msg)
print('removed from pool: ' .. member.id)
if not success then
_G.printError(msg)
end
print('removed from pool: ' .. member.id)
if not success then
_G.printError(msg)
end
end
return Swarm

View File

@@ -3,47 +3,47 @@ local Util = require('util')
local TableDB = class()
function TableDB:init(args)
local defaults = {
fileName = '',
dirty = false,
data = { },
}
Util.merge(defaults, args)
Util.merge(self, defaults)
local defaults = {
fileName = '',
dirty = false,
data = { },
}
Util.merge(defaults, args)
Util.merge(self, defaults)
end
function TableDB:load()
local t = Util.readTable(self.fileName)
if t then
self.data = t.data or t
end
local t = Util.readTable(self.fileName)
if t then
self.data = t.data or t
end
end
function TableDB:add(key, entry)
if type(key) == 'table' then
key = table.concat(key, ':')
end
self.data[key] = entry
self.dirty = true
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]
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
self.data[key] = nil
self.dirty = true
end
function TableDB:flush()
if self.dirty then
Util.writeTable(self.fileName, self.data)
self.dirty = false
end
if self.dirty then
Util.writeTable(self.fileName, self.data)
self.dirty = false
end
end
return TableDB

File diff suppressed because it is too large Load Diff