-- 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)