Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- pastebin ID: Qky674zS
- -- URL: https://pastebin.com/Qky674zS
- -- Central Server: GPS Host + Simple Mainframe Server
- -- Runs GPS host and a basic listening server in parallel
- -- Default GPS coordinates (fallback if GPS not available)
- local DEFAULT_GPS_X = -401
- local DEFAULT_GPS_Y = 66
- local DEFAULT_GPS_Z = -1007
- -- Actual GPS coordinates (will be determined at startup)
- local GPS_X, GPS_Y, GPS_Z
- -- Turtle location tracking
- local turtleLocations = {}
- local LOCATIONS_FILE = "turtle_locations.json"
- -- Precious block tracking
- local preciousReports = {}
- local PRECIOUS_FILE = "precious_reports.json"
- -- Function to save turtle locations to disk
- local function saveLocations()
- local file = fs.open(LOCATIONS_FILE, "w")
- if file then
- file.write(textutils.serialize(turtleLocations))
- file.close()
- end
- end
- -- Function to load turtle locations from disk
- local function loadLocations()
- if fs.exists(LOCATIONS_FILE) then
- local file = fs.open(LOCATIONS_FILE, "r")
- if file then
- local data = file.readAll()
- file.close()
- if data and data ~= "" then
- turtleLocations = textutils.unserialize(data) or {}
- print("Mainframe: Loaded " .. #turtleLocations .. " turtle locations from disk")
- end
- end
- end
- end
- -- Function to save precious block reports to disk
- local function savePreciousReports()
- local file = fs.open(PRECIOUS_FILE, "w")
- if file then
- file.write(textutils.serialize(preciousReports))
- file.close()
- end
- end
- -- Function to load precious block reports from disk
- local function loadPreciousReports()
- if fs.exists(PRECIOUS_FILE) then
- local file = fs.open(PRECIOUS_FILE, "r")
- if file then
- local data = file.readAll()
- file.close()
- if data and data ~= "" then
- preciousReports = textutils.unserialize(data) or {}
- local totalReports = 0
- for turtleId, reports in pairs(preciousReports) do
- totalReports = totalReports + #reports
- end
- print("Mainframe: Loaded " .. totalReports .. " precious block reports from disk")
- end
- end
- end
- end
- -- Function to calculate 3D distance between two points
- local function calculateDistance(x1, y1, z1, x2, y2, z2)
- return math.sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2)
- end
- -- Function to clean block name by removing everything before ':'
- local function cleanBlockName(blockName)
- if not blockName then return "unknown" end
- local colonPos = string.find(blockName, ":")
- if colonPos then
- return string.sub(blockName, colonPos + 1)
- else
- return blockName
- end
- end
- -- Function to open modem for the mainframe server
- local function openModem()
- local sides = {"left", "right", "top", "bottom", "front", "back"}
- for _, side in ipairs(sides) do
- if peripheral.getType(side) == "modem" then
- rednet.open(side)
- print("Mainframe: Modem opened on " .. side)
- return true
- end
- end
- return false
- end
- -- Function to determine GPS coordinates
- local function determineGPSCoordinates()
- print("Central Server: Attempting to get GPS coordinates...")
- local x, y, z = gps.locate(5) -- Wait up to 5 seconds for GPS fix
- if x and y and z then
- GPS_X, GPS_Y, GPS_Z = x, y, z
- print("Central Server: GPS coordinates obtained: (" .. GPS_X .. ", " .. GPS_Y .. ", " .. GPS_Z .. ")")
- else
- GPS_X, GPS_Y, GPS_Z = DEFAULT_GPS_X, DEFAULT_GPS_Y, DEFAULT_GPS_Z
- print("Central Server: GPS not available, using default coordinates: (" .. GPS_X .. ", " .. GPS_Y .. ", " .. GPS_Z .. ")")
- end
- end
- -- GPS Host function
- local function runGPSHost()
- print("GPS Host: Starting at coordinates (" .. GPS_X .. ", " .. GPS_Y .. ", " .. GPS_Z .. ")")
- shell.run("gps", "host", GPS_X, GPS_Y, GPS_Z)
- end
- -- Simple mainframe server function
- local function runMainframeServer()
- if not openModem() then
- print("Mainframe: No modem found!")
- return
- end
- -- Load existing location data and precious reports
- loadLocations()
- loadPreciousReports()
- print("Mainframe: Listening for turtle reports...")
- while true do
- local senderId, message = rednet.receive()
- print("Mainframe: Received from turtle " .. senderId .. ": " .. tostring(message))
- -- Handle different message types
- if message == "discover_mainframe" then
- -- Respond to mainframe discovery broadcasts
- rednet.send(senderId, "mainframe_here")
- print("Mainframe: Responded to discovery request from " .. senderId)
- elseif type(message) == "table" then
- if message.type == "location" and message.x and message.y and message.z then
- -- Store turtle location
- turtleLocations[senderId] = {
- x = message.x,
- y = message.y,
- z = message.z,
- timestamp = os.date("%Y-%m-%d %H:%M:%S")
- }
- saveLocations() -- Persist to disk
- print("Mainframe: Updated location for turtle " .. senderId .. " to (" .. message.x .. ", " .. message.y .. ", " .. message.z .. ")")
- -- No acknowledgment sent back to turtle
- elseif message.type == "precious" and message.blockName and message.x and message.y and message.z then
- -- Store precious block report (avoid duplicates)
- if not preciousReports[senderId] then
- preciousReports[senderId] = {}
- end
- -- Check for duplicate report (same turtle, same block, within 2 blocks distance)
- local isDuplicate = false
- for _, report in ipairs(preciousReports[senderId]) do
- if report.blockName == message.blockName then
- local distance = calculateDistance(report.x, report.y, report.z, message.x, message.y, message.z)
- if distance < 2 then
- isDuplicate = true
- break
- end
- end
- end
- if not isDuplicate then
- local cleanedBlockName = cleanBlockName(message.blockName)
- table.insert(preciousReports[senderId], {
- blockName = message.blockName, -- Store original for duplicate checking
- cleanedBlockName = cleanedBlockName, -- Store cleaned for display
- x = message.x,
- y = message.y,
- z = message.z,
- timestamp = os.date("%Y-%m-%d %H:%M:%S")
- })
- savePreciousReports() -- Persist to disk
- print("Mainframe: Precious block report from turtle " .. senderId .. ": " .. cleanedBlockName .. " at (" .. message.x .. ", " .. message.y .. ", " .. message.z .. ")")
- -- No acknowledgment sent back to turtle
- else
- -- Don't send acknowledgment for duplicate reports either
- print("Mainframe: Duplicate precious block report ignored from turtle " .. senderId)
- end
- else
- -- Echo other table messages back
- rednet.send(senderId, "Echo: " .. textutils.serialize(message))
- end
- elseif message == "get_locations" then
- -- Send back all turtle locations
- rednet.send(senderId, turtleLocations)
- elseif type(message) == "string" and (message == "get_precious" or message:match("^get_precious$") or message:match("^get_precious %-%-timestamp$")) then
- -- Send back all precious block reports
- local showTimestamp = string.find(message, "--timestamp") ~= nil
- local allFormattedReports = {}
- for turtleId, reports in pairs(preciousReports) do
- local turtleReports = {}
- for _, report in ipairs(reports) do
- local displayName = report.cleanedBlockName or cleanBlockName(report.blockName)
- local reportStr = displayName .. " at (" .. report.x .. ", " .. report.y .. ", " .. report.z .. ")"
- if showTimestamp then
- reportStr = reportStr .. " [" .. report.timestamp .. "]"
- end
- table.insert(turtleReports, reportStr)
- end
- if #turtleReports > 0 then
- allFormattedReports["turtle_" .. turtleId] = turtleReports
- end
- end
- rednet.send(senderId, allFormattedReports)
- elseif type(message) == "string" and message:match("^get_location ") then
- -- Get location for specific turtle
- local targetId = tonumber(message:match("get_location (%d+)"))
- if targetId and turtleLocations[targetId] then
- rednet.send(senderId, turtleLocations[targetId])
- else
- rednet.send(senderId, "Turtle not found or no location data")
- end
- elseif type(message) == "string" and message:match("^get_precious ") then
- -- Get precious reports for specific turtle
- local parts = {}
- for part in message:gmatch("%S+") do
- table.insert(parts, part)
- end
- local targetId = tonumber(parts[2])
- local showTimestamp = false
- -- Check for --timestamp flag
- for i = 3, #parts do
- if parts[i] == "--timestamp" then
- showTimestamp = true
- break
- end
- end
- if targetId and preciousReports[targetId] then
- local formattedReports = {}
- for _, report in ipairs(preciousReports[targetId]) do
- local displayName = report.cleanedBlockName or cleanBlockName(report.blockName)
- local reportStr = displayName .. " at (" .. report.x .. ", " .. report.y .. ", " .. report.z .. ")"
- if showTimestamp then
- reportStr = reportStr .. " [" .. report.timestamp .. "]"
- end
- table.insert(formattedReports, reportStr)
- end
- rednet.send(senderId, formattedReports)
- else
- rednet.send(senderId, "No precious block reports for turtle " .. (targetId or "unknown"))
- end
- elseif type(message) == "string" and message:match("^scrub_precious ") then
- -- Clear precious reports for specific turtle
- local targetId = tonumber(message:match("scrub_precious (%d+)"))
- if targetId then
- local count = preciousReports[targetId] and #preciousReports[targetId] or 0
- preciousReports[targetId] = nil
- savePreciousReports()
- print("Mainframe: Scrubbed " .. count .. " precious block reports for turtle " .. targetId)
- rednet.send(senderId, "Scrubbed " .. count .. " precious block reports for turtle " .. targetId)
- else
- rednet.send(senderId, "Invalid turtle ID for scrub command")
- end
- else
- -- Echo the message back
- rednet.send(senderId, "Echo: " .. tostring(message))
- end
- end
- end
- -- Main execution
- print("=== Central Server Starting ===")
- -- Determine GPS coordinates first
- determineGPSCoordinates()
- print("Running GPS Host and Mainframe Server in parallel...")
- -- Run both services in parallel
- parallel.waitForAll(runGPSHost, runMainframeServer)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement