Compare commits
19 Commits
98018e4a8c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba1932138 | ||
|
|
3282023edd | ||
|
|
8d3b351083 | ||
|
|
6b78404821 | ||
|
|
0ff69b53f6 | ||
|
|
4997a94cfb | ||
|
|
8a4e99aa13 | ||
|
|
cd80a9af22 | ||
|
|
1d4500a4d4 | ||
|
|
f6b76a522f | ||
|
|
408fed1ad2 | ||
|
|
d80ff4e679 | ||
|
|
147dc40365 | ||
|
|
7dca84b128 | ||
|
|
65f6555f44 | ||
|
|
b10bc73833 | ||
|
|
9177394fd0 | ||
|
|
8db86ee45c | ||
|
|
3d293d3e68 |
16
debugger.lua
16
debugger.lua
@@ -43,4 +43,18 @@ local function debugREPL(onResult, debugArgs)
|
||||
return success, (not success and retval) or nil
|
||||
end
|
||||
|
||||
return { debugREPL = debugREPL, execDebug = execDebug }
|
||||
local function hookDebugger(context, Logger)
|
||||
Logger = Logger or require("logging").getGlobalLogger()
|
||||
|
||||
local result, retval
|
||||
repeat
|
||||
result, retval = debugREPL(function(r)
|
||||
Logger:error("->", r)
|
||||
end, context)
|
||||
if not result then
|
||||
Logger:error("x>", retval)
|
||||
end
|
||||
until result
|
||||
end
|
||||
|
||||
return { debugREPL = debugREPL, execDebug = execDebug, hookDebugger = hookDebugger }
|
||||
@@ -9,7 +9,7 @@ function Event.getKeyParams(evt)
|
||||
end
|
||||
|
||||
function Event.isCharEvent(evt, char)
|
||||
return evt[1] == "char" and (key == nil or evt[2] == key)
|
||||
return evt[1] == "char" and (char == nil or evt[2] == char)
|
||||
end
|
||||
|
||||
function Event.getCharValue(evt)
|
||||
|
||||
232
gfx/keyboard.lua
Normal file
232
gfx/keyboard.lua
Normal file
@@ -0,0 +1,232 @@
|
||||
-- On-screen keyboard with hooks for standard key input events
|
||||
|
||||
local List = require("gfx.list")
|
||||
local Padding = require("gfx.padding")
|
||||
local Text = require("gfx.text")
|
||||
local Orientation = require("gfx.prop.orientation")
|
||||
local Children = require("gfx.prop.children")
|
||||
|
||||
local DEFAULT_COLOR_BG = colors.gray
|
||||
local DEFAULT_COLOR_KEY = colors.gray
|
||||
local DEFAULT_PADDING_H = 1
|
||||
local DEFAULT_PADDING_V = 1
|
||||
local HANDLER_IGNORE_CLICK = function() return true end
|
||||
|
||||
local ID_KEY_LIST = "$Keyboard$List"
|
||||
local ID_PADDED_KEY = "$Keyboard$List$Padding"
|
||||
|
||||
local Keyboard = Padding:new{
|
||||
bgColor = DEFAULT_COLOR_BG,
|
||||
keyColor = DEFAULT_COLOR_KEY,
|
||||
left = DEFAULT_PADDING_H,
|
||||
right = DEFAULT_PADDING_H,
|
||||
top = DEFAULT_PADDING_V,
|
||||
bottom = DEFAULT_PADDING_V,
|
||||
onKeyPress = function(key) end,
|
||||
onBackspace = function() end
|
||||
}
|
||||
|
||||
function Keyboard:new(o)
|
||||
local template = o or {}
|
||||
|
||||
if type(template.layout) == "function" then
|
||||
template.layout = template.layout()
|
||||
elseif type(template.layout) ~= "table" then
|
||||
template.layout = Keyboard.Layout.English()
|
||||
end
|
||||
|
||||
template.colorKey = template.colorKey or DEFAULT_COLOR_KEY
|
||||
template.keySlop = not not template.keySlop
|
||||
template.onClick = HANDLER_IGNORE_CLICK
|
||||
template.onKey = function(_, keyCode, _)
|
||||
if keyCode == keys.backspace then
|
||||
template.onBackspace()
|
||||
return true
|
||||
elseif keyCode == keys.enter then
|
||||
template.onKeyPress("\n")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
template.onChar = function(_, charCode)
|
||||
template.onKeyPress(charCode)
|
||||
return true
|
||||
end
|
||||
|
||||
template.element = List:new{
|
||||
bgColor = template.bgColor,
|
||||
[Orientation:getId()] = Orientation.VERTICAL,
|
||||
[Children:getId()] = {}
|
||||
}
|
||||
|
||||
local obj = Padding.new(self, template)
|
||||
|
||||
self:setLayout(self.layout)
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
function Keyboard:setLayout(layout)
|
||||
self.layout = layout
|
||||
|
||||
local this = self
|
||||
|
||||
local KEY_BACKSPACE = "backspace"
|
||||
local KEY_ENTER = "enter"
|
||||
local function charInputKeyList(chars, backspace, enter, spacebar)
|
||||
local keysEntries = { }
|
||||
for i=1,#chars do
|
||||
local key = chars:sub(i, i)
|
||||
local keyFunc = function()
|
||||
this.onKeyPress(key)
|
||||
return true
|
||||
end
|
||||
local keySlopFunc = this.keySlop and keyFunc or HANDLER_IGNORE_CLICK
|
||||
|
||||
-- ((not backspace) and i == #keys and 0) or 1
|
||||
table.insert(keysEntries, Padding:new{ onClick = keySlopFunc, bgColor = this.bgColor, right = 1, element = Text:new{
|
||||
id = key,
|
||||
text = key,
|
||||
bgColor = this.colorKey,
|
||||
onClick = keyFunc
|
||||
}})
|
||||
end
|
||||
if enter then
|
||||
table.insert(keysEntries, Text:new{
|
||||
id = KEY_ENTER,
|
||||
text = "[<]",
|
||||
bgColor = this.colorKey,
|
||||
onClick = function()
|
||||
this.onKeyPress("\n")
|
||||
return true
|
||||
end
|
||||
})
|
||||
end
|
||||
if backspace then
|
||||
table.insert(keysEntries, Text:new{
|
||||
id = KEY_BACKSPACE,
|
||||
text = "[x]",
|
||||
bgColor = this.colorKey,
|
||||
onClick = function()
|
||||
this.onBackspace()
|
||||
return true
|
||||
end
|
||||
})
|
||||
end
|
||||
if spacebar then
|
||||
table.insert(keysEntries, Text:new{
|
||||
id = " ",
|
||||
text = "[SPACE]",
|
||||
bgColor = this.colorKey,
|
||||
onClick = function()
|
||||
this.onKeyPress(" ")
|
||||
return true
|
||||
end
|
||||
})
|
||||
end
|
||||
return List:new{
|
||||
id = ID_KEY_LIST,
|
||||
bgColor = this.colorBg,
|
||||
[Orientation:getId()] = Orientation.HORIZONTAL,
|
||||
[Children:getId()] = keysEntries
|
||||
}
|
||||
end
|
||||
|
||||
local keyboardLines = {}
|
||||
for _,line in ipairs(this.layout) do
|
||||
local keyLineList = charInputKeyList(line[1], line.backspace, line.enter)
|
||||
table.insert(keyboardLines, keyLineList)
|
||||
end
|
||||
|
||||
self.element[Children:getId()] = keyboardLines
|
||||
self:setDirty()
|
||||
end
|
||||
|
||||
function Keyboard:setKeyColor(color)
|
||||
if color ~= self.keyColor then
|
||||
self.keyColor = color
|
||||
self:setDirty()
|
||||
end
|
||||
end
|
||||
|
||||
function Keyboard:setDirty(fullInvalidate)
|
||||
local keyList = self:findById(ID_KEY_LIST)
|
||||
for _,key in pairs(keyList[Children:getId()]) do
|
||||
if key:getId() == ID_PADDED_KEY then
|
||||
key:setBgColor(self.bgColor)
|
||||
key.element:setBgColor(self.keyColor)
|
||||
else
|
||||
key:setBgColor(self.keyColor)
|
||||
end
|
||||
end
|
||||
Padding.setDirty(self, fullInvalidate)
|
||||
end
|
||||
|
||||
local function layoutNumbers(layout)
|
||||
table.insert(layout, 1, { "1234567890" })
|
||||
return layout
|
||||
end
|
||||
|
||||
local function layoutEnter(rowIndex, layout)
|
||||
for index,layoutRow in pairs(layout) do
|
||||
if index == rowIndex then
|
||||
layoutRow.enter = true
|
||||
else
|
||||
layoutRow.enter = nil
|
||||
end
|
||||
end
|
||||
return layout
|
||||
end
|
||||
|
||||
local function layoutBackspace(rowIndex, layout)
|
||||
for index,layoutRow in pairs(layout) do
|
||||
if index == rowIndex then
|
||||
layoutRow.backspace = true
|
||||
else
|
||||
layoutRow.backspace = nil
|
||||
end
|
||||
end
|
||||
return layout
|
||||
end
|
||||
|
||||
local function layoutSpacebar(layout)
|
||||
table.insert(layout, { spacebar = true, "" })
|
||||
return layout
|
||||
end
|
||||
|
||||
local function appendNumberLayout(cond, layout)
|
||||
return cond and layoutNumbers(layout) or layout
|
||||
end
|
||||
|
||||
Keyboard.Layout = {
|
||||
ItemSearch = function()
|
||||
return layoutBackspace(1, layoutNumbers({
|
||||
{ "qwertyuiop" },
|
||||
{ "asdfghjkl" },
|
||||
{ "zxcvbnm_:" }
|
||||
}))
|
||||
end,
|
||||
English = function(numberRow)
|
||||
return layoutSpacebar(layoutBackspace(1, appendNumberLayout(numberRow, layoutEnter(2, {
|
||||
{ "qwertyuiop" },
|
||||
{ "asdfghjkl" },
|
||||
{ "zxcvbnm" }
|
||||
}))))
|
||||
end,
|
||||
Swedish = function(numberRow)
|
||||
return layoutSpacebar(layoutBackspace(1, appendNumberLayout(numberRow, layoutEnter(2, {
|
||||
{ "qwertyuiopå" },
|
||||
{ "asdfghjklöä" },
|
||||
{ "zxcvbnm" }
|
||||
}))))
|
||||
end,
|
||||
Special = function(numberRow)
|
||||
return layoutSpacebar(layoutBackspace(1, appendNumberLayout(numberRow, {
|
||||
{ "!\"#¤%&/()=?" },
|
||||
{ "@£${[]}\\+^" },
|
||||
{ "§<>|;:,.-_'*" }
|
||||
})))
|
||||
end
|
||||
}
|
||||
|
||||
return Keyboard
|
||||
@@ -1,3 +1,5 @@
|
||||
-- TODO: Rename to "Column" to better represent functionality
|
||||
|
||||
local Event = require("gfx.event")
|
||||
local Element = require("gfx.element")
|
||||
local Prop = require("gfx.prop")
|
||||
|
||||
@@ -7,6 +7,7 @@ end
|
||||
|
||||
function TextProgress:setProgress(progress)
|
||||
self.progress = progress
|
||||
self:setDirty()
|
||||
end
|
||||
|
||||
function TextProgress:draw()
|
||||
|
||||
185
quarry.lua
Normal file
185
quarry.lua
Normal file
@@ -0,0 +1,185 @@
|
||||
local args = {...}
|
||||
local Logging = require("logging")
|
||||
local Logger = Logging.firstLoad(
|
||||
Logging.OUTPUTS.file("tunnel.log"),
|
||||
Logging.OUTPUTS.stdout()
|
||||
)
|
||||
|
||||
local CHEST_SLOT = #args == 1 and tonumber(args[1]) or 1
|
||||
if type(CHEST_SLOT) ~= "number" or CHEST_SLOT < 1 or CHEST_SLOT > 16 then
|
||||
Logger:error("Slot number is not valid:", CHEST_SLOT)
|
||||
end
|
||||
local CHEST_PICKUP = #args == 2 and (args[2]:lower() )
|
||||
|
||||
local CHEST_DETAIL = turtle.getItemDetail(CHEST_SLOT)
|
||||
if CHEST_DETAIL == nil then
|
||||
Logger:error("No chest in slot! Quitting...")
|
||||
return
|
||||
end
|
||||
local CHEST_NAME = CHEST_DETAIL.name
|
||||
|
||||
local function refuel(minFuel)
|
||||
local fuelLevel = turtle.getFuelLevel()
|
||||
while fuelLevel < minFuel do
|
||||
Logger:debug("Checking fuel level:", fuelLevel)
|
||||
for i=1,16 do
|
||||
if i == CHEST_SLOT then
|
||||
goto continue
|
||||
end
|
||||
|
||||
if turtle.getItemCount(i) > 0 then
|
||||
turtle.select(i)
|
||||
turtle.refuel()
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
fuelLevel = turtle.getFuelLevel()
|
||||
end
|
||||
Logger:debug("Fuel level is sufficient:", fuelLevel)
|
||||
turtle.select(1)
|
||||
end
|
||||
|
||||
local function isFull(minEmpty)
|
||||
local emptyCount = 0
|
||||
for i=1,16 do
|
||||
if i == CHEST_SLOT then
|
||||
goto continue
|
||||
end
|
||||
|
||||
if turtle.getItemCount(i) == 0 then
|
||||
emptyCount = emptyCount + 1
|
||||
if emptyCount >= minEmpty then
|
||||
return false
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function placeChest()
|
||||
if not turtle.select(CHEST_SLOT) then
|
||||
Logger:error("Cannot select chest slot", CHEST_SLOT)
|
||||
return false, nil, nil, nil
|
||||
end
|
||||
|
||||
if turtle.placeUp() or (turtle.digUp() and turtle.placeUp()) then
|
||||
return true, turtle.dropUp, turtle.digUp, function() end
|
||||
end
|
||||
|
||||
if turtle.turnLeft() and turtle.turnLeft() and (turtle.place() or (turtle.dig() and turtle.place())) then
|
||||
return true, turtle.drop, turtle.dig, function()
|
||||
turtle.turnRight()
|
||||
turtle.turnRight()
|
||||
end
|
||||
end
|
||||
return false, nil, nil, nil
|
||||
end
|
||||
|
||||
local function handleFullInv(minEmpty)
|
||||
local didPlace = false
|
||||
|
||||
local result, drop, dig, onComplete = false, nil, nil, nil
|
||||
-- Empty inventory
|
||||
while isFull(minEmpty) do
|
||||
if not didPlace then
|
||||
local detail = turtle.getItemDetail(CHEST_SLOT)
|
||||
if type(detail) ~= "table" or detail.name ~= CHEST_NAME then
|
||||
Logger:error("Can't find chest :(")
|
||||
os.sleep(5)
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- Try: place, check block above is empty or dig it, place
|
||||
-- If all fails, print error, wait and repeat
|
||||
result, drop, dig, onComplete = placeChest()
|
||||
if not result then
|
||||
Logger:error("Can't place chest :(")
|
||||
os.sleep(5)
|
||||
goto continue
|
||||
end
|
||||
didPlace = true
|
||||
end
|
||||
|
||||
assert(drop ~= nil, "Placed chest, but drop operation is nil")
|
||||
for i=1,16 do
|
||||
if i == CHEST_SLOT then
|
||||
goto continue_SLOT
|
||||
end
|
||||
if turtle.getItemCount(i) > 0 and not (turtle.select(i) and drop()) then
|
||||
Logger:error("Couldn't drop items into chest!")
|
||||
goto continue
|
||||
end
|
||||
|
||||
::continue_SLOT::
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
if result then
|
||||
assert(dig ~= nil, "Placed chest, but dig operation is nil")
|
||||
if didPlace and CHEST_PICKUP then
|
||||
turtle.select(CHEST_SLOT)
|
||||
dig()
|
||||
end
|
||||
|
||||
assert(onComplete ~= nil, "Placed chest, but onComplete operation is nil")
|
||||
onComplete()
|
||||
end
|
||||
end
|
||||
|
||||
local function dig(checkRefuel)
|
||||
while not turtle.forward() do
|
||||
turtle.dig()
|
||||
checkRefuel()
|
||||
end
|
||||
turtle.digUp()
|
||||
turtle.digDown()
|
||||
end
|
||||
|
||||
local function line(length, turn, checkRefuel)
|
||||
turtle.digDown()
|
||||
for _=2,length do
|
||||
dig(checkRefuel)
|
||||
end
|
||||
turn()
|
||||
end
|
||||
|
||||
local function panel(width, length, leftFirst, checkRefuel, checkFullInv)
|
||||
Logger:trace("Panel:", width, length)
|
||||
local turn, otherTurn = leftFirst and turtle.turnLeft or turtle.turnRight, leftFirst and turtle.turnRight or turtle.turnLeft
|
||||
for _=2,width do
|
||||
checkFullInv()
|
||||
line(length, turn, checkRefuel)
|
||||
dig(checkRefuel)
|
||||
turn()
|
||||
turn, otherTurn = otherTurn, turn
|
||||
end
|
||||
line(length, turn, checkRefuel)
|
||||
turn()
|
||||
end
|
||||
|
||||
local function rectPrism(depth, width, length, leftFirst)
|
||||
local refuelTarget = width * length * 1.5
|
||||
local function checkRefuel()
|
||||
refuel(refuelTarget)
|
||||
end
|
||||
local invEmptyTarget = 3
|
||||
local function checkFullInv()
|
||||
Logger:debug("Handling full inventory with target:", invEmptyTarget, " handled:", handleFullInv(invEmptyTarget))
|
||||
end
|
||||
Logger:trace("RectPrism:", depth, width, length)
|
||||
for _=1,depth do
|
||||
panel(width, length, leftFirst, checkRefuel, checkFullInv)
|
||||
for __=1,3 do
|
||||
while not turtle.down() do
|
||||
turtle.digDown()
|
||||
checkRefuel()
|
||||
end
|
||||
end
|
||||
leftFirst = (not not leftFirst) ~= (width % 2 == 0)
|
||||
end
|
||||
end
|
||||
|
||||
rectPrism(200, 16, 16)
|
||||
16
reload.lua
16
reload.lua
@@ -1,5 +1,16 @@
|
||||
local CC_UTILS_DIR = "/cc-utilities"
|
||||
|
||||
local function onResume(scriptArgs)
|
||||
if #scriptArgs > 0 then
|
||||
scriptArgs[1] = CC_UTILS_DIR .. "/" .. scriptArgs[1]
|
||||
shell.run(table.unpack(scriptArgs))
|
||||
end
|
||||
end
|
||||
|
||||
if pcall(debug.getlocal, 4, 1) then
|
||||
return { onResume = onResume }
|
||||
end
|
||||
|
||||
local result, retval = pcall(fs.delete, CC_UTILS_DIR)
|
||||
if fs.exists(CC_UTILS_DIR) then
|
||||
if result then
|
||||
@@ -11,5 +22,6 @@ if fs.exists(CC_UTILS_DIR) then
|
||||
end
|
||||
|
||||
shell.run("clone https://gitea.tofvesson.se/GabrielTofvesson/cc-utilities.git")
|
||||
shell.run("bg")
|
||||
shell.run("cc-utilities/itemcontroller")
|
||||
|
||||
local nextVersion = require(CC_UTILS_DIR .. "/reload")
|
||||
local _ = ((type(nextVersion) == "table" and type(nextVersion.onResume) == "function") and nextVersion.onResume or onResume)({...})
|
||||
@@ -4,6 +4,10 @@ local Sentinel = require("storage.sentinel")
|
||||
local Storage = Sentinel:tag({}, Sentinel.STORAGE)
|
||||
Storage.__index = Storage
|
||||
|
||||
local function _attach(stor, name, homogeneous)
|
||||
table.insert(stor, Chest:fromPeripheral(name, homogeneous))
|
||||
end
|
||||
|
||||
function Storage.assumeHomogeneous(names)
|
||||
local mappings = {}
|
||||
for _,name in ipairs(names) do
|
||||
@@ -12,12 +16,13 @@ function Storage.assumeHomogeneous(names)
|
||||
return mappings
|
||||
end
|
||||
|
||||
function Storage:fromPeripherals(names)
|
||||
function Storage:fromPeripherals(peripheralDefs)
|
||||
local obj = {
|
||||
count = #names
|
||||
count = #peripheralDefs
|
||||
}
|
||||
for name,homogeneous in pairs(names) do
|
||||
table.insert(obj, Chest:fromPeripheral(name, homogeneous))
|
||||
|
||||
for name,homogeneous in pairs(peripheralDefs) do
|
||||
_attach(obj, name, homogeneous)
|
||||
end
|
||||
|
||||
setmetatable(obj, self)
|
||||
@@ -30,6 +35,7 @@ function Storage:toSerializable()
|
||||
local ser = {
|
||||
count = self.count
|
||||
}
|
||||
|
||||
for _,chest in ipairs(self) do
|
||||
table.insert(ser, chest:toSerializable())
|
||||
end
|
||||
@@ -43,7 +49,7 @@ function Storage:fromSerializable(ser)
|
||||
for _,chestSer in ipairs(ser) do
|
||||
local chest = Chest:fromSerializable(chestSer)
|
||||
if chest ~= nil then
|
||||
table.insert(obj, chest)
|
||||
table.insert(obj, chest)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,7 +73,14 @@ function Storage:attach(name, homogeneous)
|
||||
return
|
||||
end
|
||||
|
||||
table.insert(self, Chest:fromPeripheral(name, homogeneous))
|
||||
_attach(self, name, homogeneous)
|
||||
end
|
||||
|
||||
function Storage:attachAll(peripheralDefs)
|
||||
for name,homogeneous in pairs(peripheralDefs) do
|
||||
self:attach(name, homogeneous)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Storage:detach(name)
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
local Inventory = require("storage.inventory")
|
||||
local Sentinel = require("storage.sentinel")
|
||||
local Logging = require("logging")
|
||||
local Util = require("util")
|
||||
local Logger = Logging.getGlobalLogger()
|
||||
local Debugger = require("debugger")
|
||||
|
||||
local ItemStack = Sentinel:tag({}, Sentinel.ITEMSTACK)
|
||||
ItemStack.__index = ItemStack
|
||||
|
||||
local function hookDebugger(context)
|
||||
local result, retval
|
||||
repeat
|
||||
result, retval = Debugger.debugREPL(function(r)
|
||||
Logger:error("->", r)
|
||||
end, context)
|
||||
if not result then
|
||||
Logger:error("x>", retval)
|
||||
end
|
||||
until result
|
||||
end
|
||||
|
||||
function ItemStack:fromDetail(inv, detail, slot)
|
||||
local obj = {
|
||||
slot = slot,
|
||||
@@ -26,13 +14,13 @@ function ItemStack:fromDetail(inv, detail, slot)
|
||||
}
|
||||
|
||||
if detail == nil then
|
||||
obj.maxCount = inv.getItemLimit(slot)
|
||||
obj.maxCount = Util.getItemLimit(inv, slot)
|
||||
else
|
||||
obj.name = detail.name
|
||||
obj.damage = detail.damage
|
||||
obj.maxDamage = detail.maxDamage
|
||||
obj.count = detail.count
|
||||
obj.maxCount = detail.maxCount
|
||||
obj.maxCount = detail.maxCount or 64
|
||||
obj.enchantments = detail.enchantments
|
||||
obj.displayName = detail.displayName
|
||||
obj.nbt = detail.nbt
|
||||
@@ -46,16 +34,16 @@ end
|
||||
|
||||
function ItemStack:clone(withSlot)
|
||||
local obj = {
|
||||
slot = withSlot or self.slot,
|
||||
inv = self.inv,
|
||||
name = self.name,
|
||||
damage = self.damage,
|
||||
maxDamage = self.maxDamage,
|
||||
count = self.count,
|
||||
maxCount = self.maxCount,
|
||||
enchantments = self.enchantments,
|
||||
displayName = self.displayName,
|
||||
nbt = self.nbt
|
||||
slot = withSlot or self:getSlot(),
|
||||
inv = self:getInventory(),
|
||||
name = self:getName(),
|
||||
damage = self:getDamage(),
|
||||
maxDamage = self:getMaxDamage(),
|
||||
count = self:getCount(),
|
||||
maxCount = self:getMaxCount(),
|
||||
enchantments = self:getEnchantments(),
|
||||
displayName = self:getDisplayName(),
|
||||
nbt = self:getNBT()
|
||||
}
|
||||
|
||||
setmetatable(obj, self)
|
||||
@@ -66,19 +54,19 @@ end
|
||||
|
||||
function ItemStack:toSerializable()
|
||||
local ser = {
|
||||
slot = self.slot,
|
||||
maxCount = self.maxCount
|
||||
slot = self:getSlot(),
|
||||
maxCount = self:getMaxCount()
|
||||
}
|
||||
|
||||
if not self:isEmpty() then
|
||||
-- Not empty
|
||||
ser.name = self.name
|
||||
ser.damage = self.damage
|
||||
ser.maxDamage = self.maxDamage
|
||||
ser.count = self.count
|
||||
ser.enchantments = self.enchantments
|
||||
ser.displayName = self.displayName
|
||||
ser.nbt = self.nbt
|
||||
ser.name = self:getName()
|
||||
ser.damage = self:getDamage()
|
||||
ser.maxDamage = self:getMaxDamage()
|
||||
ser.count = self:getCount()
|
||||
ser.enchantments = self:getEnchantments()
|
||||
ser.displayName = self:getDisplayName()
|
||||
ser.nbt = self:getNBT()
|
||||
end
|
||||
|
||||
return ser
|
||||
@@ -130,7 +118,8 @@ function ItemStack:getNBT()
|
||||
end
|
||||
|
||||
function ItemStack:isEmpty()
|
||||
return self.count == nil or self.count == 0
|
||||
local count = self:getCount()
|
||||
return count == nil or count == 0
|
||||
end
|
||||
|
||||
function ItemStack:getDisplayName()
|
||||
@@ -162,12 +151,14 @@ function ItemStack:getSimpleName()
|
||||
end
|
||||
|
||||
function ItemStack:hasChanged(listObj, thorough)
|
||||
local listItem = listObj[self.slot]
|
||||
if listItem == nil or listItem.name ~= self.name or listItem.count ~= self.count then
|
||||
local listItem = listObj[self:getSlot()]
|
||||
if listItem == nil or listItem.name ~= self:getName() or listItem.count ~= self:getCount() then
|
||||
return true
|
||||
end
|
||||
|
||||
return thorough and (self ~= self:fromDetail(self.inv, self.inv.getItemDetail(self.slot), self.slot))
|
||||
local inv = self:getInventory()
|
||||
local slot = self:getSlot()
|
||||
return thorough and (self ~= self:fromDetail(inv, inv.getItemDetail(slot), slot))
|
||||
end
|
||||
|
||||
function ItemStack:_modify(countDelta, stack)
|
||||
@@ -178,7 +169,7 @@ function ItemStack:_modify(countDelta, stack)
|
||||
|
||||
if newCount == 0 then
|
||||
-- Clear data
|
||||
self.maxCount = self.inv.getItemLimit(self.slot)
|
||||
self.maxCount = Util.getItemLimit(self:getInventory(), self:getSlot())
|
||||
self.name = nil
|
||||
self.damage = nil
|
||||
self.maxDamage = nil
|
||||
@@ -189,14 +180,13 @@ function ItemStack:_modify(countDelta, stack)
|
||||
else
|
||||
-- If stack is empty, copy stack data from source
|
||||
if self:isEmpty() then
|
||||
self.maxCount = stack.maxCount
|
||||
self.name = stack.name
|
||||
self.damage = stack.damage
|
||||
self.maxDamage = stack.maxDamage
|
||||
self.maxCount = stack.maxCount
|
||||
self.enchantments = stack.enchantments
|
||||
self.displayName = stack.displayName
|
||||
self.nbt = stack.nbt
|
||||
self.name = stack:getName()
|
||||
self.damage = stack:getDamage()
|
||||
self.maxDamage = stack:getMaxDamage()
|
||||
self.maxCount = stack:getMaxCount()
|
||||
self.enchantments = stack:getEnchantments()
|
||||
self.displayName = stack:getDisplayName()
|
||||
self.nbt = stack:getNBT()
|
||||
end
|
||||
|
||||
self.count = newCount
|
||||
@@ -204,10 +194,6 @@ function ItemStack:_modify(countDelta, stack)
|
||||
end
|
||||
|
||||
function ItemStack:transferTo(target, count)
|
||||
if target:getMaxCount() == nil then
|
||||
Logger:error("Max count is nil?", target, "\n", self, "\n", count)
|
||||
hookDebugger({ target = target, count = count, self = self })
|
||||
end
|
||||
local cap = math.min(count or self:getCount(), target:getMaxCount() - target:getCount(), self:getCount())
|
||||
|
||||
-- If we can't transfer any data, then
|
||||
@@ -226,20 +212,6 @@ function ItemStack:transferTo(target, count)
|
||||
return false, result[2]
|
||||
end
|
||||
|
||||
if result[2] == nil then
|
||||
Logger:error(
|
||||
"Error transferring item", self:getInventory().pushItems, "\n",
|
||||
peripheral.getName(target:getInventory()), "\n",
|
||||
errC, "\n",
|
||||
cap, "\n",
|
||||
self, "\n",
|
||||
target, "\n",
|
||||
target:getInventory().getItemLimit(target:getSlot()), "\n",
|
||||
result
|
||||
)
|
||||
hookDebugger({ target = target, count = count, self = self, result = result, errC = errC, cap = cap })
|
||||
end
|
||||
|
||||
target:_modify(result[2], self)
|
||||
self:_modify(-result[2], self)
|
||||
|
||||
@@ -275,23 +247,45 @@ local function objEquals(o1, o2)
|
||||
end
|
||||
end
|
||||
|
||||
function ItemStack:__eq(other)
|
||||
return type(other) == "table" and
|
||||
self.count == other.count and
|
||||
self.maxCount == other.maxCount and
|
||||
self:canTransfer(other)
|
||||
local function runGetter(obj, name)
|
||||
local fun = obj[name]
|
||||
if type(fun) ~= "function" then
|
||||
return false, ("Function '%s' cannot be found in object"):format(name)
|
||||
end
|
||||
return pcall(fun, obj)
|
||||
end
|
||||
|
||||
local function checkEqual(obj1, obj2, funcName)
|
||||
local result1 = { runGetter(obj1, funcName) }
|
||||
local result2 = { runGetter(obj2, funcName) }
|
||||
return result1[1] and result2[1] and (result1[2] == result2[2])
|
||||
end
|
||||
|
||||
local function checkEnchantments(obj1, obj2)
|
||||
local GETTER_FUNC_NAME = "getEnchantments"
|
||||
local result1 = { runGetter(obj1, GETTER_FUNC_NAME) }
|
||||
local result2 = { runGetter(obj2, GETTER_FUNC_NAME) }
|
||||
return result1[1] and result2[1] and objEquals(result1[2], result2[2])
|
||||
end
|
||||
|
||||
function ItemStack:__eq(other)
|
||||
return type(other) == "table" and
|
||||
checkEqual(self, other, "getCount") and
|
||||
checkEqual(self, other, "getMaxCount") and
|
||||
self:canTransfer(other)
|
||||
end
|
||||
|
||||
-- Determines if two stacks can be transferred to eachother
|
||||
-- Empty stacks are always valid transfer nodes
|
||||
function ItemStack:canTransfer(stack)
|
||||
return self:isEmpty() or stack:isEmpty() or (self.name == stack.name and
|
||||
self.damage == stack.damage and
|
||||
self.maxDamage == stack.maxDamage and
|
||||
self.displayName == stack.displayName and
|
||||
self.nbt == stack.nbt and
|
||||
objEquals(self.enchantments, stack.enchantments))
|
||||
return self:isEmpty() or stack:isEmpty() or (
|
||||
checkEqual(self, stack, "getName") and
|
||||
checkEqual(self, stack, "getDamage") and
|
||||
checkEqual(self, stack, "getMaxDamage") and
|
||||
checkEqual(self, stack, "getDisplayName") and
|
||||
checkEqual(self, stack, "getNBT") and
|
||||
checkEnchantments(self, stack)
|
||||
)
|
||||
end
|
||||
|
||||
local function queryField(query, field)
|
||||
@@ -314,14 +308,14 @@ function ItemStack:matches(query)
|
||||
return query(self)
|
||||
end
|
||||
|
||||
return queryField(query.name, self.name) and
|
||||
queryField(query.damage, self.damage) and
|
||||
queryField(query.count, self.count) and
|
||||
queryField(query.maxDamage, self.maxDamage) and
|
||||
queryField(query.enchantments, self.enchantments) and
|
||||
queryField(query.maxCount, self.maxCount) and
|
||||
queryField(query.nbt, self.nbt) and
|
||||
queryField(query.displayName, self.displayName)
|
||||
return queryField(query.name, self:getName()) and
|
||||
queryField(query.damage, self:getDamage()) and
|
||||
queryField(query.count, self:getCount()) and
|
||||
queryField(query.maxDamage, self:getMaxDamage()) and
|
||||
queryField(query.enchantments, self:getEnchantments()) and
|
||||
queryField(query.maxCount, self:getMaxCount()) and
|
||||
queryField(query.nbt, self:getNBT()) and
|
||||
queryField(query.displayName, self:getDisplayName())
|
||||
end
|
||||
|
||||
return ItemStack
|
||||
@@ -18,4 +18,17 @@ function Util.boundCheck(x, y, w, h)
|
||||
end
|
||||
end
|
||||
|
||||
-- Workaround for a bug in CC: Tweaked causing inventory.getItemLimit() to return nil immediately after item transfers
|
||||
function Util.getItemLimit(inv, slot, maxTries)
|
||||
local i = 1
|
||||
while not maxTries or i <= maxTries do
|
||||
local result = inv.getItemLimit(slot)
|
||||
if result ~= nil then
|
||||
return result
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
return Util
|
||||
Reference in New Issue
Block a user