-- 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)
Comments
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|0 👍
/0 👎
0 B
|👍
/👎