divided everything

This commit is contained in:
2025-12-28 23:51:01 -05:00
parent 39fe8bdc6c
commit 91c7cc2113
8 changed files with 1711 additions and 13 deletions

42
addresses.lua Normal file
View File

@ -0,0 +1,42 @@
--[[
Address Book
Contains all known stargate addresses organized by category
]]
local addresses = {}
---------------------------------------------
-- MAIN GATES
---------------------------------------------
-- Common 7-chevron addresses for main destinations
addresses.MainGates = {
{ "OVERWORLD", { 27, 25, 4, 35, 10, 28, 0 } },
{ "Nether", { 27, 23, 4, 34, 12, 28, 0 } },
{ "End", { 13, 24, 2, 19, 3, 30, 0 } },
{ "Abydos", { 26, 6, 14, 31, 11, 29, 0 } },
{ "Chulak", { 8, 1, 22, 14, 36, 19, 0 } }
}
---------------------------------------------
-- PLAYER GATES
---------------------------------------------
-- Typically 9-chevron addresses for player bases
addresses.playerGates = {
{ "Glaive", { 33, 6, 10, 24, 1, 30, 3, 17, 0 } },
{ "Moon", { 32, 33, 8, 7, 25, 21, 14, 35, 0 } },
{ "Caldoric", { 18, 2, 24, 16, 8, 19, 4, 29, 0 } },
{ "Trading Hall", { 16, 19, 6, 18, 35, 27, 9, 8, 0 } }
}
---------------------------------------------
-- HAZARD GATES
---------------------------------------------
-- Dangerous destinations
addresses.hazardGates = {
-- Add hazardous gate addresses here
}
return addresses

55
config.lua Normal file
View File

@ -0,0 +1,55 @@
--[[
Configuration File
All user-configurable settings for the Stargate Control System
]]
local config = {}
---------------------------------------------
-- GATE BEHAVIOR
---------------------------------------------
-- Gate dialing speed (seconds between chevrons for non-Milky Way gates)
config.gatespeed = 0.5
-- Manual dial for Milky Way gates (rotating ring animation)
config.manualDial = true
-- Access control
config.canAccessHazardGates = true
---------------------------------------------
-- IRIS CONFIGURATION
---------------------------------------------
config.irisEnabled = true
config.autoCloseIrisOnIncoming = true
config.irisCloseDelay = 0.1 -- seconds before closing iris on incoming
config.autoOpenIrisAfterDisconnect = true
---------------------------------------------
-- SECURITY
---------------------------------------------
-- Whitelist (if not empty, only these addresses can enter)
-- Format: {"Name", {address_table}}
config.whitelist = {
{ "Glaive", { 33, 6, 10, 24, 1, 30, 3, 17, 0 } },
{ "Moon", { 32, 33, 8, 7, 25, 21, 14, 35, 0 } },
{ "Caldoric", { 18, 2, 24, 16, 8, 19, 4, 29, 0 } },
{ "Trading Hall", { 16, 19, 6, 18, 35, 27, 9, 8, 0 } }
}
-- Blacklist (these addresses are always blocked)
config.blacklist = {
-- {"DangerGate", {1,2,3,4,5,6,0}},
}
---------------------------------------------
-- LOGGING
---------------------------------------------
config.enableLogging = true
config.logFile = "stargate.log"
return config

View File

222
display.lua Normal file
View File

