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
|
return success, (not success and retval) or nil
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function Event.isCharEvent(evt, char)
|
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
|
end
|
||||||
|
|
||||||
function Event.getCharValue(evt)
|
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 Event = require("gfx.event")
|
||||||
local Element = require("gfx.element")
|
local Element = require("gfx.element")
|
||||||
local Prop = require("gfx.prop")
|
local Prop = require("gfx.prop")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ end
|
|||||||
|
|
||||||
function TextProgress:setProgress(progress)
|
function TextProgress:setProgress(progress)
|
||||||
self.progress = progress
|
self.progress = progress
|
||||||
|
self:setDirty()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TextProgress:draw()
|
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 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)
|
local result, retval = pcall(fs.delete, CC_UTILS_DIR)
|
||||||
if fs.exists(CC_UTILS_DIR) then
|
if fs.exists(CC_UTILS_DIR) then
|
||||||
if result then
|
if result then
|
||||||
@@ -11,5 +22,6 @@ if fs.exists(CC_UTILS_DIR) then
|
|||||||
end
|
end
|
||||||
|
|
||||||
shell.run("clone https://gitea.tofvesson.se/GabrielTofvesson/cc-utilities.git")
|
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)
|
local Storage = Sentinel:tag({}, Sentinel.STORAGE)
|
||||||
Storage.__index = Storage
|
Storage.__index = Storage
|
||||||
|
|
||||||
|
local function _attach(stor, name, homogeneous)
|
||||||
|
table.insert(stor, Chest:fromPeripheral(name, homogeneous))
|
||||||
|
end
|
||||||
|
|
||||||
function Storage.assumeHomogeneous(names)
|
function Storage.assumeHomogeneous(names)
|
||||||
local mappings = {}
|
local mappings = {}
|
||||||
for _,name in ipairs(names) do
|
for _,name in ipairs(names) do
|
||||||
@@ -12,12 +16,13 @@ function Storage.assumeHomogeneous(names)
|
|||||||
return mappings
|
return mappings
|
||||||
end
|
end
|
||||||
|
|
||||||
function Storage:fromPeripherals(names)
|
function Storage:fromPeripherals(peripheralDefs)
|
||||||
local obj = {
|
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
|
end
|
||||||
|
|
||||||
setmetatable(obj, self)
|
setmetatable(obj, self)
|
||||||
@@ -30,6 +35,7 @@ function Storage:toSerializable()
|
|||||||
local ser = {
|
local ser = {
|
||||||
count = self.count
|
count = self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
for _,chest in ipairs(self) do
|
for _,chest in ipairs(self) do
|
||||||
table.insert(ser, chest:toSerializable())
|
table.insert(ser, chest:toSerializable())
|
||||||
end
|
end
|
||||||
@@ -43,10 +49,10 @@ function Storage:fromSerializable(ser)
|
|||||||
for _,chestSer in ipairs(ser) do
|
for _,chestSer in ipairs(ser) do
|
||||||
local chest = Chest:fromSerializable(chestSer)
|
local chest = Chest:fromSerializable(chestSer)
|
||||||
if chest ~= nil then
|
if chest ~= nil then
|
||||||
table.insert(obj, chest)
|
table.insert(obj, chest)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(obj, self)
|
setmetatable(obj, self)
|
||||||
obj.__index = self
|
obj.__index = self
|
||||||
|
|
||||||
@@ -67,7 +73,14 @@ function Storage:attach(name, homogeneous)
|
|||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function Storage:detach(name)
|
function Storage:detach(name)
|
||||||
|
|||||||
@@ -1,24 +1,12 @@
|
|||||||
local Inventory = require("storage.inventory")
|
local Inventory = require("storage.inventory")
|
||||||
local Sentinel = require("storage.sentinel")
|
local Sentinel = require("storage.sentinel")
|
||||||
local Logging = require("logging")
|
local Logging = require("logging")
|
||||||
|
local Util = require("util")
|
||||||
local Logger = Logging.getGlobalLogger()
|
local Logger = Logging.getGlobalLogger()
|
||||||
local Debugger = require("debugger")
|
|
||||||
|
|
||||||
local ItemStack = Sentinel:tag({}, Sentinel.ITEMSTACK)
|
local ItemStack = Sentinel:tag({}, Sentinel.ITEMSTACK)
|
||||||
ItemStack.__index = 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)
|
function ItemStack:fromDetail(inv, detail, slot)
|
||||||
local obj = {
|
local obj = {
|
||||||
slot = slot,
|
slot = slot,
|
||||||
@@ -26,13 +14,13 @@ function ItemStack:fromDetail(inv, detail, slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if detail == nil then
|
if detail == nil then
|
||||||
obj.maxCount = inv.getItemLimit(slot)
|
obj.maxCount = Util.getItemLimit(inv, slot)
|
||||||
else
|
else
|
||||||
obj.name = detail.name
|
obj.name = detail.name
|
||||||
obj.damage = detail.damage
|
obj.damage = detail.damage
|
||||||
obj.maxDamage = detail.maxDamage
|
obj.maxDamage = detail.maxDamage
|
||||||
obj.count = detail.count
|
obj.count = detail.count
|
||||||
obj.maxCount = detail.maxCount
|
obj.maxCount = detail.maxCount or 64
|
||||||
obj.enchantments = detail.enchantments
|
obj.enchantments = detail.enchantments
|
||||||
obj.displayName = detail.displayName
|
obj.displayName = detail.displayName
|
||||||
obj.nbt = detail.nbt
|
obj.nbt = detail.nbt
|
||||||
@@ -46,16 +34,16 @@ end
|
|||||||
|
|
||||||
function ItemStack:clone(withSlot)
|
function ItemStack:clone(withSlot)
|
||||||
local obj = {
|
local obj = {
|
||||||
slot = withSlot or self.slot,
|
slot = withSlot or self:getSlot(),
|
||||||
inv = self.inv,
|
inv = self:getInventory(),
|
||||||
name = self.name,
|
name = self:getName(),
|
||||||
damage = self.damage,
|
damage = self:getDamage(),
|
||||||
maxDamage = self.maxDamage,
|
maxDamage = self:getMaxDamage(),
|
||||||
count = self.count,
|
count = self:getCount(),
|
||||||
maxCount = self.maxCount,
|
maxCount = self:getMaxCount(),
|
||||||
enchantments = self.enchantments,
|
enchantments = self:getEnchantments(),
|
||||||
displayName = self.displayName,
|
displayName = self:getDisplayName(),
|
||||||
nbt = self.nbt
|
nbt = self:getNBT()
|
||||||
}
|
}
|
||||||
|
|
||||||
setmetatable(obj, self)
|
setmetatable(obj, self)
|
||||||
@@ -66,19 +54,19 @@ end
|
|||||||
|
|
||||||
function ItemStack:toSerializable()
|
function ItemStack:toSerializable()
|
||||||
local ser = {
|
local ser = {
|
||||||
slot = self.slot,
|
slot = self:getSlot(),
|
||||||
maxCount = self.maxCount
|
maxCount = self:getMaxCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
if not self:isEmpty() then
|
if not self:isEmpty() then
|
||||||
-- Not empty
|
-- Not empty
|
||||||
ser.name = self.name
|
ser.name = self:getName()
|
||||||
ser.damage = self.damage
|
ser.damage = self:getDamage()
|
||||||
ser.maxDamage = self.maxDamage
|
ser.maxDamage = self:getMaxDamage()
|
||||||
ser.count = self.count
|
ser.count = self:getCount()
|
||||||
ser.enchantments = self.enchantments
|
ser.enchantments = self:getEnchantments()
|
||||||
ser.displayName = self.displayName
|
ser.displayName = self:getDisplayName()
|
||||||
ser.nbt = self.nbt
|
ser.nbt = self:getNBT()
|
||||||
end
|
end
|
||||||
|
|
||||||
return ser
|
return ser
|
||||||
@@ -130,7 +118,8 @@ function ItemStack:getNBT()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ItemStack:isEmpty()
|
function ItemStack:isEmpty()
|
||||||
return self.count == nil or self.count == 0
|
local count = self:getCount()
|
||||||
|
return count == nil or count == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function ItemStack:getDisplayName()
|
function ItemStack:getDisplayName()
|
||||||
@@ -162,12 +151,14 @@ function ItemStack:getSimpleName()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ItemStack:hasChanged(listObj, thorough)
|
function ItemStack:hasChanged(listObj, thorough)
|
||||||
local listItem = listObj[self.slot]
|
local listItem = listObj[self:getSlot()]
|
||||||
if listItem == nil or listItem.name ~= self.name or listItem.count ~= self.count then
|
if listItem == nil or listItem.name ~= self:getName() or listItem.count ~= self:getCount() then
|
||||||
return true
|
return true
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
function ItemStack:_modify(countDelta, stack)
|
function ItemStack:_modify(countDelta, stack)
|
||||||
@@ -178,7 +169,7 @@ function ItemStack:_modify(countDelta, stack)
|
|||||||
|
|
||||||
if newCount == 0 then
|
if newCount == 0 then
|
||||||
-- Clear data
|
-- Clear data
|
||||||
self.maxCount = self.inv.getItemLimit(self.slot)
|
self.maxCount = Util.getItemLimit(self:getInventory(), self:getSlot())
|
||||||
self.name = nil
|
self.name = nil
|
||||||
self.damage = nil
|
self.damage = nil
|
||||||
self.maxDamage = nil
|
self.maxDamage = nil
|
||||||
@@ -189,14 +180,13 @@ function ItemStack:_modify(countDelta, stack)
|
|||||||
else
|
else
|
||||||
-- If stack is empty, copy stack data from source
|
-- If stack is empty, copy stack data from source
|
||||||
if self:isEmpty() then
|
if self:isEmpty() then
|
||||||
self.maxCount = stack.maxCount
|
self.name = stack:getName()
|
||||||
self.name = stack.name
|
self.damage = stack:getDamage()
|
||||||
self.damage = stack.damage
|
self.maxDamage = stack:getMaxDamage()
|
||||||
self.maxDamage = stack.maxDamage
|
self.maxCount = stack:getMaxCount()
|
||||||
self.maxCount = stack.maxCount
|
self.enchantments = stack:getEnchantments()
|
||||||
self.enchantments = stack.enchantments
|
self.displayName = stack:getDisplayName()
|
||||||
self.displayName = stack.displayName
|
self.nbt = stack:getNBT()
|
||||||
self.nbt = stack.nbt
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.count = newCount
|
self.count = newCount
|
||||||
@@ -204,10 +194,6 @@ function ItemStack:_modify(countDelta, stack)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ItemStack:transferTo(target, count)
|
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())
|
local cap = math.min(count or self:getCount(), target:getMaxCount() - target:getCount(), self:getCount())
|
||||||
|
|
||||||
-- If we can't transfer any data, then
|
-- If we can't transfer any data, then
|
||||||
@@ -226,20 +212,6 @@ function ItemStack:transferTo(target, count)
|
|||||||
return false, result[2]
|
return false, result[2]
|
||||||
end
|
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)
|
target:_modify(result[2], self)
|
||||||
self:_modify(-result[2], self)
|
self:_modify(-result[2], self)
|
||||||
|
|
||||||
@@ -275,23 +247,45 @@ local function objEquals(o1, o2)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ItemStack:__eq(other)
|
local function runGetter(obj, name)
|
||||||
return type(other) == "table" and
|
local fun = obj[name]
|
||||||
self.count == other.count and
|
if type(fun) ~= "function" then
|
||||||
self.maxCount == other.maxCount and
|
return false, ("Function '%s' cannot be found in object"):format(name)
|
||||||
self:canTransfer(other)
|
end
|
||||||
|
return pcall(fun, obj)
|
||||||
end
|
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
|
-- Determines if two stacks can be transferred to eachother
|
||||||
-- Empty stacks are always valid transfer nodes
|
-- Empty stacks are always valid transfer nodes
|
||||||
function ItemStack:canTransfer(stack)
|
function ItemStack:canTransfer(stack)
|
||||||
return self:isEmpty() or stack:isEmpty() or (self.name == stack.name and
|
return self:isEmpty() or stack:isEmpty() or (
|
||||||
self.damage == stack.damage and
|
checkEqual(self, stack, "getName") and
|
||||||
self.maxDamage == stack.maxDamage and
|
checkEqual(self, stack, "getDamage") and
|
||||||
self.displayName == stack.displayName and
|
checkEqual(self, stack, "getMaxDamage") and
|
||||||
self.nbt == stack.nbt and
|
checkEqual(self, stack, "getDisplayName") and
|
||||||
objEquals(self.enchantments, stack.enchantments))
|
checkEqual(self, stack, "getNBT") and
|
||||||
|
checkEnchantments(self, stack)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function queryField(query, field)
|
local function queryField(query, field)
|
||||||
@@ -314,14 +308,14 @@ function ItemStack:matches(query)
|
|||||||
return query(self)
|
return query(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
return queryField(query.name, self.name) and
|
return queryField(query.name, self:getName()) and
|
||||||
queryField(query.damage, self.damage) and
|
queryField(query.damage, self:getDamage()) and
|
||||||
queryField(query.count, self.count) and
|
queryField(query.count, self:getCount()) and
|
||||||
queryField(query.maxDamage, self.maxDamage) and
|
queryField(query.maxDamage, self:getMaxDamage()) and
|
||||||
queryField(query.enchantments, self.enchantments) and
|
queryField(query.enchantments, self:getEnchantments()) and
|
||||||
queryField(query.maxCount, self.maxCount) and
|
queryField(query.maxCount, self:getMaxCount()) and
|
||||||
queryField(query.nbt, self.nbt) and
|
queryField(query.nbt, self:getNBT()) and
|
||||||
queryField(query.displayName, self.displayName)
|
queryField(query.displayName, self:getDisplayName())
|
||||||
end
|
end
|
||||||
|
|
||||||
return ItemStack
|
return ItemStack
|
||||||
@@ -18,4 +18,17 @@ function Util.boundCheck(x, y, w, h)
|
|||||||
end
|
end
|
||||||
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
|
return Util
|
||||||
Reference in New Issue
Block a user