Skip to content

Instantly share code, notes, and snippets.

@maham
Last active April 11, 2023 07:20
Show Gist options
  • Select an option

  • Save maham/1c091a68c370212becb2fc7265652fae to your computer and use it in GitHub Desktop.

Select an option

Save maham/1c091a68c370212becb2fc7265652fae to your computer and use it in GitHub Desktop.
local FunctionalTable = {}
FunctionalTable.new = function(self, o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
FunctionalTable.map = function(self, f)
local result = FunctionalTable:new{}
for k, v in pairs(self) do
result[k] = f(v)
end
return result
end
FunctionalTable.filter = function(self, f)
local result = FunctionalTable:new{}
for k, v in pairs(self) do
if f(v) then
result[k] = v
end
end
return result
end
FunctionalTable.forEach = function(self, f)
for k, v in pairs(self) do
f(v)
end
end
FunctionalTable.reduce = function(self, f, initialValue)
local result = initialValue
for k, v in pairs(self) do
result = f(result, v)
end
return result
end
return FunctionalTable
local Redstone = require("redstone")
--- Helper methods for Astro and Kazahms Temple of Mysteries
--
-- Note: Any field that starts with an underscore is considered private and should not be accessed directly
--- Helper to be able to log to multiple targets
--
-- A log printer is any table with any or all of the log levels as methods
--
LoggerHelper = {
_logPrinters = {},
}
--- Adds a log printer to the list of printers
--
-- @param logPrinter The log printer to add
--
-- @usage
-- LoggerHelper:addLogPrinter(aLogPrinter)
--
LoggerHelper.addLogPrinter = function (self, logPrinter)
table.insert(self._logPrinters, logPrinter)
end
--- Logs a fatal message
--
-- @param message The message to log
--
-- @usage
-- LoggerHelper:fatal("Something very bad happened!")
--
LoggerHelper.fatal = function (self, message)
for _, logPrinter in ipairs(self._logPrinters) do
if logPrinter.fatal then
logPrinter:fatal("FATAL: " .. message)
end
end
end
--- Logs an error message
--
-- @param message The message to log
--
-- @usage
-- LoggerHelper:fatal("Something unfortunate happened!")
--
LoggerHelper.error = function (self, message)
for _, logPrinter in ipairs(self._logPrinters) do
if logPrinter.error then
logPrinter:error("ERROR: " .. message)
end
end
end
--- Logs an informational message
--
-- @param message The message to log
--
-- @usage
-- LoggerHelper:fatal("Something noteworthy happened!")
--
LoggerHelper.info = function (self, message)
for _, logPrinter in ipairs(self._logPrinters) do
if logPrinter.info then
logPrinter:info("INFO: " .. message)
end
end
end
--- Logs a debug message
--
-- @param message The message to log
--
-- @usage
-- LoggerHelper:fatal("Some detail happened!")
--
LoggerHelper.debug = function (self, message)
for _, logPrinter in ipairs(self._logPrinters) do
if logPrinter.debug then
logPrinter:debug(message)
end
end
end
-- Kept for Astro
--
-- MonitorLogPrinter = {
-- _monitor = nil,
-- _x = 1,
-- _y = 1,
-- }
-- MonitorLogPrinter.new = function (self, monitor)
-- o = {}
-- setmetatable(o, self)
-- self.__index = self
-- o._monitor = monitor
-- return o
-- end
-- MonitorLogPrinter.error = function (self, message)
-- self._monitor.setCursorPos(self._x, self._y)
-- self._monitor.write(message)
-- self._y = self._y + 1
-- end
-- mlp = MonitorLogPrinter:new(someMonitor)
-- mlp2 = MonitorLogPrinter:new(anotherMonitor)
-- mlp2.fatal = function (self, message)
-- self._monitor.setCursorPos(self._x, self._y)
-- self._monitor.write(message)
-- self._y = self._y + 1
-- end
-- mlp2.error = function (self, message)
-- self._monitor.setCursorPos(self._x, self._y)
-- self._monitor.write(message)
-- self._y = self._y - 1
-- end
-- LoggerHelper:addLogPrinter(mlp)
--- Helper to take care of handling multiple tasks as coroutines
--
-- This helper is meant to run a bunch of coroutines which if they yield properly will
-- take turns running until they are all dead. As this isn't true multitasking it's possible
-- to add new coroutines while the dispatcher is running.
--
-- Note: Any function added will run either to it's conclusion or until it yields
--
local CoroutineHelper = {
_coroutines = {},
}
--- Adds a function that will be run in a coroutine
--
-- @param func The function to add
--
-- @usage
-- local function test()
-- print("Hello World!")
-- end
--
-- CoroutineHelper:addCoroutine(test)
--
CoroutineHelper.addCoroutine = function (self, func)
local co = coroutine.create(func)
table.insert(self._threads, func)
end
--- Processes all threads until they are all dead
--
-- Note: This is a blocking call
--
-- Note: Each thread will only run once per tick to prevent lag
--
-- @usage ThreadHelper:dispatcher()
--
CoroutineHelper.dispatcher = function (self)
while true do
local numThreads = #self._threads
if numThreads == 0 then break end
for i, currentThread in ipairs(self._threads) do
if coroutine.status(currentThread) == "dead" then
table.remove(self._threads, i)
else
coroutine.resume(currentThread)
end
end
-- Sleep for the rest of the tick
sleep(0)
end
end
--- Object to encapsulate a bounding box defined by two opposing corners
--
-- @field posOne The first corner of the bounding box
--
-- @field posTwo The second corner of the bounding box
--
local Area = {
posOne = nil,
posTwo = nil,
}
--- Creates a new Area object
--
-- @param o The table to create the Area from
-- Note: o.posOne and o.posTwo are required
--
-- @return A new Area
--
-- @usage
-- local area = Area:new({x=1, y=1, z=1}, {x=10, y=10, z=10})
--
Area.new = function(self, o)
assert(o.posOne == nil or o.posTwo == nil, "Area.new() requires two positions to be passed in!")
setmetatable(o, self)
self.__index = self
return o
end
--- An area to be monitored for players
--
-- @field name The name of the area
--
-- @field area The area to be monitored
--
-- @field playerDetector The player detector to use
--
local MonitoredArea = {
name = nil,
area = nil,
playerDetector = nil,
_monitorArea = false,
}
--- Creates a MonitoredArea
--
-- @param o The table to create the MonitoredArea from
-- Note: o.name, o.area, and o.playerDetector are required
--
-- @return A new MonitoredArea
--
-- @usage
-- local m = MonitoredArea:new({name="Entrance", area=area, playerDetector=playerDetector})
--
MonitoredArea.new = function (self, o)
assert(o.name ~= nil, "MonitoredArea.new() requires a name to be present in o!")
assert(o.area ~= nil, "MonitoredArea.new() requires an area to be present in o!")
assert(o.playerDetector ~= nil, "MonitoredArea.new() requires a playerDetector to be passed in!")
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
--- Starts monitoring the area for players and queue an event when a player is found
--
-- To stop waiting for players, call MonitoredArea.stopWaitingForPlayers()
--
-- @usage local m = MonitoredArea:new({name="Entrance", area=area, playerDetector=playerDetector})
-- local players = m:waitForPlayers()
--
MonitoredArea.waitForPlayers = function(self)
waitForPlayers = function()
while self._monitorArea do
foundPlayers = self.playerDetector.getPlayersInCoords(self.area.posOne, self.area.posTwo)
if #foundPlayers > 0 then
os.queueEvent("MonitoredArea.PlayerFound", self.name, foundPlayers)
end
coroutine.yield()
end
end
CoroutineHelper:addCoroutine(waitForPlayers)
end
--- Stops monitoring the area for players
--
MonitoredArea.stopWaitingForPlayers = function(self)
self._monitorArea = false
end
--- Helper for the chat box
--
-- @field chatBox The chat box to use
-- @field playerDetector The player detector to use - optional
--
local ChatHelper = {
chatBox = nil,
playerDetector = nil,
}
--- Creates a new ChatHelper
--
-- @param o The table to create the ChatHelper from
--
-- @return A new ChatHelper
--
-- @usage
-- local chatHelper = ChatHelper:new({chatBox=chatBox, playerDetector=playerDetector})
--
ChatHelper.new = function(self, o)
assert(o.chatBox ~= nil, "ChatHelper.new() requires a chatBox to be passed in!")
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
--- Sends a message to all players in a given area
--
-- @param message The message to send
-- @param area The area to send the message to
--
-- @usage
-- local chatHelper = ChatHelper:new({chatBox=chatBox, playerDetector=playerDetector})
-- chatHelper:sendMessageToPlayersInArea("Hello World!", area)
--
ChatHelper.sendMessageToPlayersInArea = function(self, message, area)
assert(self.playerDetector ~= nil, "ChatHelper.sendMessageToPlayersInArea() requires a playerDetector to be set!")
local players = self.playerDetector.getPlayersInCoords(area.posOne, area.posTwo)
if #players > 0 then
for _, player in ipairs(players) do
self.chatBox.sendMessageToPlayer(message, player)
end
end
end
spatialIOPortRedstoneTarget = RedstoneIntegratorTarget({
side = "top",
integrator = peripheral.find("redstoneIntegrator")[1],
})
CellLibrary = {
_cells = {},
}
CellLibrary.new = function(self, inventory)
o = {}
setmetatable(o, self)
self.__index = self
for slot, item in pairs(inventory.list()) do
table.insert(o._cells, Cell:new({name=item.name, slot=slot}))
end
return o
end
--- Helper to manage spatial cells
--
-- @field cellFilename The filename to use for the cell file
-- @field cells The cells to manage
--
-- Note: There is a special cell called "currentRoom" that is used to track the room currently in the world
--
SpatialCellHelper = {
cellFilename = nil,
cells = {},
}
--- Creates a new SpatialCellHelper
--
-- Creates a spatial cell helper and reads in the cells from the cell file
--
-- @param o The table to create the SpatialCellHelper from
-- Note: o.cellFilename is required
--
SpatialCellHelper.new = function(self, o)
assert(o.cellFilename ~= nil, "SpatialCellHelper.new() requires a cellFilename to be passed in!")
o = o or {}
setmetatable(o, self)
self.__index = self
self.cellFilename = o.cellFilename
self.cells = self:readState()
return o
end
--- Associates a room with a cell
--
-- @param room The room to associate with the cell
-- @param cell The cell to associate with the room
--
-- @usage
-- local spatialCellHelper = SpatialCellHelper:new({cellFilename="spatialCells"})
-- spatialCellHelper:addRoomToCell("room1", "cell1")
--
SpatialCellHelper.addRoomToCell = function(self, room, cell)
assert(self.cells[cell] == nil, "Cell already exists: " .. cell)
table.insert(self.cells[cell], room)
self:writeState()
end
--- Switches the current room to a given room
--
-- @param newRoom The room to switch to
--
-- @usage
-- local spatialCellHelper = SpatialCellHelper:new({cellFilename="spatialCells"})
-- spatialCellHelper:switchRoom("room1")
--
SpatialCellHelper.switchRoom = function(self, newRoom)
for cell, room in pairs(self.cells) do
if room == newRoom then
if cell == "currentRoom" then
return
end
self.cells[cell] = self.cells["currentRoom"]
self.cells["currentRoom"] = newRoom
self:writeState()
return
end
error("Room not found: " .. newRoom)
end
end
--- Reads the state of the spatial cells from a file
--
-- @param filename The filename to read the cells from - optional
--
-- @usage
-- local spatialCellHelper = SpatialCellHelper:new({cellFilename="spatialCells"})
-- spatialCellHelper:readState("spatialCells")
--
SpatialCellHelper.readState = function(self, filename)
local file = fs.open(filename or self.filename, "r")
self.cells = textutils.unserialize(file.readAll())
file.close()
end
--- Writes the state of the spatial cells to a file
--
-- @param filename The filename to write the cells to - optional
--
-- @usage
-- local spatialCellHelper = SpatialCellHelper:new({cellFilename="spatialCells"})
-- spatialCellHelper:writeState("spatialCells")
--
SpatialCellHelper.writeState = function(self, filename)
local file = fs.open(filename or self.filename, "w")
file.write(textutils.serialize(self.cells))
file.close()
end
--- Helper for managing a Spatial IO Port and an accompanying library
--
-- @field input The peripheral from the modem connected to the side of the Spatial IO Port
-- @field output The peripheral from the modem connected to the bottom of the Spatial IO Port
-- @field library The peripheral from the model connected to the inventory to use as the library
-- @field cellHelper The SpatialCellHelper that takes care of syncing cell names and room names
--
SpatialIOHelper = {
input = nil,
output = nil,
library = nil,
cellHelper = nil,
redstoneHelper = nil,
}
SpatialIOHelper.new = function (self, o)
assert(o.input ~= nil, "SpatialIOHelper.new() requires an input to be passed in!")
assert(o.output ~= nil, "SpatialIOHelper.new() requires an output to be passed in!")
assert(o.library ~= nil, "SpatialIOHelper.new() requires a library to be passed in!")
assert(o.cellHelper ~= nil, "SpatialIOHelper.new() requires a cellHelper to be passed in!")
setmetatable(o, self)
self.__index = self
return o
end
SpatialIOHelper.addRoomToCell = function (self, room, cell)
self.cellHelper:addRoomToCell(room, cell)
end
SpatialIOHelper.switchRoom = function (self, newRoom)
self.cellHelper:switchRoom(newRoom)
end
return {
CoroutineHelper = CoroutineHelper,
Area = Area,
MonitoredArea = MonitoredArea,
ChatHelper = ChatHelper,
SpatialCellHelper = SpatialCellHelper,
}
FunctionalTable = require('functional_table')
local Inventory = FunctionalTable:new{
peripheral = nil,
}
Inventory.new = function(self, o)
assert(o.peripheral ~= nil, "Inventory.new() requires an inventoryPeripheral to be passed in!")
o.name = o.name or peripheral.getName(o.peripheral)
setmetatable(o, self)
self.__index = self
self._type = "Inventory"
return o
end
Inventory.allItems = function(self)
local items = FunctionalTable:new{}
for slot, item in pairs(self.peripheral.list()) do
items[slot] = item
end
return items
end
return {
Inventory = Inventory,
}
-- Program to control a Spatial IO port with a library of Spatial Storage Cells which have been named in an anvil.
Log = {
logPrinters = {},
error = function(self, message)
for printer in self.logPrinters do
printer.error(message)
end
end,
info = function(self, message)
for printer in self.logPrinters do
printer.info(message)
end
end,
}
--- Clears a monitor and resets the cursor to the top left corner.
-- @param monitor The monitor to clear.
function resetMonitor(monitor)
monitor.clear()
monitor.setCursorPos(1,1)
end
local xp --temp variable for monitor x position
local yp --temp variable for monitor y position
local monitor = peripheral.find("monitor") -- search for connected monitor
print("Monitor : ", peripheral.getName(monitor))
if monitor then
resetMonitor(monitor)
monitor.write("Peripheral Report")
monitor.setCursorPos(1,2)
monitor.write("Monitor : ")
monitor.write(peripheral.getName(monitor))
end
-- NOTE: This is the section with hard-coded peripheral names for the Spatial IO Port Modems!
-- If you break or move these items, you'll have to change the corresponding names
-- of the wrapped modems! The lua command peripheral.getNames() can help you fix this!
local spatialIO = {
insert = peripheral.wrap("ae2:spatial_io_port_2"),
output = peripheral.wrap("ae2:spatial_io_port_3"),
}
local spatialIOin = peripheral.wrap("ae2:spatial_io_port_2") -- wrap modem/inventory for Spatial IO input (one on the side/top of Spatial IO Port)
local spatialIOout = peripheral.wrap("ae2:spatial_io_port_3") -- wrap modem/inventory for Spatial IO output (one on the BOTTOM of Spatial IO Port)
-- NOTE: You can ONLY pull from the BOTTOM of the Spatial IO Port!!
local library = peripheral.wrap("sophisticatedstorage:barrel_0") -- wrap modem/inventory for the system "library" which is a Sophisticated Storage Barrel with slot memory set!
if spatialIOin and spatialIOout then --if both are true, both are found and we are ok to proceed!
print("spatialIOin : ", peripheral.getName(spatialIOin))
print("spatialIOout: ", peripheral.getName(spatialIOout))
if spatialIO.insert then
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOin : ")
monitor.write(peripheral.getName(spatialIOin))
end
if spatialIO.output then
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOout: ")
monitor.write(peripheral.getName(spatialIOout))
end
else -- something is wrong
print("Missing Spatial IO Port!")
resetMonitor(monitor)
monitor.write("ERROR!: ")
if not spatialIOin then
print("spatialIOin is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOin is offline, missing or named incorrectly")
assert(true == false, "spatialIOin is offline, missing or named incorrectly")
end
if not spatialIOout then
print("spatialIOout is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOout is offline, missing or named incorrectly")
error("spatialIOout is offline, missing or named incorrectly")
end
end
if library then -- we have a library and can continue!
print("Library : ", peripheral.getName(library))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Library : ")
monitor.write(peripheral.getName(library))
else
print("library barrel is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("library barrel is offline, missing or named incorrectly")
error("library barrel is offline, missing or named incorrectly")
end
--End of Custom section
local speaker = peripheral.find("speaker") -- search for connected speaker
if speaker then
print("Speaker : ", peripheral.getName(speaker))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Speaker : ")
monitor.write(peripheral.getName(speaker))
end
local modem = peripheral.find("modem") -- search for connected wired modem
if modem then
print("Modem : ", peripheral.getName(modem))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Modem : ")
monitor.write(peripheral.getName(modem))
end
local drive = peripheral.find("drive") -- search for connected disk drive
if drive then
print("drive : ", peripheral.getName(drive))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Drive : ")
monitor.write(peripheral.getName(drive))
end
local integrator = peripheral.find("redstoneIntegrator") -- search for connected redstone integrator
-- integrator is used for: redstone I/O to control Spatial IO Port loading/unloading
-- : possibly player pressure plate
if integrator then
print("Integrator : ", peripheral.getName(integrator))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Integrator : ")
monitor.write(peripheral.getName(integrator))
-- use functional names for the sides of the integrator.
local spatialIOpulse = "front"
end
local detector = peripheral.find("playerDetector") -- search for connected playerDetector
-- detector is used for: detection of player(s) in entryway
-- : detection of player(s) inside the swap room, (so we can prevent storing them!)
if detector then
print("Detector : ", peripheral.getName(detector))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Detector : ")
monitor.write(peripheral.getName(detector))
end
local chatBox = peripheral.find("chatBox") -- search for connected chat box
-- chatBox is used for: talking to player(s) detected in entryway
-- : warning player(s) in room trying to be stored
if chatBox then
print("chatBox : ", peripheral.getName(chatBox))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("chatBox : ")
monitor.write(peripheral.getName(chatBox))
end
local blockReader = peripheral.find("blockReader") -- search for connected blockReader
--blockReader is used to detect WHICH room is currently loaded below
if blockReader then
print("blockReader : ", peripheral.getName(blockReader))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("blockReader : ")
monitor.write(peripheral.getName(blockReader))
end
--create variables for use lower down
local dfpwm = require("cc.audio.dfpwm") --used fo audio decoding of dfpwm files
local decoder = dfpwm.make_decoder() --used fo audio decoding of dfpwm files
--local repeattime = 10
local event, id --used to pull events
local currentRoom -- used to store the name of the center roof block that indicates which room is loaded
-- use functional names for the sides of the integrator.
local spatialIOpulse = "front"
--Check on boot-up status, reset things to a known state if needed
-- Pull any cells out of the spatial IO port if there are any and put them back into the library
library.pullItems(peripheral.getName(spatialIOin),1)
library.pullItems(peripheral.getName(spatialIOout),2)
if blockReader.getBlockName() == "none" then -- if there isn't a room loaded, load the default room, which is slot 1 of the library barrel
spatialIOin.pullItems(peripheral.getName(library),1)
integrator.setOutput(spatialIOpulse, true)
integrator.setOutput(spatialIOpulse, false)
library.pullItems(peripheral.getName(spatialIOout),2)
end
FunctionalTable = require('functional_table')
--- This is just an abstract class setting the template for how a RedstoneTarget should be implemented
--
local RedstoneTarget = {
}
RedstoneTarget.new = function(self, o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
RedstoneTarget.pulse = function(self, pulseLength)
error("RedstoneTarget.pulse() is not implemented!")
end
RedstoneTarget.turnOn = function(self)
error("RedstoneTarget.turnOn() is not implemented!")
end
RedstoneTarget.turnOff = function(self)
error("RedstoneTarget.turnOff() is not implemented!")
end
RedstoneTarget.isPowered = function(self)
error("RedstoneTarget.isPowered() is not implemented!")
end
RedstoneTarget.getName = function(self)
assert(self.name ~= nil, "RedstoneTarget.getName() requires a name to be set!")
return self.name
end
--- A RedstoneTarget that is a computer
--
local RedstoneComputerTarget = RedstoneTarget:new({
side = nil,
})
--- Creates a new RedstoneComputerTarget
--
-- @param o The table to create the RedstoneComputerTarget from
-- Note: o.side is required
--
-- @return A new RedstoneComputerTarget
--
RedstoneComputerTarget.new = function(self, o)
assert(o.side ~= nil, "RedstoneTarget.new() requires a side to be passed in!")
o.name = o.name or o.side
setmetatable(o, self)
self.__index = self
return o
end
--- Pulses the redstone target with a given pulse length
--
-- @param pulseLength The length of the pulse
--
-- @usage
-- local redstoneTarget = RedstoneComputerTarget:new({side="top"})
--
RedstoneComputerTarget.pulse = function (self, pulseLength)
pulseLength = pulseLength or 1
redstone.setOutput(self.side, true)
sleep(self.pulseLength * 0.05)
redstone.setOutput(self.side, false)
end
--- Turns the redstone target on
--
-- @usage
-- local redstoneTarget = RedstoneComputerTarget:new({side="top"})
-- redstoneTarget:turnOn()
--
RedstoneComputerTarget.turnOn = function (self)
redstone.setOutput(self.side, true)
end
--- Turns the target off
--
-- @usage
-- local redstoneTarget = RedstoneComputerTarget:new({side="top"})
-- redstoneTarget:turnOff()
--
RedstoneComputerTarget.turnOff = function (self)
redstone.setOutput(self.side, false)
end
--- Checks if the redstone target is powered
--
-- @return True if the redstone target is powered, false otherwise
--
-- @usage
-- local redstoneTarget = RedstoneComputerTarget:new({side="top"})
-- local isPowered = redstoneTarget:isPowered()
--
RedstoneComputerTarget.isPowered = function (self)
return redstone.getInput(self.side)
end
--- A RedstoneTarget that is a Redstone Integrator from Advanced Peripherals
--
-- @field side The side of the integrator to use
--
-- @field integrator The integrator to use
--
local RedstoneIntegratorTarget = RedstoneTarget:new{
side = nil,
integrator = nil,
}
--- Creates a new RedstoneIntegratorTarget
--
-- @param o The table to create the RedstoneIntegratorTarget from
-- Note: o.side and o.integrator are required
--
-- @return A new RedstoneIntegratorTarget
--
RedstoneIntegratorTarget.new = function(self, o)
assert(o.integrator ~= nil, "RedstoneTarget.new() requires an integrator to be passed in!")
assert(o.side ~= nil, "RedstoneTarget.new() requires a side to be passed in!")
o.name = o.name or peripheral.getName(o.integrator) .. "_" .. o.side
setmetatable(o, self)
self.__index = self
return o
end
--- Pulses the redstone target with a given pulse length
--
-- @param pulseLength The length of the pulse
--
-- @usage
-- local redstoneTarget = RedstoneIntegratorTarget:new({side="top", integrator=integrator})
-- redstoneTarget:pulse()
--
RedstoneIntegratorTarget.pulse = function (self, pulseLength)
pulseLength = pulseLength or 1
self.integrator.setOutput(self.side, true)
sleep(self.pulseLength * 0.05)
self.integrator.setOutput(self.side, false)
end
--- Turns the redstone target on
--
-- @usage
-- local redstoneTarget = RedstoneIntegratorTarget:new({side="top", integrator=integrator})
-- redstoneTarget:turnOn()
--
RedstoneIntegratorTarget.turnOn = function (self)
self.integrator.setOutput(self.side, true)
end
--- Turns the redstone target off
--
-- @usage
-- local redstoneTarget = RedstoneIntegratorTarget:new({side="top", integrator=integrator})
-- redstoneTarget:turnOff()
--
RedstoneIntegratorTarget.turnOff = function (self)
self.integrator.setOutput(self.side, false)
end
--- Checks if the redstone target is powered
--
-- @return True if the redstone target is powered, false otherwise
--
-- @usage
-- local redstoneTarget = RedstoneIntegratorTarget:new({side="top", integrator=integrator})
-- local isPowered = redstoneTarget:isPowered()
--
RedstoneIntegratorTarget.isPowered = function (self)
return self.integrator.getInput(self.side)
end
--- Gets the name of the redstone integrator for the target
--
-- @return The name of the redstone integrator
--
RedstoneIntegratorTarget.getPeripheralName = function(self)
return peripheral.getName(self.integrator)
end
--- Enumerates all possible redstone targets
--
-- Note: There will be one RedstoneComputerTarget for each side of the computer without a peripheral
-- There will be 6 RedstoneIntegratorTargets for each side of each redstoneIntegrator
--
function enumerateRedstoneTargets()
redstoneTargets = FunctionalTable:new{}
for _, side in ipairs(redstone.getSides()) do
local name = side
if not peripheral.isPresent(side) then
table.insert(redstoneTargets, RedstoneComputerTarget:new{name = name, side = side})
end
end
for _, redstoneIntegrator in ipairs({peripheral.find("redstoneIntegrator")}) do
for _, side in ipairs(redstone.getSides()) do
local name = peripheral.getName(redstoneIntegrator) .. "_" .. side
table.insert(redstoneTargets, RedstoneIntegratorTarget:new{name = name, side = side, integrator = redstoneIntegrator})
end
end
return redstoneTargets
end
function isRedstoneTarget(target)
if target == nil then
return false
end
if getmetatable(target) == RedstoneTarget then
return true
end
return isRedstoneTarget(getmetatable(target))
end
return {
allTargets = enumerateRedstoneTargets(),
isRedstoneTarget = isRedstoneTarget,
RedstoneTarget = RedstoneTarget,
RedstoneComputerTarget = RedstoneComputerTarget,
RedstoneIntegratorTarget = RedstoneIntegratorTarget,
}
FunctionalTable = require('functional_table')
local SpatialIOSystem = {}
SpatialIOSystem.new = function(self, o)
o = o or {}
setmetatable(o, self)
self.__index = self
self._type = "SpatialIOSystem"
return o
end
SpatialIOSystem.initialize = function(self)
print("Initializing SpatialIOSystem")
end
function findSpatialIOPorts()
return FunctionalTable:new{peripheral.find('ae2:spatial_io_port')}
end
function findInventories()
return FunctionalTable:new{peripheral.find('inventory')}
end
return {
SpatialIOSystem = SpatialIOSystem,
findInventories = findInventories,
findSpatialIOPorts = findSpatialIOPorts,
}
-- Program to control a Spatial IO port with a library of Spatial Storage Cells which have been named in an anvil.
xp = 1 --temp variable for monitor x position
yp = 1 --temp variable for monitor y position
monitor = peripheral.find("monitor") -- search for connected monitor
print("Monitor : ", peripheral.getName(monitor))
if monitor then
monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("Peripheral Report")
monitor.setCursorPos(1,2)
monitor.write("Monitor : ")
monitor.write(peripheral.getName(monitor))
end
-- NOTE: This is the section with hard-coded peripheral names for the Spatial IO Port Modems!
-- If you break or move these items, you'll have to change the corresponding names
-- of the wrapped modems! The lua command peripheral.getNames() can help you fix this!
spatialIOin = peripheral.wrap("ae2:spatial_io_port_2") -- wrap modem/inventory for Spatial IO input (one on the side/top of Spatial IO Port)
spatialIOout = peripheral.wrap("ae2:spatial_io_port_3") -- wrap modem/inventory for Spatial IO output (one on the BOTTOM of Spatial IO Port)
-- NOTE: You can ONLY pull from the BOTTOM of the Spatial IO Port!!
library = peripheral.wrap("sophisticatedstorage:barrel_0") -- wrap modem/inventory for the system "library" which is a Sophisticated Storage Barrel with slot memory set!
if spatialIOin and spatialIOout then --if both are true, both are found and we are ok to proceed!
print("spatialIOin : ", peripheral.getName(spatialIOin))
print("spatialIOout: ", peripheral.getName(spatialIOout))
if spatialIOin then
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOin : ")
monitor.write(peripheral.getName(spatialIOin))
end
if spatialIOout then
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOout: ")
monitor.write(peripheral.getName(spatialIOout))
end
else -- something is wrong
print("Missing Spatial IO Port!")
monitor.clear()
monitor.setCursorPos(1,1)
monitor.write("ERROR!: ")
if not spatialIOin then
print("spatialIOin is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOin is offline, missing or named incorrectly")
assert(true == false, "spatialIOin is offline, missing or named incorrectly")
end
if not spatialIOout then
print("spatialIOout is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("spatialIOout is offline, missing or named incorrectly")
error("spatialIOout is offline, missing or named incorrectly")
end
end
if library then -- we have a library and can continue!
print("Library : ", peripheral.getName(library))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Library : ")
monitor.write(peripheral.getName(library))
else
print("library barrel is offline, missing or named incorrectly")
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("library barrel is offline, missing or named incorrectly")
error("library barrel is offline, missing or named incorrectly")
end
-- Library documentation:
-- Barrel Slot name of cell/block
-- 1 minecraft:gold_block
-- 2 minecraft:diamond_block
--End of Custom section
speaker = peripheral.find("speaker") -- search for connected speaker
if speaker then
print("Speaker : ", peripheral.getName(speaker))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Speaker : ")
monitor.write(peripheral.getName(speaker))
end
modem = peripheral.find("modem") -- search for connected wired modem
if modem then
print("Modem : ", peripheral.getName(modem))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Modem : ")
monitor.write(peripheral.getName(modem))
end
drive = peripheral.find("drive") -- search for connected disk drive
if drive then
print("drive : ", peripheral.getName(drive))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Drive : ")
monitor.write(peripheral.getName(drive))
end
integrator = peripheral.find("redstoneIntegrator") -- search for connected redstone integrator
-- integrator is used for: redstone I/O to control Spatial IO Port loading/unloading
-- : possibly player pressure plate
if integrator then
print("Integrator : ", peripheral.getName(integrator))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Integrator : ")
monitor.write(peripheral.getName(integrator))
-- use functional names for the sides of the integrator.
local spatialIOpulse = "front"
end
detector = peripheral.find("playerDetector") -- search for connected playerDetector
-- detector is used for: detection of player(s) in entryway
-- : detection of player(s) inside the swap room, (so we can prevent storing them!)
if detector then
print("Detector : ", peripheral.getName(detector))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("Detector : ")
monitor.write(peripheral.getName(detector))
end
chatBox = peripheral.find("chatBox") -- search for connected chat box
-- chatBox is used for: talking to player(s) detected in entryway
-- : warning player(s) in room trying to be stored
if chatBox then
print("chatBox : ", peripheral.getName(chatBox))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("chatBox : ")
monitor.write(peripheral.getName(chatBox))
end
blockReader = peripheral.find("blockReader") -- search for connected blockReader
--blockReader is used to detect WHICH room is currently loaded below
if blockReader then
print("blockReader : ", peripheral.getName(blockReader))
xp, yp = monitor.getCursorPos()
monitor.setCursorPos(1, yp+1)
monitor.write("blockReader : ")
monitor.write(peripheral.getName(blockReader))
end
--create variables for use lower down
dfpwm = require("cc.audio.dfpwm") --used fo audio decoding of dfpwm files
decoder = dfpwm.make_decoder() --used fo audio decoding of dfpwm files
--local repeattime = 10
pretty = require("cc.pretty")
event = 1 -- used to pull events
id = 1 --used to pull events
currentRoom = "minecraft:gold_block" -- used to store the name of the center roof block that indicates which room is loaded
-- use functional names for the sides of the integrator.
spatialIOpulse = "front"
--Check on boot-up status, reset things to a known state if needed
-- Pull any cells out of the spatial IO port if there are any and put them back into the library
library.pullItems(peripheral.getName(spatialIOin),1)
library.pullItems(peripheral.getName(spatialIOout),2)
if blockReader.getBlockName() == "none" then -- if there isn't a room loaded, load the default room, which is slot 1 of the library barrel
spatialIOin.pullItems(peripheral.getName(library),1)
integrator.setOutput(spatialIOpulse, true)
integrator.setOutput(spatialIOpulse, false)
library.pullItems(peripheral.getName(spatialIOout),2)
end
entrance= {p1={x=-2707, y=71, z=41}, p2={x=-2711, y=76, z=54}}
atcomputer= {p1={x=-2679, y=87, z=62}, p2={x=-2674, y=90, z=47}}
-- Returns a table of players inside a region inside minecraft, given a player detector reference, and a region,
-- where a region is specified by 2 sets of x, y, z coordinates.
-- @param detector for the detector to use, and region for the volume used to detect the players
-- for example entrance is a region is defined as:
-- entrance= {p1={x=-2707, y=71, z=41}, p2={x=-2711, y=76, z=54}}
function getPlayersInRegion(detector, region)
return detector.getPlayersInCoords(region.p1, region.p2)
end
sleep(5)
player = getPlayersInRegion(detector,atcomputer)[1]
print("Who is there? ", pretty.pretty_print(getPlayersInRegion(detector,atcomputer)))
while player==nil do
sleep(1)
player = getPlayersInRegion(detector,atcomputer)[1]
end
speaker.playSound("minecraft:block.portal.travel")
say=player .. ", you have entered a magical realm!"
chatBox.sendMessageToPlayer(say, player)
oldplayer = player
--player = getPlayersInRegion(detector,atcomputer)[1]
repeat
sleep(1)
player = getPlayersInRegion(detector,atcomputer)[1]
until player == nil
speaker.playSound("minecraft:entity.wither.spawn")
say=oldplayer .. ", be wary as you venture forth!"
chatBox.sendMessageToPlayer(say, oldplayer)
local kaRedstone = require('redstone')
print('Testing redstone.lua')
print('Found redstone targets:')
for i, redstoneTarget in ipairs(kaRedstone.allTargets) do
print('\t' .. i .. ') ' .. redstoneTarget.name)
end
print('Turning all redstone targets on and off:')
for i, redstoneTarget in ipairs(kaRedstone.allTargets) do
print('\tTurning ' .. redstoneTarget.name .. ' on')
redstoneTarget:turnOn()
sleep(1)
print('\tTurning ' .. redstoneTarget.name .. ' off')
redstoneTarget:turnOff()
end
SpatialIOSystem = require("spatial_io_system")
Redstone = require("redstone")
Inventory = require("inventory")
-- sio1 = SpatialIOSystem:new("SIO1")
-- sio1.initialize()
-- local inventories = SpatialIOSystem.findInventories()
-- print(#inventories .. ' inventories found:')
-- inventories:map(
-- function(inventoryPeripheral)
-- return peripheral.getName(inventoryPeripheral)
-- end
-- ):forEach(
-- function(inventoryName)
-- print(inventoryName)
-- end
-- )
-- print('\n')
--
-- local spatialIOPorts = SpatialIOSystem.findSpatialIOPorts()
-- print(#spatialIOPorts .. ' spatial IO ports found:')
-- spatialIOPorts:map(
-- function(spatialIOPeripheral)
-- return peripheral.getName(spatialIOPeripheral)
-- end
-- ):forEach(
-- function(spatialIOName)
-- print(spatialIOName)
-- end
-- )
-- print('\n')
--
-- local redstoneTargets = Redstone.allTargets
-- print(#redstoneTargets .. ' redstone targets found:')
-- FunctionalTable:new(redstoneTargets):map(
-- function(redstoneTarget)
-- return redstoneTarget.name
-- end
-- ):forEach(
-- function(redstoneTargetName)
-- print(redstoneTargetName)
-- end
-- )
-- print('\n')
--
-- print('First item in redstoneTargets is a RedstoneTarget: ' .. tostring(Redstone.isRedstoneTarget(redstoneTargets[1])))
local inventories = SpatialIOSystem.findInventories():map(
function(inventoryPeripheral)
return Inventory.Inventory:new{peripheral=inventoryPeripheral}
end
)
print(#inventories .. ' inventories found:')
inventories:forEach(
function(inventory)
local items = inventory:allItems()
print('\t' .. inventory.name .. ' has ' .. #items .. ' items')
-- if #items then
-- for slot, item in pairs(items) do
-- if item ~= nil then
-- print('\t' .. slot .. ') ' .. item.name .. (item.count > 1 and ' x' .. item.count or ''))
-- print('\t\t' .. inventory.peripheral.getItemDetail(slot).displayName)
-- end
-- end
-- else
-- print('\t(No items found)')
-- end
end
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment