Compare commits

...

19 Commits

Author SHA1 Message Date
Gabriel Tofvesson
4ba1932138 Propagate keyboard color changes properly 2025-05-25 17:05:31 +02:00
Gabriel Tofvesson
3282023edd Implement on-screen keyboard element 2025-05-25 16:35:52 +02:00
Gabriel Tofvesson
8d3b351083 Simplify attaching multiple chests after initializing storage 2024-12-07 02:05:38 +01:00
Gabriel Tofvesson
6b78404821 Fix path separator 2024-12-04 22:52:19 +01:00
Gabriel Tofvesson
0ff69b53f6 Implement post-deploy execution from latest version of reload script 2024-12-04 22:51:03 +01:00
Gabriel Tofvesson
4997a94cfb Fix variable naming 2024-12-04 22:31:28 +01:00
Gabriel Tofvesson
8a4e99aa13 Implement workaround for illegal nil-return value from inventory.getItemLimit 2024-12-04 20:53:56 +01:00
Gabriel Tofvesson
cd80a9af22 Fix bug in object equality check 2024-12-04 17:54:53 +01:00
Gabriel Tofvesson
1d4500a4d4 Move down 3 blocks instead of 2 2024-12-03 23:17:57 +01:00
Gabriel Tofvesson
f6b76a522f Fix nil check assertions 2024-12-03 23:10:09 +01:00
Gabriel Tofvesson
408fed1ad2 Dig down twice after a panel 2024-12-03 23:00:39 +01:00
Gabriel Tofvesson
d80ff4e679 Add more options for placing chests 2024-12-03 22:58:38 +01:00
Gabriel Tofvesson
147dc40365 Try to enforce better encapsulation with getters 2024-12-03 22:36:23 +01:00
Gabriel Tofvesson
7dca84b128 Don't use chest slot as fuel 2024-12-03 22:04:52 +01:00
Gabriel Tofvesson
65f6555f44 Select chest slot 2024-12-01 05:04:52 +01:00
Gabriel Tofvesson
b10bc73833 Fix quarry boundary conditions 2024-12-01 04:37:58 +01:00
Gabriel Tofvesson
9177394fd0 Implement quarry command 2024-12-01 04:09:55 +01:00
Gabriel Tofvesson
8db86ee45c Remove debug statements 2024-11-30 00:20:21 +01:00
Gabriel Tofvesson
3d293d3e68 Implement default debugger REPL loop 2024-11-30 00:20:10 +01:00
10 changed files with 561 additions and 95 deletions

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,7 @@ end
function TextProgress:setProgress(progress)
self.progress = progress
self:setDirty()
end
function TextProgress:draw()

185
quarry.lua Normal file
View 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)

View File

@@ -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)({...})

View File

@@ -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,10 +49,10 @@ 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
setmetatable(obj, self)
obj.__index = self
@@ -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)

View File

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

View File

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