@ -0,0 +1,222 @@
--[[
Display Functions
Handles all monitor/screen drawing operations
]]
local display = {}
-- Will be set by startup.lua
local mon
local config
local addresses
local utils
-- State variables
local buttonXY = {}
local computerAddresses = {}
local computerNames = {}
local x, y = 0, 0
function display.init(monitor, cfg, addr, utilsModule)
mon = monitor
config = cfg
addresses = addr
utils = utilsModule
end
function display.getButtonData()
return buttonXY, computerAddresses, computerNames
end
function display.clearButtonData()
buttonXY = {}
computerAddresses = {}
computerNames = {}
end
---------------------------------------------
-- DRAWING FUNCTIONS
---------------------------------------------
function display.drawIrisStatus()
mon.setCursorPos(1, 19)
mon.setBackgroundColor(colors.black)
local irisState = utils.getIrisState()
if irisState == "OPEN" then
mon.setTextColor(colors.green)
elseif irisState == "CLOSED" then
mon.setTextColor(colors.red)
else
mon.setTextColor(colors.gray)
end
mon.write("IRIS: " .. irisState .. " ")
mon.setTextColor(colors.white)
if irisState == "MOVING" then
sleep(0.1)
display.drawIrisStatus()
end
end
function display.screenWrite(list, fcount, fy)
for i = 1, #list do
local x1, x2 = 0, 0
if fcount == 0 then
x = 2
fcount = 1
elseif fcount == 1 then
x = 11
fcount = 2
else
x = 20
fcount = 0
fy = fy + 2
end
mon.setCursorPos(x, fy)
mon.write(list[i][1])
x1 = x
x2 = x + 7
table.insert(buttonXY, { x1, x2, fy })
table.insert(computerNames, list[i][1])
table.insert(computerAddresses, list[i][2])
end
local oldterm = term.redirect(mon)
paintutils.drawFilledBox(23, 17, 28, 19, colors.red)
mon.setCursorPos(24, 18)
mon.write("Back")
term.redirect(oldterm)
return fcount, fy
end
function display.selectionTabs()
mon.setBackgroundColor(colors.black)
mon.clear()
local oldterm = term.redirect(mon)
if #addresses.MainGates ~= 0 then
paintutils.drawFilledBox(2, 2, 13, 6, colors.purple)
mon.setCursorPos(4, 4)
mon.setBackgroundColor(colors.purple)
mon.write("Main Gates")
end
if #addresses.playerGates ~= 0 then
paintutils.drawFilledBox(16, 2, 27, 6, colors.green)
mon.setCursorPos(18, 4)
mon.setBackgroundColor(colors.green)
mon.write("Player")
mon.setCursorPos(18, 5)
mon.write("Base gates")
end
if (#addresses.hazardGates ~= 0) and (config.canAccessHazardGates == true) then
paintutils.drawFilledBox(2, 8, 13, 12, colors.red)
mon.setCursorPos(4, 9)
mon.setBackgroundColor(colors.red)
mon.write("Hazard")
mon.setCursorPos(4, 11)
mon.write("gates")
end
paintutils.drawFilledBox(23, 17, 28, 19, colors.red)
mon.setCursorPos(24, 18)
mon.write("Back")
display.drawIrisStatus()
term.redirect(oldterm)
end
function display.showIncoming(addressString, allowed, reason)
mon.setBackgroundColor(colors.black)
mon.clear()
if allowed then
mon.setBackgroundColor(colors.green)
mon.setTextScale(1)
mon.setCursorPos(1, 2)
mon.write("INCOMING - AUTHORIZED")
else
mon.setBackgroundColor(colors.red)
mon.setTextScale(1)
mon.setCursorPos(1, 2)
mon.write("INCOMING - UNAUTHORIZED")
mon.setCursorPos(1, 4)
mon.write(reason)
end
mon.setCursorPos(1, 6)
mon.setBackgroundColor(colors.black)
mon.write("Address:\n" .. addressString)
end
function display.showEntity(entityType, entityName, allowed)
mon.setTextScale(1)
mon.setCursorPos(1, 10)
mon.write("Type: " .. entityType)
mon.setCursorPos(1, 12)
mon.write("Name: " .. entityName)
if not allowed then
mon.setCursorPos(1, 14)
mon.setTextColor(colors.red)
mon.write("IRIS IMPACT!")
mon.setTextColor(colors.white)
end
end
function display.showDialing(chevron, symbol, gateType)
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(2)
mon.setCursorPos(2, 3)
mon.write("DIALING GATE")
mon.setCursorPos(4, 5)
mon.write("CHEVERON")
mon.setCursorPos(7, 7)
mon.setBackgroundColor(colors.black)
mon.write(chevron)
mon.setBackgroundColor(colors.red)
if symbol ~= 0 then
mon.setCursorPos(4, 9)
mon.write("ENGAGED")
else
mon.setCursorPos(5, 9)
mon.setBackgroundColor(colors.green)
mon.write("LOCKED")
end
end
function display.showConnected(destName, destAddr)
mon.setBackgroundColor(colors.green)
mon.clear()
mon.setTextScale(1)
mon.setCursorPos(6, 5)
mon.write(destName)
mon.setCursorPos(3, 10)
for i = 1, #destAddr do
mon.write(destAddr[i])
mon.write(" ")
end
display.drawIrisStatus()
end
function display.showMainMenu()
mon.setTextScale(1)
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setCursorPos(9, 1)
mon.setBackgroundColor(colors.red)
mon.write("press to start")
display.drawIrisStatus()
end
return display

View File

@ -0,0 +1,427 @@
--[[
Stargate Control System - Main Entry Point
For Stargate Journey Mod - AllTheMods 9
Comprehensive control program featuring:
- Full dialing system with touch screen interface
- Automatic iris control with security features
- Incoming/outgoing wormhole management
- Address book with categories
- Entity tracking and logging
- Whitelist/blacklist security
]]
---------------------------------------------
-- LOAD MODULES
---------------------------------------------
local config = require("config")
local addresses = require("addresses")
local utils = require("utils")
local display = require("display")
---------------------------------------------
-- INITIALIZATION
---------------------------------------------
-- Find and initialize peripherals
local mon = peripheral.find("monitor")
local gate = peripheral.find("advanced_crystal_interface")
or peripheral.find("crystal_interface")
or peripheral.find("basic_interface")
if gate == nil then
error("Stargate interface not found! Please connect an interface.")
end
if mon == nil then
error("Monitor not found! Please connect a monitor.")
end
-- Check iris availability
if gate.getIris() == nil then
print("Config has Iris enabled, but there is no iris! Disabling Iris")
config.irisEnabled = false
end
-- Initialize modules
utils.init(config, gate)
display.init(mon, config, addresses, utils)
-- Ensure gate starts disconnected
gate.disconnectStargate()
-- Ensure iris starts open
if config.irisEnabled then
gate.openIris()
end
---------------------------------------------
-- GLOBAL STATE
---------------------------------------------
local dialing = false
local totalstate = nil
local disconnect = false
local incomingAddress = {}
local incomingEntityType = ""
local incomingEntityName = ""
local destAddress = {}
local destAddressname = ""
local selx, sely = 0, 0
local y = 0
---------------------------------------------
-- EVENT HANDLERS
---------------------------------------------
local function GetClick()
mon.setTextScale(1)
local event, _, xPos, yPos = os.pullEvent("monitor_touch")
return xPos, yPos
end
local function GetActivation()
_, _, incomingAddress = os.pullEvent("stargate_incoming_wormhole")
utils.log("Incoming wormhole: " .. gate.addressToString(incomingAddress))
return 1
end
local function ParaDisconnect()
local dx, dy = 0, 0
_, _, dx, dy = os.pullEvent("monitor_touch")
if (dx ~= 0) and (dy ~= 0) then
gate.disconnectStargate()
redstone.setOutput("top", false)
utils.log("Manual disconnect triggered")
end
return 1
end
local function EntityRead()
sleep(0.1)
_, _, incomingEntityType, incomingEntityName, _ = os.pullEvent("stargate_reconstructing_entity")
utils.log("Entity reconstructed: " .. incomingEntityName .. " (" .. incomingEntityType .. ")")
return 1
end
local function DisconnectCheck()
local _, _, disCode = os.pullEvent("stargate_disconnected")
redstone.setOutput("top", false)
utils.log("Stargate disconnected (code: " .. tostring(disCode) .. ")")
if config.autoOpenIrisAfterDisconnect then
utils.openIris()
end
return 2
end
local function Paratimeout()
sleep(300)
return 2
end
---------------------------------------------
-- INCOMING WORMHOLE HANDLER
---------------------------------------------
local function handleIncomingWormhole()
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(1)
mon.setCursorPos(9, 4)
mon.write("INCOMING")
incomingAddress = utils.addressToTable(incomingAddress)
-- Check security
local allowed, reason = utils.isAddressAllowed(incomingAddress)
local addressString = gate.addressToString(incomingAddress) or "Unknown"
utils.log("Incoming wormhole from: " .. addressString .. " " .. reason)
-- Show incoming connection status
display.showIncoming(addressString, allowed, reason)
-- Handle iris
if config.autoCloseIrisOnIncoming then
sleep(config.irisCloseDelay)
if allowed then
utils.openIris()
else
utils.closeIris()
end
end
-- Monitor for entities
disconnect = false
while (disconnect == false) do
-- parallel.waitForAny runs multiple functions at the same time and returns which one finished first
-- Here we're watching for 3 things simultaneously:
-- 1 = EntityRead (someone/something came through the gate)
-- 2 = DisconnectCheck (gate disconnected on its own)
-- ParaDisconnect (user clicked screen to manually disconnect)
-- Whichever happens first, that function returns and we handle it
local incomingcheck = parallel.waitForAny(EntityRead, DisconnectCheck, ParaDisconnect)
if (incomingcheck == 1) then
display.showEntity(incomingEntityType, incomingEntityName, allowed)
incomingEntityType = ""
incomingEntityName = ""
else
disconnect = true
end
end
disconnect = false
end
---------------------------------------------
-- DIALING FUNCTIONS
---------------------------------------------
local function dialGate(address)
utils.log("Dialing: " .. gate.addressToString(address))
local gateType = gate.getStargateType()
-- Manual Milky Way dialing with ring rotation
if gateType == "sgjourney:milky_way_stargate" and config.manualDial == true then
local addressLength = #address
if addressLength == 8 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 6, 7, 8, 5 })
elseif addressLength == 9 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 })
end
local start = gate.getChevronsEngaged() + 1
for chevron = start, addressLength, 1 do
local symbol = address[chevron]
if chevron % 2 == 0 then
gate.rotateClockwise(symbol)
else
gate.rotateAntiClockwise(symbol)
end
while (not gate.isCurrentSymbol(symbol)) do
sleep(0)
end
gate.openChevron()
sleep(1)
gate.closeChevron()
sleep(0.5)
display.showDialing(chevron, symbol, gateType)
end
else
-- Automatic dialing for other gate types
if gateType ~= "sgjourney:universe_stargate" then
local addressLength = #address
if addressLength == 8 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 6, 7, 8, 5 })
elseif addressLength == 9 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 })
end
end
local start = gate.getChevronsEngaged() + 1
for chevron = start, #address, 1 do
local symbol = address[chevron]
gate.engageSymbol(symbol)
sleep(config.gatespeed)
display.showDialing(chevron, symbol, gateType)
if (symbol) ~= 0 then
if (gateType == "sgjourney:universe_stargate") or (gateType == "sgjourney:pegasus_stargate") then
os.pullEvent("stargate_chevron_engaged")
end
else
if gateType == "sgjourney:universe_stargate" then
os.pullEvent("stargate_chevron_engaged")
redstone.setOutput("top", true)
elseif (gateType == "sgjourney:pegasus_stargate") then
os.pullEvent("stargate_chevron_engaged")
end
end
end
end
end
local function selectGateFromList()
local selecting = true
while dialing == false and selecting == true do
selx, sely = GetClick()
local buttonXY, computerAddresses, computerNames = display.getButtonData()
for i = 1, #buttonXY do
if (sely == buttonXY[i][3]) and ((selx >= buttonXY[i][1]) and (selx <= buttonXY[i][2])) then
dialGate(computerAddresses[i])
destAddressname = computerNames[i]
destAddress = computerAddresses[i]
dialing = true
sely = 0
selx = 0
elseif sely >= 17 and selx >= 23 then
selecting = false
sely = 0
selx = 0
end
end
end
display.clearButtonData()
return dialing
end
local function selectCategory()
local state = true
while state == true do
display.selectionTabs()
local tabx, taby = GetClick()
y = 2
local count = 0
if (taby >= 2) and (taby <= 6) and ((tabx >= 2) and (tabx <= 13)) then
if #addresses.MainGates ~= 0 then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.purple)
count, y = display.screenWrite(addresses.MainGates, count, y)
local returnstate = selectGateFromList()
if returnstate == true then
state = false
end
display.clearButtonData()
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (taby >= 2) and (taby <= 6) and ((tabx >= 16) and (tabx <= 27)) then
if #addresses.playerGates ~= 0 then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.green)
count, y = display.screenWrite(addresses.playerGates, count, y)
local returnstate = selectGateFromList()
if returnstate == true then
state = false
end
display.clearButtonData()
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (((taby >= 8) and (taby <= 12)) and ((tabx >= 2) and (tabx <= 13))) and (config.canAccessHazardGates == true) then
if (#addresses.hazardGates ~= 0) and (config.canAccessHazardGates == true) then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
count, y = display.screenWrite(addresses.hazardGates, count, y)
local returnstate = selectGateFromList()
if returnstate == true then
state = false
end
display.clearButtonData()
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (taby >= 17) and (tabx >= 23) then
state = false
totalstate = false
end
end
return 1
end
local function handleOutgoingDial()
totalstate = true
local PDO = 0
-- parallel.waitForAny runs functions simultaneously and returns which finished first
-- Here we're waiting for either:
-- 1 = selectCategory (user selected a gate to dial)
-- 2 = Paratimeout (5 minutes passed with no selection)
-- This prevents the gate from staying on the selection screen forever
PDO = parallel.waitForAny(selectCategory, Paratimeout)
if (PDO == 1) and totalstate == true then
sleep(1)
os.pullEvent("stargate_outgoing_wormhole")
display.showConnected(destAddressname, destAddress)
if (gate.isStargateConnected() == true) then
-- parallel.waitForAny runs functions at the same time, returns which finished first
-- While the wormhole is open, we wait for:
-- DisconnectCheck = gate disconnects naturally (timeout or remote disconnect)
-- ParaDisconnect = user manually clicks screen to disconnect
-- Paratimeout = safety timeout (5 minutes)
-- Whichever happens first ends the connection
PDO = parallel.waitForAny(DisconnectCheck, ParaDisconnect, Paratimeout)
dialing = false
end
end
display.clearButtonData()
destAddress = {}
destAddressname = ""
end
---------------------------------------------
-- MAIN MENU
---------------------------------------------
local function mainMenu()
while true do
display.showMainMenu()
-- parallel.waitForAny runs multiple functions simultaneously, returns which completes first
-- The main menu waits for any of these events:
-- 1 = GetClick (user touched the monitor anywhere - assumes they want to dial out)
-- 2 = GetActivation (incoming wormhole detected with address)
-- Note: We don't wait for CheveronActivation here because it fires at the same time
-- as the incoming wormhole event, causing a race condition where we might miss the address
local answer = parallel.waitForAny(GetClick, GetActivation)
if (answer == 1) then
handleOutgoingDial()
else
handleIncomingWormhole()
end
end
end
---------------------------------------------
-- STARTUP
---------------------------------------------
utils.log("=== Stargate Control System Starting ===")
utils.log("Gate Type: " .. gate.getStargateType())
utils.log("Iris Available: " .. tostring(config.irisEnabled))
-- Start the main menu
mainMenu()

826
startup_old.lua Normal file
View File

@ -0,0 +1,826 @@
-- Gate dialing speed (seconds between chevrons for non-Milky Way gates)
local gatespeed = 0.5
local manualDial = true
local canAccessHazardGates = true
local irisEnabled = true
local autoCloseIrisOnIncoming = true
local irisCloseDelay = 0.1 -- seconds before closing iris on incoming
local autoOpenIrisAfterDisconnect = true
local whitelist = {
{ "Glaive", { 33, 6, 10, 24, 1, 30, 3, 17, 0 } },
{ "Moon", { 32, 33, 8, 7, 25, 21, 14, 35, 0 } },
{ "Caldoric", { 18, 2, 24, 16, 8, 19, 4, 29, 0 } },
{ "Trading Hall", { 16, 19, 6, 18, 35, 27, 9, 8, 0 } }
}
local blacklist = {
-- {"DangerGate", {1,2,3,4,5,6,0}},
}
local enableLogging = true
local logFile = "stargate.log"
---------------------------------------------
-- ADDRESS BOOK
---------------------------------------------
-- Main Gates (7-chevron addresses for common destinations)
local MainGates = {
{ "OVERWORLD", { 27, 25, 4, 35, 10, 28, 0 } },
{ "Nether", { 27, 23, 4, 34, 12, 28, 0 } },
{ "End", { 13, 24, 2, 19, 3, 30, 0 } },
{ "Abydos", { 26, 6, 14, 31, 11, 29, 0 } },
{ "Chulak", { 8, 1, 22, 14, 36, 19, 0 } }
}
-- Player Gates (typically 9-chevron addresses)
local playerGates = {
{ "Glaive", { 33, 6, 10, 24, 1, 30, 3, 17, 0 } },
{ "Moon", { 32, 33, 8, 7, 25, 21, 14, 35, 0 } },
{ "Caldoric", { 18, 2, 24, 16, 8, 19, 4, 29, 0 } },
{ "Trading Hall", { 16, 19, 6, 18, 35, 27, 9, 8, 0 } }
}
-- Hazard Gates (dangerous destinations)
local hazardGates = {
-- Add hazardous gate addresses here
}
---------------------------------------------
-- INITIALIZATION
---------------------------------------------
-- Find and initialize peripherals
local mon = peripheral.find("monitor")
local gate = peripheral.find("advanced_crystal_interface")
if gate == nil then
error("Stargate interface not found! Please connect an interface.")
end
if mon == nil then
error("Monitor not found! Please connect a monitor.")
end
-- Ensure gate starts disconnected
gate.disconnectStargate()
-- Ensure iris starts open (unless there's a threat)
if irisEnabled then
gate.openIris()
end
---------------------------------------------
-- GLOBAL VARIABLES
---------------------------------------------
-- Outgoing connection state
local destAddress = {}
local buttonXY = {}
local computerAddresses = {}
local computerNames = {}
local destAddressname = ""
local x, y = 0, 0
local selx, sely = 0, 0
local dialing = false
local totalstate = nil
-- Incoming connection state
local incomingAddress = {}
local incomingEntityType = ""
local incomingEntityName = ""
-- Menu state
local disconnect = false
---------------------------------------------
-- UTILITY FUNCTIONS
---------------------------------------------
local function deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else -- number, string, boolean, etc
copy = orig
end
return copy
end
local function log(message)
if enableLogging then
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
local logEntry = "[" .. timestamp .. "]\n" .. message
-- local logEntry = message
-- Write to console
print(logEntry)
-- Write to file
local file = fs.open(logFile, "a")
if file then
file.writeLine(logEntry)
file.close()
end
end
end
local function addressToTable(address)
if type(address) == "table" then
return address
end
return {}
end
local function compareAddresses(addr1, addr2)
addr1 = gate.addressToString(addr1)
addr2 = gate.addressToString(addr2)
return addr1 == addr2
end
local function isAddressInList(address, list)
for _, entry in ipairs(list) do
local listAddr = entry[2]
tmp = deepcopy(listAddr)
table.remove(tmp)
if compareAddresses(address, tmp) then
return true, entry[1]
end
end
return false, nil
end
local function isAddressAllowed(address)
-- Check blacklist first
local isBlacklisted, blackName = isAddressInList(address, blacklist)
if isBlacklisted then
return false, "Blacklisted: " .. blackName
end
-- If whitelist is not empty, check whitelist
if #whitelist > 0 then
local isWhitelisted, whiteName = isAddressInList(address, whitelist)
if isWhitelisted then
return true, "Whitelisted: " .. whiteName
else
return false, "Not on whitelist"
end
end
-- If no whitelist, allow all non-blacklisted
return true, "Allowed"
end
---------------------------------------------
-- IRIS CONTROL FUNCTIONS
---------------------------------------------
local function closeIris()
if irisEnabled then
gate.closeIris()
log("Iris closed")
return true
end
return false
end
local function openIris()
if irisEnabled then
gate.openIris()
log("Iris opened")
return true
end
return false
end
local function getIrisState()
if irisEnabled then
if gate.getIrisProgressPercentage() == 0 then
return "OPEN"
else
if gate.getIrisProgressPercentage() == 100 then
return "CLOSED"
else
return "MOVING"
end
end
end
return "NO IRIS"
end
---------------------------------------------
-- DISPLAY FUNCTIONS
---------------------------------------------
local function screenWrite(list, fcount, fy)
local internaladdress = {}
for i = 1, #list do
local x1, x2 = 0, 0
if fcount == 0 then
x = 2
fcount = 1
elseif fcount == 1 then
x = 11
fcount = 2
else
x = 20
fcount = 0
fy = fy + 2
end
mon.setCursorPos(x, fy)
mon.write(list[i][1])
x1 = x
x2 = x + 7
table.insert(buttonXY, { x1, x2, fy })
table.insert(computerNames, list[i][1])
-- list[i][2] is now the address table directly
table.insert(computerAddresses, list[i][2])
internaladdress = {}
end
local oldterm = term.redirect(mon)
paintutils.drawFilledBox(23, 17, 28, 19, colors.red)
mon.setCursorPos(24, 18)
mon.write("Back")
term.redirect(oldterm)
return fcount, fy
end
local function drawIrisStatus()
mon.setCursorPos(1, 19)
mon.setBackgroundColor(colors.black)
local irisState = getIrisState()
if irisState == "OPEN" then
mon.setTextColor(colors.green)
elseif irisState == "CLOSED" then
mon.setTextColor(colors.red)
else
mon.setTextColor(colors.gray)
end
mon.write("IRIS: " .. irisState .. " ")
mon.setTextColor(colors.white)
if irisState == "MOVING" then
sleep(0.1)
drawIrisStatus()
end
end
local function SelectDial()
local x1, x2 = 0, 0
local count = 0
y = 2
mon.setBackgroundColor(colors.black)
mon.clear()
if #MainGates ~= 0 then
mon.setBackgroundColor(colors.purple)
count, y = screenWrite(MainGates, count, y)
end
if #playerGates ~= 0 then
mon.setBackgroundColor(colors.green)
count, y = screenWrite(playerGates, count, y)
end
if (#hazardGates ~= 0) and (canAccessHazardGates == true) then
mon.setBackgroundColor(colors.red)
count, y = screenWrite(hazardGates, count, y)
end
drawIrisStatus()
return 1
end
local function selectionTabs()
mon.setBackgroundColor(colors.black)
mon.clear()
local oldterm = term.redirect(mon)
if #MainGates ~= 0 then
paintutils.drawFilledBox(2, 2, 13, 6, colors.purple)
mon.setCursorPos(4, 4)
mon.setBackgroundColor(colors.purple)
mon.write("Main Gates")
end
if #playerGates ~= 0 then
paintutils.drawFilledBox(16, 2, 27, 6, colors.green)
mon.setCursorPos(18, 4)
mon.setBackgroundColor(colors.green)
mon.write("Player")
mon.setCursorPos(18, 5)
mon.write("Base gates")
end
if (#hazardGates ~= 0) and (canAccessHazardGates == true) then
paintutils.drawFilledBox(2, 8, 13, 12, colors.red)
mon.setCursorPos(4, 9)
mon.setBackgroundColor(colors.red)
mon.write("Hazard")
mon.setCursorPos(4, 11)
mon.write("gates")
end
paintutils.drawFilledBox(23, 17, 28, 19, colors.red)
mon.setCursorPos(24, 18)
mon.write("Back")
drawIrisStatus()
term.redirect(oldterm)
end
---------------------------------------------
-- EVENT HANDLING FUNCTIONS
---------------------------------------------
local function GetClick()
mon.setTextScale(1)
local event, _, xPos, yPos = os.pullEvent("monitor_touch")
return xPos, yPos
end
local function GetActivation()
_, _, incomingAddress = os.pullEvent("stargate_incoming_wormhole")
return 1
end
local function CheveronActivation()
local event, _, _, _, incomingBool = os.pullEvent("stargate_chevron_engaged")
if incomingBool == true then
log("External dial detected")
else
log("Internal dial detected")
end
return 1
end
local function ParaDisconnect()
local dx, dy = 0, 0
_, _, dx, dy = os.pullEvent("monitor_touch")
if (dx ~= 0) and (dy ~= 0) then
gate.disconnectStargate()
redstone.setOutput("top", false)
log("Manual disconnect triggered")
end
return 1
end
local function EntityRead()
sleep(0.1)
_, _, incomingEntityType, incomingEntityName, _ = os.pullEvent("stargate_reconstructing_entity")
log("Entity reconstructed: " .. incomingEntityName .. " (" .. incomingEntityType .. ")")
return 1
end
local function DisconnectCheck()
local _, _, disCode = os.pullEvent("stargate_disconnected")
redstone.setOutput("top", false)
log("Stargate disconnected (code: " .. tostring(disCode) .. ")")
-- Auto-open iris after disconnect
if autoOpenIrisAfterDisconnect then
openIris()
end
return 2
end
---------------------------------------------
-- INCOMING WORMHOLE HANDLER
---------------------------------------------
local function PRIMARYwormholeIncoming()
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(1)
mon.setCursorPos(9, 4)
mon.write("INCOMING")
-- Convert address to table if needed
incomingAddress = addressToTable(incomingAddress)
-- Check security
local allowed, reason = isAddressAllowed(incomingAddress)
-- Try to get address string
local addressString = gate.addressToString(incomingAddress) or "Unknown"
log("Incoming wormhole from: " .. addressString .. " " .. reason)
mon.setBackgroundColor(colors.black)
mon.clear()
if allowed then
mon.setBackgroundColor(colors.green)
mon.setTextScale(1)
mon.setCursorPos(1, 2)
mon.write("INCOMING - AUTHORIZED")
-- Open iris for authorized connections
if autoCloseIrisOnIncoming then
sleep(irisCloseDelay)
openIris()
end
else
mon.setBackgroundColor(colors.red)
mon.setTextScale(1)
mon.setCursorPos(1, 2)
mon.write("INCOMING - UNAUTHORIZED")
mon.setCursorPos(1, 4)
mon.write(reason)
-- Close iris for unauthorized connections
if autoCloseIrisOnIncoming then
sleep(irisCloseDelay)
closeIris()
end
end
mon.setCursorPos(1, 6)
mon.setBackgroundColor(colors.black)
mon.write("Address:")
mon.setCursorPos(1, 7)
mon.write(addressString)
-- Monitor for incoming entities
disconnect = false
while (disconnect == false) do
-- parallel.waitForAny runs multiple functions at the same time and returns which one finished first
-- Here we're watching for 3 things simultaneously:
-- 1 = EntityRead (someone/something came through the gate)
-- 2 = DisconnectCheck (gate disconnected on its own)
-- ParaDisconnect (user clicked screen to manually disconnect)
-- Whichever happens first, that function returns and we handle it
local incomingcheck = parallel.waitForAny(EntityRead, DisconnectCheck, ParaDisconnect)
if (incomingcheck == 1) then
mon.setTextScale(1)
mon.setCursorPos(1, 10)
mon.write("Type: " .. incomingEntityType)
mon.setCursorPos(1, 12)
mon.write("Name: " .. incomingEntityName)
-- Check if entity should be blocked
if not allowed then
mon.setCursorPos(1, 14)
mon.setTextColor(colors.red)
mon.write("IRIS IMPACT!")
mon.setTextColor(colors.white)
end
incomingEntityType = ""
incomingEntityName = ""
else
disconnect = true
end
end
disconnect = false
end
---------------------------------------------
-- DIALING FUNCTIONS
---------------------------------------------
local function Dial(address)
log("Dialing: " .. gate.addressToString(address))
local gateType = gate.getStargateType()
-- Manual Milky Way dialing with ring rotation
if gateType == "sgjourney:milky_way_stargate" and manualDial == true then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(2)
mon.setCursorPos(2, 3)
mon.write("DIALING GATE")
local addressLength = #address
if addressLength == 8 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 6, 7, 8, 5 })
elseif addressLength == 9 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 })
end
local start = gate.getChevronsEngaged() + 1
for chevron = start, addressLength, 1 do
local symbol = address[chevron]
if chevron % 2 == 0 then
gate.rotateClockwise(symbol)
else
gate.rotateAntiClockwise(symbol)
end
while (not gate.isCurrentSymbol(symbol)) do
sleep(0)
end
gate.openChevron()
sleep(1)
gate.closeChevron()
sleep(0.5)
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(2)
mon.setCursorPos(2, 3)
mon.write("DIALING GATE")
mon.setCursorPos(4, 5)
mon.write("CHEVERON")
mon.setCursorPos(7, 7)
mon.setBackgroundColor(colors.black)
mon.write(chevron)
mon.setBackgroundColor(colors.red)
if symbol ~= 0 then
mon.setCursorPos(4, 9)
mon.write("ENGAGED")
else
mon.setCursorPos(5, 9)
mon.setBackgroundColor(colors.green)
mon.write("LOCKED")
end
end
else
-- Automatic dialing for other gate types
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(2)
mon.setCursorPos(2, 3)
mon.write("DIALING GATE")
if gateType ~= "sgjourney:universe_stargate" then
local addressLength = #address
if addressLength == 8 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 6, 7, 8, 5 })
elseif addressLength == 9 then
gate.setChevronConfiguration({ 1, 2, 3, 4, 5, 6, 7, 8 })
end
end
local start = gate.getChevronsEngaged() + 1
for chevron = start, #address, 1 do
local symbol = address[chevron]
gate.engageSymbol(symbol)
sleep(gatespeed)
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
mon.setTextScale(2)
mon.setCursorPos(2, 3)
mon.write("DIALING GATE")
mon.setCursorPos(4, 5)
mon.write("CHEVERON")
mon.setCursorPos(7, 7)
mon.setBackgroundColor(colors.black)
mon.write(chevron)
mon.setBackgroundColor(colors.red)
if (symbol) ~= 0 then
mon.setCursorPos(4, 9)
mon.write("ENGAGED")
if (gateType == "sgjourney:universe_stargate") or (gateType == "sgjourney:pegasus_stargate") then
os.pullEvent("stargate_chevron_engaged")
end
else
if gateType == "sgjourney:universe_stargate" then
os.pullEvent("stargate_chevron_engaged")
redstone.setOutput("top", true)
elseif (gateType == "sgjourney:pegasus_stargate") then
os.pullEvent("stargate_chevron_engaged")
end
mon.setCursorPos(5, 9)
mon.setBackgroundColor(colors.green)
mon.write("LOCKED")
end
end
address = nil
end
end
local function ParaDial()
local selecting = true
while dialing == false and selecting == true do
selx, sely = GetClick()
for i = 1, #buttonXY do
if (sely == buttonXY[i][3]) and ((selx >= buttonXY[i][1]) and (selx <= buttonXY[i][2])) then
Dial(computerAddresses[i])
destAddressname = computerNames[i]
destAddress = computerAddresses[i]
dialing = true
sely = 0
selx = 0
elseif sely >= 17 and selx >= 23 then
selecting = false
sely = 0
selx = 0
end
end
end
buttonXY = {}
computerAddresses = {}
computerNames = {}
return dialing
end
local function tabSelector()
local state = true
while state == true do
mon.setBackgroundColor(colors.black)
mon.clear()
selectionTabs()
local tabx, taby = GetClick()
y = 2
local count = 0
if (taby >= 2) and (taby <= 6) and ((tabx >= 2) and (tabx <= 13)) then
if #MainGates ~= 0 then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.purple)
count, y = screenWrite(MainGates, count, y)
local returnstate = ParaDial()
if returnstate == true then
state = false
end
computerAddresses = {}
computerNames = {}
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (taby >= 2) and (taby <= 6) and ((tabx >= 16) and (tabx <= 27)) then
if #playerGates ~= 0 then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.green)
count, y = screenWrite(playerGates, count, y)
local returnstate = ParaDial()
if returnstate == true then
state = false
end
computerAddresses = {}
computerNames = {}
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (((taby >= 8) and (taby <= 12)) and ((tabx >= 2) and (tabx <= 13))) and (canAccessHazardGates == true) then
if (#hazardGates ~= 0) and (canAccessHazardGates == true) then
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setBackgroundColor(colors.red)
count, y = screenWrite(hazardGates, count, y)
local returnstate = ParaDial()
if returnstate == true then
state = false
end
computerAddresses = {}
computerNames = {}
else
mon.setCursorPos(9, 7)
mon.write("no gates available")
sleep(5)
end
elseif (taby >= 17) and (tabx >= 23) then
state = false
totalstate = false
end
end
return 1
end
local function Paratimeout()
sleep(300)
return 2
end
local function DialText()
mon.setBackgroundColor(colors.green)
mon.clear()
mon.setTextScale(1)
mon.setCursorPos(6, 5)
mon.write(destAddressname)
mon.setCursorPos(3, 10)
for i = 1, #destAddress do
mon.write(destAddress[i])
mon.write(" ")
end
drawIrisStatus()
destAddress = {}
destAddressname = ""
end
local function PRIMARYDialingOut()
totalstate = true
local PDO = 0
PDO = parallel.waitForAny(tabSelector, Paratimeout)
if (PDO == 1) and totalstate == true then
sleep(1)
os.pullEvent("stargate_outgoing_wormhole")
DialText()
if (gate.isStargateConnected() == true) then
PDO = parallel.waitForAny(DisconnectCheck, ParaDisconnect, Paratimeout)
dialing = false
end
end
computerAddresses = {}
computerNames = {}
end
---------------------------------------------
-- MAIN MENU
---------------------------------------------
function Menu()
while true do
mon.setTextScale(1)
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setCursorPos(9, 1)
mon.setBackgroundColor(colors.red)
mon.write("press to start")
drawIrisStatus()
local answer = parallel.waitForAny(GetClick, GetActivation)
if (answer == 1) then
PRIMARYDialingOut()
else
PRIMARYwormholeIncoming()
end
end
end
---------------------------------------------
-- STARTUP
---------------------------------------------
if gate.getIris() == nil then
log("Config has Iris enabled, but there is no iris! Disabling Iris")
irisEnabled = false
end
-- log("=== Stargate Control System Starting ===")
-- log("Gate Type: " .. gate.getStargateType())
-- log("Iris Available: " .. tostring(irisEnabled))
-- log("Configuration: Manual Dial=" .. tostring(manualDial) .. ", Auto Iris=" .. tostring(autoCloseIrisOnIncoming))
-- Start the main menu
Menu()

View File

@ -1,13 +0,0 @@
shell.run("clear")
local interface = peripheral.find("basic_interface") or peripheral.find("crystal_interface") or peripheral.find("advanced_crystal_interface")
interface.openIris()
while true do
local _, _, address = os.pullEvent("stargate_incoming_wormhole")
interface.closeIris()
print("Incoming connection from " .. interface.addressToString(address))
local _, _, _, name, _ = os.pullEvent(stargate_reconstructing_entity)
print(name .. " got squished")
interface.disconnectStargate()
interface.openIris()
end

139
utils.lua Normal file
View File

@ -0,0 +1,139 @@
--[[
Utility Functions
Helper functions for logging, address handling, and iris control
]]
local utils = {}
-- Import config (set by startup.lua)
local config
local gate
function utils.init(cfg, gateInterface)
config = cfg
gate = gateInterface
end
---------------------------------------------
-- LOGGING
---------------------------------------------
function utils.log(message)
if config.enableLogging then
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
local logEntry = "[" .. timestamp .. "] " .. message
-- Write to console
print(logEntry)
-- Write to file
local file = fs.open(config.logFile, "a")
if file then
file.writeLine(logEntry)
file.close()
end
end
end
---------------------------------------------
-- ADDRESS UTILITIES
---------------------------------------------
function utils.addressToTable(address)
if type(address) == "table" then
return address
end
return {}
end
function utils.compareAddresses(addr1, addr2)
addr1 = gate.addressToString(addr1)
addr2 = gate.addressToString(addr2)
return addr1 == addr2
end
function utils.deepcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[utils.deepcopy(orig_key)] = utils.deepcopy(orig_value)
end
setmetatable(copy, utils.deepcopy(getmetatable(orig)))
else
copy = orig
end
return copy
end
function utils.isAddressInList(address, list)
for _, entry in ipairs(list) do
local listAddr = entry[2]
local tmp = utils.deepcopy(listAddr)
table.remove(tmp) -- Remove point of origin
if utils.compareAddresses(address, tmp) then
return true, entry[1]
end
end
return false, nil
end
function utils.isAddressAllowed(address)
-- Check blacklist first
local isBlacklisted, blackName = utils.isAddressInList(address, config.blacklist)
if isBlacklisted then
return false, "Blacklisted: " .. blackName
end
-- If whitelist is not empty, check whitelist
if #config.whitelist > 0 then
local isWhitelisted, whiteName = utils.isAddressInList(address, config.whitelist)
if isWhitelisted then
return true, "Whitelisted: " .. whiteName
else
return false, "Not on whitelist"
end
end
-- If no whitelist, allow all non-blacklisted
return true, "Allowed"
end
---------------------------------------------
-- IRIS CONTROL
---------------------------------------------
function utils.closeIris()
if config.irisEnabled then
gate.closeIris()
utils.log("Iris closed")
return true
end
return false
end
function utils.openIris()
if config.irisEnabled then
gate.openIris()
utils.log("Iris opened")
return true
end
return false
end
function utils.getIrisState()
if config.irisEnabled then
local progress = gate.getIrisProgressPercentage()
if progress == 0 then
return "OPEN"
elseif progress == 100 then
return "CLOSED"
else
return "MOVING"
end
end
return "NO IRIS"
end
return utils