-- nanomachine_server.lua local component = require("component") local event = require("event") local serialization = require("serialization") local filesystem = require("filesystem") -- Config local PORT = 2000 local UPDATE_INTERVAL = 1 local SAVE_FILE = "/home/nanomachine_data.cfg" -- Components local modem = component.modem local nano = component.nanomachines -- State Management local state = { power = 0, maxPower = 0, health = 0, maxHealth = 20, hunger = 0, activeInputs = 0, totalInputs = 0, activeEffects = 0, currentProfile = nil, autoProtect = false, healthThreshold = 10, hungerThreshold = 6, discoveryActive = false, discoveryProgress = 0, discoveryTested = 0, discoveryFound = 0, lastUpdate = 0 } -- Data Storage local profiles = {} local inputStates = {} local discoveredEffects = {} local discoveryQueue = {} local discoveryIndex = 1 -- Initialize local function initialize() print("=== NANOMACHINE SERVER INITIALIZING ===") print("") modem.open(PORT) print("✓ Modem listening on port " .. PORT) print("✓ Server Address: " .. modem.address) print("") -- Check for nanomachines if not nano then print("⚠ WARNING: No nanomachines component found!") print("Make sure nanomachines are installed and connected.") return false end print("✓ Nanomachines detected") -- Get total inputs state.totalInputs = nano.getInputCount() print("✓ Total inputs: " .. state.totalInputs) -- Initialize input states for i = 1, state.totalInputs do inputStates[i] = { id = i, active = false, lastToggled = 0 } end -- Load saved data loadData() print("") print("=== SERVER READY ===") print("") return true end -- Save/Load Functions local function saveData() local data = { profiles = profiles, discoveredEffects = discoveredEffects, autoProtect = state.autoProtect, healthThreshold = state.healthThreshold, hungerThreshold = state.hungerThreshold } local file = io.open(SAVE_FILE, "w") if file then file:write(serialization.serialize(data)) file:close() print("[SAVE] Data saved successfully") return true else print("[ERROR] Failed to save data") return false end end local function loadData() if not filesystem.exists(SAVE_FILE) then print("[LOAD] No saved data found, starting fresh") -- Create default profiles profiles = { { name = "Combat", description = "Speed + Strength + Resistance", inputs = {} }, { name = "Mining", description = "Haste + Night Vision", inputs = {} }, { name = "Safe", description = "Regeneration only", inputs = {} } } return end local file = io.open(SAVE_FILE, "r") if file then local content = file:read("*a") file:close() local success, data = pcall(serialization.unserialize, content) if success and data then profiles = data.profiles or {} discoveredEffects = data.discoveredEffects or {} state.autoProtect = data.autoProtect or false state.healthThreshold = data.healthThreshold or 10 state.hungerThreshold = data.hungerThreshold or 6 print("[LOAD] Data loaded successfully") print(" Profiles: " .. #profiles) print(" Discovered Effects: " .. #discoveredEffects) else print("[ERROR] Failed to parse saved data") end end end -- Nanomachine Control Functions local function updateNanoStatus() if not nano then return end -- Get power state.power = nano.getPowerState() state.maxPower = nano.getMaxPower() -- Count active inputs state.activeInputs = 0 for i = 1, state.totalInputs do if nano.getInput(i) then inputStates[i].active = true state.activeInputs = state.activeInputs + 1 else inputStates[i].active = false end end -- Get active effects local effects = nano.getActiveEffects() state.activeEffects = effects and #effects or 0 state.lastUpdate = os.time() end local function setInput(inputId, active) if not nano or inputId < 1 or inputId > state.totalInputs then return false end nano.setInput(inputId, active) inputStates[inputId].active = active inputStates[inputId].lastToggled = os.time() print("[INPUT] Input " .. inputId .. " set to " .. (active and "ON" or "OFF")) return true end local function toggleInput(inputId) if not nano or inputId < 1 or inputId > state.totalInputs then return false end local currentState = nano.getInput(inputId) return setInput(inputId, not currentState) end local function disableAllInputs() print("[ACTION] Disabling all inputs...") for i = 1, state.totalInputs do setInput(i, false) end state.currentProfile = nil print("[ACTION] All inputs disabled") end -- Profile Management local function activateProfile(profileName) print("[PROFILE] Activating profile: " .. profileName) -- Find profile local profile = nil for _, p in ipairs(profiles) do if p.name == profileName then profile = p break end end if not profile then print("[ERROR] Profile not found: " .. profileName) return false end -- Disable all first disableAllInputs() -- Activate profile inputs if profile.inputs and #profile.inputs > 0 then for _, inputId in ipairs(profile.inputs) do setInput(inputId, true) end end state.currentProfile = profileName print("[PROFILE] Profile activated: " .. profileName) return true end local function createProfile(profileName) print("[PROFILE] Creating profile: " .. profileName) -- Get current active inputs local activeInputs = {} for i = 1, state.totalInputs do if inputStates[i].active then table.insert(activeInputs, i) end end -- Create profile local profile = { name = profileName, description = "Custom profile", inputs = activeInputs, created = os.time() } table.insert(profiles, profile) saveData() print("[PROFILE] Profile created with " .. #activeInputs .. " inputs") return true end local function deleteProfile(profileName) for i, profile in ipairs(profiles) do if profile.name == profileName then table.remove(profiles, i) saveData() print("[PROFILE] Deleted profile: " .. profileName) return true end end print("[ERROR] Profile not found: " .. profileName) return false end -- Auto-Protection System local function checkAutoProtection() if not state.autoProtect or not nano then return end -- Check health (would need player component or other method to get real health) -- This is a placeholder - you'd need to implement actual health checking -- For now, we'll use a simple low power protection if state.power < (state.maxPower * 0.2) then print("[AUTO-PROTECT] Low power detected, activating emergency profile") -- Could activate a specific safe profile here end end -- Discovery System local function initializeDiscovery() print("[DISCOVERY] Initializing discovery system...") discoveryQueue = {} -- Generate all possible single input combinations for i = 1, state.totalInputs do table.insert(discoveryQueue, {i}) end -- Generate all possible double input combinations for i = 1, state.totalInputs do for j = i + 1, state.totalInputs do table.insert(discoveryQueue, {i, j}) end end -- Could add triple combinations but that's a lot -- For 32 inputs: 32 + 496 + 4960 = 5488 combinations print("[DISCOVERY] Queue size: " .. #discoveryQueue .. " combinations") discoveryIndex = 1 state.discoveryTested = 0 state.discoveryFound = 0 end local function runDiscoveryStep() if not state.discoveryActive or discoveryIndex > #discoveryQueue then state.discoveryActive = false print("[DISCOVERY] Discovery complete!") saveData() return end local combination = discoveryQueue[discoveryIndex] -- Disable all inputs for i = 1, state.totalInputs do setInput(i, false) end -- Wait a bit for effects to clear os.sleep(0.5) -- Enable combination for _, inputId in ipairs(combination) do setInput(inputId, true) end -- Wait for effects to activate os.sleep(1) -- Check for effects local effects = nano.getActiveEffects() if effects and #effects > 0 then local effectData = { combination = combination, effects = effects, discovered = os.time() } table.insert(discoveredEffects, effectData) state.discoveryFound = state.discoveryFound + 1 print("[DISCOVERY] Found effects: " .. table.concat(effects, ", ")) print(" Inputs: " .. table.concat(combination, ", ")) end state.discoveryTested = state.discoveryTested + 1 state.discoveryProgress = math.floor((discoveryIndex / #discoveryQueue) * 100) discoveryIndex = discoveryIndex + 1 end -- Message Handler local function handleMessage(sender, port, distance, command, data) print("[REQUEST] " .. command .. " from " .. sender:sub(1, 8)) if command == "GET_STATUS" then local serialized = serialization.serialize(state) modem.send(sender, PORT, "GET_STATUS_RESPONSE", serialized) elseif command == "GET_PROFILES" then local serialized = serialization.serialize(profiles) modem.send(sender, PORT, "GET_PROFILES_RESPONSE", serialized) elseif command == "GET_INPUTS" then local serialized = serialization.serialize(inputStates) modem.send(sender, PORT, "GET_INPUTS_RESPONSE", serialized) elseif command == "ACTIVATE_PROFILE" then activateProfile(data) modem.send(sender, PORT, "ACK") elseif command == "CREATE_PROFILE" then createProfile(data) modem.send(sender, PORT, "ACK") elseif command == "DELETE_PROFILE" then deleteProfile(data) modem.send(sender, PORT, "ACK") elseif command == "TOGGLE_INPUT" then toggleInput(data) modem.send(sender, PORT, "ACK") elseif command == "DISABLE_ALL" then disableAllInputs() modem.send(sender, PORT, "ACK") elseif command == "EMERGENCY_STOP" then disableAllInputs() state.autoProtect = false state.discoveryActive = false print("[EMERGENCY] Emergency stop activated!") modem.send(sender, PORT, "ACK") elseif command == "TOGGLE_AUTO" then state.autoProtect = not state.autoProtect saveData() print("[AUTO-PROTECT] " .. (state.autoProtect and "ENABLED" or "DISABLED")) modem.send(sender, PORT, "ACK") elseif command == "SET_HEALTH_THRESHOLD" then state.healthThreshold = data saveData() print("[SETTING] Health threshold set to " .. data) modem.send(sender, PORT, "ACK") elseif command == "SET_HUNGER_THRESHOLD" then state.hungerThreshold = data saveData() print("[SETTING] Hunger threshold set to " .. data) modem.send(sender, PORT, "ACK") elseif command == "START_DISCOVERY" then initializeDiscovery() state.discoveryActive = true print("[DISCOVERY] Discovery started") modem.send(sender, PORT, "ACK") elseif command == "PAUSE_DISCOVERY" then state.discoveryActive = false print("[DISCOVERY] Discovery paused") modem.send(sender, PORT, "ACK") elseif command == "RESET_DISCOVERY" then initializeDiscovery() state.discoveryActive = true print("[DISCOVERY] Discovery reset and restarted") modem.send(sender, PORT, "ACK") elseif command == "PING" then modem.send(sender, PORT, "PONG") else modem.send(sender, PORT, "ERROR") end end -- Status Display local function displayStatus() print("╔═══════════════════════════════════════════════╗") print("║ NANOMACHINE SERVER STATUS ║") print("╚═══════════════════════════════════════════════╝") print("") print("Server: " .. modem.address:sub(1, 8) .. "...") print("Port: " .. PORT) print("") print("Power: " .. state.power .. "/" .. state.maxPower) print("Active Inputs: " .. state.activeInputs .. "/" .. state.totalInputs) print("Active Effects: " .. state.activeEffects) print("") print("Current Profile: " .. (state.currentProfile or "None")) print("Auto-Protect: " .. (state.autoProtect and "ENABLED" or "DISABLED")) print("") if state.discoveryActive then print("Discovery: ACTIVE") print(" Progress: " .. state.discoveryProgress .. "%") print(" Tested: " .. state.discoveryTested) print(" Found: " .. state.discoveryFound .. " effects") else print("Discovery: IDLE") print(" Total Discovered: " .. #discoveredEffects .. " effects") end print("") print("Profiles: " .. #profiles) print("") print("Press Ctrl+C to stop server") print("───────────────────────────────────────────────") end -- Main Loop local function main() if not initialize() then print("Failed to initialize server") return end local lastStatusDisplay = 0 local lastDataUpdate = 0 local lastAutoCheck = 0 local lastDiscoveryStep = 0 while true do local currentTime = os.time() -- Update nanomachine status if currentTime - lastDataUpdate >= UPDATE_INTERVAL then updateNanoStatus() lastDataUpdate = currentTime end -- Check auto-protection if currentTime - lastAutoCheck >= 2 then checkAutoProtection() lastAutoCheck = currentTime end -- Run discovery step if state.discoveryActive and currentTime - lastDiscoveryStep >= 2 then runDiscoveryStep() lastDiscoveryStep = currentTime end -- Display status if currentTime - lastStatusDisplay >= 5 then displayStatus() lastStatusDisplay = currentTime end -- Handle messages local _, _, sender, port, distance, command, data = event.pull(0.1, "modem_message") if command then handleMessage(sender, port, distance, command, data) end end end -- Cleanup local function cleanup() print("") print("=== SERVER SHUTTING DOWN ===") -- Save data saveData() -- Close modem modem.close(PORT) print("✓ Server stopped") end -- Error handling local success, err = xpcall(main, debug.traceback) if not success then print("") print("ERROR: " .. tostring(err)) end cleanup()