Skip to content

Instantly share code, notes, and snippets.

@Unixkitty
Created January 25, 2024 18:50
Show Gist options
  • Save Unixkitty/de7bdfa57fdcb32c7e5c825e1620148a to your computer and use it in GitHub Desktop.
Save Unixkitty/de7bdfa57fdcb32c7e5c825e1620148a to your computer and use it in GitHub Desktop.
--[[
1. getStargateType
2. setChevronConfiguration
3. getRotation
4. setRestrictNetwork
5. getRecentFeedback
6. endRotation
7. getLocalAddress
8. getEnergy
9. disconnectStargate
10. getNetwork
11. raiseChevron
12. engageSymbol
13. isCurrentSymbol
14. getRestrictNetwork
15. getEnergyTarget
16. getCurrentSymbol
17. setEnergyTarget
18. encodeChevron
19. getStargateEnergy
20. getOpenTime
21. isStargateConnected
22. getConnectedAddress
23. getChevronsEngaged
24. setNetwork
25. getStargateGeneration
26. rotateClockwise
27. getDialedAddress
28. rotateAntiClockwise
29. lowerChevron
-------------------------------------
TODO
- Begin on commands:
- help
- help <command>
]]--
-- Init
program_name = "StargateOS"
program_version = "0.5.2"
program_name_text = program_name .. " v" .. program_version
stargate = peripheral.find("advanced_crystal_interface") or error("Stargate interface not found!")
monitor = peripheral.wrap("top") or error("Place a monitor on top of this computer")
chevronMonitor = peripheral.find("monitor") or error("Connect an additional monitor via network cable")
chevronWindows = {}
gateMaxOpenTimeSeconds = 2280
knownAddresses = {
ABYDOS = { 26, 6, 14, 31, 11, 29 },
XEN = { 13, 24, 2, 19, 3, 30 },
XEN_PEGASUS = { 14, 30, 6, 13, 17, 23 },
CHULAK = { 8, 1, 22, 14, 36, 19 },
P3W_451 = { 18, 7, 3, 36, 25, 15 }
}
monitor.setTextScale(0.5)
chevronMonitor.setTextScale(0.5)
termWidth, termHeight = term.getSize()
monitorWidth, monitorHeight = monitor.getSize()
chevronMonitorWidth, chevronMonitorHeight = chevronMonitor.getSize()
statusWindow = window.create(term.current(), 1, 1, termWidth, 1, true)
mainWindow = window.create(term.current(), 1, 2, termWidth, termHeight - 1, true)
monitorStatusWindow = window.create(monitor, (monitorWidth / 2) - 4, 2, 11, 1, true)
monitorEnergyWindow = window.create(monitor, 1, 4, monitorWidth, 1, true)
stargateEnergy = 0
stargateEnergyRate = 0
stargateStatuses = { IDLE = "IDLE", DIALING = "DIALING", CONNECTED = "CONNECTED" }
stargateStatus = stargateStatuses.IDLE
lastStargateStatus = stargateStatus
incomingWormhole = false
stargateRotation = stargate.getRotation()
speedDialActive = false
-- Log file functions
function getFreshLogCreatedEntry()
return "Creating log file at: " .. os.date()
end
-- [2024-01-19 15:54:54] [INFO/ERROR] [function name]: <message>
function writeLogEntry(fileObject, level, functionName, message)
fileObject.writeLine("[" .. os.date("%F %T") .. "] [" .. functionName .. "] [" .. level .. "]: " .. message)
end
function _log(logLevel, functionName, messageText)
local logfile_name = "/" .. program_name .. ".log"
local logfile_enabled = true
local error_only = false
if logfile_enabled == true and not fs.exists(logfile_name) then
local file = fs.open(logfile_name, "w")
file.writeLine(getFreshLogCreatedEntry())
file.close()
end
if logLevel == "ERROR" then
if logfile_enabled == true then
local file = fs.open(logfile_name, "a")
writeLogEntry(file, logLevel, functionName, messageText)
file.close()
end
else
if logfile_enabled == true and error_only == false then
if not fs.exists(logfile_name) then
local file = fs.open(logfile_name, "w")
file.writeLine(getFreshLogCreatedEntry())
file.close()
end
local file = fs.open(logfile_name, "a")
writeLogEntry(file, logLevel, functionName, messageText)
file.close()
end
end
end
function log(functionName, messageText)
_log("INFO", functionName, messageText)
end
function logError(functionName, messageText)
_log("ERROR", functionName, messageText)
end
--Functions
function cleanMainWindow()
mainWindow.clear()
mainWindow.setCursorPos(1, termHeight - 1)
end
function makeChevronWindow(number)
local w = window.create(chevronMonitor, chevronMonitorWidth - 3, number, 4, 1, true)
w.setBackgroundColor(colors.gray)
w.clear()
return w
end
function updateStatus(status)
lastStargateStatus = stargateStatus
stargateStatus = status
if lastStargateStatus ~= stargateStatus then
log("updateStatus", "Status change: " .. lastStargateStatus .. " > " .. stargateStatus)
-- Clean lower half of the main monitor on status change
for i = 6, monitorHeight, 1
do
monitor.setCursorPos(1, i)
monitor.clearLine()
end
end
end
function updateChevronDisplay(chevron, symbol)
chevronWindows[chevron].setCursorPos(4 - string.len(symbol), 1)
chevronWindows[chevron].clear()
chevronWindows[chevron].write(symbol)
end
function resetChevronDisplay(address)
for chevron = 1, 9, 1
do
if address[chevron] == nil then
updateChevronDisplay(chevron, "-")
else
updateChevronDisplay(chevron, address[chevron])
end
end
end
function getCenterTextStart(width, textLength)
return ((width / 2) - (textLength / 2)) + 1
end
function updateMonitorLine(line, text, centered)
local x = 1
if centered then
x = getCenterTextStart(monitorWidth, #text)
end
monitor.setCursorPos(x, line)
monitor.clearLine()
monitor.write(text)
end
function setConnectedToText(text)
chevronWindows[10].clear()
chevronWindows[10].setCursorPos(getCenterTextStart(chevronMonitorWidth, #text), 1)
chevronWindows[10].write(text)
end
-- Continue init
log("init", "Starting up " .. program_name_text)
term.clear()
term.setCursorPos(1, 1)
monitor.setPaletteColor(colors.lightBlue, 0x0A1E36)
monitor.setBackgroundColor(colors.lightBlue)
monitor.clear()
monitor.setCursorPos(1, 1)
chevronMonitor.setPaletteColor(colors.lightBlue, 0x0A1E36)
chevronMonitor.setBackgroundColor(colors.lightBlue)
chevronMonitor.clear()
chevronMonitor.setCursorPos(1, 1)
statusWindow.setBackgroundColor(colors.blue)
statusWindow.clear()
statusWindow.setCursorPos(1, 1)
rootWindow = term.redirect(statusWindow)
--TODO switch back
textutils.slowWrite(program_name_text .. " initializing...")
--statusWindow.write(program_name_text .. " initializing...")
term.redirect(rootWindow)
for chevron = 1, 9, 1
do
chevronMonitor.setCursorPos(1, chevron)
chevronMonitor.write("Chevron " .. chevron .. ": ")
table.insert(chevronWindows, makeChevronWindow(chevron))
end
resetChevronDisplay(stargate.getConnectedAddress())
table.insert(chevronWindows, window.create(chevronMonitor, 1, 10, chevronMonitorWidth, 1, true))
chevronWindows[10].setBackgroundColor(colors.gray)
setConnectedToText("-")
statusWindow.clear()
statusWindow.setCursorPos(1, 1)
statusWindow.write(program_name_text)
mainWindow.setPaletteColor(colors.lightBlue, 0x0A1E36)
mainWindow.setBackgroundColor(colors.lightBlue)
cleanMainWindow()
--Begin program
function updateMonitor()
updateMonitorLine(1, "Status:", true)
updateMonitorLine(3, "Energy:", true)
for i = 1, monitorWidth, 1
do
monitor.setCursorPos(i, 5)
monitor.write("=")
end
monitorStatusWindow.setBackgroundColor(colors.gray)
monitorStatusWindow.clear()
monitorEnergyWindow.setBackgroundColor(colors.gray)
monitorEnergyWindow.clear()
while (true)
do
monitorStatusWindow.setCursorPos(((monitorWidth / 2) - (#stargateStatus / 2)) - 1, 1)
monitorStatusWindow.clear()
if stargateStatus == stargateStatuses.IDLE then
monitorStatusWindow.setTextColor(colors.green)
elseif stargateStatus == stargateStatuses.DIALING then
monitorStatusWindow.setTextColor(colors.yellow)
elseif stargateStatus == stargateStatuses.CONNECTED then
monitorStatusWindow.setTextColor(colors.red)
else
monitorStatusWindow.setTextColor(colors.purple)
end
monitorStatusWindow.write(stargateStatus)
monitorEnergyWindow.setCursorPos(1, 1)
monitorEnergyWindow.clear()
monitorEnergyWindow.write(stargateEnergy .. " RF")
sleep(1)
end
end
function updateMonitorSecondary()
while (true)
do
if stargateStatus == stargateStatuses.DIALING then
updateMonitorLine(6, "Rotation: " .. stargateRotation .. "°", false)
elseif stargateStatus == stargateStatuses.CONNECTED then
updateMonitorLine(7, math.ceil(stargate.getOpenTime() / 20) .. "s / " .. gateMaxOpenTimeSeconds .. "s", false)
updateMonitorLine(8, stargateEnergyRate .. " RF/t", false)
end
sleep(1)
end
end
function updateChevronMonitor()
while (true)
do
-- Pinging the display to avoid it being black on chunk reload
chevronMonitor.setCursorPos(1, 1)
chevronMonitor.write("C")
sleep(3)
end
end
function updateEnergy()
local lastStargateEnergy = stargateEnergy
while (true)
do
stargateEnergy = stargate.getStargateEnergy()
stargateEnergyRate = stargateEnergy - lastStargateEnergy
lastStargateEnergy = stargateEnergy
sleep(0.05)
end
end
-- EVENTS
function watchChevrons()
while (true)
do
local _, chevron, incoming, symbol = os.pullEvent("stargate_chevron_engaged")
incomingWormhole = incoming
local incomingText = "outgoing"
if incoming then
incomingText = "incoming"
end
log("watchChevrons", "Chevron " .. chevron .. " encoded with symbol " .. symbol .. " by an " .. incomingText .. " connection")
updateChevronDisplay(chevron, symbol)
updateStatus(stargateStatuses.DIALING)
end
end
function watchDisconnects()
while (true)
do
local _, feedback = os.pullEvent("stargate_disconnected")
local result = "in an unknown manner"
if feedback == 7 then
result = "manually"
elseif feedback == 8 then
result = "by point of origin"
elseif feedback == 9 then
result = "by network"
elseif feedback == 10 then
result = "automatically"
end
log("watchDisconnects", "Existing connection was closed " .. result .. " (code " .. feedback .. ")")
updateStatus(stargateStatuses.IDLE)
end
end
function lookupAddress(searchAddress)
for name, address in pairs(knownAddresses)
do
local isMatch = true
for i, value in ipairs(address)
do
if value ~= searchAddress[i] then
isMatch = false
break
end
end
if isMatch then
return name
end
end
return "UNKNOWN ADDRESS"
end
function setConnectedStatus(address, incoming)
local typeText = "OUTGOING"
if incoming then
typeText = "INCOMING"
end
updateStatus(stargateStatuses.CONNECTED)
updateMonitorLine(6, "Type: " .. typeText, false)
local connectedTo = lookupAddress(address)
setConnectedToText(connectedTo)
log("setConnectionStatus", typeText .. " connection established with: -" .. table.concat(address, "-") .. "- " .. connectedTo)
end
function watchIncoming()
while (true)
do
local _, address = os.pullEvent("stargate_incoming_wormhole")
setConnectedStatus(address, true)
end
end
function watchOutgoing()
while (true)
do
local _, address = os.pullEvent("stargate_outgoing_wormhole")
setConnectedStatus(address, false)
end
end
function cleanUp()
local e = os.pullEventRaw("terminate")
if e == "terminate" then
term.redirect(mainWindow)
print("Shutting down " .. program_name_text)
log("cleanUp", "Shutting down " .. program_name)
monitor.setBackgroundColor(colors.black)
monitor.clear()
chevronMonitor.setBackgroundColor(colors.black)
chevronMonitor.clear()
term.redirect(rootWindow)
term.clear()
error("Goodbye")
else
error("How did we get here?")
end
end
function handleEvents()
parallel.waitForAll(watchChevrons, watchDisconnects, watchIncoming, watchOutgoing)
end
function updateDial()
local lastAddress = stargate.getConnectedAddress()
local lastRotation = stargate.getRotation()
resetStargate()
while (true)
do
local address = stargate.getConnectedAddress()
stargateRotation = stargate.getRotation()
if #address == 0 and #lastAddress > 0 then
resetChevronDisplay(address)
updateStatus(stargateStatuses.IDLE)
setConnectedToText("-")
end
if stargateRotation ~= lastRotation then
updateStatus(stargateStatuses.DIALING)
end
lastAddress = address
lastRotation = stargateRotation
sleep(1)
end
end
function updateClock()
local timeWindow = window.create(statusWindow, termWidth - 9, 1, 9, 1, true)
timeWindow.setBackgroundColor(colors.blue)
while (true)
do
timeWindow.setCursorPos(1, 1)
timeWindow.clear()
timeWindow.write(textutils.formatTime(os.time()))
sleep(1)
end
end
-- Gate operation functions
function resetStargate()
stargate.disconnectStargate()
end
function fastEncodeSymbol(symbol)
end
function slowEncodeSymbol(chevron, symbol)
if chevron % 2 == 0 then
print("Rotating the ring clockwise")
stargate.rotateClockwise(symbol)
else
print("Rotating the ring counter-clockwise")
stargate.rotateAntiClockwise(symbol)
end
--Wait for the current rotation to complete
while(not stargate.isCurrentSymbol(symbol))
do
sleep(0)
end
print("Rotation complete")
--Grace delays when controlling chevrons
sleep(1)
print("Encoding chevron " .. chevron)
stargate.raiseChevron()
sleep(1)
stargate.lowerChevron()
sleep(1)
print("Chevron " .. chevron .. " encoded with: " .. symbol)
sleep(0.05)
end
function dialGate(address)
-- TODO dialing sequence code
print("Dialing -" .. table.concat(address, "-") .. "- " .. lookupAddress(address))
log("dialGate", "Initiating dialing sequence with address: " .. table.concat(address, ","))
resetStargate()
for chevron = 1,#address,1 do
local symbol = address[chevron]
if symbol == 0 then
print("Unexpected point of origin in address. Aborting.")
logError("dialGate", "Unexpected point of origin in address. Aborting.")
resetStargate()
return
end
if speedDialActive then
print("Encoding symbol: " .. symbol)
stargate.engageSymbol(symbol)
sleep(0.5)
else
slowEncodeSymbol(chevron, symbol)
end
end
if stargate.getChevronsEngaged() > 5 then
if speedDialActive then
print("Engaging Point of Origin")
stargate.engageSymbol(0)
else
slowEncodeSymbol(stargate.getChevronsEngaged() + 1, 0)
end
end
if speedDialActive then
speedDialActive = false
print("Speed dial: " .. tostring(speedDialActive))
end
end
function dialGateByName(name)
for key, address in pairs(knownAddresses) do
if key == name then
dialGate(address)
return
end
end
print("Gate address not found for: " .. name .. "")
end
function dialGateAddress(address)
-- Check if the input matches the comma-separated format
local addressTable = {}
for numberStr in address:gmatch("%-?%d+") do
table.insert(addressTable, tonumber(numberStr))
end
-- Check if the input matches the dash-surrounded format
if #addressTable == 0 then
for numberStr in address:gmatch("%-(%d+)%-") do
table.insert(addressTable, tonumber(numberStr))
end
end
-- Validate the size of the address (between 6 and 8)
if #addressTable < 6 or #addressTable > 8 then
print("Invalid address format. Address must have between 6 and 8 glyphs.")
return
end
-- Remove any dashes from the addressTable
for i, value in ipairs(addressTable) do
addressTable[i] = math.abs(value)
end
-- Call dialGate with the parsed address
dialGate(addressTable)
end
-- Interactive console
function runConsole()
term.redirect(mainWindow)
mainWindow.setPaletteColor(colors.lightBlue, 0x0A1E36)
mainWindow.setBackgroundColor(colors.lightBlue)
cleanMainWindow()
log("runConsole", "Startup complete")
while (true)
do
mainWindow.write("> ")
mainWindow.setCursorBlink(true)
local input = io.read()
local command, args = string.match(input, "^(%S+)%s*(.*)")
sleep(0)
mainWindow.setCursorBlink(false)
log("runConsole", "\"" .. input .. "\" sent to command terminal")
if command == "help" then
if args == "" then
print("Available commands:")
--print("help <command>")
print("dial <NAME>")
print("dialAddress | dial_address <full address>")
--print("iris [ open | close ]")
print("speedDial [ true | false ]")
print("disconnect | stop | abort")
else
print("Help for '" .. args .. "'")
if args == "dial" then
print("\nExample:")
print("\t'dial ABYDOS'")
elseif args == "dialAddress" or args == "dial_address" then
print("Example:")
print("\tdialAddress 26,6,14,31,11,29")
print("\ndialAddress -26-6-14-31-11-29-")
elseif args == "speedDial" or args == "fastDial" then
print("Example:")
print("\tspeedDial true")
end
end
elseif command == "dial" then
if args == "" then
print("Known addresses for dialing by name:")
local keys = {}
for key in pairs(knownAddresses) do
table.insert(keys, key)
end
print(table.concat(keys, ", "))
print("\nExample:")
print("\t'dial ABYDOS'")
else
dialGateByName(args)
end
elseif command == "dialAddress" or command == "dial_address" then
if args == "" then
print("Example:")
print("\tdialAddress 26,6,14,31,11,29")
print("\ndialAddress -26-6-14-31-11-29-")
else
dialGateAddress(args)
end
elseif command == "speedDial" or command == "fastDial" then
if args == "" then
speedDialActive = not speedDialActive
print("Speed dial: " .. tostring(speedDialActive))
elseif args == "true" then
speedDialActive = true
print("Speed dial: " .. tostring(speedDialActive))
elseif args == "false" then
speedDialActive = false
print("Speed dial: " .. tostring(speedDialActive))
else
print("Example:")
print("\tspeedDial true")
end
elseif command == "disconnect" or command == "stop" or command == "abort" then
print("Resetting stargate...")
log("runConsole", "Resetting stargate")
resetStargate()
print("Stargate reset.")
else
print("Unknown command. Type 'help' for a list of available commands.")
end
end
end
parallel.waitForAll(cleanUp, updateMonitor, updateMonitorSecondary, updateChevronMonitor, updateClock, updateEnergy, updateDial, handleEvents, runConsole)
@Unixkitty
Copy link
Author

console
passive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment