--[[ VoidAI - Self Learning Roblox AI Companion Version: 1.0.0 Author: Taz / TheStrongestOfTomorrow Features: - Observer Mode (learns movement, UI, sequences) - Per-universe brain files with per-place entries - Ghost Mode (client-side AI playback) - Lend Mode (AI takes full input control) - LLM Mode (Claude / ChatGPT / Gemini with brain context) - GUI Panel with minimize to draggable button - PC Keybinds (rebindable) + Mobile floating buttons - Platform auto-detection - Hotkey/tap reclaim control - AI Confidence Meter - Session Replay Viewer - Persona Profiles - Stats Dashboard - Stealth Mode - Schedule Mode - Threat Detection Mode - Mental Map - Adaptive Learning Cooldown - Place Transition Continuity - Base Knowledge embedded - Universal Executor Compatibility - LLM gate (requires trained brain) ]] -- ============================================================ -- SECTION 1: SERVICES -- ============================================================ local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local TweenService = game:GetService("TweenService") local TeleportService = game:GetService("TeleportService") local HttpService = game:GetService("HttpService") local GuiService = game:GetService("GuiService") local StarterGui = game:GetService("StarterGui") local LocalPlayer = Players.LocalPlayer local PlayerGui = LocalPlayer:WaitForChild("PlayerGui") local Camera = workspace.CurrentCamera -- ============================================================ -- SECTION 2: PLATFORM DETECTION -- ============================================================ local isMobile = UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled local isPC = not isMobile -- ============================================================ -- SECTION 3: EXECUTOR COMPATIBILITY LAYER -- ============================================================ local Exec = {} -- File system function Exec.readFile(path) if readfile then local ok, result = pcall(readfile, path) if ok then return result end end return nil end function Exec.writeFile(path, data) if writefile then pcall(writefile, path, data) return true end return false end function Exec.appendFile(path, data) if appendfile then pcall(appendfile, path, data) return true elseif writefile then local existing = Exec.readFile(path) or "" pcall(writefile, path, existing .. data) return true end return false end function Exec.isFile(path) if isfile then local ok, result = pcall(isfile, path) return ok and result elseif readfile then local ok = pcall(readfile, path) return ok end return false end function Exec.makeFolder(path) if makefolder then if isfolder then local ok, exists = pcall(isfolder, path) if not (ok and exists) then pcall(makefolder, path) end else pcall(makefolder, path) end end end function Exec.isFolder(path) if isfolder then local ok, result = pcall(isfolder, path) return ok and result end return false end function Exec.listFiles(path) if listfiles then local ok, result = pcall(listfiles, path) if ok then return result end end return {} end -- Input simulation fallback chain function Exec.mouseClick() if mouse1click then pcall(mouse1click) elseif Input and Input.click then pcall(Input.click) end end function Exec.mouseMove(x, y) if mousemoveabs then pcall(mousemoveabs, x, y) elseif mousemoverel then pcall(mousemoverel, x, y) end end function Exec.keyPress(keycode) if keypress then pcall(keypress, keycode) elseif Input and Input.keypress then pcall(Input.keypress, keycode) end end function Exec.keyRelease(keycode) if keyrelease then pcall(keyrelease, keycode) elseif Input and Input.keyrelease then pcall(Input.keyrelease, keycode) end end function Exec.fireButton(button) -- Universal UI click fallback - works on all executors + mobile if button and button:IsA("GuiButton") then pcall(function() button:FireMouseButton1Click() end) end end -- HTTP for LLM calls function Exec.httpPost(url, headers, body) -- Try syn.request first (Synapse), then request (most executors), then HttpService if syn and syn.request then local ok, res = pcall(syn.request, { Url = url, Method = "POST", Headers = headers, Body = body }) if ok then return res end end if request then local ok, res = pcall(request, { Url = url, Method = "POST", Headers = headers, Body = body }) if ok then return res end end if http and http.request then local ok, res = pcall(http.request, { Url = url, Method = "POST", Headers = headers, Body = body }) if ok then return res end end -- Fallback: HttpService (limited but better than nothing) local ok, res = pcall(function() return HttpService:RequestAsync({ Url = url, Method = "POST", Headers = headers, Body = body }) end) if ok then return res end return nil end -- ============================================================ -- SECTION 4: BASE KNOWLEDGE (EMBEDDED) -- ============================================================ local BASE_KNOWLEDGE = { version = "1.0", pc = { movement = { forward = Enum.KeyCode.W, backward = Enum.KeyCode.S, left = Enum.KeyCode.A, right = Enum.KeyCode.D, jump = Enum.KeyCode.Space, sprint = Enum.KeyCode.LeftShift, }, camera = "MouseDelta", }, mobile = { movement = "ThumbstickPosition", jump = "JumpButton", camera = "TouchDelta", }, commonUI = { playButton = {"Play", "Start", "Begin", "PlayButton", "StartButton"}, exitButton = {"Exit", "Leave", "Quit", "Back"}, confirmButton= {"Confirm", "Yes", "OK", "Accept"}, shopButton = {"Shop", "Store", "Buy"}, }, horrorDefaults = { threatKeywords = { "Entity", "Monster", "Rush", "Ambush", "Halt", "Eyes", "Figure", "Seek", "Screech", "Dupe", "Jack", "Hide", "Timothy", "El Goblino", }, safeObjects = {"Locker", "Bed", "Cabinet", "Closet"}, runTriggers = {"Roar", "Scream", "Chase"}, } } -- ============================================================ -- SECTION 5: BRAIN FILE SYSTEM -- ============================================================ local BRAIN_FOLDER = "VoidAI" local CONFIG_FILE = "VoidAI/config.json" local Brain = {} local BrainPath = "" local ActivePlace = "" local function getUniverseId() local ok, id = pcall(function() return game.GameId end) return ok and tostring(id) or tostring(game.PlaceId) end local function getPlaceId() return tostring(game.PlaceId) end local function getGameName() local ok, name = pcall(function() return MarketplaceService:GetProductInfo(game.PlaceId).Name end) if ok and name then return name end return "UnknownGame_" .. game.PlaceId end local function getBrainPath() return BRAIN_FOLDER .. "/universe_" .. getUniverseId() .. ".json" end local function newPlaceEntry(placeName) return { placeName = placeName or ("Place_" .. getPlaceId()), sessions = {}, mentalMap = { landmarks = {}, safeZones = {}, dangerZones = {}, itemSpawns = {}, exits = {}, }, confidence = { movement = 0, ui = 0, sequences = 0, }, topUIButtons = {}, totalActions = 0, totalPlaytime = 0, lastUpdated = os.time(), } end local function newBrainFile() return { version = "1.0", universeId = getUniverseId(), baseKnowledge = BASE_KNOWLEDGE, places = {}, config = { activeProvider = "local", apiKeys = { claude = "", chatgpt = "", gemini = "" }, activePersona = "Mirror", keybinds = { reclaim = "F", toggleObs = "G", toggleLend= "H", toggleGUI = "J", }, scheduleEnabled = false, scheduleStartMin = 0, scheduleDuration = 30, stealthMode = false, }, totalSessions = 0, createdAt = os.time(), lastUpdated = os.time(), } end local function saveBrain() if not Brain or not BrainPath or BrainPath == "" then return end Brain.lastUpdated = os.time() local ok, encoded = pcall(HttpService.JSONEncode, HttpService, Brain) if ok then Exec.writeFile(BrainPath, encoded) end end local function loadBrain() Exec.makeFolder(BRAIN_FOLDER) BrainPath = getBrainPath() ActivePlace = getPlaceId() if Exec.isFile(BrainPath) then local raw = Exec.readFile(BrainPath) if raw and raw ~= "" then local ok, decoded = pcall(HttpService.JSONDecode, HttpService, raw) if ok and decoded then Brain = decoded -- Ensure base knowledge is always up to date Brain.baseKnowledge = BASE_KNOWLEDGE -- Ensure this place entry exists if not Brain.places[ActivePlace] then Brain.places[ActivePlace] = newPlaceEntry() end return true end end end -- New brain Brain = newBrainFile() Brain.places[ActivePlace] = newPlaceEntry() saveBrain() return false end local function getCurrentPlace() if Brain and Brain.places and Brain.places[ActivePlace] then return Brain.places[ActivePlace] end return nil end -- ============================================================ -- SECTION 6: CONFIG SYSTEM -- ============================================================ local Config = {} local function loadConfig() if Exec.isFile(CONFIG_FILE) then local raw = Exec.readFile(CONFIG_FILE) if raw and raw ~= "" then local ok, decoded = pcall(HttpService.JSONDecode, HttpService, raw) if ok then Config = decoded return end end end Config = { apiKeys = { claude = "", chatgpt = "", gemini = "" }, activeProvider= "local", activePersona = "Mirror", stealthMode = false, keybinds = { reclaim = "F", toggleObs = "G", toggleLend = "H", toggleGUI = "J", } } end local function saveConfig() local ok, encoded = pcall(HttpService.JSONEncode, HttpService, Config) if ok then Exec.writeFile(CONFIG_FILE, encoded) end end -- ============================================================ -- SECTION 7: ADAPTIVE COOLDOWN + FPS MONITOR -- ============================================================ local FPS = 60 local LearnCooldown = 0.1 local lastFPSUpdate = 0 local frameCount = 0 local function updateFPS(dt) frameCount += 1 lastFPSUpdate += dt if lastFPSUpdate >= 1 then FPS = frameCount frameCount = 0 lastFPSUpdate = 0 -- Adaptive cooldown based on FPS if FPS > 50 then LearnCooldown = 0.1 -- High end: fast learning elseif FPS >= 30 then LearnCooldown = 0.3 -- Mid range: balanced elseif FPS >= 15 then LearnCooldown = 0.7 -- Low end: stable else LearnCooldown = 1.5 -- Potato mode: survive end end end -- ============================================================ -- SECTION 8: AI STATE -- ============================================================ local AIState = { mode = "idle", -- idle | observing | ghost | lend | llm isLearning = false, isPaused = false, isStealth = false, persona = "Mirror", -- Mirror | Aggressive | Passive currentSession = nil, sessionStart = 0, lastLearnTick = 0, lastSaveTick = 0, tickCounter = 0, -- For throttling low-priority sampling llmProvider = "gemini", llmCooldown = 0, threatDetected = false, threatCooldown = 0, reclaimPending = false, scheduleTimer = 0, scheduleActive = false, } local PERSONAS = { Mirror = { aggressionBias = 0.5, grindBias = 0.5, explorationBias = 0.5 }, Aggressive = { aggressionBias = 0.9, grindBias = 0.3, explorationBias = 0.7 }, Passive = { aggressionBias = 0.1, grindBias = 0.9, explorationBias = 0.3 }, } -- ============================================================ -- SECTION 9: OBSERVER - DATA RECORDING -- ============================================================ local Observer = {} Observer.lastPosition = Vector3.new(0,0,0) Observer.pendingBatch = {} Observer.batchFlushInterval = 30 -- seconds function Observer.startSession() AIState.currentSession = { id = os.time(), placeId = getPlaceId(), starred = false, priority = 1, actions = {}, movements = {}, uiClicks = {}, sequences = {}, startTime = os.time(), endTime = nil, notes = "", } AIState.sessionStart = os.time() end function Observer.endSession() if not AIState.currentSession then return end AIState.currentSession.endTime = os.time() local place = getCurrentPlace() if place then table.insert(place.sessions, AIState.currentSession) place.totalPlaytime += (os.time() - AIState.sessionStart) Observer.updateConfidence(place) saveBrain() end AIState.currentSession = nil end function Observer.recordMovement(pos) if not AIState.currentSession then return end local delta = (pos - Observer.lastPosition).Magnitude if delta < 2 then return end -- Ignore micro-movements Observer.lastPosition = pos local entry = { pos = { x = pos.X, y = pos.Y, z = pos.Z }, t = os.time() - AIState.sessionStart, } table.insert(AIState.currentSession.movements, entry) table.insert(AIState.currentSession.actions, { type = "move", data = entry }) -- Update mental map Observer.updateMentalMap(pos) end function Observer.recordUIClick(buttonName, buttonPath) if not AIState.currentSession then return end local entry = { name = buttonName, path = buttonPath or "", t = os.time() - AIState.sessionStart, } table.insert(AIState.currentSession.uiClicks, entry) table.insert(AIState.currentSession.actions, { type = "ui_click", data = entry }) -- Update top UI buttons tally local place = getCurrentPlace() if place then place.topUIButtons[buttonName] = (place.topUIButtons[buttonName] or 0) + 1 place.totalActions += 1 end end function Observer.recordSequence(label) if not AIState.currentSession then return end table.insert(AIState.currentSession.sequences, { label = label, t = os.time() - AIState.sessionStart, actionIndex = #AIState.currentSession.actions, }) end function Observer.updateConfidence(place) local sessions = place.sessions local n = #sessions if n == 0 then return end local totalMoves, totalUI, totalSeq = 0, 0, 0 for _, s in ipairs(sessions) do totalMoves += #(s.movements or {}) totalUI += #(s.uiClicks or {}) totalSeq += #(s.sequences or {}) end -- Confidence grows logarithmically, capped at 100 local moveCap = math.min(100, math.floor(math.log(totalMoves + 1) * 15)) local uiCap = math.min(100, math.floor(math.log(totalUI + 1) * 20)) local seqCap = math.min(100, math.floor(math.log(totalSeq + 1) * 25)) place.confidence.movement = moveCap place.confidence.ui = uiCap place.confidence.sequences = seqCap end function Observer.updateMentalMap(pos) local place = getCurrentPlace() if not place then return end -- Only update every 10 ticks (very low priority) if AIState.tickCounter % 10 ~= 0 then return end local map = place.mentalMap local posKey = math.floor(pos.X/10) .. "_" .. math.floor(pos.Z/10) if not map.landmarks[posKey] then map.landmarks[posKey] = { pos = { x = pos.X, y = pos.Y, z = pos.Z }, tag = "visited", visits= 1, } else map.landmarks[posKey].visits += 1 -- High visit count = likely safe zone if map.landmarks[posKey].visits > 5 then map.landmarks[posKey].tag = "safe" end end end function Observer.tagCurrentZone(tag) local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") if not hrp then return end local pos = hrp.Position local place = getCurrentPlace() if not place then return end local posKey = math.floor(pos.X/10) .. "_" .. math.floor(pos.Z/10) if not place.mentalMap.landmarks[posKey] then place.mentalMap.landmarks[posKey] = { pos = { x = pos.X, y = pos.Y, z = pos.Z }, tag = tag, visits = 1, } else place.mentalMap.landmarks[posKey].tag = tag end end -- ============================================================ -- SECTION 10: THREAT DETECTION -- ============================================================ local ThreatDetector = {} function ThreatDetector.scan() local place = getCurrentPlace() local keywords = BASE_KNOWLEDGE.horrorDefaults.threatKeywords -- Extend with any game-specific keywords from brain if place and place.customThreatKeywords then for _, kw in ipairs(place.customThreatKeywords) do table.insert(keywords, kw) end end -- Scan workspace for threat entities by name for _, obj in ipairs(workspace:GetDescendants()) do local name = obj.Name:lower() for _, kw in ipairs(keywords) do if name:find(kw:lower()) then return true, obj.Name end end end -- Scan for players sprinting (3+ players suddenly running = threat) local runningCount = 0 for _, p in ipairs(Players:GetPlayers()) do if p ~= LocalPlayer and p.Character then local hum = p.Character:FindFirstChildOfClass("Humanoid") if hum and hum.WalkSpeed > 20 then runningCount += 1 end end end if runningCount >= 2 then return true, "MultiPlayerFlee" end return false, nil end function ThreatDetector.respondToThreat(threatName) AIState.threatDetected = true AIState.threatCooldown = 8 -- seconds of threat mode -- Tag current zone as danger Observer.tagCurrentZone("danger") -- Log threat in session if AIState.currentSession then table.insert(AIState.currentSession.actions, { type = "threat_detected", data = { name = threatName, t = os.time() - AIState.sessionStart } }) end -- If in lend/ghost mode, switch to survival behavior if AIState.mode == "lend" or AIState.mode == "ghost" then GhostController.runSurvivalPattern() end end -- ============================================================ -- SECTION 11: GHOST / LEND CONTROLLER -- ============================================================ local GhostController = {} GhostController.replayIndex = 1 GhostController.replaySession = nil GhostController.inputDisabled = false function GhostController.pickBestSession() local place = getCurrentPlace() if not place or #place.sessions == 0 then return nil end -- Prioritize starred sessions, then by action count local best = nil local bestScore = -1 for _, s in ipairs(place.sessions) do local score = #(s.actions or {}) * (s.priority or 1) if s.starred then score = score * 2 end if score > bestScore then bestScore = score best = s end end return best end -- Ghost avatar reference GhostController.ghostModel = nil function GhostController.spawnGhostAvatar() -- Destroy old ghost if any if GhostController.ghostModel then pcall(function() GhostController.ghostModel:Destroy() end) GhostController.ghostModel = nil end local char = LocalPlayer.Character if not char then return end -- Clone the player's character model local ghost = char:Clone() ghost.Name = "VoidAI_Ghost" -- Remove scripts, animate, humanoid state changes that could error for _, v in ipairs(ghost:GetDescendants()) do if v:IsA("Script") or v:IsA("LocalScript") or v:IsA("ModuleScript") then v:Destroy() end end -- Make every part semi-transparent ghostly blue for _, part in ipairs(ghost:GetDescendants()) do if part:IsA("BasePart") then part.Transparency = 0.55 part.CanCollide = false part.Anchored = false part.CastShadow = false -- Tint blue-white part.Color = Color3.fromRGB(140, 180, 255) part.Material = Enum.Material.Neon end -- Hide accessories/hats being weird if part:IsA("Decal") or part:IsA("SpecialMesh") then -- keep them, just let transparency handle it end end -- Put the ghost near the player local hrp = char:FindFirstChild("HumanoidRootPart") local ghostHRP = ghost:FindFirstChild("HumanoidRootPart") if hrp and ghostHRP then ghostHRP.CFrame = hrp.CFrame * CFrame.new(3, 0, 0) end -- Give it a name tag local billboard = Instance.new("BillboardGui") billboard.Size = UDim2.new(0, 80, 0, 20) billboard.StudsOffset = Vector3.new(0, 3, 0) billboard.AlwaysOnTop = false billboard.Parent = ghostHRP or ghost.PrimaryPart or ghost:FindFirstChildOfClass("BasePart") local tag = Instance.new("TextLabel") tag.Size = UDim2.new(1,0,1,0) tag.BackgroundTransparency = 1 tag.Text = "👻 VoidAI" tag.TextColor3 = Color3.fromRGB(160, 200, 255) tag.Font = Enum.Font.GothamBold tag.TextSize = 11 tag.Parent = billboard ghost.Parent = workspace GhostController.ghostModel = ghost return ghost end function GhostController.destroyGhostAvatar() if GhostController.ghostModel then pcall(function() GhostController.ghostModel:Destroy() end) GhostController.ghostModel = nil end end function GhostController.startGhost() GhostController.replaySession = GhostController.pickBestSession() if not GhostController.replaySession then VoidGUI.notify("No sessions to replay. Train the AI first!") return false end GhostController.replayIndex = 1 AIState.mode = "ghost" -- Spawn the ghost avatar GhostController.spawnGhostAvatar() VoidGUI.notify("👻 Ghost spawned!") return true end function GhostController.startLend() GhostController.replaySession = GhostController.pickBestSession() if not GhostController.replaySession then VoidGUI.notify("No sessions to replay. Train the AI first!") return false end GhostController.replayIndex = 1 GhostController.inputDisabled = true AIState.mode = "lend" -- Disable player input if isMobile then -- On mobile we directly control HumanoidRootPart, nothing to disable else -- Block keyboard/mouse by consuming input UserInputService.InputBegan:Connect(function(input, processed) if GhostController.inputDisabled and not AIState.reclaimPending then -- Allow reclaim key through end end) end return true end function GhostController.reclaim() GhostController.inputDisabled = false AIState.mode = "idle" AIState.reclaimPending = true GhostController.destroyGhostAvatar() VoidGUI.notify("Control reclaimed!") task.wait(0.1) AIState.reclaimPending = false end function GhostController.stepReplay() if not GhostController.replaySession then return end local actions = GhostController.replaySession.actions if not actions or #actions == 0 then return end if GhostController.replayIndex > #actions then GhostController.replayIndex = 1 -- Loop return end local action = actions[GhostController.replayIndex] GhostController.replayIndex += 1 if action.type == "move" then GhostController.executeMove(action.data) elseif action.type == "ui_click" then GhostController.executeUIClick(action.data) end end function GhostController.executeMove(data) local targetPos = Vector3.new(data.pos.x, data.pos.y, data.pos.z) -- In ghost mode: move the ghost avatar, NOT the real player if AIState.mode == "ghost" and GhostController.ghostModel then local ghost = GhostController.ghostModel local ghostHRP = ghost:FindFirstChild("HumanoidRootPart") local ghostHum = ghost:FindFirstChildOfClass("Humanoid") if ghostHRP and ghostHum then local speed = 16 if AIState.persona == "Aggressive" then speed = 24 elseif AIState.persona == "Passive" then speed = 14 end ghostHum.WalkSpeed = speed ghostHum:MoveTo(targetPos) elseif ghostHRP then -- Fallback: lerp CFrame if humanoid is gone ghostHRP.CFrame = CFrame.new(targetPos) end return end -- Lend / LLM mode: move the real character local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then return end if AIState.persona == "Aggressive" then hum.WalkSpeed = 24 elseif AIState.persona == "Passive" then hum.WalkSpeed = 14 else hum.WalkSpeed = 16 end hum:MoveTo(targetPos) end function GhostController.executeUIClick(data) -- Search PlayerGui for button by name local function searchGUI(parent, targetName) for _, child in ipairs(parent:GetDescendants()) do if child:IsA("GuiButton") and child.Name == targetName then return child end end return nil end local button = searchGUI(PlayerGui, data.name) if button then Exec.fireButton(button) end end function GhostController.runSurvivalPattern() local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then return end -- Find nearest tagged safe zone from mental map local place = getCurrentPlace() if not place then return end local nearest = nil local nearestDist = math.huge for _, landmark in pairs(place.mentalMap.landmarks) do if landmark.tag == "safe" then local lpos = Vector3.new(landmark.pos.x, landmark.pos.y, landmark.pos.z) local dist = (hrp.Position - lpos).Magnitude if dist < nearestDist then nearestDist = dist nearest = lpos end end end if nearest then hum.WalkSpeed = 24 -- Sprint to safety hum:MoveTo(nearest) else -- No safe zone known: run away from danger direction hum.WalkSpeed = 24 local runDir = hrp.CFrame.LookVector * -1 hum:MoveTo(hrp.Position + runDir * 20) end end -- ============================================================ -- SECTION 12: LLM CONTROLLER -- ============================================================ local LLMController = {} LLMController.isWaiting = false LLMController.callCooldown = 3 -- seconds between LLM calls local LLM_PROVIDERS = { claude = { url = "https://api.anthropic.com/v1/messages", model = "claude-opus-4-5", buildHeaders = function(key) return { ["Content-Type"] = "application/json", ["x-api-key"] = key, ["anthropic-version"] = "2023-06-01", } end, buildBody = function(prompt) return HttpService:JSONEncode({ model = "claude-opus-4-5", max_tokens = 512, messages = {{ role = "user", content = prompt }} }) end, parseResponse = function(body) local ok, decoded = pcall(HttpService.JSONDecode, HttpService, body) if ok and decoded.content and decoded.content[1] then return decoded.content[1].text end return nil end, }, chatgpt = { url = "https://api.openai.com/v1/chat/completions", model = "gpt-4o", buildHeaders = function(key) return { ["Content-Type"] = "application/json", ["Authorization"] = "Bearer " .. key, } end, buildBody = function(prompt) return HttpService:JSONEncode({ model = "gpt-4o", messages = {{ role = "user", content = prompt }}, max_tokens = 512, }) end, parseResponse = function(body) local ok, decoded = pcall(HttpService.JSONDecode, HttpService, body) if ok and decoded.choices and decoded.choices[1] then return decoded.choices[1].message.content end return nil end, }, gemini = { url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent", model = "gemini-pro", buildHeaders = function(key) return { ["Content-Type"] = "application/json", ["x-goog-api-key"]= key, } end, buildBody = function(prompt) return HttpService:JSONEncode({ contents = {{ parts = {{ text = prompt }} }} }) end, parseResponse = function(body) local ok, decoded = pcall(HttpService.JSONDecode, HttpService, body) if ok and decoded.candidates and decoded.candidates[1] then local parts = decoded.candidates[1].content.parts if parts and parts[1] then return parts[1].text end end return nil end, }, } function LLMController.canUseLLM() local place = getCurrentPlace() if not place then return false, "No brain loaded" end if not place.sessions or #place.sessions == 0 then return false, "No sessions trained for this game" end local totalActions = 0 for _, s in ipairs(place.sessions) do totalActions += #(s.actions or {}) end if totalActions == 0 then return false, "Sessions exist but no actions recorded" end local provider = Config.activeProvider if provider == "local" then return false, "No LLM provider selected" end local key = Config.apiKeys[provider] if not key or key == "" then return false, "No API key for " .. provider end return true, nil end function LLMController.buildPrompt(gameState) local place = getCurrentPlace() if not place then return nil end local safeZones, dangerZones = {}, {} for _, lm in pairs(place.mentalMap.landmarks) do if lm.tag == "safe" then table.insert(safeZones, string.format("(%.0f,%.0f,%.0f)", lm.pos.x, lm.pos.y, lm.pos.z)) elseif lm.tag == "danger" then table.insert(dangerZones, string.format("(%.0f,%.0f,%.0f)", lm.pos.x, lm.pos.y, lm.pos.z)) end end local topUI = {} for name, count in pairs(place.topUIButtons) do table.insert(topUI, name .. "(" .. count .. "x)") end return string.format([[ You are an AI controlling a Roblox character in %s. You have been trained by a human player and know this game. GAME KNOWLEDGE: - Sessions recorded: %d - Total actions learned: %d - Known safe zones: %s - Known danger zones: %s - Frequently clicked UI: %s - Confidence: Movement %d%%, UI %d%%, Sequences %d%% - Active persona: %s CURRENT SITUATION: - Character position: (%.1f, %.1f, %.1f) - Nearby players: %d - Threat detected: %s - Current mode: %s Respond ONLY with a JSON object. No explanation. No markdown. Just raw JSON. Use this exact format: {"action":"move","direction":"forward","duration":1.0,"next":null} Available actions: move, jump, sprint, click_ui, wait, hide, run_to_safety For click_ui, add "target":"ButtonName" For move, direction can be: forward, backward, left, right, or "to_safe_zone" ]], place.placeName, #place.sessions, place.totalActions, table.concat(safeZones, ", "), table.concat(dangerZones, ", "), table.concat(topUI, ", "), place.confidence.movement, place.confidence.ui, place.confidence.sequences, AIState.persona, gameState.pos.x, gameState.pos.y, gameState.pos.z, gameState.nearbyPlayers, tostring(gameState.threatDetected), AIState.mode ) end function LLMController.parseAction(responseText) if not responseText then return nil end -- Strip any accidental markdown local clean = responseText:gsub("```json", ""):gsub("```", ""):match("^%s*(.-)%s*$") local ok, action = pcall(HttpService.JSONDecode, HttpService, clean) if ok and action and action.action then return action end return nil end function LLMController.executeAction(action) if not action then return end local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if action.action == "move" then if hrp and hum then local dir = action.direction local moveVec = Vector3.new(0,0,0) if dir == "forward" then moveVec = hrp.CFrame.LookVector elseif dir == "backward" then moveVec = hrp.CFrame.LookVector * -1 elseif dir == "left" then moveVec = hrp.CFrame.RightVector * -1 elseif dir == "right" then moveVec = hrp.CFrame.RightVector elseif dir == "to_safe_zone" then GhostController.runSurvivalPattern() return end hum:MoveTo(hrp.Position + moveVec * 10) end elseif action.action == "jump" then if hum then hum.Jump = true end elseif action.action == "sprint" then if hum then hum.WalkSpeed = 24 end elseif action.action == "click_ui" then GhostController.executeUIClick({ name = action.target or "" }) elseif action.action == "hide" then -- Find nearest safe object (locker/cabinet) for _, obj in ipairs(workspace:GetDescendants()) do for _, safeObj in ipairs(BASE_KNOWLEDGE.horrorDefaults.safeObjects) do if obj.Name:find(safeObj) and obj:IsA("BasePart") then if hum then hum:MoveTo(obj.Position) end return end end end elseif action.action == "run_to_safety" then GhostController.runSurvivalPattern() elseif action.action == "wait" then task.wait(action.duration or 1) end end function LLMController.callLLM() if LLMController.isWaiting then return end local canUse, reason = LLMController.canUseLLM() if not canUse then VoidGUI.notify("LLM unavailable: " .. (reason or "unknown")) AIState.mode = "idle" return end local char = LocalPlayer.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local pos = hrp and hrp.Position or Vector3.new(0,0,0) local nearby = 0 for _, p in ipairs(Players:GetPlayers()) do if p ~= LocalPlayer and p.Character then local phrp = p.Character:FindFirstChild("HumanoidRootPart") if phrp and (phrp.Position - pos).Magnitude < 50 then nearby += 1 end end end local gameState = { pos = { x = pos.X, y = pos.Y, z = pos.Z }, nearbyPlayers = nearby, threatDetected = AIState.threatDetected, } local prompt = LLMController.buildPrompt(gameState) if not prompt then return end local provider = Config.activeProvider local prov = LLM_PROVIDERS[provider] if not prov then return end LLMController.isWaiting = true task.spawn(function() local headers = prov.buildHeaders(Config.apiKeys[provider]) local body = prov.buildBody(prompt) local response = Exec.httpPost(prov.url, headers, body) if response and response.Body then local text = prov.parseResponse(response.Body) local action = LLMController.parseAction(text) if action then LLMController.executeAction(action) else -- Fallback to local AI GhostController.stepReplay() end else -- No response: fallback to local GhostController.stepReplay() end LLMController.isWaiting = false end) end -- ============================================================ -- SECTION 13: PLACE TRANSITION HANDLING -- ============================================================ local function handlePlaceTransition() -- Save current session before transition if AIState.isLearning and AIState.currentSession then Observer.endSession() end saveBrain() -- Wait for new place to load task.wait(2) -- Re-initialize brain for new place local newPlaceId = getPlaceId() ActivePlace = newPlaceId if not Brain.places[ActivePlace] then Brain.places[ActivePlace] = newPlaceEntry() end if AIState.isLearning then Observer.startSession() end VoidGUI.notify("Transitioned to new place. Brain updated.") VoidGUI.updateDisplay() end -- Listen for teleport arrivals pcall(function() TeleportService.LocalPlayerArrivedFromTeleport:Connect(function() handlePlaceTransition() end) end) -- ============================================================ -- SECTION 14: UI EVENT HOOKS (Event-driven, zero polling cost) -- ============================================================ local UIHooks = {} local function hookUIClicks(parent) for _, obj in ipairs(parent:GetDescendants()) do if obj:IsA("GuiButton") then obj.MouseButton1Click:Connect(function() if AIState.isLearning and AIState.currentSession then Observer.recordUIClick(obj.Name, obj:GetFullName()) end end) end end parent.DescendantAdded:Connect(function(obj) if obj:IsA("GuiButton") then obj.MouseButton1Click:Connect(function() if AIState.isLearning and AIState.currentSession then Observer.recordUIClick(obj.Name, obj:GetFullName()) end end) end end) end -- Hook existing GUI task.spawn(function() task.wait(2) for _, gui in ipairs(PlayerGui:GetChildren()) do if gui:IsA("ScreenGui") and gui.Name ~= "VoidAIGui" then hookUIClicks(gui) end end PlayerGui.ChildAdded:Connect(function(gui) if gui:IsA("ScreenGui") and gui.Name ~= "VoidAIGui" then hookUIClicks(gui) end end) end) -- ============================================================ -- SECTION 15: KEYBIND SYSTEM (PC + Rebindable) -- ============================================================ local Keybinds = {} Keybinds.binds = { reclaim = Enum.KeyCode.F, toggleObs = Enum.KeyCode.G, toggleLend = Enum.KeyCode.H, toggleGUI = Enum.KeyCode.J, } local KEY_MAP = { F = Enum.KeyCode.F, G = Enum.KeyCode.G, H = Enum.KeyCode.H, J = Enum.KeyCode.J, K = Enum.KeyCode.K, L = Enum.KeyCode.L, Z = Enum.KeyCode.Z, X = Enum.KeyCode.X, C = Enum.KeyCode.C, V = Enum.KeyCode.V, B = Enum.KeyCode.B, N = Enum.KeyCode.N, M = Enum.KeyCode.M, R = Enum.KeyCode.R, T = Enum.KeyCode.T, Y = Enum.KeyCode.Y, U = Enum.KeyCode.U, I = Enum.KeyCode.I, O = Enum.KeyCode.O, P = Enum.KeyCode.P, } function Keybinds.setKey(action, keyName) if KEY_MAP[keyName] then Keybinds.binds[action] = KEY_MAP[keyName] if Config.keybinds then Config.keybinds[action] = keyName saveConfig() end end end if not isMobile then UserInputService.InputBegan:Connect(function(input, processed) if processed then return end if input.KeyCode == Keybinds.binds.reclaim then if AIState.mode == "lend" or AIState.mode == "ghost" or AIState.mode == "llm" then GhostController.reclaim() VoidGUI.updateDisplay() end elseif input.KeyCode == Keybinds.binds.toggleObs then if AIState.isLearning then AIState.isLearning = false Observer.endSession() VoidGUI.notify("Learning stopped") else AIState.isLearning = true Observer.startSession() VoidGUI.notify("Learning started") end VoidGUI.updateDisplay() elseif input.KeyCode == Keybinds.binds.toggleLend then if AIState.mode == "lend" then GhostController.reclaim() else GhostController.startLend() end VoidGUI.updateDisplay() elseif input.KeyCode == Keybinds.binds.toggleGUI then VoidGUI.toggle() end end) end -- ============================================================ -- SECTION 16: SCHEDULE MODE -- ============================================================ local function updateSchedule(dt) if not Config.scheduleEnabled then return end AIState.scheduleTimer += dt local startSec = (Config.scheduleStartMin or 0) * 60 local durSec = (Config.scheduleDuration or 30) * 60 if not AIState.scheduleActive and AIState.scheduleTimer >= startSec then AIState.scheduleActive = true GhostController.startLend() VoidGUI.notify("Schedule: Lend Mode started") end if AIState.scheduleActive and AIState.scheduleTimer >= startSec + durSec then AIState.scheduleActive = false GhostController.reclaim() AIState.scheduleTimer = 0 VoidGUI.notify("Schedule: Session complete") end end -- ============================================================ -- SECTION 17: MAIN LOOP -- ============================================================ local lastLearnTick = 0 local lastSaveTick = 0 local lastThreatTick= 0 local lastLLMTick = 0 RunService.Heartbeat:Connect(function(dt) updateFPS(dt) updateSchedule(dt) AIState.tickCounter += 1 -- Threat detection (always runs, every 0.5s) lastThreatTick += dt if lastThreatTick >= 0.5 then lastThreatTick = 0 local isThreat, tName = ThreatDetector.scan() if isThreat and not AIState.threatDetected then ThreatDetector.respondToThreat(tName) end if AIState.threatCooldown > 0 then AIState.threatCooldown -= 0.5 if AIState.threatCooldown <= 0 then AIState.threatDetected = false end end end -- Observer learning tick (adaptive cooldown) lastLearnTick += dt if lastLearnTick >= LearnCooldown then lastLearnTick = 0 if AIState.isLearning and AIState.currentSession then local char = LocalPlayer.Character if char then local hrp = char:FindFirstChild("HumanoidRootPart") if hrp then Observer.recordMovement(hrp.Position) end end end end -- Ghost/Lend step (every 0.2s) if AIState.mode == "ghost" or AIState.mode == "lend" then lastLLMTick += dt if lastLLMTick >= 0.2 then lastLLMTick = 0 if not AIState.isPaused then GhostController.stepReplay() end end end -- LLM step (every LLMController.callCooldown seconds) if AIState.mode == "llm" then lastLLMTick += dt if lastLLMTick >= LLMController.callCooldown then lastLLMTick = 0 if not AIState.isPaused then LLMController.callLLM() end end end -- Batch save (every 30s) lastSaveTick += dt if lastSaveTick >= 30 then lastSaveTick = 0 if AIState.isLearning then saveBrain() end end end) -- ============================================================ -- SECTION 18: GUI SYSTEM -- ============================================================ VoidGUI = {} VoidGUI.isOpen = true VoidGUI.tab = "main" -- main | stats | replay | settings local screenGui, mainFrame, miniButton local COLORS = { bg = Color3.fromRGB(12, 12, 18), panel = Color3.fromRGB(18, 18, 28), accent = Color3.fromRGB(88, 101, 242), accentHot = Color3.fromRGB(120, 130, 255), text = Color3.fromRGB(220, 220, 235), textDim = Color3.fromRGB(120, 120, 145), success = Color3.fromRGB(87, 242, 135), warning = Color3.fromRGB(254, 231, 92), danger = Color3.fromRGB(237, 66, 69), border = Color3.fromRGB(35, 35, 55), } local MODE_ICONS = { idle = "🌙", observing = "🧠", ghost = "👻", lend = "🎮", llm = "🤖", paused = "⏸", stealth = "🔇", } local function makeDraggable(frame, handle) local dragging, dragStart, startPos handle = handle or frame handle.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = frame.Position end end) -- Use UserInputService so the drag never reaches Roblox camera UserInputService.InputChanged:Connect(function(input) if not dragging then return end if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then local delta = input.Position - dragStart frame.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end end) UserInputService.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end end) end local function makeButton(parent, text, size, pos, color) local btn = Instance.new("TextButton") btn.Size = size btn.Position = pos btn.BackgroundColor3 = color or COLORS.accent btn.TextColor3 = COLORS.text btn.Text = text btn.Font = Enum.Font.GothamBold btn.TextSize = isMobile and 13 or 12 btn.BorderSizePixel = 0 btn.AutoButtonColor = false btn.Parent = parent local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 6) corner.Parent = btn -- Hover effect btn.MouseEnter:Connect(function() TweenService:Create(btn, TweenInfo.new(0.15), {BackgroundColor3 = COLORS.accentHot}):Play() end) btn.MouseLeave:Connect(function() TweenService:Create(btn, TweenInfo.new(0.15), {BackgroundColor3 = color or COLORS.accent}):Play() end) return btn end local function makeLabel(parent, text, size, pos, textSize, color) local lbl = Instance.new("TextLabel") lbl.Size = size lbl.Position = pos lbl.BackgroundTransparency = 1 lbl.TextColor3 = color or COLORS.text lbl.Text = text lbl.Font = Enum.Font.Gotham lbl.TextSize = textSize or 12 lbl.TextXAlignment = Enum.TextXAlignment.Left lbl.Parent = parent return lbl end local function makeBar(parent, pos, value, color) local track = Instance.new("Frame") track.Size = UDim2.new(1, -12, 0, 6) track.Position = pos track.BackgroundColor3= COLORS.border track.BorderSizePixel = 0 track.Parent = parent local tc = Instance.new("UICorner") tc.CornerRadius = UDim.new(0,3) tc.Parent = track local fill = Instance.new("Frame") fill.Size = UDim2.new(value/100, 0, 1, 0) fill.BackgroundColor3 = color or COLORS.accent fill.BorderSizePixel = 0 fill.Parent = track local fc = Instance.new("UICorner") fc.CornerRadius = UDim.new(0,3) fc.Parent = fill return track, fill end function VoidGUI.notify(msg) if AIState.isStealth then return end -- Simple toast notification local toast = Instance.new("TextLabel") toast.Size = UDim2.new(0, 220, 0, 32) toast.Position = UDim2.new(0.5, -110, 0, 60) toast.BackgroundColor3 = COLORS.panel toast.TextColor3 = COLORS.text toast.Text = msg toast.Font = Enum.Font.Gotham toast.TextSize = 12 toast.BorderSizePixel = 0 toast.ZIndex = 100 toast.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0,8) corner.Parent = toast TweenService:Create(toast, TweenInfo.new(0.3), {BackgroundTransparency=0}):Play() task.delay(2.5, function() TweenService:Create(toast, TweenInfo.new(0.3), {BackgroundTransparency=1, TextTransparency=1}):Play() task.wait(0.35) toast:Destroy() end) end function VoidGUI.getModeIcon() if AIState.isStealth then return MODE_ICONS.stealth end if AIState.isPaused then return MODE_ICONS.paused end if AIState.mode == "llm" then return MODE_ICONS.llm end return MODE_ICONS[AIState.mode] or MODE_ICONS.idle end function VoidGUI.getModeLabel() if AIState.isStealth then return "STEALTH" end if AIState.isPaused then return "PAUSED" end local labels = { idle = "IDLE", observing = "OBSERVING", ghost = "GHOST MODE", lend = "LEND MODE", llm = "LLM MODE", } return labels[AIState.mode] or "IDLE" end -- Main GUI labels refs for live updates local lblMode, lblGame, lblSessions, lblActions, lblFPS local barMove, barUI, barSeq local btnLearn, btnGhost, btnLend, btnLLM, btnPause function VoidGUI.updateDisplay() if AIState.isStealth then return end local place = getCurrentPlace() if lblMode then lblMode.Text = VoidGUI.getModeIcon() .. " " .. VoidGUI.getModeLabel() end if lblGame then lblGame.Text = "Game: " .. (place and place.placeName or "Unknown") end if lblSessions then lblSessions.Text = "Sessions: " .. (place and #place.sessions or 0) end if lblActions then lblActions.Text = "Actions: " .. (place and place.totalActions or 0) end if lblFPS then lblFPS.Text = "FPS: " .. FPS .. " Cooldown: " .. string.format("%.0fms", LearnCooldown * 1000) end if place then local c = place.confidence if barMove then barMove.Size = UDim2.new(c.movement/100, 0, 1, 0) end if barUI then barUI.Size = UDim2.new(c.ui/100, 0, 1, 0) end if barSeq then barSeq.Size = UDim2.new(c.sequences/100,0, 1, 0) end end -- Update mini button icon if miniButton then miniButton.Text = VoidGUI.getModeIcon() end end function VoidGUI.toggle() if mainFrame then mainFrame.Visible = not mainFrame.Visible if miniButton then miniButton.Visible = not mainFrame.Visible end end end function VoidGUI.minimize() if mainFrame then mainFrame.Visible = false if miniButton then miniButton.Visible = true end end end function VoidGUI.maximize() if mainFrame then mainFrame.Visible = true if miniButton then miniButton.Visible = false end end end function VoidGUI.buildMainTab(container) local y = 0 -- Mode display lblMode = makeLabel(container, "🌙 IDLE", UDim2.new(1,-12,0,22), UDim2.new(0,6,0,y), 15, COLORS.accent) lblMode.Font = Enum.Font.GothamBold y += 26 lblGame = makeLabel(container, "Game: Loading...", UDim2.new(1,-12,0,16), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 18 -- Divider local div = Instance.new("Frame") div.Size = UDim2.new(1,-12,0,1) div.Position = UDim2.new(0,6,0,y) div.BackgroundColor3 = COLORS.border div.BorderSizePixel = 0 div.Parent = container y += 8 lblSessions = makeLabel(container, "Sessions: 0", UDim2.new(0.5,-6,0,14), UDim2.new(0,6,0,y), 11) lblActions = makeLabel(container, "Actions: 0", UDim2.new(0.5,-6,0,14), UDim2.new(0.5,0,0,y), 11) y += 18 lblFPS = makeLabel(container, "FPS: 60 Cooldown: 100ms", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 10, COLORS.textDim) y += 20 -- Confidence bars makeLabel(container, "Confidence", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 15 makeLabel(container, "Move", UDim2.new(0,30,0,12), UDim2.new(0,6,0,y), 10, COLORS.textDim) local _, mf = makeBar(container, UDim2.new(0,38,0,y+2), 0, COLORS.success) barMove = mf y += 14 makeLabel(container, "UI ", UDim2.new(0,30,0,12), UDim2.new(0,6,0,y), 10, COLORS.textDim) local _, uf = makeBar(container, UDim2.new(0,38,0,y+2), 0, COLORS.accent) barUI = uf y += 14 makeLabel(container, "Seq ", UDim2.new(0,30,0,12), UDim2.new(0,6,0,y), 10, COLORS.textDim) local _, sf = makeBar(container, UDim2.new(0,38,0,y+2), 0, COLORS.warning) barSeq = sf y += 20 -- Action buttons btnLearn = makeButton(container, "▶ Start Learning", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y), COLORS.success) btnLearn.TextColor3 = Color3.fromRGB(20,20,30) y += 32 btnGhost = makeButton(container, "👻 Ghost Mode", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y)) y += 32 btnLend = makeButton(container, "🎮 Lend Control", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y), COLORS.warning) btnLend.TextColor3 = Color3.fromRGB(20,20,30) y += 32 -- LLM button (gated) btnLLM = makeButton(container, "🤖 Lend to LLM", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y), COLORS.panel) btnLLM.TextColor3 = COLORS.textDim y += 32 btnPause = makeButton(container, "⏸ Pause", UDim2.new(0.5,-9,0,26), UDim2.new(0,6,0,y), COLORS.panel) local btnReset = makeButton(container, "🗑 Reset", UDim2.new(0.5,-9,0,26), UDim2.new(0.5,3,0,y), COLORS.danger) y += 32 -- Wire up buttons btnLearn.MouseButton1Click:Connect(function() if AIState.isLearning then AIState.isLearning = false Observer.endSession() btnLearn.Text = "▶ Start Learning" VoidGUI.notify("Learning stopped. Brain saved.") else AIState.isLearning = true Observer.startSession() btnLearn.Text = "⏹ Stop Learning" VoidGUI.notify("Learning started!") end VoidGUI.updateDisplay() end) btnGhost.MouseButton1Click:Connect(function() if AIState.mode == "ghost" then GhostController.reclaim() btnGhost.Text = "👻 Ghost Mode" else if GhostController.startGhost() then btnGhost.Text = "⏹ Stop Ghost" end end VoidGUI.updateDisplay() end) btnLend.MouseButton1Click:Connect(function() if AIState.mode == "lend" then GhostController.reclaim() btnLend.Text = "🎮 Lend Control" else if GhostController.startLend() then btnLend.Text = "⏹ Reclaim" if isMobile then VoidGUI.notify("Tap ✋ to reclaim control") else VoidGUI.notify("Press " .. (Config.keybinds and Config.keybinds.reclaim or "F") .. " to reclaim") end end end VoidGUI.updateDisplay() end) btnLLM.MouseButton1Click:Connect(function() local canUse, reason = LLMController.canUseLLM() if not canUse then VoidGUI.notify("⚠ " .. (reason or "Train AI first!")) return end if AIState.mode == "llm" then GhostController.reclaim() btnLLM.Text = "🤖 Lend to LLM" btnLLM.BackgroundColor3 = COLORS.panel btnLLM.TextColor3 = COLORS.textDim else AIState.mode = "llm" btnLLM.Text = "⏹ Stop LLM" btnLLM.BackgroundColor3 = COLORS.accent btnLLM.TextColor3 = COLORS.text local place = getCurrentPlace() if place and place.confidence.movement < 40 then VoidGUI.notify("⚠ Low training data. LLM may perform poorly.") end end VoidGUI.updateDisplay() end) btnPause.MouseButton1Click:Connect(function() AIState.isPaused = not AIState.isPaused btnPause.Text = AIState.isPaused and "▶ Resume" or "⏸ Pause" VoidGUI.notify(AIState.isPaused and "Paused" or "Resumed") VoidGUI.updateDisplay() end) btnReset.MouseButton1Click:Connect(function() -- Confirmation inline btnReset.Text = "Confirm?" task.delay(2, function() if btnReset.Text == "Confirm?" then btnReset.Text = "🗑 Reset" end end) if btnReset.Text == "Confirm?" then return end local place = getCurrentPlace() if place then place.sessions = {} place.totalActions = 0 place.confidence = { movement=0, ui=0, sequences=0 } saveBrain() VoidGUI.notify("Brain reset for this game.") end btnReset.Text = "🗑 Reset" VoidGUI.updateDisplay() end) -- Update LLM button state periodically task.spawn(function() while true do task.wait(2) local canUse = LLMController.canUseLLM() if canUse and AIState.mode ~= "llm" then btnLLM.BackgroundColor3 = COLORS.accent btnLLM.TextColor3 = COLORS.text elseif AIState.mode ~= "llm" then btnLLM.BackgroundColor3 = COLORS.panel btnLLM.TextColor3 = COLORS.textDim end end end) end function VoidGUI.buildStatsTab(container) local place = getCurrentPlace() local y = 0 makeLabel(container, "📊 Stats Dashboard", UDim2.new(1,-12,0,18), UDim2.new(0,6,0,y), 14, COLORS.accent).Font = Enum.Font.GothamBold y += 24 local sessions = place and #place.sessions or 0 local actions = place and place.totalActions or 0 local playtime = place and place.totalPlaytime or 0 local brainSize = 0 if Exec.isFile(BrainPath) then local raw = Exec.readFile(BrainPath) brainSize = raw and #raw or 0 end local stats = { {"Sessions", sessions}, {"Total Actions", actions}, {"Playtime", string.format("%.0fm %.0fs", playtime/60, playtime%60)}, {"Brain File Size", string.format("%.1f KB", brainSize/1024)}, {"Current FPS", FPS}, {"Learn Cooldown", string.format("%.0fms", LearnCooldown*1000)}, {"Universe ID", getUniverseId()}, {"Place ID", getPlaceId()}, } for _, stat in ipairs(stats) do makeLabel(container, stat[1], UDim2.new(0.5,-6,0,16), UDim2.new(0,6,0,y), 11, COLORS.textDim) makeLabel(container, tostring(stat[2]), UDim2.new(0.5,-6,0,16), UDim2.new(0.5,0,0,y), 11, COLORS.text) y += 18 end y += 6 makeLabel(container, "Top UI Buttons", UDim2.new(1,-12,0,16), UDim2.new(0,6,0,y), 11, COLORS.accent) y += 18 if place then local sorted = {} for name, count in pairs(place.topUIButtons) do table.insert(sorted, {name=name, count=count}) end table.sort(sorted, function(a,b) return a.count > b.count end) for i = 1, math.min(5, #sorted) do local s = sorted[i] makeLabel(container, s.name .. " x" .. s.count, UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 10, COLORS.text) y += 15 end end end function VoidGUI.buildReplayTab(container) local y = 0 makeLabel(container, "📼 Session Replay", UDim2.new(1,-12,0,18), UDim2.new(0,6,0,y), 14, COLORS.accent).Font = Enum.Font.GothamBold y += 24 local place = getCurrentPlace() if not place or #place.sessions == 0 then makeLabel(container, "No sessions recorded yet.", UDim2.new(1,-12,0,20), UDim2.new(0,6,0,y), 11, COLORS.textDim) return end -- Scrollable session list local scroll = Instance.new("ScrollingFrame") scroll.Size = UDim2.new(1,0,0,180) scroll.Position = UDim2.new(0,0,0,y) scroll.BackgroundTransparency = 1 scroll.ScrollBarThickness = 3 scroll.ScrollBarImageColor3 = COLORS.accent scroll.Parent = container local layout = Instance.new("UIListLayout") layout.Padding = UDim.new(0,4) layout.Parent = scroll for i, session in ipairs(place.sessions) do local row = Instance.new("Frame") row.Size = UDim2.new(1,-6,0,40) row.BackgroundColor3 = COLORS.panel row.BorderSizePixel = 0 row.Parent = scroll local rc = Instance.new("UICorner") rc.CornerRadius = UDim.new(0,6) rc.Parent = row local starIcon = session.starred and "⭐" or "☆" local lbl = makeLabel(row, string.format("%s Session %d — %d actions", starIcon, i, #(session.actions or {})), UDim2.new(0.7,0,0,18), UDim2.new(0,6,0,4), 10) makeLabel(row, "Priority: " .. (session.priority or 1), UDim2.new(0.7,0,0,14), UDim2.new(0,6,0,22), 9, COLORS.textDim) -- Star button local starBtn = makeButton(row, starIcon, UDim2.new(0,28,0,28), UDim2.new(1,-64,0,6), COLORS.panel) starBtn.MouseButton1Click:Connect(function() session.starred = not session.starred starBtn.Text = session.starred and "⭐" or "☆" lbl.Text = string.format("%s Session %d — %d actions", session.starred and "⭐" or "☆", i, #(session.actions or {})) saveBrain() end) -- Delete button local delBtn = makeButton(row, "🗑", UDim2.new(0,28,0,28), UDim2.new(1,-32,0,6), COLORS.danger) delBtn.MouseButton1Click:Connect(function() table.remove(place.sessions, i) saveBrain() row:Destroy() VoidGUI.notify("Session " .. i .. " deleted") Observer.updateConfidence(place) end) -- Priority +/- local prioUp = makeButton(row, "+", UDim2.new(0,18,0,18), UDim2.new(1,-96,0,6), COLORS.success) local prioDn = makeButton(row, "-", UDim2.new(0,18,0,18), UDim2.new(1,-96,0,24), COLORS.danger) prioUp.TextColor3 = Color3.fromRGB(20,20,30) prioUp.MouseButton1Click:Connect(function() session.priority = math.min(5, (session.priority or 1) + 1) saveBrain() end) prioDn.MouseButton1Click:Connect(function() session.priority = math.max(1, (session.priority or 1) - 1) saveBrain() end) end scroll.CanvasSize = UDim2.new(0,0,0,#place.sessions * 44) end function VoidGUI.buildSettingsTab(container) local y = 0 makeLabel(container, "⚙ Settings", UDim2.new(1,-12,0,18), UDim2.new(0,6,0,y), 14, COLORS.accent).Font = Enum.Font.GothamBold y += 24 -- Persona makeLabel(container, "Persona", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 16 local personas = {"Mirror","Aggressive","Passive"} for _, pname in ipairs(personas) do local isActive = Config.activePersona == pname local pbtn = makeButton(container, pname, UDim2.new(1/3,-5,0,24), UDim2.new((table.find(personas,pname)-1)/3, 3, 0, y), isActive and COLORS.accent or COLORS.panel) pbtn.MouseButton1Click:Connect(function() Config.activePersona = pname AIState.persona = pname saveConfig() VoidGUI.notify("Persona: " .. pname) end) end y += 30 -- LLM Provider makeLabel(container, "LLM Provider", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 16 local providers = {"claude","chatgpt","gemini"} for _, prov in ipairs(providers) do local isActive = Config.activeProvider == prov local pvbtn = makeButton(container, prov, UDim2.new(1/3,-5,0,24), UDim2.new((table.find(providers,prov)-1)/3, 3, 0, y), isActive and COLORS.accent or COLORS.panel) pvbtn.MouseButton1Click:Connect(function() Config.activeProvider = prov saveConfig() VoidGUI.notify("Provider: " .. prov) end) end y += 30 -- API Key input makeLabel(container, "API Key (active provider)", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 16 local keyBox = Instance.new("TextBox") keyBox.Size = UDim2.new(1,-12,0,28) keyBox.Position = UDim2.new(0,6,0,y) keyBox.BackgroundColor3 = COLORS.panel keyBox.TextColor3 = COLORS.text keyBox.PlaceholderText = "Enter API key..." keyBox.PlaceholderColor3= COLORS.textDim keyBox.Text = Config.apiKeys[Config.activeProvider] or "" keyBox.Font = Enum.Font.Code keyBox.TextSize = 10 keyBox.ClearTextOnFocus = false keyBox.BorderSizePixel = 0 keyBox.TextXAlignment = Enum.TextXAlignment.Left keyBox.TextEditable = true keyBox.Parent = container local kbc = Instance.new("UICorner"); kbc.CornerRadius = UDim.new(0,6); kbc.Parent = keyBox local kbp = Instance.new("UIPadding"); kbp.PaddingLeft = UDim.new(0,6); kbp.Parent = keyBox keyBox.FocusLost:Connect(function() Config.apiKeys[Config.activeProvider] = keyBox.Text saveConfig() VoidGUI.notify("API key saved") end) y += 34 -- Keybinds (PC only) if isPC then makeLabel(container, "Keybinds (PC)", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 16 local bindNames = { {key="reclaim", label="Reclaim"}, {key="toggleObs", label="Observe"}, {key="toggleLend",label="Lend"}, {key="toggleGUI", label="GUI"}, } for _, b in ipairs(bindNames) do makeLabel(container, b.label, UDim2.new(0.4,0,0,22), UDim2.new(0,6,0,y), 10) local bindBox = Instance.new("TextBox") bindBox.Size = UDim2.new(0.3,-3,0,22) bindBox.Position = UDim2.new(0.4,3,0,y) bindBox.BackgroundColor3 = COLORS.panel bindBox.TextColor3 = COLORS.text bindBox.Text = Config.keybinds and Config.keybinds[b.key] or "F" bindBox.Font = Enum.Font.GothamBold bindBox.TextSize = 11 bindBox.BorderSizePixel = 0 bindBox.Parent = container local bbc = Instance.new("UICorner"); bbc.CornerRadius = UDim.new(0,4); bbc.Parent = bindBox bindBox.FocusLost:Connect(function() local k = bindBox.Text:upper() Keybinds.setKey(b.key, k) bindBox.Text = k end) y += 26 end end -- Stealth toggle local stealthBtn = makeButton(container, Config.stealthMode and "🔇 Stealth: ON" or "🔈 Stealth: OFF", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y), Config.stealthMode and COLORS.accent or COLORS.panel) stealthBtn.MouseButton1Click:Connect(function() Config.stealthMode = not Config.stealthMode AIState.isStealth = Config.stealthMode stealthBtn.Text = Config.stealthMode and "🔇 Stealth: ON" or "🔈 Stealth: OFF" stealthBtn.BackgroundColor3 = Config.stealthMode and COLORS.accent or COLORS.panel saveConfig() if Config.stealthMode then VoidGUI.minimize() end end) y += 34 -- Schedule makeLabel(container, "Schedule (minutes)", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,y), 11, COLORS.textDim) y += 16 local schedBtn = makeButton(container, Config.scheduleEnabled and "⏱ Schedule: ON" or "⏱ Schedule: OFF", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,y), Config.scheduleEnabled and COLORS.success or COLORS.panel) schedBtn.MouseButton1Click:Connect(function() Config.scheduleEnabled = not Config.scheduleEnabled schedBtn.Text = Config.scheduleEnabled and "⏱ Schedule: ON" or "⏱ Schedule: OFF" schedBtn.BackgroundColor3 = Config.scheduleEnabled and COLORS.success or COLORS.panel saveConfig() end) end function VoidGUI.build() -- Main ScreenGui screenGui = Instance.new("ScreenGui") screenGui.Name = "VoidAIGui" screenGui.ResetOnSpawn = false screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling screenGui.IgnoreGuiInset = true screenGui.Parent = PlayerGui -- ---- MINI BUTTON (shown when minimized) ---- miniButton = Instance.new("TextButton") miniButton.Size = UDim2.new(0, isMobile and 52 or 44, 0, isMobile and 52 or 44) miniButton.Position = UDim2.new(0, 10, 0.4, 0) miniButton.BackgroundColor3 = COLORS.accent miniButton.TextColor3 = COLORS.text miniButton.Text = "🌙" miniButton.Font = Enum.Font.GothamBold miniButton.TextSize = isMobile and 22 or 20 miniButton.BorderSizePixel = 0 miniButton.Visible = false miniButton.ZIndex = 50 miniButton.Parent = screenGui local mc = Instance.new("UICorner") mc.CornerRadius = UDim.new(1,0) mc.Parent = miniButton makeDraggable(miniButton) miniButton.MouseButton1Click:Connect(function() VoidGUI.maximize() end) -- ---- MAIN PANEL ---- local panelW = isMobile and 420 or 480 local panelH = isMobile and 280 or 320 mainFrame = Instance.new("Frame") mainFrame.Name = "VoidAIPanel" mainFrame.Size = UDim2.new(0, panelW, 0, panelH) mainFrame.Position = UDim2.new(0, 10, 0.1, 0) mainFrame.BackgroundColor3 = COLORS.bg mainFrame.BorderSizePixel = 0 mainFrame.ClipsDescendants = true mainFrame.Parent = screenGui local mc2 = Instance.new("UICorner") mc2.CornerRadius = UDim.new(0,10) mc2.Parent = mainFrame -- Border glow local stroke = Instance.new("UIStroke") stroke.Color = COLORS.accent stroke.Thickness = 1 stroke.Transparency = 0.5 stroke.Parent = mainFrame -- Title bar local titleBar = Instance.new("Frame") titleBar.Size = UDim2.new(1,0,0,32) titleBar.BackgroundColor3 = COLORS.panel titleBar.BorderSizePixel = 0 titleBar.Parent = mainFrame local tbc = Instance.new("UICorner"); tbc.CornerRadius = UDim.new(0,10); tbc.Parent = titleBar makeLabel(titleBar, " 🤖 VoidAI", UDim2.new(0.7,0,1,0), UDim2.new(0,0,0,0), 13, COLORS.text).Font = Enum.Font.GothamBold local closeBtn = Instance.new("TextButton") closeBtn.Size = UDim2.new(0,28,0,28) closeBtn.Position = UDim2.new(1,-32,0,2) closeBtn.BackgroundColor3 = COLORS.danger closeBtn.Text = "×" closeBtn.Font = Enum.Font.GothamBold closeBtn.TextSize = 16 closeBtn.TextColor3 = COLORS.text closeBtn.BorderSizePixel = 0 closeBtn.Parent = titleBar local cc = Instance.new("UICorner"); cc.CornerRadius = UDim.new(0,6); cc.Parent = closeBtn closeBtn.MouseButton1Click:Connect(function() VoidGUI.minimize() end) makeDraggable(mainFrame, titleBar) -- ---- RESIZE HANDLE (bottom-right corner) ---- local resizeHandle = Instance.new("TextButton") resizeHandle.Size = UDim2.new(0, 16, 0, 16) resizeHandle.Position = UDim2.new(1, -16, 1, -16) resizeHandle.BackgroundColor3 = COLORS.accent resizeHandle.Text = "" resizeHandle.BorderSizePixel = 0 resizeHandle.ZIndex = 20 resizeHandle.Parent = mainFrame local rhc = Instance.new("UICorner"); rhc.CornerRadius = UDim.new(0,3); rhc.Parent = resizeHandle -- small diagonal lines icon local rhLbl = Instance.new("TextLabel") rhLbl.Size = UDim2.new(1,0,1,0); rhLbl.BackgroundTransparency=1 rhLbl.Text = "⤡"; rhLbl.TextSize=10; rhLbl.TextColor3=COLORS.text rhLbl.Font=Enum.Font.GothamBold; rhLbl.Parent=resizeHandle do local resizing, resizeStart, startSize = false, nil, nil resizeHandle.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then resizing = true resizeStart = input.Position startSize = mainFrame.AbsoluteSize end end) UserInputService.InputChanged:Connect(function(input) if not resizing then return end if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then local delta = input.Position - resizeStart local newW = math.clamp(startSize.X + delta.X, 320, 700) local newH = math.clamp(startSize.Y + delta.Y, 220, 600) mainFrame.Size = UDim2.new(0, newW, 0, newH) end end) UserInputService.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then resizing = false end end) end -- Tab bar local tabBar = Instance.new("Frame") tabBar.Size = UDim2.new(1,0,0,28) tabBar.Position = UDim2.new(0,0,0,32) tabBar.BackgroundColor3 = COLORS.panel tabBar.BorderSizePixel = 0 tabBar.Parent = mainFrame local tabs = { {id="main", label="Main"}, {id="stats", label="Stats"}, {id="replay", label="Replay"}, {id="settings", label="Setup"}, } local tabContents = {} for i, tab in ipairs(tabs) do local tbtn = Instance.new("TextButton") tbtn.Size = UDim2.new(1/#tabs,0,1,0) tbtn.Position = UDim2.new((i-1)/#tabs,0,0,0) tbtn.BackgroundTransparency = 1 tbtn.Text = tab.label tbtn.Font = Enum.Font.GothamBold tbtn.TextSize = 10 tbtn.TextColor3 = COLORS.textDim tbtn.Parent = tabBar -- Content frame local content = Instance.new("ScrollingFrame") content.Size = UDim2.new(1,0,1,0) content.Position = UDim2.new(0,0,0,60) content.BackgroundTransparency = 1 content.ScrollBarThickness = 3 content.ScrollBarImageColor3 = COLORS.accent content.CanvasSize = UDim2.new(0,0,0,500) content.Visible = (tab.id == "main") content.Parent = mainFrame tabContents[tab.id] = content tbtn.MouseButton1Click:Connect(function() VoidGUI.tab = tab.id for _, tc in pairs(tabContents) do tc.Visible = false end content.Visible = true for _, child in ipairs(tabBar:GetChildren()) do if child:IsA("TextButton") then child.TextColor3 = COLORS.textDim end end tbtn.TextColor3 = COLORS.accent end) -- Active underline if tab.id == "main" then tbtn.TextColor3 = COLORS.accent end end -- Build tab contents VoidGUI.buildMainTab(tabContents["main"]) VoidGUI.buildStatsTab(tabContents["stats"]) VoidGUI.buildReplayTab(tabContents["replay"]) VoidGUI.buildSettingsTab(tabContents["settings"]) -- Mobile floating action buttons (reclaim etc) if isMobile then local reclaimBtn = Instance.new("TextButton") reclaimBtn.Size = UDim2.new(0,60,0,60) reclaimBtn.Position = UDim2.new(1,-70,0.8,0) reclaimBtn.BackgroundColor3 = COLORS.danger reclaimBtn.Text = "✋" reclaimBtn.Font = Enum.Font.GothamBold reclaimBtn.TextSize = 26 reclaimBtn.TextColor3 = COLORS.text reclaimBtn.BorderSizePixel = 0 reclaimBtn.Visible = false reclaimBtn.ZIndex = 60 reclaimBtn.Parent = screenGui local rc3 = Instance.new("UICorner"); rc3.CornerRadius = UDim.new(1,0); rc3.Parent = reclaimBtn makeDraggable(reclaimBtn) reclaimBtn.MouseButton1Click:Connect(function() GhostController.reclaim() VoidGUI.updateDisplay() end) -- Show reclaim button only when AI is in control RunService.Heartbeat:Connect(function() reclaimBtn.Visible = (AIState.mode == "lend" or AIState.mode == "ghost" or AIState.mode == "llm") end) end end -- ============================================================ -- SECTION 20: THREAT HUD -- ============================================================ local ThreatHUD = {} local function buildThreatHUD() if AIState.isStealth or not screenGui then return end local indicator = Instance.new("Frame") indicator.Name = "ThreatIndicator" indicator.Size = UDim2.new(0, 190, 0, 30) indicator.Position = UDim2.new(0.5, -95, 0, 8) indicator.BackgroundColor3 = Color3.fromRGB(180, 30, 30) indicator.BorderSizePixel = 0 indicator.Visible = false indicator.ZIndex = 80 indicator.Parent = screenGui local ic = Instance.new("UICorner") ic.CornerRadius = UDim.new(0, 8) ic.Parent = indicator local lbl = Instance.new("TextLabel") lbl.Size = UDim2.new(1, 0, 1, 0) lbl.BackgroundTransparency = 1 lbl.TextColor3 = Color3.fromRGB(255, 255, 255) lbl.Font = Enum.Font.GothamBold lbl.TextSize = 13 lbl.Text = "🚨 THREAT DETECTED" lbl.Parent = indicator ThreatHUD.frame = indicator ThreatHUD.label = lbl -- Pulse task.spawn(function() while indicator and indicator.Parent do TweenService:Create(indicator, TweenInfo.new(0.3), {BackgroundTransparency = 0.5}):Play() task.wait(0.3) TweenService:Create(indicator, TweenInfo.new(0.3), {BackgroundTransparency = 0}):Play() task.wait(0.3) end end) RunService.Heartbeat:Connect(function() if indicator and indicator.Parent then indicator.Visible = AIState.threatDetected and not AIState.isStealth end end) end -- ============================================================ -- SECTION 21: SEQUENCE DETECTOR -- ============================================================ local SequenceDetector = {} SequenceDetector.windowSize = 5 SequenceDetector.knownPatterns = {} function SequenceDetector.analyze() local place = getCurrentPlace() if not place or #place.sessions < 2 then return end local seqMap = {} for _, session in ipairs(place.sessions) do local actions = session.actions or {} for i = 1, #actions - SequenceDetector.windowSize do local key = "" for j = i, i + SequenceDetector.windowSize - 1 do key = key .. (actions[j].type or "?") .. "|" end seqMap[key] = (seqMap[key] or 0) + 1 end end SequenceDetector.knownPatterns = {} for seq, count in pairs(seqMap) do if count >= 3 then table.insert(SequenceDetector.knownPatterns, {seq = seq, count = count}) end end table.sort(SequenceDetector.knownPatterns, function(a, b) return a.count > b.count end) end function SequenceDetector.matchCurrent(recentActions) if #SequenceDetector.knownPatterns == 0 then return nil end local key = "" local start = math.max(1, #recentActions - SequenceDetector.windowSize + 1) for i = start, #recentActions do key = key .. (recentActions[i].type or "?") .. "|" end for _, pat in ipairs(SequenceDetector.knownPatterns) do if pat.seq == key then return pat end end return nil end task.spawn(function() while true do task.wait(60) SequenceDetector.analyze() end end) -- ============================================================ -- SECTION 22: SMART REPLAY (pattern-aware) -- ============================================================ local _originalStepReplay = GhostController.stepReplay function GhostController.stepReplay() if not GhostController.replaySession then return end local actions = GhostController.replaySession.actions if not actions or #actions == 0 then return end -- Pattern-based decision local place = getCurrentPlace() if place and #SequenceDetector.knownPatterns > 0 then local match = SequenceDetector.matchCurrent(actions) if match then for _, session in ipairs(place.sessions) do local sactions = session.actions or {} for i = 1, #sactions - SequenceDetector.windowSize do local key = "" for j = i, i + SequenceDetector.windowSize - 1 do key = key .. (sactions[j].type or "?") .. "|" end if key == match.seq and sactions[i + SequenceDetector.windowSize] then local nextAction = sactions[i + SequenceDetector.windowSize] if nextAction.type == "move" then GhostController.executeMove(nextAction.data) elseif nextAction.type == "ui_click" then GhostController.executeUIClick(nextAction.data) elseif nextAction.type == "jump" then local char = LocalPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") if hum then hum.Jump = true end end return end end end end end -- Linear fallback if GhostController.replayIndex > #actions then GhostController.replayIndex = 1 return end local action = actions[GhostController.replayIndex] GhostController.replayIndex += 1 local char = LocalPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") if action.type == "move" then GhostController.executeMove(action.data) elseif action.type == "ui_click" then GhostController.executeUIClick(action.data) elseif action.type == "jump" then if hum then hum.Jump = true end elseif action.type == "sprint_start" then if hum then hum.WalkSpeed = AIState.persona == "Passive" and 14 or 24 end elseif action.type == "sprint_end" then if hum then hum.WalkSpeed = AIState.persona == "Aggressive" and 20 or 16 end end end -- ============================================================ -- SECTION 23: JUMP + SPRINT TRACKING (Event-driven) -- ============================================================ if not isMobile then UserInputService.InputBegan:Connect(function(input, processed) if processed then return end if not AIState.isLearning or not AIState.currentSession then return end if input.KeyCode == Enum.KeyCode.Space then table.insert(AIState.currentSession.actions, { type = "jump", data = {t = os.time() - AIState.sessionStart} }) elseif input.KeyCode == Enum.KeyCode.LeftShift then table.insert(AIState.currentSession.actions, { type = "sprint_start", data = {t = os.time() - AIState.sessionStart} }) end end) UserInputService.InputEnded:Connect(function(input, processed) if not AIState.isLearning or not AIState.currentSession then return end if input.KeyCode == Enum.KeyCode.LeftShift then table.insert(AIState.currentSession.actions, { type = "sprint_end", data = {t = os.time() - AIState.sessionStart} }) end end) end -- Re-hook on respawn LocalPlayer.CharacterAdded:Connect(function(char) task.wait(1) local hum = char:WaitForChild("Humanoid", 5) if hum then if isMobile then hum.Jumping:Connect(function(active) if active and AIState.isLearning and AIState.currentSession then table.insert(AIState.currentSession.actions, { type = "jump", data = {t = os.time() - AIState.sessionStart} }) end end) end -- Reset position tracking local hrp = char:WaitForChild("HumanoidRootPart", 5) if hrp then Observer.lastPosition = hrp.Position end end -- Auto-pause AI control during respawn if AIState.mode == "lend" or AIState.mode == "ghost" then AIState.isPaused = true task.wait(2) AIState.isPaused = false end end) -- ============================================================ -- SECTION 24: OTHER PLAYER OBSERVER (low priority) -- ============================================================ RunService.Heartbeat:Connect(function() if AIState.tickCounter % 5 ~= 0 then return end if not AIState.isLearning then return end for _, p in ipairs(Players:GetPlayers()) do if p ~= LocalPlayer and p.Character then local hum = p.Character:FindFirstChildOfClass("Humanoid") local hrp = p.Character:FindFirstChild("HumanoidRootPart") if hum and hrp and hum.WalkSpeed > 20 then -- Multiple players fleeing = potential threat signal -- Already handled in ThreatDetector.scan() end end end end) -- ============================================================ -- SECTION 25: CONFIDENCE COLOR CODING -- ============================================================ local function getConfidenceColor(value) if value >= 70 then return COLORS.success elseif value >= 40 then return COLORS.warning else return COLORS.danger end end local _origUpdateDisplay = VoidGUI.updateDisplay function VoidGUI.updateDisplay() _origUpdateDisplay() local place = getCurrentPlace() if place then if barMove then barMove.BackgroundColor3 = getConfidenceColor(place.confidence.movement) end if barUI then barUI.BackgroundColor3 = getConfidenceColor(place.confidence.ui) end if barSeq then barSeq.BackgroundColor3 = getConfidenceColor(place.confidence.sequences) end end end -- ============================================================ -- SECTION 26: LOW CONFIDENCE WARNING -- ============================================================ local _origStartGhost = GhostController.startGhost function GhostController.startGhost() local place = getCurrentPlace() if place then local avg = (place.confidence.movement + place.confidence.ui + place.confidence.sequences) / 3 if avg < 20 then VoidGUI.notify("⚠ Very low confidence (" .. math.floor(avg) .. "%). Train more!") task.wait(1.5) elseif avg < 40 then VoidGUI.notify("⚠ Low confidence (" .. math.floor(avg) .. "%). AI may be rough.") end end return _origStartGhost() end -- ============================================================ -- SECTION 27: CHAT COMMANDS -- ============================================================ local CHAT_PREFIX = "/void" local CHAT_COMMANDS = { learn = function() AIState.isLearning = true; Observer.startSession(); VoidGUI.notify("Learning started") end, stop = function() AIState.isLearning = false; Observer.endSession(); VoidGUI.notify("Learning stopped") end, ghost = function() GhostController.startGhost() end, lend = function() GhostController.startLend() end, reclaim = function() GhostController.reclaim() end, pause = function() AIState.isPaused = not AIState.isPaused VoidGUI.notify(AIState.isPaused and "Paused" or "Resumed") end, stealth = function() Config.stealthMode = not Config.stealthMode AIState.isStealth = Config.stealthMode saveConfig() if Config.stealthMode then VoidGUI.minimize() else VoidGUI.maximize() end end, safe = function() Observer.tagCurrentZone("safe"); VoidGUI.notify("Zone: SAFE") end, danger = function() Observer.tagCurrentZone("danger"); VoidGUI.notify("Zone: DANGER") end, exit = function() Observer.tagCurrentZone("exit"); VoidGUI.notify("Zone: EXIT") end, item = function() Observer.tagCurrentZone("item_spawn"); VoidGUI.notify("Zone: ITEM") end, save = function() saveBrain(); VoidGUI.notify("Brain saved!") end, llm = function() local canUse, reason = LLMController.canUseLLM() if canUse then AIState.mode = "llm"; VoidGUI.notify("LLM mode ON") else VoidGUI.notify("LLM blocked: " .. (reason or "?")) end end, status = function() local place = getCurrentPlace() VoidGUI.notify(string.format("Mode:%s Sess:%d Move:%d%% UI:%d%%", AIState.mode, place and #place.sessions or 0, place and place.confidence.movement or 0, place and place.confidence.ui or 0)) end, help = function() VoidGUI.notify("Cmds: learn stop ghost lend reclaim pause stealth safe danger exit item save llm status") end, } pcall(function() LocalPlayer.Chatted:Connect(function(msg) local parts = msg:lower():split(" ") if parts[1] ~= CHAT_PREFIX then return end local cmd = parts[2] if cmd and CHAT_COMMANDS[cmd] then CHAT_COMMANDS[cmd]() VoidGUI.updateDisplay() end end) end) -- ============================================================ -- SECTION 28: MENTAL MAP VISUALIZER -- ============================================================ local function buildMentalMapView(parent, yPos) local place = getCurrentPlace() if not place then return end local TAG_COLORS = { visited = Color3.fromRGB(50, 50, 90), safe = Color3.fromRGB(87, 242, 135), danger = Color3.fromRGB(237, 66, 69), item_spawn = Color3.fromRGB(254, 231, 92), exit = Color3.fromRGB(88, 101, 242), } local mapFrame = Instance.new("Frame") mapFrame.Size = UDim2.new(1, -12, 0, 110) mapFrame.Position = UDim2.new(0, 6, 0, yPos) mapFrame.BackgroundColor3 = Color3.fromRGB(8, 8, 14) mapFrame.BorderSizePixel = 0 mapFrame.ClipsDescendants = true mapFrame.Parent = parent local mc = Instance.new("UICorner"); mc.CornerRadius = UDim.new(0,6); mc.Parent = mapFrame makeLabel(mapFrame, "🗺 Mental Map", UDim2.new(1,0,0,14), UDim2.new(0,4,0,2), 9, COLORS.textDim) local landmarks = place.mentalMap.landmarks or {} local minX, maxX, minZ, maxZ = math.huge, -math.huge, math.huge, -math.huge for _, lm in pairs(landmarks) do if lm.pos.x < minX then minX = lm.pos.x end if lm.pos.x > maxX then maxX = lm.pos.x end if lm.pos.z < minZ then minZ = lm.pos.z end if lm.pos.z > maxZ then maxZ = lm.pos.z end end local rangeX = math.max(1, maxX - minX) local rangeZ = math.max(1, maxZ - minZ) local dotCount = 0 for _, lm in pairs(landmarks) do if dotCount >= 150 then break end dotCount += 1 local nx = (lm.pos.x - minX) / rangeX local nz = (lm.pos.z - minZ) / rangeZ local dot = Instance.new("Frame") dot.Size = UDim2.new(0, 4, 0, 4) dot.Position = UDim2.new(nx * 0.9 + 0.05, -2, nz * 0.7 + 0.15, -2) dot.BackgroundColor3 = TAG_COLORS[lm.tag] or TAG_COLORS.visited dot.BorderSizePixel = 0 dot.Parent = mapFrame local dc = Instance.new("UICorner"); dc.CornerRadius = UDim.new(1,0); dc.Parent = dot end -- Player position dot local char = LocalPlayer.Character if char then local hrp = char:FindFirstChild("HumanoidRootPart") if hrp then local nx = rangeX > 1 and (hrp.Position.X - minX) / rangeX or 0.5 local nz = rangeZ > 1 and (hrp.Position.Z - minZ) / rangeZ or 0.5 local pd = Instance.new("Frame") pd.Size = UDim2.new(0, 7, 0, 7) pd.Position = UDim2.new(math.clamp(nx*0.9+0.05,0,1), -3, math.clamp(nz*0.7+0.15,0,1), -3) pd.BackgroundColor3 = Color3.fromRGB(255, 255, 255) pd.BorderSizePixel = 0 pd.ZIndex = 5 pd.Parent = mapFrame local pdc = Instance.new("UICorner"); pdc.CornerRadius = UDim.new(1,0); pdc.Parent = pd end end -- Legend row local legendData = {{"safe","Safe"},{"danger","Danger"},{"exit","Exit"},{"item_spawn","Item"}} local lx = 4 for _, li in ipairs(legendData) do local ldot = Instance.new("Frame") ldot.Size = UDim2.new(0,5,0,5); ldot.Position = UDim2.new(0,lx,1,-14) ldot.BackgroundColor3 = TAG_COLORS[li[1]]; ldot.BorderSizePixel = 0; ldot.Parent = mapFrame local lc = Instance.new("UICorner"); lc.CornerRadius = UDim.new(1,0); lc.Parent = ldot makeLabel(mapFrame, li[2], UDim2.new(0,28,0,10), UDim2.new(0,lx+7,1,-16), 8, COLORS.textDim) lx += 40 end end -- ============================================================ -- SECTION 29: BRAIN EXPORT -- ============================================================ local function exportBrainSummary() local place = getCurrentPlace() if not place then VoidGUI.notify("No brain loaded"); return end local lines = { "=== VoidAI Brain Export ===", "Universe: " .. getUniverseId(), "Place: " .. getPlaceId() .. " (" .. (place.placeName or "?") .. ")", "Sessions: " .. #place.sessions, "Total Actions: " .. (place.totalActions or 0), string.format("Confidence - Move:%d%% UI:%d%% Seq:%d%%", place.confidence.movement, place.confidence.ui, place.confidence.sequences), "", "--- Top UI Buttons ---", } local sorted = {} for name, count in pairs(place.topUIButtons or {}) do table.insert(sorted, name .. ": " .. count .. "x") end table.sort(sorted) for _, s in ipairs(sorted) do table.insert(lines, " " .. s) end table.insert(lines, "") table.insert(lines, "--- Mental Map Landmarks ---") local lmCount = 0 for _, lm in pairs(place.mentalMap.landmarks or {}) do lmCount += 1 table.insert(lines, string.format(" [%s] (%.0f,%.0f,%.0f) visits:%d", lm.tag, lm.pos.x, lm.pos.y, lm.pos.z, lm.visits)) end if lmCount == 0 then table.insert(lines, " (none yet)") end table.insert(lines, "") table.insert(lines, "--- Known Patterns ---") if #SequenceDetector.knownPatterns > 0 then for i, pat in ipairs(SequenceDetector.knownPatterns) do if i > 10 then break end table.insert(lines, string.format(" Pattern %d (x%d): %s", i, pat.count, pat.seq)) end else table.insert(lines, " (none — train 2+ sessions first)") end table.insert(lines, "") table.insert(lines, "Exported: " .. os.date and os.date("%Y-%m-%d %H:%M:%S") or tostring(os.time())) local path = BRAIN_FOLDER .. "/export_" .. getPlaceId() .. ".txt" Exec.writeFile(path, table.concat(lines, "\n")) VoidGUI.notify("Exported to " .. path) end -- ============================================================ -- SECTION 30: HORROR GAME AUTO-DETECT -- ============================================================ local HORROR_KEYWORDS = { "doors","horror","scary","haunted","dark","nightmare", "paranormal","escape","survival","entity","monster","backrooms", } local function detectAndConfigureHorror() local place = getCurrentPlace() if not place then return end local gname = (place.placeName or ""):lower() local isHorror = false for _, kw in ipairs(HORROR_KEYWORDS) do if gname:find(kw) then isHorror = true; break end end if not isHorror then return end VoidGUI.notify("🚨 Horror game detected — threat detection enhanced") -- Pre-tag safe objects in workspace for _, obj in ipairs(workspace:GetDescendants()) do if obj:IsA("BasePart") then for _, safe in ipairs(BASE_KNOWLEDGE.horrorDefaults.safeObjects) do if obj.Name:lower():find(safe:lower()) then local posKey = math.floor(obj.Position.X/10) .. "_" .. math.floor(obj.Position.Z/10) if not place.mentalMap.landmarks[posKey] then place.mentalMap.landmarks[posKey] = { pos = {x=obj.Position.X, y=obj.Position.Y, z=obj.Position.Z}, tag = "safe", visits= 1, note = "auto:" .. obj.Name, } end end end end end end -- ============================================================ -- SECTION 31: SCHEDULE COUNTDOWN -- ============================================================ task.spawn(function() while true do task.wait(10) if Config.scheduleEnabled and not AIState.scheduleActive then local startSec = (Config.scheduleStartMin or 0) * 60 local remaining = startSec - AIState.scheduleTimer if remaining > 0 and remaining < 120 then VoidGUI.notify(string.format("⏱ AI starts in %.0f sec", remaining)) end end end end) -- ============================================================ -- SECTION 32: SAFETY HOOKS -- ============================================================ Players.LocalPlayer.AncestryChanged:Connect(function() if not Players.LocalPlayer.Parent then if AIState.isLearning and AIState.currentSession then Observer.endSession() end saveBrain() saveConfig() end end) LocalPlayer.CharacterRemoving:Connect(function() if AIState.mode ~= "idle" and AIState.mode ~= "observing" then GhostController.reclaim() VoidGUI.notify("Character removed — control reclaimed") end end) -- ============================================================ -- SECTION 19: INITIALIZATION (FINAL) -- ============================================================ local function init() -- Setup folders Exec.makeFolder(BRAIN_FOLDER) -- Load config first loadConfig() -- Apply saved config if Config.stealthMode then AIState.isStealth = true end if Config.activePersona then AIState.persona = Config.activePersona end if Config.keybinds then for action, keyName in pairs(Config.keybinds) do if KEY_MAP[keyName] then Keybinds.binds[action] = KEY_MAP[keyName] end end end -- Load brain loadBrain() -- Build GUI if not AIState.isStealth then VoidGUI.build() VoidGUI.updateDisplay() else -- Stealth: build but hide, mini button only VoidGUI.build() if mainFrame then mainFrame.Visible = false end if miniButton then miniButton.Visible = true end end -- Build threat HUD after GUI exists task.spawn(function() task.wait(0.3) buildThreatHUD() end) -- Run horror detection after brain loads task.spawn(function() task.wait(4) detectAndConfigureHorror() end) -- Run sequence analysis on startup if brain already has sessions task.spawn(function() task.wait(3) SequenceDetector.analyze() end) -- Add mental map to stats tab after GUI builds task.spawn(function() task.wait(0.5) if screenGui then local panel = screenGui:FindFirstChild("VoidAIPanel") if panel then local scrollFrames = {} for _, child in ipairs(panel:GetChildren()) do if child:IsA("ScrollingFrame") then table.insert(scrollFrames, child) end end -- Stats tab = index 2, Settings tab = index 4 local statsFrame = scrollFrames[2] local settingsFrame = scrollFrames[4] if statsFrame then buildMentalMapView(statsFrame, 330) statsFrame.CanvasSize = UDim2.new(0,0,0,460) end if settingsFrame then local exportBtn = makeButton(settingsFrame, "📤 Export Brain Summary", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,500), COLORS.panel) exportBtn.MouseButton1Click:Connect(exportBrainSummary) settingsFrame.CanvasSize = UDim2.new(0,0,0,560) end end end end) -- Live display update loop (every second) task.spawn(function() while true do task.wait(1) VoidGUI.updateDisplay() end end) -- Welcome notification task.wait(0.5) if not AIState.isStealth then local platform = isMobile and "Mobile 📱" or "PC 🖥" local brainStatus = Exec.isFile(getBrainPath()) and "Brain loaded ✓" or "New brain created" VoidGUI.notify("VoidAI v1.0 — " .. platform .. " — " .. brainStatus) end -- Print to output for executor console print("[VoidAI] Loaded successfully") print("[VoidAI] Platform: " .. (isMobile and "Mobile" or "PC")) print("[VoidAI] Brain path: " .. getBrainPath()) print("[VoidAI] Universe: " .. getUniverseId() .. " | Place: " .. getPlaceId()) print("[VoidAI] Chat commands: /void help") if isPC then print("[VoidAI] Keybinds: G=Learn H=Lend J=GUI F=Reclaim") end end -- ============================================================ -- SECTION 33: ADAPTIVE THINKING MODE -- ============================================================ --[[ Adaptive Thinking Mode (ATM): - Activates automatically when player is AFK (no input for N seconds) - OR manually toggled from GUI / chat command - AI watches ALL other players in the server simultaneously - Learns their movement paths, sequences, clustering patterns - Cross-references: 3+ players took same path = high-confidence route - Tags player clusters as "safe", player flee-zones as "danger" - All observed data is weighted at 60% trust vs 100% for self-recorded - Stops instantly the moment user touches any input - Brain data from ATM is clearly marked so you can see what came from it ]] local AdaptiveThinking = {} -- State AdaptiveThinking.active = false AdaptiveThinking.manualOverride= false -- user forced it on via GUI AdaptiveThinking.afkTimer = 0 AdaptiveThinking.afkThreshold = 30 -- seconds of no input = AFK AdaptiveThinking.TRUST_WEIGHT = 0.6 -- observed data trust vs 1.0 for self AdaptiveThinking.tickAccum = 0 AdaptiveThinking.sampleRate = 0.4 -- seconds between player samples (adaptive) AdaptiveThinking.sessionStart = 0 -- Per-player tracking table: stores last known positions + action hints AdaptiveThinking.playerTrackers = {} -- Observed session accumulator (separate from self-recorded sessions) AdaptiveThinking.observedSession = nil -- Path frequency map: posKey -> count across all observed players AdaptiveThinking.pathFrequency = {} -- ---- AFK DETECTION ---- local lastInputTime = os.time() if not isMobile then UserInputService.InputBegan:Connect(function(input, processed) -- Any real input = not AFK local t = input.UserInputType if t == Enum.UserInputType.Keyboard or t == Enum.UserInputType.MouseButton1 or t == Enum.UserInputType.MouseButton2 or t == Enum.UserInputType.MouseMovement then lastInputTime = os.time() -- If ATM was running in auto mode, stop it if AdaptiveThinking.active and not AdaptiveThinking.manualOverride then AdaptiveThinking.stop("Input detected — AFK mode off") end end end) UserInputService.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then lastInputTime = os.time() if AdaptiveThinking.active and not AdaptiveThinking.manualOverride then AdaptiveThinking.stop("Mouse moved — AFK mode off") end end end) else -- Mobile: any touch = not AFK UserInputService.TouchStarted:Connect(function() lastInputTime = os.time() if AdaptiveThinking.active and not AdaptiveThinking.manualOverride then AdaptiveThinking.stop("Touch detected — AFK mode off") end end) end -- ---- CORE FUNCTIONS ---- function AdaptiveThinking.start(reason) if AdaptiveThinking.active then return end AdaptiveThinking.active = true AdaptiveThinking.sessionStart = os.time() AdaptiveThinking.pathFrequency= {} AdaptiveThinking.playerTrackers = {} -- Create a fresh observed session AdaptiveThinking.observedSession = { id = os.time(), type = "adaptive_observed", -- marked as ATM data trustWeight = AdaptiveThinking.TRUST_WEIGHT, actions = {}, movements = {}, sequences = {}, playerPaths = {}, -- per-player path logs startTime = os.time(), endTime = nil, playerCount = #Players:GetPlayers() - 1, -- exclude self source = "adaptive_thinking", } VoidGUI.notify("🧠 Adaptive Thinking ON — watching " .. tostring(#Players:GetPlayers() - 1) .. " players") print("[VoidAI:ATM] Started — reason: " .. (reason or "manual")) end function AdaptiveThinking.stop(reason) if not AdaptiveThinking.active then return end AdaptiveThinking.active = false AdaptiveThinking.manualOverride= false -- Finalize and merge observed session into brain if AdaptiveThinking.observedSession then AdaptiveThinking.observedSession.endTime = os.time() AdaptiveThinking.mergeIntoBrain() end AdaptiveThinking.observedSession = nil VoidGUI.notify("🧠 Adaptive Thinking OFF — brain updated") print("[VoidAI:ATM] Stopped — reason: " .. (reason or "manual")) VoidGUI.updateDisplay() end function AdaptiveThinking.toggle() if AdaptiveThinking.active then AdaptiveThinking.manualOverride = false AdaptiveThinking.stop("manual toggle") else AdaptiveThinking.manualOverride = true AdaptiveThinking.start("manual toggle") end end -- ---- PLAYER SAMPLING ---- function AdaptiveThinking.samplePlayers() if not AdaptiveThinking.active then return end local place = getCurrentPlace() if not place then return end local session = AdaptiveThinking.observedSession if not session then return end local allPlayers = Players:GetPlayers() local activeSamples = 0 for _, p in ipairs(allPlayers) do if p == LocalPlayer then continue end if not p.Character then continue end local hrp = p.Character:FindFirstChild("HumanoidRootPart") local hum = p.Character:FindFirstChildOfClass("Humanoid") if not hrp or not hum then continue end local pos = hrp.Position local pid = p.UserId activeSamples += 1 -- Initialize tracker for this player if not AdaptiveThinking.playerTrackers[pid] then AdaptiveThinking.playerTrackers[pid] = { name = p.Name, lastPos = pos, lastMoveT = os.time(), pathPoints = {}, isRunning = false, fleeCount = 0, } session.playerPaths[tostring(pid)] = { name = p.Name, points = {}, } end local tracker = AdaptiveThinking.playerTrackers[pid] local delta = (pos - tracker.lastPos).Magnitude -- Only record if player actually moved (>2 studs, same threshold as self-observer) if delta >= 2 then tracker.lastPos = pos tracker.lastMoveT= os.time() -- Log point to this player's path local point = { pos = {x = pos.X, y = pos.Y, z = pos.Z}, t = os.time() - AdaptiveThinking.sessionStart, spd = hum.WalkSpeed, } table.insert(tracker.pathPoints, point) if session.playerPaths[tostring(pid)] then table.insert(session.playerPaths[tostring(pid)].points, point) end -- Update path frequency map for this grid cell local posKey = math.floor(pos.X/10) .. "_" .. math.floor(pos.Z/10) AdaptiveThinking.pathFrequency[posKey] = (AdaptiveThinking.pathFrequency[posKey] or 0) + 1 -- Add to observed session as a weighted movement action table.insert(session.actions, { type = "move", source = "observed_" .. p.Name, trustWeight = AdaptiveThinking.TRUST_WEIGHT, data = point, }) table.insert(session.movements, point) end -- Detect fleeing (high walkspeed = running) local isFleeing = hum.WalkSpeed > 20 if isFleeing and not tracker.isRunning then tracker.isRunning = true tracker.fleeCount += 1 -- Record flee event table.insert(session.actions, { type = "flee_observed", source = p.Name, data = { pos = {x = pos.X, y = pos.Y, z = pos.Z}, t = os.time() - AdaptiveThinking.sessionStart, } }) -- If 3+ players flee from roughly same area = strong danger signal local nearbyFleeing = 0 for _, p2 in ipairs(allPlayers) do if p2 ~= LocalPlayer and p2 ~= p and p2.Character then local hrp2 = p2.Character:FindFirstChild("HumanoidRootPart") local hum2 = p2.Character:FindFirstChildOfClass("Humanoid") if hrp2 and hum2 and hum2.WalkSpeed > 20 then if (hrp2.Position - pos).Magnitude < 60 then nearbyFleeing += 1 end end end end if nearbyFleeing >= 2 then -- Tag flee origin as danger local fleeKey = math.floor(pos.X/10) .. "_" .. math.floor(pos.Z/10) place.mentalMap.landmarks[fleeKey] = { pos = {x = pos.X, y = pos.Y, z = pos.Z}, tag = "danger", visits = nearbyFleeing, note = "atm:mass_flee", } print("[VoidAI:ATM] Mass flee detected — tagged danger at " .. fleeKey) end elseif not isFleeing then tracker.isRunning = false end end -- Update sample rate based on player count (more players = slower sample to avoid lag) if activeSamples > 10 then AdaptiveThinking.sampleRate = 0.8 elseif activeSamples > 5 then AdaptiveThinking.sampleRate = 0.5 else AdaptiveThinking.sampleRate = 0.3 end end -- ---- CROSS-REFERENCE & ZONE TAGGING ---- function AdaptiveThinking.processPathFrequency() if not AdaptiveThinking.active then return end local place = getCurrentPlace() if not place then return end for posKey, count in pairs(AdaptiveThinking.pathFrequency) do local parts = posKey:split("_") if #parts >= 2 then local wx = tonumber(parts[1]) * 10 local wz = tonumber(parts[2]) * 10 if not place.mentalMap.landmarks[posKey] then place.mentalMap.landmarks[posKey] = { pos = {x = wx, y = 0, z = wz}, tag = "visited", visits = 0, note = "atm", } end local lm = place.mentalMap.landmarks[posKey] -- Increment visits by weighted count lm.visits = (lm.visits or 0) + math.floor(count * AdaptiveThinking.TRUST_WEIGHT) -- Cross-reference: 3+ distinct players passed here = likely safe/important route if count >= 3 and lm.tag == "visited" then lm.tag = "safe" lm.note = "atm:high_traffic" end end end end -- ---- MERGE INTO BRAIN ---- function AdaptiveThinking.mergeIntoBrain() local place = getCurrentPlace() if not place or not AdaptiveThinking.observedSession then return end local session = AdaptiveThinking.observedSession -- Process path frequency → zone tags AdaptiveThinking.processPathFrequency() -- Only add observed session if it has meaningful data local actionCount = #session.actions if actionCount < 10 then print("[VoidAI:ATM] Observed session too sparse (" .. actionCount .. " actions) — discarded") return end -- Add to place sessions with trust weight metadata table.insert(place.sessions, session) place.totalActions = (place.totalActions or 0) + actionCount -- Recalculate confidence, but dampen ATM contribution -- ATM sessions count as 0.6x a normal session for confidence local atmSessions = 0 local selfSessions = 0 for _, s in ipairs(place.sessions) do if s.type == "adaptive_observed" then atmSessions += 1 else selfSessions += 1 end end -- Weighted confidence: self sessions worth 1.0, ATM sessions worth 0.6 local weightedCount = selfSessions + atmSessions * AdaptiveThinking.TRUST_WEIGHT if weightedCount > 0 then local totalMoves, totalUI, totalSeq = 0, 0, 0 for _, s in ipairs(place.sessions) do local w = (s.type == "adaptive_observed") and AdaptiveThinking.TRUST_WEIGHT or 1.0 totalMoves = totalMoves + #(s.movements or {}) * w totalUI = totalUI + #(s.uiClicks or {}) * w totalSeq = totalSeq + #(s.sequences or {}) * w end place.confidence.movement = math.min(100, math.floor(math.log(totalMoves + 1) * 15)) place.confidence.ui = math.min(100, math.floor(math.log(totalUI + 1) * 20)) place.confidence.sequences = math.min(100, math.floor(math.log(totalSeq + 1) * 25)) end -- Run sequence analysis on the new data SequenceDetector.analyze() saveBrain() print(string.format("[VoidAI:ATM] Merged — %d actions from %d players | Conf: Move%d%% UI%d%%", actionCount, session.playerCount, place.confidence.movement, place.confidence.ui)) end -- ---- MAIN HEARTBEAT HOOK ---- RunService.Heartbeat:Connect(function(dt) -- AFK timer (only auto-trigger if not manual override) if not AdaptiveThinking.manualOverride then local idleTime = os.time() - lastInputTime if idleTime >= AdaptiveThinking.afkThreshold and not AdaptiveThinking.active then -- Auto-start ATM if player appears to be AFK -- Only if not already in another active AI mode if AIState.mode == "idle" or AIState.mode == "observing" then AdaptiveThinking.start("AFK auto-trigger (" .. idleTime .. "s idle)") end end end -- Sample players while ATM is active if AdaptiveThinking.active then AdaptiveThinking.tickAccum += dt if AdaptiveThinking.tickAccum >= AdaptiveThinking.sampleRate then AdaptiveThinking.tickAccum = 0 AdaptiveThinking.samplePlayers() -- Process path frequency every 15 seconds local elapsed = os.time() - AdaptiveThinking.sessionStart if elapsed > 0 and elapsed % 15 == 0 then AdaptiveThinking.processPathFrequency() end end end end) -- ---- GUI INTEGRATION ---- -- Add ATM button and status to main tab after GUI builds task.spawn(function() task.wait(1) if not screenGui then return end local panel = screenGui:FindFirstChild("VoidAIPanel") if not panel then return end -- Find main tab ScrollingFrame (first one) local scrollFrames = {} for _, child in ipairs(panel:GetChildren()) do if child:IsA("ScrollingFrame") then table.insert(scrollFrames, child) end end local mainScroll = scrollFrames[1] if not mainScroll then return end -- ATM toggle button local atmBtn = makeButton(mainScroll, "🧠 Adaptive Thinking: OFF", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,310), COLORS.panel) atmBtn.TextSize = 11 -- AFK timer label local atmStatus = makeLabel(mainScroll, "AFK: 0s / 30s — 0 players watched", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,342), 9, COLORS.textDim) atmBtn.MouseButton1Click:Connect(function() AdaptiveThinking.toggle() if AdaptiveThinking.active then atmBtn.Text = "🧠 Adaptive Thinking: ON" atmBtn.BackgroundColor3 = COLORS.accent else atmBtn.Text = "🧠 Adaptive Thinking: OFF" atmBtn.BackgroundColor3 = COLORS.panel end end) -- Live status updater for ATM button task.spawn(function() while true do task.wait(1) local idleTime = os.time() - lastInputTime local pCount = math.max(0, #Players:GetPlayers() - 1) if AdaptiveThinking.active then local elapsed = os.time() - AdaptiveThinking.sessionStart local actions = AdaptiveThinking.observedSession and #AdaptiveThinking.observedSession.actions or 0 atmStatus.Text = string.format( "ATM: %ds active | %d players | %d actions learned", elapsed, pCount, actions) atmStatus.TextColor3 = COLORS.success atmBtn.Text = "🧠 Adaptive Thinking: ON" atmBtn.BackgroundColor3 = COLORS.accent else local threshold = AdaptiveThinking.afkThreshold local remaining = math.max(0, threshold - idleTime) atmStatus.Text = string.format( "AFK: %ds idle | auto-starts in %ds | %d players", math.floor(idleTime), math.floor(remaining), pCount) atmStatus.TextColor3 = COLORS.textDim atmBtn.Text = "🧠 Adaptive Thinking: OFF" atmBtn.BackgroundColor3 = COLORS.panel end end end) -- Expand canvas to fit new button mainScroll.CanvasSize = UDim2.new(0,0,0,580) end) -- ---- CHAT COMMAND ---- CHAT_COMMANDS["atm"] = function() AdaptiveThinking.toggle() VoidGUI.notify(AdaptiveThinking.active and "🧠 ATM ON — watching players" or "🧠 ATM OFF — brain saved") end CHAT_COMMANDS["afk"] = function() -- Set AFK threshold to 0 to force immediate ATM trigger lastInputTime = 0 VoidGUI.notify("AFK forced — ATM will start shortly") end -- ---- STATS TAB INTEGRATION ---- -- Patch stats display to show ATM session count separately local _origBuildStats = VoidGUI.buildStatsTab function VoidGUI.buildStatsTab(container) _origBuildStats(container) -- Add ATM-specific stat rows local place = getCurrentPlace() if not place then return end local atmCount = 0 local selfCount = 0 for _, s in ipairs(place.sessions) do if s.type == "adaptive_observed" then atmCount += 1 else selfCount += 1 end end makeLabel(container, "Self Sessions", UDim2.new(0.6,0,0,16), UDim2.new(0,6,0,195), 11, COLORS.textDim) makeLabel(container, tostring(selfCount), UDim2.new(0.4,0,0,16), UDim2.new(0.6,0,0,195), 11, COLORS.success) makeLabel(container, "ATM Sessions (0.6x)", UDim2.new(0.6,0,0,16), UDim2.new(0,6,0,213), 11, COLORS.textDim) makeLabel(container, tostring(atmCount), UDim2.new(0.4,0,0,16), UDim2.new(0.6,0,0,213), 11, COLORS.accent) end -- ============================================================ -- SECTION 34: EXTENDED ADAPTIVE THINKING (EAT) -- ============================================================ --[[ Extended Adaptive Thinking (EAT): Runs while the USER plays normally — no lending, no control taken. Learns from BOTH the user's own actions AND other players simultaneously. Layered with AI-mimicking systems: - Pattern Reinforcement (dual-source confirmation) - Attention Focus (prioritize active players) - Action Chunking / Macro system - Forgetting Curve (session time decay) - Next-Action Prediction Engine - Working Memory Buffer (short-term vs long-term) - Behavior Clustering (path generalization) ]] local EAT = {} -- ---- STATE ---- EAT.active = false EAT.sessionStart = 0 EAT.tickAccum = 0 EAT.sampleRate = 0.25 -- base sample rate, adapts by FPS + player count -- ---- WORKING MEMORY BUFFER (short-term) ---- -- Holds last N actions seen by user. Checked before long-term brain. EAT.workingMemory = {} -- circular buffer EAT.WM_CAPACITY = 20 -- max entries -- ---- MACRO / CHUNK SYSTEM ---- EAT.macros = {} -- named action chunks EAT.currentChunk = {} -- current chunk being built EAT.CHUNK_MIN_LEN = 3 -- minimum actions to form a chunk EAT.CHUNK_MAX_LEN = 8 EAT.chunkLabels = { ["move|move|move|ui_click"] = "approach_and_interact", ["sprint_start|move|move|jump"] = "parkour_sequence", ["move|ui_click|move|move"] = "click_and_move", ["jump|move|move|move"] = "jump_traverse", ["sprint_start|move|move|move"] = "sprint_path", ["ui_click|ui_click|move"] = "multi_interact", ["move|move|jump|move|move"] = "gap_cross", ["ui_click|move|ui_click"] = "ui_navigate", ["move|move|move|move|move"] = "long_path", ["sprint_start|sprint_end|ui_click"] = "sprint_to_objective", } -- ---- ATTENTION SCORER ---- -- Each player gets a score 0-100 representing how worth-watching they are EAT.attentionScores = {} -- [userId] = score EAT.attentionHistory= {} -- [userId] = {lastPos, lastActionCount, lastUpdateTime} -- ---- FORGETTING CURVE ---- -- Returns weight multiplier [0.0 - 1.0] based on session age in seconds local FORGETTING_CURVE = { {days=0, weight=1.00}, {days=3, weight=0.80}, {days=7, weight=0.60}, {days=14, weight=0.30}, {days=30, weight=0.10}, {days=999, weight=0.05}, } local SECONDS_PER_DAY = 86400 function EAT.getTimeDecayWeight(sessionTimestamp) if not sessionTimestamp then return 1.0 end local ageSeconds = os.time() - sessionTimestamp local ageDays = ageSeconds / SECONDS_PER_DAY local weight = 0.05 for i = 1, #FORGETTING_CURVE - 1 do local a = FORGETTING_CURVE[i] local b = FORGETTING_CURVE[i + 1] if ageDays >= a.days and ageDays < b.days then -- Linear interpolation between curve points local t = (ageDays - a.days) / (b.days - a.days) weight = a.weight + (b.weight - a.weight) * t break end end return math.max(0.05, weight) end -- ---- PATTERN REINFORCEMENT ---- -- Tracks which sequences were seen from BOTH self AND observed players EAT.reinforcedPatterns = {} -- sequenceKey -> {selfCount, observedCount, totalWeight} function EAT.reinforcePattern(seqKey, source) if not EAT.reinforcedPatterns[seqKey] then EAT.reinforcedPatterns[seqKey] = { selfCount = 0, observedCount = 0, totalWeight = 0, } end local pat = EAT.reinforcedPatterns[seqKey] if source == "self" then pat.selfCount += 1 else pat.observedCount += 1 end -- Weight doubles when BOTH self and observed confirm it if pat.selfCount > 0 and pat.observedCount > 0 then pat.totalWeight = (pat.selfCount + pat.observedCount) * 2.0 -- dual-source bonus else pat.totalWeight = pat.selfCount * 1.0 + pat.observedCount * 0.6 end end function EAT.getPatternWeight(seqKey) local pat = EAT.reinforcedPatterns[seqKey] if not pat then return 0 end return pat.totalWeight end -- ---- WORKING MEMORY ---- function EAT.pushWorkingMemory(action) table.insert(EAT.workingMemory, action) if #EAT.workingMemory > EAT.WM_CAPACITY then table.remove(EAT.workingMemory, 1) -- drop oldest end end function EAT.getWorkingMemoryKey() -- Builds a sequence key from recent working memory entries local key = "" local start = math.max(1, #EAT.workingMemory - 4) for i = start, #EAT.workingMemory do key = key .. (EAT.workingMemory[i].type or "?") .. "|" end return key end -- ---- ACTION CHUNKING ---- function EAT.pushChunk(actionType) table.insert(EAT.currentChunk, actionType) if #EAT.currentChunk > EAT.CHUNK_MAX_LEN then table.remove(EAT.currentChunk, 1) end -- Check if current chunk matches any label EAT.detectMacro() end function EAT.detectMacro() if #EAT.currentChunk < EAT.CHUNK_MIN_LEN then return nil end -- Try matching from longest to shortest window for len = math.min(#EAT.currentChunk, EAT.CHUNK_MAX_LEN), EAT.CHUNK_MIN_LEN, -1 do local key = "" local startIdx = #EAT.currentChunk - len + 1 for i = startIdx, #EAT.currentChunk do key = key .. EAT.currentChunk[i] .. "|" end -- Remove trailing | key = key:sub(1, -2) local label = EAT.chunkLabels[key] if label then -- Register or reinforce this macro if not EAT.macros[label] then EAT.macros[label] = { label = label, key = key, count = 0, actions = {}, lastSeen = 0, } end EAT.macros[label].count += 1 EAT.macros[label].lastSeen = os.time() -- Save actual action data snapshot for replay local place = getCurrentPlace() if place and AIState.currentSession then local total = #AIState.currentSession.actions local slice = {} for i = math.max(1, total - len + 1), total do table.insert(slice, AIState.currentSession.actions[i]) end EAT.macros[label].actions = slice end print("[VoidAI:EAT] Macro detected: " .. label .. " (x" .. EAT.macros[label].count .. ")") return label end end return nil end function EAT.saveMacros() -- Persist macros into brain file local place = getCurrentPlace() if not place then return end place.macros = EAT.macros end function EAT.loadMacros() local place = getCurrentPlace() if not place then return end if place.macros then EAT.macros = place.macros local count = 0 for _ in pairs(EAT.macros) do count += 1 end if count > 0 then print("[VoidAI:EAT] Loaded " .. count .. " macros from brain") end end end -- ---- ATTENTION FOCUS ---- function EAT.updateAttentionScore(player) local pid = player.UserId local char = player.Character if not char then return 0 end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then return 0 end if not EAT.attentionHistory[pid] then EAT.attentionHistory[pid] = { lastPos = hrp.Position, lastActionCount = 0, lastUpdateTime = os.time(), score = 50, } end local hist = EAT.attentionHistory[pid] local timeDelta= os.time() - hist.lastUpdateTime if timeDelta < 0.5 then return hist.score end local score = 0 -- Movement activity (0-40 pts) local moveDelta = (hrp.Position - hist.lastPos).Magnitude score += math.min(40, moveDelta * 2) -- Walk speed (running = interesting, 0-20 pts) if hum.WalkSpeed > 20 then score += 20 elseif hum.WalkSpeed > 14 then score += 10 end -- Health change detection (combat/damage = interesting, 0-20 pts) if hum.Health < hum.MaxHealth * 0.9 then score += 20 elseif hum.Health < hum.MaxHealth then score += 10 end -- Idle penalty if moveDelta < 1 and hum.WalkSpeed <= 0 then score = math.max(0, score - 30) end -- Smooth score with exponential moving average hist.score = hist.score * 0.7 + score * 0.3 hist.lastPos = hrp.Position hist.lastUpdateTime= os.time() EAT.attentionScores[pid] = hist.score return hist.score end function EAT.getSortedPlayers() -- Returns players sorted by attention score descending local scored = {} for _, p in ipairs(Players:GetPlayers()) do if p ~= LocalPlayer then local score = EAT.updateAttentionScore(p) table.insert(scored, {player = p, score = score}) end end table.sort(scored, function(a, b) return a.score > b.score end) return scored end -- ---- BEHAVIOR CLUSTERING ---- -- Groups similar movement positions into cluster centroids -- So AI generalizes paths instead of memorizing exact coordinates EAT.clusters = {} -- list of {centroid, members, tag} EAT.CLUSTER_RADIUS = 15 -- studs — positions within this distance merge function EAT.addToCluster(pos, tag) -- Find nearest existing cluster local nearest = nil local nearestDist= math.huge for i, cluster in ipairs(EAT.clusters) do local c = cluster.centroid local dist= (Vector3.new(c.x,c.y,c.z) - pos).Magnitude if dist < nearestDist then nearestDist = dist nearest = i end end if nearest and nearestDist <= EAT.CLUSTER_RADIUS then -- Merge into existing cluster — update centroid local cluster = EAT.clusters[nearest] local n = #cluster.members + 1 cluster.centroid = { x = (cluster.centroid.x * (n-1) + pos.X) / n, y = (cluster.centroid.y * (n-1) + pos.Y) / n, z = (cluster.centroid.z * (n-1) + pos.Z) / n, } table.insert(cluster.members, {x=pos.X, y=pos.Y, z=pos.Z}) if tag and tag ~= "visited" then cluster.tag = tag end else -- Create new cluster table.insert(EAT.clusters, { centroid = {x=pos.X, y=pos.Y, z=pos.Z}, members = {{x=pos.X, y=pos.Y, z=pos.Z}}, tag = tag or "visited", weight = 1, }) end end function EAT.getNearestCluster(pos) local nearest = nil local nearestDist= math.huge for _, cluster in ipairs(EAT.clusters) do local c = cluster.centroid local dist= (Vector3.new(c.x,c.y,c.z) - pos).Magnitude if dist < nearestDist then nearestDist = dist nearest = cluster end end return nearest, nearestDist end function EAT.saveClusters() local place = getCurrentPlace() if not place then return end -- Cap at 500 clusters to avoid bloat if #EAT.clusters > 500 then -- Keep only the most-membered clusters table.sort(EAT.clusters, function(a,b) return #a.members > #b.members end) local trimmed = {} for i = 1, 500 do trimmed[i] = EAT.clusters[i] end EAT.clusters = trimmed end place.clusters = EAT.clusters end function EAT.loadClusters() local place = getCurrentPlace() if not place then return end if place.clusters then EAT.clusters = place.clusters print("[VoidAI:EAT] Loaded " .. #EAT.clusters .. " behavior clusters") end end -- ---- NEXT-ACTION PREDICTION ENGINE ---- -- Scores candidate actions based on: -- 1. Working memory context (recent actions) -- 2. Reinforced pattern weights -- 3. Cluster proximity -- 4. Forgetting-curve-weighted session history EAT.lastPrediction = nil EAT.predictionScores= {} local CANDIDATE_ACTIONS = { "move", "jump", "sprint_start", "ui_click", "hide", "flee", "interact", "wait", } function EAT.predictNextAction() local place = getCurrentPlace() if not place then return nil end local wmKey = EAT.getWorkingMemoryKey() local scores = {} for _, candidate in ipairs(CANDIDATE_ACTIONS) do local score = 0 -- 1. Working memory match: does recent history predict this next? local testKey = wmKey .. candidate for seqKey, pat in pairs(EAT.reinforcedPatterns) do if seqKey:find(testKey, 1, true) then score += EAT.getPatternWeight(seqKey) * 10 end end -- 2. Session history: how often does this action follow current context? for _, session in ipairs(place.sessions) do local decay = EAT.getTimeDecayWeight(session.startTime or session.id) local trust = (session.type == "adaptive_observed") and 0.6 or 1.0 local actions= session.actions or {} for i = 2, #actions do if actions[i-1].type == (EAT.workingMemory[#EAT.workingMemory] or {}).type then if actions[i].type == candidate then score += decay * trust * 5 end end end end -- 3. Threat modifier: if threat detected, boost survival actions if AIState.threatDetected then if candidate == "hide" or candidate == "flee" then score += 50 end if candidate == "ui_click" or candidate == "wait" then score -= 20 end end -- 4. Persona modifier if AIState.persona == "Aggressive" then if candidate == "sprint_start" or candidate == "move" then score += 10 end if candidate == "hide" or candidate == "wait" then score -= 15 end elseif AIState.persona == "Passive" then if candidate == "wait" or candidate == "ui_click" then score += 10 end if candidate == "sprint_start" then score -= 10 end end scores[candidate] = math.max(0, score) end -- Find highest scoring candidate local bestAction = "move" local bestScore = -1 for action, score in pairs(scores) do if score > bestScore then bestScore = score bestAction = action end end EAT.lastPrediction = bestAction EAT.predictionScores = scores return bestAction, bestScore, scores end -- ---- FORGETTING CURVE APPLICATION ---- -- Recalculates confidence using time-decayed session weights -- Called periodically so confidence reflects recent relevance function EAT.applyForgettingCurve() local place = getCurrentPlace() if not place or #place.sessions == 0 then return end local totalMoves, totalUI, totalSeq = 0, 0, 0 for _, session in ipairs(place.sessions) do local decay = EAT.getTimeDecayWeight(session.startTime or session.id) local trust = (session.type == "adaptive_observed") and AdaptiveThinking.TRUST_WEIGHT or 1.0 local w = decay * trust totalMoves = totalMoves + #(session.movements or {}) * w totalUI = totalUI + #(session.uiClicks or {}) * w totalSeq = totalSeq + #(session.sequences or {}) * w end place.confidence.movement = math.min(100, math.floor(math.log(totalMoves + 1) * 15)) place.confidence.ui = math.min(100, math.floor(math.log(totalUI + 1) * 20)) place.confidence.sequences = math.min(100, math.floor(math.log(totalSeq + 1) * 25)) end -- ---- CORE: OBSERVE SELF TICK ---- -- Runs while EAT is active AND user is actively playing function EAT.observeSelf() local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then return end local pos = hrp.Position -- Record movement to working memory local moveDelta = (pos - Observer.lastPosition).Magnitude if moveDelta >= 2 then local action = { type = "move", source = "self", data = {pos={x=pos.X,y=pos.Y,z=pos.Z}, t=os.time()-AIState.sessionStart}, } EAT.pushWorkingMemory(action) EAT.pushChunk("move") -- Add to behavior clusters EAT.addToCluster(pos, "visited") -- Reinforce this as a self-observed pattern local wmKey = EAT.getWorkingMemoryKey() EAT.reinforcePattern(wmKey, "self") end end -- ---- CORE: OBSERVE OTHERS TICK ---- -- Attention-weighted player sampling function EAT.observeOthers() local place = getCurrentPlace() if not place then return end local sortedPlayers = EAT.getSortedPlayers() -- Top 30% of players get 3x more samples, bottom 20% are skipped local total = #sortedPlayers if total == 0 then return end for rank, entry in ipairs(sortedPlayers) do local p = entry.player local score = entry.score -- Skip idle players entirely (score < 15) if score < 15 then continue end -- Sub-sample low-attention players (50% chance) local normalized = rank / total -- 0=highest attention, 1=lowest if normalized > 0.7 then if math.random() > 0.5 then continue end end local char = p.Character if not char then continue end local hrp = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then continue end local pos = hrp.Position -- Track this player's previous position local pid = p.UserId if not AdaptiveThinking.playerTrackers[pid] then AdaptiveThinking.playerTrackers[pid] = { name = p.Name, lastPos = pos, lastMoveT = os.time(), pathPoints= {}, isRunning = false, fleeCount = 0, } end local tracker = AdaptiveThinking.playerTrackers[pid] local moveDelta= (pos - tracker.lastPos).Magnitude if moveDelta < 2 then continue end tracker.lastPos = pos -- Build action from observation local observedAction = { type = "move", source = "observed_" .. p.Name, trustWeight = AdaptiveThinking.TRUST_WEIGHT, data = { pos = {x=pos.X, y=pos.Y, z=pos.Z}, t = os.time() - EAT.sessionStart, spd = hum.WalkSpeed, }, } -- Push to working memory with lower trust EAT.pushWorkingMemory(observedAction) -- Pattern reinforcement — observed source local wmKey = EAT.getWorkingMemoryKey() EAT.reinforcePattern(wmKey, "observed") -- Add to clusters EAT.addToCluster(pos, "visited") -- Detect fleeing if hum.WalkSpeed > 20 and not tracker.isRunning then tracker.isRunning = true EAT.addToCluster(pos, "danger") elseif hum.WalkSpeed <= 16 then tracker.isRunning = false end -- Check if same path was also taken by self recently -- If so, reinforce double local selfNearby = false if LocalPlayer.Character then local selfHRP = LocalPlayer.Character:FindFirstChild("HumanoidRootPart") if selfHRP and (selfHRP.Position - pos).Magnitude < EAT.CLUSTER_RADIUS then selfNearby = true end end if selfNearby then EAT.reinforcePattern(wmKey, "self") -- dual-source reinforce end end end -- ---- MAIN EAT TICK (plugged into RunService) ---- RunService.Heartbeat:Connect(function(dt) if not EAT.active then return end EAT.tickAccum += dt -- Adapt sample rate same as ATM local playerCount = #Players:GetPlayers() - 1 if FPS > 50 and playerCount <= 5 then EAT.sampleRate = 0.2 elseif FPS > 30 then EAT.sampleRate = 0.35 else EAT.sampleRate = 0.6 end if EAT.tickAccum < EAT.sampleRate then return end EAT.tickAccum = 0 -- Observe self EAT.observeSelf() -- Observe others EAT.observeOthers() -- Run prediction every 2 seconds (low priority) if AIState.tickCounter % 8 == 0 then EAT.predictNextAction() end -- Apply forgetting curve every 30 seconds if AIState.tickCounter % 120 == 0 then EAT.applyForgettingCurve() end -- Auto-save macros + clusters every 60 seconds if AIState.tickCounter % 240 == 0 then EAT.saveMacros() EAT.saveClusters() saveBrain() end end) -- ---- PUBLIC API ---- function EAT.start() if EAT.active then return end EAT.active = true EAT.sessionStart = os.time() EAT.workingMemory = {} EAT.currentChunk = {} AdaptiveThinking.playerTrackers = {} -- Load existing macros + clusters from brain EAT.loadMacros() EAT.loadClusters() -- Make sure observer session is also running (self-learning) if not AIState.isLearning then AIState.isLearning = true Observer.startSession() end VoidGUI.notify("⚡ Extended Adaptive Thinking ON") print("[VoidAI:EAT] Started — dual-source learning active") end function EAT.stop() if not EAT.active then return end EAT.active = false -- Finalize EAT.saveMacros() EAT.saveClusters() EAT.applyForgettingCurve() saveBrain() -- Print summary local macroCount = 0 local clusterCount = #EAT.clusters local patCount = 0 for _ in pairs(EAT.macros) do macroCount += 1 end for _ in pairs(EAT.reinforcedPatterns) do patCount += 1 end VoidGUI.notify(string.format("⚡ EAT OFF — %d macros | %d clusters | %d patterns", macroCount, clusterCount, patCount)) print(string.format("[VoidAI:EAT] Stopped — Macros:%d Clusters:%d Patterns:%d", macroCount, clusterCount, patCount)) end function EAT.toggle() if EAT.active then EAT.stop() else EAT.start() end end -- ---- GHOST/LEND INTEGRATION ---- -- GhostController checks EAT prediction before doing linear replay local _eatWrappedStepReplay = GhostController.stepReplay function GhostController.stepReplay() -- If EAT prediction is available and confident, use it if EAT.lastPrediction and EAT.predictionScores then local bestScore = EAT.predictionScores[EAT.lastPrediction] or 0 if bestScore > 20 then -- confidence threshold local char = LocalPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") local hrp = char and char:FindFirstChild("HumanoidRootPart") if EAT.lastPrediction == "jump" and hum then hum.Jump = true EAT.pushChunk("jump") return elseif EAT.lastPrediction == "sprint_start" and hum then hum.WalkSpeed = 24 EAT.pushChunk("sprint_start") return elseif EAT.lastPrediction == "hide" then GhostController.runSurvivalPattern() return elseif EAT.lastPrediction == "flee" then GhostController.runSurvivalPattern() return elseif EAT.lastPrediction == "move" then -- Use nearest cluster centroid as target if hrp then local cluster, dist = EAT.getNearestCluster(hrp.Position) if cluster and dist > 5 then local target = Vector3.new( cluster.centroid.x, cluster.centroid.y, cluster.centroid.z ) if hum then hum:MoveTo(target) end EAT.pushChunk("move") return end end end end end -- Fallback: check macro library first local wmKey = EAT.getWorkingMemoryKey() for label, macro in pairs(EAT.macros) do if macro.count >= 2 and #macro.actions > 0 then -- Find a macro whose key is predicted by current context if wmKey:find(macro.key:sub(1,6), 1, true) then -- Replay macro actions task.spawn(function() for _, action in ipairs(macro.actions) do if AIState.mode ~= "ghost" and AIState.mode ~= "lend" then break end if AIState.isPaused then break end local char = LocalPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") if action.type == "move" and action.data then GhostController.executeMove(action.data) elseif action.type == "ui_click" and action.data then GhostController.executeUIClick(action.data) elseif action.type == "jump" and hum then hum.Jump = true end task.wait(0.15) end end) return end end end -- Final fallback: linear replay _eatWrappedStepReplay() end -- ---- GUI INTEGRATION ---- task.spawn(function() task.wait(1.2) if not screenGui then return end local panel = screenGui:FindFirstChild("VoidAIPanel") if not panel then return end local scrollFrames = {} for _, child in ipairs(panel:GetChildren()) do if child:IsA("ScrollingFrame") then table.insert(scrollFrames, child) end end local mainScroll = scrollFrames[1] local settingsScroll = scrollFrames[4] if mainScroll then -- EAT toggle button (below ATM button) local eatBtn = makeButton(mainScroll, "⚡ Ext. Adaptive Thinking: OFF", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,356), COLORS.panel) eatBtn.TextSize = 11 -- Prediction display local predLabel = makeLabel(mainScroll, "Prediction: —", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,388), 9, COLORS.textDim) -- Macro count local macroLabel = makeLabel(mainScroll, "Macros: 0 | Clusters: 0 | Patterns: 0", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,404), 9, COLORS.textDim) eatBtn.MouseButton1Click:Connect(function() EAT.toggle() if EAT.active then eatBtn.Text = "⚡ Ext. Adaptive Thinking: ON" eatBtn.BackgroundColor3 = COLORS.accentHot else eatBtn.Text = "⚡ Ext. Adaptive Thinking: OFF" eatBtn.BackgroundColor3 = COLORS.panel end end) -- Live update loop for EAT status task.spawn(function() while true do task.wait(1) if not mainScroll or not mainScroll.Parent then break end -- Update button state if EAT.active then eatBtn.Text = "⚡ Ext. Adaptive Thinking: ON" eatBtn.BackgroundColor3 = COLORS.accentHot else eatBtn.Text = "⚡ Ext. Adaptive Thinking: OFF" eatBtn.BackgroundColor3 = COLORS.panel end -- Update prediction label if EAT.lastPrediction then local score = EAT.predictionScores and EAT.predictionScores[EAT.lastPrediction] or 0 predLabel.Text = string.format("Prediction: %s (%.0f pts)", EAT.lastPrediction, score) predLabel.TextColor3 = score > 20 and COLORS.success or COLORS.textDim else predLabel.Text = "Prediction: — (not enough data)" predLabel.TextColor3 = COLORS.textDim end -- Macro / cluster / pattern counts local macroCount = 0 local patternCount = 0 for _ in pairs(EAT.macros) do macroCount += 1 end for _ in pairs(EAT.reinforcedPatterns) do patternCount += 1 end macroLabel.Text = string.format( "Macros:%d | Clusters:%d | Patterns:%d", macroCount, #EAT.clusters, patternCount) end end) mainScroll.CanvasSize = UDim2.new(0,0,0,650) end -- Add EAT stats to settings tab if settingsScroll then makeLabel(settingsScroll, "EAT Settings", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,540), 11, COLORS.accent).Font = Enum.Font.GothamBold -- AFK threshold slider (text input) makeLabel(settingsScroll, "AFK Threshold (sec)", UDim2.new(0.55,0,0,22), UDim2.new(0,6,0,558), 10, COLORS.textDim) local afkBox = Instance.new("TextBox") afkBox.Size = UDim2.new(0.35,0,0,22) afkBox.Position = UDim2.new(0.6,0,0,558) afkBox.BackgroundColor3 = COLORS.panel afkBox.TextColor3 = COLORS.text afkBox.Text = tostring(AdaptiveThinking.afkThreshold) afkBox.Font = Enum.Font.GothamBold afkBox.TextSize = 11 afkBox.BorderSizePixel = 0 afkBox.Parent = settingsScroll local afkc = Instance.new("UICorner"); afkc.CornerRadius = UDim.new(0,4); afkc.Parent = afkBox afkBox.FocusLost:Connect(function() local val = tonumber(afkBox.Text) if val and val >= 5 and val <= 300 then AdaptiveThinking.afkThreshold = val VoidGUI.notify("AFK threshold: " .. val .. "s") else afkBox.Text = tostring(AdaptiveThinking.afkThreshold) end end) -- Cluster radius input makeLabel(settingsScroll, "Cluster Radius (studs)", UDim2.new(0.55,0,0,22), UDim2.new(0,6,0,584), 10, COLORS.textDim) local clusterBox = Instance.new("TextBox") clusterBox.Size = UDim2.new(0.35,0,0,22) clusterBox.Position = UDim2.new(0.6,0,0,584) clusterBox.BackgroundColor3 = COLORS.panel clusterBox.TextColor3 = COLORS.text clusterBox.Text = tostring(EAT.CLUSTER_RADIUS) clusterBox.Font = Enum.Font.GothamBold clusterBox.TextSize = 11 clusterBox.BorderSizePixel = 0 clusterBox.Parent = settingsScroll local clc = Instance.new("UICorner"); clc.CornerRadius = UDim.new(0,4); clc.Parent = clusterBox clusterBox.FocusLost:Connect(function() local val = tonumber(clusterBox.Text) if val and val >= 5 and val <= 100 then EAT.CLUSTER_RADIUS = val else clusterBox.Text = tostring(EAT.CLUSTER_RADIUS) end end) -- Clear clusters button local clearBtn = makeButton(settingsScroll, "🗑 Clear Clusters", UDim2.new(1,-12,0,26), UDim2.new(0,6,0,610), COLORS.danger) clearBtn.MouseButton1Click:Connect(function() EAT.clusters = {} local place = getCurrentPlace() if place then place.clusters = {} end VoidGUI.notify("Clusters cleared") end) settingsScroll.CanvasSize = UDim2.new(0,0,0,660) end end) -- ---- CHAT COMMANDS ---- CHAT_COMMANDS["eat"] = function() EAT.toggle() end CHAT_COMMANDS["macros"] = function() local count = 0 local names = {} for label, macro in pairs(EAT.macros) do count += 1 table.insert(names, label .. "(x" .. macro.count .. ")") end VoidGUI.notify("Macros (" .. count .. "): " .. table.concat(names, ", "):sub(1, 80)) end CHAT_COMMANDS["predict"] = function() local action, score = EAT.predictNextAction() VoidGUI.notify("Prediction: " .. (action or "none") .. " (" .. math.floor(score or 0) .. " pts)") end CHAT_COMMANDS["forget"] = function() EAT.applyForgettingCurve() VoidGUI.notify("Forgetting curve applied — confidence recalculated") end -- ---- INIT HOOK ---- -- Load EAT data when brain loads (runs after main init) task.spawn(function() task.wait(2) EAT.loadMacros() EAT.loadClusters() local macroCount = 0 for _ in pairs(EAT.macros) do macroCount += 1 end if macroCount > 0 then print("[VoidAI:EAT] " .. macroCount .. " macros ready | " .. #EAT.clusters .. " clusters loaded") end end) -- ============================================================ -- SECTION 35: ANOMALY DETECTION -- ============================================================ --[[ Watches for unusual events the AI hasn't seen before. Flags them as "anomalies" and stores them separately. Over time, anomalies that repeat get promoted to normal patterns. Mimics how a real AI handles out-of-distribution inputs. ]] local AnomalyDetector = {} AnomalyDetector.anomalies = {} -- {event, count, firstSeen, lastSeen} AnomalyDetector.PROMOTE_COUNT= 3 -- seen N times = no longer anomaly function AnomalyDetector.check(actionType, context) local place = getCurrentPlace() if not place or #place.sessions < 2 then return false end -- Check if this action type has ever appeared in any session local seen = false for _, session in ipairs(place.sessions) do for _, action in ipairs(session.actions or {}) do if action.type == actionType then seen = true break end end if seen then break end end if not seen then -- New anomaly local key = actionType .. "|" .. (context or "") if not AnomalyDetector.anomalies[key] then AnomalyDetector.anomalies[key] = { event = actionType, context = context, count = 0, firstSeen = os.time(), lastSeen = os.time(), promoted = false, } end local a = AnomalyDetector.anomalies[key] a.count += 1 a.lastSeen = os.time() if a.count >= AnomalyDetector.PROMOTE_COUNT and not a.promoted then a.promoted = true print("[VoidAI:Anomaly] Promoted to pattern: " .. key) VoidGUI.notify("🔍 New pattern learned: " .. actionType) end return true end return false end function AnomalyDetector.getUnpromoted() local list = {} for _, a in pairs(AnomalyDetector.anomalies) do if not a.promoted then table.insert(list, a) end end table.sort(list, function(a,b) return a.count > b.count end) return list end -- ============================================================ -- SECTION 36: EMOTION / URGENCY STATE -- ============================================================ --[[ The AI maintains an internal urgency level (0-100). Low urgency = slow careful decisions. High urgency = fast aggressive decisions. Driven by: threat detection, player health, nearby fleeing players, time pressure signals (timers in UI), and persona. Mimics an emotional state layer found in modern RL agents. ]] local UrgencySystem = {} UrgencySystem.level = 0 -- 0 = calm, 100 = panic UrgencySystem.history = {} -- rolling history for smoothing UrgencySystem.MAX_HIST = 10 function UrgencySystem.update() local rawUrgency = 0 -- Threat detected = massive urgency spike if AIState.threatDetected then rawUrgency += 60 end -- Player health local char = LocalPlayer.Character if char then local hum = char:FindFirstChildOfClass("Humanoid") if hum and hum.MaxHealth > 0 then local healthRatio = hum.Health / hum.MaxHealth if healthRatio < 0.3 then rawUrgency += 40 elseif healthRatio < 0.6 then rawUrgency += 20 end end end -- Nearby players fleeing local fleeCount = 0 for _, p in ipairs(Players:GetPlayers()) do if p ~= LocalPlayer and p.Character then local h = p.Character:FindFirstChildOfClass("Humanoid") if h and h.WalkSpeed > 20 then fleeCount += 1 end end end rawUrgency += math.min(30, fleeCount * 10) -- Persona modifier if AIState.persona == "Aggressive" then rawUrgency = rawUrgency * 1.3 elseif AIState.persona == "Passive" then rawUrgency = rawUrgency * 0.6 end rawUrgency = math.min(100, rawUrgency) -- Smooth with rolling average table.insert(UrgencySystem.history, rawUrgency) if #UrgencySystem.history > UrgencySystem.MAX_HIST then table.remove(UrgencySystem.history, 1) end local sum = 0 for _, v in ipairs(UrgencySystem.history) do sum += v end UrgencySystem.level = sum / #UrgencySystem.history end function UrgencySystem.getLabel() if UrgencySystem.level >= 75 then return "PANIC", COLORS.danger elseif UrgencySystem.level >= 50 then return "HIGH", COLORS.warning elseif UrgencySystem.level >= 25 then return "MED", COLORS.accent else return "CALM", COLORS.success end end -- Wire urgency into replay speed — higher urgency = faster action cadence local function getReplayInterval() local base = 0.2 local urgencyFactor = 1 - (UrgencySystem.level / 100) * 0.7 return math.max(0.05, base * urgencyFactor) end -- Update urgency every second in heartbeat local lastUrgencyTick = 0 RunService.Heartbeat:Connect(function(dt) lastUrgencyTick += dt if lastUrgencyTick >= 1 then lastUrgencyTick = 0 UrgencySystem.update() end end) -- ============================================================ -- SECTION 37: GOAL INFERENCE ENGINE -- ============================================================ --[[ Tries to infer what the player's current goal is based on observed actions + mental map context. Goals feed into the prediction engine and LLM prompts. Mimics goal-directed planning in modern AI agents. ]] local GoalEngine = {} GoalEngine.currentGoal = "explore" -- default GoalEngine.goalHistory = {} GoalEngine.goalScores = {} local GOAL_SIGNALS = { explore = {"move", "move", "move", "move"}, combat = {"sprint_start", "jump", "move", "sprint_start"}, interact_ui = {"ui_click", "ui_click", "move"}, collect = {"move", "ui_click", "move", "ui_click"}, escape = {"sprint_start", "move", "jump", "sprint_start", "move"}, idle = {"wait", "wait", "wait"}, } function GoalEngine.infer() if #EAT.workingMemory < 4 then return GoalEngine.currentGoal end -- Build recent action string local recent = {} local start = math.max(1, #EAT.workingMemory - 5) for i = start, #EAT.workingMemory do table.insert(recent, EAT.workingMemory[i].type or "?") end GoalEngine.goalScores = {} for goal, signals in pairs(GOAL_SIGNALS) do local score = 0 for i, sig in ipairs(signals) do if recent[i] == sig then score += 1 end end GoalEngine.goalScores[goal] = score / #signals end -- Threat override if AIState.threatDetected then GoalEngine.goalScores["escape"] = 1.0 end -- Pick highest local bestGoal = GoalEngine.currentGoal local bestScore = 0 for goal, score in pairs(GoalEngine.goalScores) do if score > bestScore then bestScore = score bestGoal = goal end end if bestGoal ~= GoalEngine.currentGoal then table.insert(GoalEngine.goalHistory, { from = GoalEngine.currentGoal, to = bestGoal, t = os.time(), }) GoalEngine.currentGoal = bestGoal print("[VoidAI:Goal] Inferred goal: " .. bestGoal) end return GoalEngine.currentGoal end -- Patch LLM prompt to include goal local _origBuildPrompt = LLMController.buildPrompt function LLMController.buildPrompt(gameState) local base = _origBuildPrompt(gameState) if not base then return nil end local urgLabel = UrgencySystem.getLabel() local goal = GoalEngine.infer() local anomalies= AnomalyDetector.getUnpromoted() local anomStr = "" for i, a in ipairs(anomalies) do if i > 3 then break end anomStr = anomStr .. a.event .. "(x" .. a.count .. ") " end return base .. string.format("\nInferred goal: %s", goal) .. string.format("\nUrgency level: %s (%.0f/100)", urgLabel, UrgencySystem.level) .. string.format("\nUnexplained events: %s", anomStr ~= "" and anomStr or "none") .. string.format("\nActive macros: %d | Behavior clusters: %d", (function() local c=0; for _ in pairs(EAT.macros) do c+=1 end; return c end)(), #EAT.clusters) end -- ============================================================ -- SECTION 38: SELF-ASSESSMENT REPORT -- ============================================================ --[[ Periodically generates a plain-text self-assessment of the AI's current knowledge state. Useful for the user to understand what the AI knows and what it still needs to learn. Also used as context when switching from Local AI to LLM mode. ]] local SelfAssessment = {} function SelfAssessment.generate() local place = getCurrentPlace() local urgLabel = UrgencySystem.getLabel() local goal = GoalEngine.currentGoal local macroCount, patternCount = 0, 0 for _ in pairs(EAT.macros) do macroCount += 1 end for _ in pairs(EAT.reinforcedPatterns) do patternCount += 1 end local anomalies = AnomalyDetector.getUnpromoted() local weakAreas = {} local strongAreas= {} if place then if place.confidence.movement < 40 then table.insert(weakAreas, "movement") else table.insert(strongAreas, "movement") end if place.confidence.ui < 40 then table.insert(weakAreas, "UI interaction") else table.insert(strongAreas, "UI interaction") end if place.confidence.sequences < 40 then table.insert(weakAreas, "action sequences") else table.insert(strongAreas, "action sequences") end end local lines = { "=== VoidAI Self-Assessment ===", "Game: " .. (place and place.placeName or "Unknown"), "Sessions: " .. (place and #place.sessions or 0), "Goal: " .. goal, "Urgency: " .. urgLabel .. string.format(" (%.0f/100)", UrgencySystem.level), "", "KNOWLEDGE:", " Strong: " .. (#strongAreas > 0 and table.concat(strongAreas, ", ") or "none yet"), " Weak: " .. (#weakAreas > 0 and table.concat(weakAreas, ", ") or "none"), "", "LEARNED STRUCTURES:", " Macros: " .. macroCount, " Clusters: " .. #EAT.clusters, " Patterns: " .. patternCount, " Anomalies:" .. #anomalies .. " unresolved", "", "RECOMMENDATIONS:", } if #weakAreas > 0 then table.insert(lines, " → Train more: " .. table.concat(weakAreas, ", ")) end if macroCount < 3 then table.insert(lines, " → Play longer to build macro library") end if #EAT.clusters < 10 then table.insert(lines, " → Explore more areas to build mental map") end if place and #place.sessions >= 5 and macroCount >= 3 then table.insert(lines, " ✓ AI is ready for LLM-assisted play") end table.insert(lines, "") table.insert(lines, "Generated: " .. tostring(os.time())) local report = table.concat(lines, "\n") -- Save to file local path = BRAIN_FOLDER .. "/assessment_" .. getPlaceId() .. ".txt" Exec.writeFile(path, report) return report end -- Add to chat commands CHAT_COMMANDS["assess"] = function() local report = SelfAssessment.generate() -- Show first 3 lines as notification local firstLines = report:split("\n") local preview = "" for i = 1, math.min(3, #firstLines) do preview = preview .. firstLines[i] .. " | " end VoidGUI.notify(preview) print(report) end -- ============================================================ -- SECTION 39: REPLAY SPEED CONTROL + LOOP MODES -- ============================================================ --[[ Gives the user fine control over how the AI replays sessions. Modes: - Normal: plays actions at recorded pace - Fast: 2x speed - Cautious: 0.5x speed, more pauses - Loop: repeats best session forever - Once: plays once then stops Also integrates urgency — high urgency overrides to Fast mode. ]] local ReplayControl = {} ReplayControl.speed = 1.0 -- multiplier ReplayControl.loopMode = "loop" -- "loop" | "once" ReplayControl.paused = false local SPEED_PRESETS = { Cautious = 0.5, Normal = 1.0, Fast = 2.0, Panic = 4.0, -- auto-set by urgency } function ReplayControl.setSpeed(preset) ReplayControl.speed = SPEED_PRESETS[preset] or 1.0 VoidGUI.notify("Replay speed: " .. preset) end function ReplayControl.getInterval() local base = 0.2 local urgency = UrgencySystem.level -- High urgency overrides to faster replay local urgencyMod = 1 - (urgency / 100) * 0.7 local finalInterval = (base / ReplayControl.speed) * urgencyMod return math.max(0.04, finalInterval) end -- Patch main heartbeat ghost/lend step to use ReplayControl interval local replayAccum = 0 RunService.Heartbeat:Connect(function(dt) if AIState.mode ~= "ghost" and AIState.mode ~= "lend" then replayAccum = 0 return end if AIState.isPaused then return end replayAccum += dt if replayAccum >= ReplayControl.getInterval() then replayAccum = 0 GhostController.stepReplay() end end) -- ============================================================ -- SECTION 40: MULTI-BRAIN SUPPORT -- ============================================================ --[[ Allows saving and loading multiple named brain profiles for the same game. Useful if you want a "grind" brain and a "exploration" brain for the same experience. Named brains are stored as universe_ID_profilename.json ]] local MultiBrain = {} MultiBrain.profiles = {} function MultiBrain.listProfiles() local files = Exec.listFiles(BRAIN_FOLDER) local profiles = {} local prefix = "universe_" .. getUniverseId() for _, f in ipairs(files) do if f:find(prefix) then -- Extract profile name from filename local name = f:match("universe_%d+_?(.-)%.json") or "default" table.insert(profiles, {file = f, name = name == "" and "default" or name}) end end return profiles end function MultiBrain.saveAs(profileName) local safeName = profileName:gsub("[^%w%-_]", "") if safeName == "" then safeName = "default" end local path = BRAIN_FOLDER .. "/universe_" .. getUniverseId() .. "_" .. safeName .. ".json" local ok, encoded = pcall(HttpService.JSONEncode, HttpService, Brain) if ok then Exec.writeFile(path, encoded) VoidGUI.notify("Brain saved as: " .. safeName) end end function MultiBrain.loadProfile(profileName) local safeName = profileName:gsub("[^%w%-_]", "") local path = BRAIN_FOLDER .. "/universe_" .. getUniverseId() .. "_" .. safeName .. ".json" if not Exec.isFile(path) then VoidGUI.notify("Profile not found: " .. safeName) return false end local raw = Exec.readFile(path) if not raw then return false end local ok, decoded = pcall(HttpService.JSONDecode, HttpService, raw) if ok and decoded then Brain = decoded Brain.baseKnowledge = BASE_KNOWLEDGE EAT.loadMacros() EAT.loadClusters() VoidGUI.notify("Loaded brain: " .. safeName) VoidGUI.updateDisplay() return true end return false end -- Chat commands for multi-brain CHAT_COMMANDS["saveas"] = function() -- /void saveas profilename -- Parse not possible from single command, use notify to guide VoidGUI.notify("Type /void saveas_ to save a profile") end -- Dynamic command for /void saveas_grind, /void saveas_explore etc. local _origChatHandler = nil pcall(function() LocalPlayer.Chatted:Connect(function(msg) local lower = msg:lower() local parts = lower:split(" ") if parts[1] ~= CHAT_PREFIX then return end local cmd = parts[2] or "" -- Handle saveas_ prefix if cmd:sub(1, 7) == "saveas_" then local profileName = cmd:sub(8) if profileName and profileName ~= "" then MultiBrain.saveAs(profileName) end elseif cmd:sub(1, 5) == "load_" then local profileName = cmd:sub(6) if profileName and profileName ~= "" then MultiBrain.loadProfile(profileName) end end end) end) -- ============================================================ -- SECTION 41: PERFORMANCE PROFILER -- ============================================================ --[[ Tracks how long each VoidAI subsystem takes per frame. Displayed in stats tab. Helps identify bottlenecks on low-end devices. Auto-disables expensive subsystems if they exceed budget. ]] local Profiler = {} Profiler.budgetMs = 2.0 -- max ms per frame allowed for VoidAI Profiler.times = { observer = 0, eat = 0, atm = 0, threat = 0, urgency = 0, total = 0, } Profiler.warnings = {} Profiler.enabled = true local function profiledRun(label, fn) if not Profiler.enabled then fn(); return end local start = os.clock() local ok, err = pcall(fn) local elapsed = (os.clock() - start) * 1000 -- ms Profiler.times[label] = Profiler.times[label] * 0.8 + elapsed * 0.2 -- EMA if elapsed > Profiler.budgetMs then table.insert(Profiler.warnings, { label = label, ms = elapsed, time = os.time(), }) -- Cap warnings list if #Profiler.warnings > 20 then table.remove(Profiler.warnings, 1) end end if not ok then warn("[VoidAI:Profiler] Error in " .. label .. ": " .. tostring(err)) end end -- ============================================================ -- SECTION 42: FINAL GUI POLISH — URGENCY + GOAL + PREDICTION -- ============================================================ task.spawn(function() task.wait(1.5) if not screenGui then return end local panel = screenGui:FindFirstChild("VoidAIPanel") if not panel then return end local scrollFrames = {} for _, child in ipairs(panel:GetChildren()) do if child:IsA("ScrollingFrame") then table.insert(scrollFrames, child) end end local mainScroll = scrollFrames[1] local statsScroll = scrollFrames[2] -- Add urgency + goal bar to main tab if mainScroll then local urgencyLabel = makeLabel(mainScroll, "Urgency: CALM | Goal: explore", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,422), 9, COLORS.success) task.spawn(function() while true do task.wait(1) if not urgencyLabel or not urgencyLabel.Parent then break end local label, color = UrgencySystem.getLabel() local goal = GoalEngine.currentGoal urgencyLabel.Text = string.format( "Urgency: %s (%.0f) | Goal: %s", label, UrgencySystem.level, goal) urgencyLabel.TextColor3 = color end end) mainScroll.CanvasSize = UDim2.new(0,0,0,700) end -- Add profiler readout to stats tab if statsScroll then makeLabel(statsScroll, "⚡ Subsystem Timing (ms avg)", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,440), 11, COLORS.accent).Font = Enum.Font.GothamBold local profLabels = {} local subsystems = {"observer","eat","atm","threat","urgency","total"} for i, sys in ipairs(subsystems) do local lbl = makeLabel(statsScroll, sys .. ": 0.0ms", UDim2.new(1,-12,0,13), UDim2.new(0,6,0,456 + (i-1)*14), 9, COLORS.textDim) profLabels[sys] = lbl end task.spawn(function() while true do task.wait(1) for sys, lbl in pairs(profLabels) do if lbl and lbl.Parent then local ms = Profiler.times[sys] or 0 local color = ms > 1.5 and COLORS.danger or ms > 0.8 and COLORS.warning or COLORS.success lbl.Text = string.format("%s: %.2fms", sys, ms) lbl.TextColor3 = color end end end end) statsScroll.CanvasSize = UDim2.new(0,0,0,580) end -- Add self-assessment button to stats tab if statsScroll then local assessBtn = makeButton(statsScroll, "📋 Generate Self-Assessment", UDim2.new(1,-12,0,28), UDim2.new(0,6,0,548), COLORS.panel) assessBtn.MouseButton1Click:Connect(function() local report = SelfAssessment.generate() local lines = report:split("\n") VoidGUI.notify(lines[1] .. " — see console") print(report) end) statsScroll.CanvasSize = UDim2.new(0,0,0,620) end -- Replay speed buttons in settings tab local settingsScroll = scrollFrames[4] if settingsScroll then makeLabel(settingsScroll, "Replay Speed", UDim2.new(1,-12,0,14), UDim2.new(0,6,0,640), 11, COLORS.textDim) local speedPresets = {"Cautious","Normal","Fast"} for i, preset in ipairs(speedPresets) do local spBtn = makeButton(settingsScroll, preset, UDim2.new(1/3,-5,0,24), UDim2.new((i-1)/3, 3, 0, 658), ReplayControl.speed == SPEED_PRESETS[preset] and COLORS.accent or COLORS.panel) spBtn.TextSize = 10 spBtn.MouseButton1Click:Connect(function() ReplayControl.setSpeed(preset) end) end -- Loop mode toggle local loopBtn = makeButton(settingsScroll, "Loop: " .. ReplayControl.loopMode, UDim2.new(1,-12,0,26), UDim2.new(0,6,0,688), COLORS.panel) loopBtn.TextSize = 10 loopBtn.MouseButton1Click:Connect(function() ReplayControl.loopMode = ReplayControl.loopMode == "loop" and "once" or "loop" loopBtn.Text = "Loop: " .. ReplayControl.loopMode end) settingsScroll.CanvasSize = UDim2.new(0,0,0,740) end end) -- ============================================================ -- SECTION 43: LOOP MODE ENFORCEMENT -- ============================================================ -- Patch GhostController to respect loopMode = "once" local _baseStepForLoop = GhostController.stepReplay local hasPlayedOnce = false function GhostController.stepReplayFinal() if ReplayControl.loopMode == "once" then if not GhostController.replaySession then return end local actions = GhostController.replaySession.actions if GhostController.replayIndex > #(actions or {}) then if not hasPlayedOnce then hasPlayedOnce = true GhostController.reclaim() VoidGUI.notify("Replay complete (once mode)") end return end end hasPlayedOnce = false _baseStepForLoop() end GhostController.stepReplay = GhostController.stepReplayFinal -- ============================================================ -- SECTION 44: COMPLETE CHAT COMMAND REFERENCE -- ============================================================ -- Add remaining missing commands and a full help output CHAT_COMMANDS["help"] = function() local cmds = { "--- VoidAI Commands (/void ) ---", "learn / stop — toggle observer mode", "ghost / lend — toggle ghost / lend mode", "llm — toggle LLM mode", "eat — toggle Extended Adaptive Thinking", "atm — toggle Adaptive Thinking (AFK mode)", "afk — force AFK trigger", "reclaim — take back control", "pause — pause AI", "safe/danger/exit/item — tag current zone", "save — save brain now", "assess — generate self-assessment", "predict — show next action prediction", "forget — apply forgetting curve", "macros — list learned macros", "status — show current AI status", "stealth — toggle stealth mode", "saveas_ — save brain profile", "load_ — load brain profile", "help — show this list", } for _, line in ipairs(cmds) do print("[VoidAI] " .. line) end VoidGUI.notify("Full command list printed to console") end CHAT_COMMANDS["speed"] = function() local speeds = {"Cautious (0.5x)","Normal (1x)","Fast (2x)"} VoidGUI.notify("Speeds: " .. table.concat(speeds, " | ") .. " — use /void speed_") end -- Dynamic speed command pcall(function() LocalPlayer.Chatted:Connect(function(msg) local lower = msg:lower() local parts = lower:split(" ") if parts[1] ~= CHAT_PREFIX then return end local cmd = parts[2] or "" if cmd:sub(1,6) == "speed_" then local preset = cmd:sub(7) local map = {cautious="Cautious", normal="Normal", fast="Fast"} if map[preset] then ReplayControl.setSpeed(map[preset]) end end end) end) -- ============================================================ -- SECTION 45: STARTUP SUMMARY -- ============================================================ local function printStartupSummary() local place = getCurrentPlace() local mc, patc = 0, 0 for _ in pairs(EAT.macros) do mc += 1 end for _ in pairs(EAT.reinforcedPatterns) do patc += 1 end local function pad(s, n) s = tostring(s):sub(1, n) while #s < n do s = s .. " " end return s end print("╔════════════════════════════════════╗") print("║ VoidAI v1.0 — Ready ║") print("╠════════════════════════════════════╣") print("║ Platform : " .. pad(isMobile and "Mobile" or "PC", 25) .. "║") print("║ Universe : " .. pad(getUniverseId(), 25) .. "║") print("║ Place : " .. pad(getPlaceId(), 25) .. "║") if place then print("║ Game : " .. pad((place.placeName or "Unknown"), 25) .. "║") print("║ Sessions : " .. pad(#place.sessions, 25) .. "║") print("║ Conf Mov : " .. pad(place.confidence.movement .. "%", 25) .. "║") print("║ Conf UI : " .. pad(place.confidence.ui .. "%", 25) .. "║") print("║ Conf Seq : " .. pad(place.confidence.sequences .. "%", 25) .. "║") end print("║ Macros : " .. pad(mc, 25) .. "║") print("║ Clusters : " .. pad(#EAT.clusters, 25) .. "║") print("║ Patterns : " .. pad(patc, 25) .. "║") print("╠════════════════════════════════════╣") if isPC then print("║ Keybinds: G=Learn H=Lend ║") print("║ J=GUI F=Reclaim ║") else print("║ Mobile: Tap floating buttons ║") print("║ ✋ = Reclaim control ║") end print("╠════════════════════════════════════╣") print("║ Chat commands: /void help ║") print("╚════════════════════════════════════╝") end -- ============================================================ -- SECTION 46: CONSOLIDATED FINAL HEARTBEAT -- ============================================================ -- Single authoritative heartbeat — replaces fragmented ones above. -- All per-frame logic is profiled and rate-limited here. local _fb_learn = 0 local _fb_threat = 0 local _fb_urgency = 0 local _fb_save = 0 local _fb_goal = 0 local _fb_afk = 0 local _fb_eat = 0 local _fb_atm = 0 RunService.Heartbeat:Connect(function(dt) updateFPS(dt) AIState.tickCounter += 1 updateSchedule(dt) -- AFK check every 5s _fb_afk += dt if _fb_afk >= 5 then _fb_afk = 0 if not AdaptiveThinking.manualOverride then local idle = os.time() - lastInputTime if idle >= AdaptiveThinking.afkThreshold and not AdaptiveThinking.active and (AIState.mode == "idle" or AIState.mode == "observing") then AdaptiveThinking.start("AFK auto (" .. idle .. "s)") end end end -- Threat detection every 0.5s (always runs regardless of FPS) _fb_threat += dt if _fb_threat >= 0.5 then _fb_threat = 0 local ok2 = pcall(function() local isThreat, tName = ThreatDetector.scan() if isThreat and not AIState.threatDetected then ThreatDetector.respondToThreat(tName) end if AIState.threatCooldown > 0 then AIState.threatCooldown -= 0.5 if AIState.threatCooldown <= 0 then AIState.threatDetected = false end end end) if not ok2 then end -- silent fail on threat scan errors end -- Observer learning (adaptive cooldown) _fb_learn += dt if _fb_learn >= LearnCooldown then _fb_learn = 0 if AIState.isLearning and AIState.currentSession then pcall(function() local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") if not hrp then return end Observer.recordMovement(hrp.Position) -- Feed EAT if active if EAT.active then EAT.pushChunk("move") EAT.reinforcePattern(EAT.getWorkingMemoryKey(), "self") EAT.addToCluster(hrp.Position, "visited") end -- Anomaly check if #AIState.currentSession.actions > 0 then local last = AIState.currentSession.actions[#AIState.currentSession.actions] AnomalyDetector.check(last.type or "unknown", GoalEngine.currentGoal) end end) end end -- EAT sampling (adaptive per FPS + player count) if EAT.active then _fb_eat += dt local pcount = math.max(1, #Players:GetPlayers() - 1) local eatRate = (FPS > 50 and pcount <= 5) and 0.2 or (FPS > 30) and 0.35 or 0.6 if _fb_eat >= eatRate then _fb_eat = 0 pcall(EAT.observeSelf) pcall(EAT.observeOthers) end end -- ATM sampling if AdaptiveThinking.active then _fb_atm += dt if _fb_atm >= AdaptiveThinking.sampleRate then _fb_atm = 0 pcall(AdaptiveThinking.samplePlayers) end end -- Urgency update every 1s _fb_urgency += dt if _fb_urgency >= 1 then _fb_urgency = 0 pcall(UrgencySystem.update) end -- Goal inference + prediction every 3s _fb_goal += dt if _fb_goal >= 3 then _fb_goal = 0 pcall(GoalEngine.infer) if EAT.active then pcall(EAT.predictNextAction) end end -- LLM step if AIState.mode == "llm" and not AIState.isPaused then AIState.llmCooldown = (AIState.llmCooldown or 0) + dt if AIState.llmCooldown >= LLMController.callCooldown then AIState.llmCooldown = 0 pcall(LLMController.callLLM) end end -- Batch save + forgetting curve + sequence analysis every 30s _fb_save += dt if _fb_save >= 30 then _fb_save = 0 if AIState.isLearning or EAT.active or AdaptiveThinking.active then pcall(EAT.saveMacros) pcall(EAT.saveClusters) pcall(saveBrain) end -- Every 5 minutes: forgetting curve + sequence analysis if AIState.tickCounter % 10 == 0 then pcall(EAT.applyForgettingCurve) pcall(SequenceDetector.analyze) end end end) -- ============================================================ -- SECTION 47: BRAIN VERSION MIGRATION -- ============================================================ local CURRENT_VERSION = "1.0" local function migrateBrain() if not Brain then return end if Brain.version == CURRENT_VERSION then return end Brain.version = CURRENT_VERSION for _, place in pairs(Brain.places or {}) do if not place.macros then place.macros = {} end if not place.clusters then place.clusters = {} end if not place.topUIButtons then place.topUIButtons = {} end if not place.totalActions then place.totalActions = 0 end if not place.totalPlaytime then place.totalPlaytime = 0 end if not place.confidence then place.confidence = { movement=0, ui=0, sequences=0 } end if not place.mentalMap then place.mentalMap = { landmarks={}, safeZones={}, dangerZones={}, itemSpawns={}, exits={}, } end for _, session in ipairs(place.sessions or {}) do if not session.type then session.type = "self" end if not session.priority then session.priority = 1 end if not session.starred then session.starred = false end if not session.startTime then session.startTime = session.id end if not session.movements then session.movements = {} end if not session.uiClicks then session.uiClicks = {} end if not session.sequences then session.sequences = {} end if not session.actions then session.actions = {} end end end saveBrain() print("[VoidAI] Brain migrated to v" .. CURRENT_VERSION) end -- ============================================================ -- SECTION 48: MOBILE FINAL WIRING -- ============================================================ if isMobile then task.spawn(function() task.wait(3) local function hookThumbstick() local pgui = LocalPlayer:FindFirstChild("PlayerGui") if not pgui then return end for _, gui in ipairs(pgui:GetChildren()) do local ts = gui:FindFirstChild("DynamicThumbstick", true) or gui:FindFirstChild("Thumbstick", true) if ts then RunService.Heartbeat:Connect(function() if not AIState.isLearning then return end if AIState.tickCounter % 3 ~= 0 then return end local char = LocalPlayer.Character if not char then return end local hrp = char:FindFirstChild("HumanoidRootPart") if hrp then Observer.recordMovement(hrp.Position) end end) return true end end return false end if not hookThumbstick() then PlayerGui.ChildAdded:Connect(function() task.wait(1) hookThumbstick() end) end end) end -- ============================================================ -- ENTRY POINT -- ============================================================ local ok, err = pcall(function() -- Core setup Exec.makeFolder(BRAIN_FOLDER) loadConfig() -- Apply config to live state if Config.stealthMode then AIState.isStealth = true end if Config.activePersona then AIState.persona = Config.activePersona end if Config.keybinds then for action, keyName in pairs(Config.keybinds) do if KEY_MAP[keyName] then Keybinds.binds[action] = KEY_MAP[keyName] end end end -- Load + migrate brain loadBrain() migrateBrain() -- Build GUI VoidGUI.build() if AIState.isStealth then if mainFrame then mainFrame.Visible = false end if miniButton then miniButton.Visible = true end end -- Deferred post-init (let game fully load first) task.spawn(function() task.wait(2) -- Load EAT persistent data EAT.loadMacros() EAT.loadClusters() -- Startup analysis passes EAT.applyForgettingCurve() SequenceDetector.analyze() GoalEngine.infer() -- Build threat HUD buildThreatHUD() -- Horror game detection + safe object pre-tagging detectAndConfigureHorror() -- Live display update loop task.spawn(function() while true do task.wait(1) VoidGUI.updateDisplay() end end) -- Welcome notification if not AIState.isStealth then local place = getCurrentPlace() local isNewBrain= (not place) or (#place.sessions == 0) if isNewBrain then VoidGUI.notify("VoidAI ready — press G (or tap 🧠) to start learning!") else local mc = 0 for _ in pairs(EAT.macros) do mc += 1 end VoidGUI.notify(string.format( "VoidAI ready — %d sessions | %d macros | %d clusters", place and #place.sessions or 0, mc, #EAT.clusters)) end end -- Print full console summary printStartupSummary() end) end) if not ok then warn("[VoidAI] Critical init error: " .. tostring(err)) pcall(function() Exec.makeFolder(BRAIN_FOLDER) loadBrain() VoidGUI.build() VoidGUI.notify("⚠ VoidAI: init error — check console") print("[VoidAI] Recovery mode. Error was: " .. tostring(err)) end) end -- ============================================================ -- END OF VOIDAI v1.0 -- ============================================================ --[[ SYSTEM INDEX: 01 Services + platform detection 02 Executor compatibility (Synapse/KRNL/Fluxus/Arceus/Delta/Hydrogen/Codex) 03 Base knowledge (embedded WASD + mobile defaults + horror keywords) 04 Brain file system (per-universe JSON, per-place entries, cumulative) 05 Config system (persisted settings) 06 Adaptive learning cooldown + FPS monitor 07 AI state machine 08 Observer (movement, UI clicks, jump, sprint — event-driven) 09 Threat detection + survival response 10 Ghost controller (client-side AI playback) 11 Lend controller (AI takes full input control) 12 LLM controller (Claude / ChatGPT / Gemini with brain context) 13 Place transition continuity (survives teleports in same universe) 14 UI click hooks (event-driven, zero polling cost) 15 Keybind system (PC, fully rebindable via GUI) 16 Schedule mode (auto start/stop AI at set times) 17 GUI system (4 tabs, minimize to draggable floating button) 18 Threat HUD (pulsing indicator) 19 Sequence detector (cross-session pattern mining) 20 Smart pattern-aware replay 21 Jump + sprint event tracking 22 Other player passive observer 23 Confidence color coding (green/yellow/red bars) 24 Low confidence warnings before ghost/lend 25 Chat command system (/void ) — 20+ commands 26 Mental map visualizer (top-down dot map in Stats tab) 27 Brain export to readable .txt file 28 Horror game auto-detect + safe object pre-tagging 29 Schedule countdown notifications 30 Safety hooks (BindToClose, CharacterRemoving, respawn) 31 Adaptive Thinking Mode (ATM) — AFK multi-player observer 32 Extended Adaptive Thinking (EAT) — dual-source live learning 33 Pattern reinforcement (dual-source weight doubling) 34 Attention focus (per-player activity scoring) 35 Action chunking / macro system (10 built-in macro labels) 36 Forgetting curve (logarithmic time-decay confidence) 37 Next-action prediction engine (scored candidates) 38 Working memory buffer (short-term vs long-term split) 39 Behavior clustering (path generalization via centroid merge) 40 Anomaly detection + pattern promotion 41 Urgency / emotion state (0-100, CALM/MED/HIGH/PANIC) 42 Goal inference engine (explore/combat/interact/escape/etc) 43 Self-assessment report generator 44 Replay speed control (Cautious/Normal/Fast) + loop modes 45 Multi-brain profile support (saveas_/load_ commands) 46 Performance profiler (per-subsystem ms EMA tracking) 47 Consolidated heartbeat (single connection, all systems) 48 Mobile thumbstick wiring 49 Brain version migration ]]