spaces->tab, equipper improvements, supertreefarm rewrite, follow improvements, sensor cleanup, milo multiple items allowed in recipes, remote canvas access
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
32
core/apis/proxy.lua
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user