--!nonstrict --[[ X.GPT PRO - Plugin Roblox Studio Fichier unique : copie ce fichier "X.GPT PRO.plugin.lua" directement dans %LOCALAPPDATA%\Roblox\Plugins\ puis ouvre Roblox Studio -> onglet Plugins -> bouton "X.GPT PRO". Se connecte au pont X.GPT PRO (http://127.0.0.1:8765), lance automatiquement par l'app X.GPT PRO, et execute les commandes envoyees par l'IA directement dans le place ouvert. ]] local success, err = pcall(function() local HttpService = game:GetService("HttpService") local BRIDGE_URL = "http://127.0.0.1:8765" local HEARTBEAT_INTERVAL = 3 local POLL_INTERVAL = 1 local running = false local bridgeOnline = false local httpBlocked = false -- Les plugins n'ont PAS besoin d'activer HttpEnabled : Studio autorise les -- requetes HTTP des plugins directement (comme le plugin Servat AI). -- On detecte juste si Studio bloque quand meme les requetes. local function post(path, body) local ok, result = pcall(function() return HttpService:PostAsync(BRIDGE_URL .. path, HttpService:JSONEncode(body), Enum.HttpContentType.ApplicationJson) end) return ok, result end local function get(path) local ok, result = pcall(function() return HttpService:GetAsync(BRIDGE_URL .. path) end) if ok then ok, result = pcall(function() return HttpService:JSONDecode(result) end) end return ok, result end -- --------------------------------------------------------------------------- -- Barre d'outils + panneau (API 2026, avec repli sur l'ancienne API) -- --------------------------------------------------------------------------- local toolbar = plugin:CreateToolbar("X.GPT PRO") local toggleBtn = toolbar:CreateButton("X.GPT PRO", "Ouvrir/fermer le panneau X.GPT PRO", "") local gui local ok = false -- Nouvelle API 2026 if DockWidgetPluginGuiInfo and plugin.CreateDockWidgetPluginGuiAsync then ok = pcall(function() local info = DockWidgetPluginGuiInfo.new( Enum.InitialDockState.Right, true, -- InitialEnabled : le panneau s'ouvre au chargement false, -- InitialEnabledShouldOverrideRestore 320, -- FloatingXSize 460, -- FloatingYSize 280, -- MinWidth 200 -- MinHeight ) gui = plugin:CreateDockWidgetPluginGuiAsync("XGPTPRO_Main", info) end) end -- Ancienne API (repli) if not ok or not gui then ok = pcall(function() local info = DockWidgetPluginGuiInfo.new( Enum.InitialDockState.Right, true, false, 320, 460 ) gui = plugin:CreateDockWidgetPluginGui("XGPTPRO_Main", info) end) end if not gui then print("[X.GPT PRO] ERREUR: impossible de creer l'interface") return end gui.Title = "X.GPT PRO" gui.Name = "XGPTPRO_Main" -- --------------------------------------------------------------------------- -- Interface noire -- --------------------------------------------------------------------------- local BLACK = Color3.fromRGB(8, 8, 10) local BLACK2 = Color3.fromRGB(16, 16, 20) local WHITE = Color3.fromRGB(230, 230, 238) local GREY = Color3.fromRGB(120, 120, 132) local GREEN = Color3.fromRGB(34, 180, 100) local RED = Color3.fromRGB(210, 60, 60) local YELLOW = Color3.fromRGB(250, 204, 21) local PURPLE = Color3.fromRGB(157, 140, 255) local frame = Instance.new("Frame") frame.Name = "XGPTPRO_Main" frame.Size = UDim2.new(1, 0, 1, 0) frame.BackgroundColor3 = BLACK frame.BorderSizePixel = 0 frame.Parent = gui local title = Instance.new("TextLabel") title.Name = "Title" title.Size = UDim2.new(1, 0, 0, 40) title.BackgroundTransparency = 1 title.Font = Enum.Font.GothamBold title.Text = "X.GPT PRO" title.TextColor3 = PURPLE title.TextSize = 20 title.Parent = frame local placeLbl = Instance.new("TextLabel") placeLbl.Name = "Place" placeLbl.Position = UDim2.new(0, 8, 0, 42) placeLbl.Size = UDim2.new(1, -16, 0, 20) placeLbl.BackgroundTransparency = 1 placeLbl.Font = Enum.Font.Gotham placeLbl.Text = "Place : " .. tostring(game.Name) placeLbl.TextColor3 = GREY placeLbl.TextSize = 12 placeLbl.TextXAlignment = Enum.TextXAlignment.Left placeLbl.Parent = frame local status = Instance.new("TextLabel") status.Name = "Status" status.Position = UDim2.new(0, 8, 0, 64) status.Size = UDim2.new(1, -16, 0, 34) status.BackgroundTransparency = 1 status.Font = Enum.Font.GothamBold status.Text = "Deconnecte" status.TextColor3 = GREY status.TextWrapped = true status.TextSize = 13 status.Parent = frame local dot = Instance.new("Frame") dot.Name = "Dot" dot.Position = UDim2.new(0, 12, 0, 76) dot.Size = UDim2.new(0, 10, 0, 10) dot.BackgroundColor3 = GREY dot.BorderSizePixel = 0 dot.Parent = frame -- Bouton unique : CONNECTER (vert) / DECONNECTER (rouge) local connectBtn = Instance.new("TextButton") connectBtn.Name = "ConnectButton" connectBtn.Position = UDim2.new(0, 8, 0, 104) connectBtn.Size = UDim2.new(1, -16, 0, 48) connectBtn.BackgroundColor3 = GREEN connectBtn.BorderSizePixel = 0 connectBtn.Font = Enum.Font.GothamBold connectBtn.Text = "CONNECTER" connectBtn.TextColor3 = WHITE connectBtn.TextSize = 16 connectBtn.Parent = frame local log = Instance.new("TextLabel") log.Name = "Log" log.Position = UDim2.new(0, 8, 0, 160) log.Size = UDim2.new(1, -16, 1, -168) log.BackgroundColor3 = BLACK2 log.BorderSizePixel = 0 log.Font = Enum.Font.Code log.Text = "Pret. Appuie sur CONNECTER pour lier l'IA a ce place." log.TextColor3 = Color3.fromRGB(170, 170, 185) log.TextXAlignment = Enum.TextXAlignment.Left log.TextYAlignment = Enum.TextYAlignment.Top log.TextWrapped = true log.TextSize = 12 log.Parent = frame local function logLine(text) log.Text = text .. "\n" .. log.Text end -- --------------------------------------------------------------------------- -- Etat de l'interface -- --------------------------------------------------------------------------- local function updateUI() if running and bridgeOnline then connectBtn.Text = "DECONNECTER" connectBtn.BackgroundColor3 = RED status.Text = "Connecte a X.GPT PRO" status.TextColor3 = GREEN dot.BackgroundColor3 = GREEN elseif running and httpBlocked then connectBtn.Text = "CONNECTER" connectBtn.BackgroundColor3 = GREEN status.Text = "HTTP bloque par Studio - active les requetes HTTP" status.TextColor3 = RED dot.BackgroundColor3 = RED elseif running then connectBtn.Text = "CONNECTER" connectBtn.BackgroundColor3 = GREEN status.Text = "Pont introuvable - ouvre l'app X.GPT PRO" status.TextColor3 = YELLOW dot.BackgroundColor3 = YELLOW else connectBtn.Text = "CONNECTER" connectBtn.BackgroundColor3 = GREEN status.Text = "Deconnecte" status.TextColor3 = GREY dot.BackgroundColor3 = GREY end end -- --------------------------------------------------------------------------- -- Coeur de connexion -- --------------------------------------------------------------------------- local StudioService = game:GetService("StudioService") local function isGameplayActive() local okRes, active = pcall(function() return StudioService:IsGameplayActive() end) return okRes and active == true end -- Boucle qui garde le pont a jour toutes les 3s : si l'app s'ouvre apres, -- le bouton passe tout seul sur DECONNECTER. local function managerLoop() while running do local okRes, errMsg = post("/status", { connected = true, place = tostring(game.Name), version = "4.0.0", }) bridgeOnline = okRes == true httpBlocked = false if not okRes and tostring(errMsg or ""):find("Http", 1, true) then httpBlocked = true end updateUI() task.wait(HEARTBEAT_INTERVAL) end end local function pollLoop() while running do if isGameplayActive() then task.wait(0.5) else local okRes, data = get("/commands") if okRes and type(data) == "table" and type(data.commands) == "table" then for _, command in ipairs(data.commands) do if not running then break end logLine("Commande recue: " .. tostring(command.type)) local resultOk, output = executeCommand(command) post("/result", { id = command.id, ok = resultOk, output = output, }) end end task.wait(POLL_INTERVAL) end end end function connect() if running then return end running = true bridgeOnline = false httpBlocked = false updateUI() logLine("Connexion au pont " .. BRIDGE_URL .. " ...") task.spawn(managerLoop) task.spawn(pollLoop) end function disconnect() running = false bridgeOnline = false post("/status", { connected = false }) updateUI() logLine("Deconnecte.") end -- --------------------------------------------------------------------------- -- Annulation (Ctrl+Z) : chaque action de l'IA est enregistree dans l'historique -- --------------------------------------------------------------------------- local ChangeHistoryService = game:GetService("ChangeHistoryService") local function beginRecording(name) local okRec, recording = pcall(function() return ChangeHistoryService:TryBeginRecording(name) end) return okRec and recording or nil end local function commitRecording(recording) if recording then pcall(function() ChangeHistoryService:FinishRecording(recording, Enum.FinishRecordingOperation.Commit) end) end end -- --------------------------------------------------------------------------- -- Execution des commandes dans le place -- --------------------------------------------------------------------------- -- Declare a l'avance : implemente plus bas (resout un chemin vers une instance) local resolveInstance local function normalizeValue(value) if type(value) ~= "table" then return value end if value.__type == "Vector3" then return Vector3.new(value.x or 0, value.y or 0, value.z or 0) end if value.__type == "Color3" then return Color3.new(value.r or 0, value.g or 0, value.b or 0) end if value.x ~= nil and value.y ~= nil and value.z ~= nil then return Vector3.new(value.x, value.y, value.z) end if value.r ~= nil and value.g ~= nil and value.b ~= nil then return Color3.new(value.r, value.g, value.b) end return value end local function applyProperties(instance, properties) if type(properties) ~= "table" then return end for key, value in pairs(properties) do if key == "Parent" and type(value) == "string" then local resolved = resolveInstance(value) if resolved then instance.Parent = resolved end else local okRes, result = pcall(function() instance[key] = normalizeValue(value) end) if not okRes then warn("[X.GPT PRO] propriete ignoree ", key, result) end end end end local function getWorkspaceParent(parentName) local workspace = game:GetService("Workspace") if not parentName or parentName == "" then return workspace end local folder = workspace:FindFirstChild(parentName) if not folder then folder = Instance.new("Folder") folder.Name = parentName folder.Parent = workspace end return folder end local function createPart(args) local recording = beginRecording("X.GPT PRO: creer part") local part = Instance.new("Part") part.Name = args.name or "XGPTPro_Part" applyProperties(part, args.properties) part.Parent = getWorkspaceParent(args.parent) commitRecording(recording) return part:GetFullName() end local function createFolder(args) local recording = beginRecording("X.GPT PRO: creer dossier") local folder = Instance.new("Folder") folder.Name = args.name or "XGPTPro_Folder" applyProperties(folder, args.properties) folder.Parent = getWorkspaceParent(args.parent) commitRecording(recording) return folder:GetFullName() end local function createModel(args) local recording = beginRecording("X.GPT PRO: creer modele") local model = Instance.new("Model") model.Name = args.name or "XGPTPro_Model" applyProperties(model, args.properties) model.Parent = getWorkspaceParent(args.parent) if type(args.parts) == "table" then for _, partArgs in ipairs(args.parts) do local part = Instance.new("Part") part.Name = partArgs.name or "Part" applyProperties(part, partArgs.properties) part.Parent = model end end commitRecording(recording) return model:GetFullName() end local SCRIPT_CONTAINERS = { ServerScriptService = function() return game:GetService("ServerScriptService") end, ServerStorage = function() return game:GetService("ServerStorage") end, ReplicatedStorage = function() return game:GetService("ReplicatedStorage") end, Workspace = function() return game:GetService("Workspace") end, StarterPlayerScripts = function() local sp = game:GetService("StarterPlayer") local container = sp:FindFirstChild("StarterPlayerScripts") if not container then container = Instance.new("StarterPlayerScripts") container.Parent = sp end return container end, } local function createScript(args) local isClient = args.client == true local container if args.container then local getter = SCRIPT_CONTAINERS[args.container] if not getter then return nil, "Container inconnu: " .. tostring(args.container) .. " (accepte: " .. table.concat({ "ServerScriptService", "ServerStorage", "ReplicatedStorage", "Workspace", "StarterPlayerScripts" }, ", ") .. ")" end container = getter() else container = isClient and (game:GetService("StarterPlayer"):FindFirstChild("StarterPlayerScripts") or game:GetService("StarterPlayer")) or game:GetService("ServerScriptService") end local recording = beginRecording("X.GPT PRO: creer script") local script = Instance.new(isClient and "LocalScript" or "Script") script.Name = args.name or "XGPTPRO_Run" script.Source = args.code or "-- script vide" script.Parent = container commitRecording(recording) return script:GetFullName() .. " (s'execute quand tu appuies sur Play)", nil end -- --------------------------------------------------------------------------- -- Inspection du place / scripts existants -- --------------------------------------------------------------------------- -- Resout un chemin du style "Workspace.MonModel.Script", "game.Workspace.X" -- ou "StarterPlayer.StarterPlayerScripts.MonScript". function resolveInstance(path) if type(path) ~= "string" or path == "" then return nil end local clean = (path:gsub("^game%.", "")):gsub("^%.", "") local current = game for part in string.gmatch(clean, "[^%.]+") do local found = current:FindFirstChild(part) if not found then return nil end current = found end return current end local function inspectCommand() local lines = {} local function add(text) if #lines < 70 then table.insert(lines, text) end end local containers = { game:GetService("Workspace"), game:GetService("ServerScriptService"), game:GetService("ServerStorage"), game:GetService("ReplicatedStorage"), game:GetService("Lighting"), } local starterScripts = game:GetService("StarterPlayer"):FindFirstChild("StarterPlayerScripts") if starterScripts then table.insert(containers, starterScripts) end for _, container in ipairs(containers) do add(container:GetFullName() .. ":") local children = container:GetChildren() if #children == 0 then add(" (vide)") end for _, child in ipairs(children) do if #lines >= 70 then break end add(" " .. child.Name .. " (" .. child.ClassName .. ")") end end add("Scripts presents dans le place:") for _, child in ipairs(game:GetService("Workspace"):GetDescendants()) do if #lines >= 70 then break end if child:IsA("LuaSourceContainer") then add(" " .. child:GetFullName()) end end return true, table.concat(lines, "\n") end local function readScriptCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Script introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins exacts." end if not instance:IsA("LuaSourceContainer") then return false, instance:GetFullName() .. " n'est pas un script (" .. instance.ClassName .. ")." end return true, instance:GetFullName() .. "\n\n" .. tostring(instance.Source) end local function updateScriptCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Script introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins exacts." end if not instance:IsA("LuaSourceContainer") then return false, instance:GetFullName() .. " n'est pas un script (" .. instance.ClassName .. ")." end local recording = beginRecording("X.GPT PRO: modifier script") instance.Source = args.code or "" commitRecording(recording) return true, "Mis a jour: " .. instance:GetFullName() .. " (" .. #tostring(args.code or "") .. " caracteres)" end -- --------------------------------------------------------------------------- -- Boite a outils Roblox (recherche catalogue + insertion par id) -- --------------------------------------------------------------------------- local CATALOG_URL = "https://catalog.roblox.com/v1/search/items/details" local INSERTABLE_TYPES = { [10] = "Modele", [11] = "Mesh", [13] = "Decal", } local function toolboxSearchCommand(args) local query = tostring(args.query or "") if query == "" then return false, "Donne un mot-cle en anglais a chercher (ex: \"tree\", \"rock\", \"house\", \"door\")." end local url = CATALOG_URL .. "?Category=3&Limit=30&sortType=Relevance&Keyword=" .. HttpService:UrlEncode(query) local okGet, body = pcall(function() return HttpService:GetAsync(url) end) if not okGet then return false, "Recherche impossible: " .. tostring(body) .. ". Verifie dans Studio que les requetes HTTP du plugin sont autorisees." end local okDecode, data = pcall(function() return HttpService:JSONDecode(body) end) if not okDecode or type(data) ~= "table" or type(data.data) ~= "table" then return false, "Reponse Roblox inattendue." end local candidates = {} for _, item in ipairs(data.data) do local label = INSERTABLE_TYPES[item.assetType] if label and (item.price == nil or item.price == 0) then table.insert(candidates, item) end end -- Trier par popularite : les assets les plus favoris sont les plus beaux/fiables table.sort(candidates, function(a, b) return (a.favoriteCount or 0) > (b.favoriteCount or 0) end) local results = {} for i = 1, math.min(12, #candidates) do local item = candidates[i] table.insert(results, string.format( " id=%d | %s | %s | par %s | \u{2764} %d | gratuit", item.id, tostring(item.name):gsub("\n", " "), INSERTABLE_TYPES[item.assetType], tostring(item.creatorName or "?"), item.favoriteCount or 0 )) end if #results == 0 then return true, "Aucun asset gratuit trouve pour \"" .. query .. "\". Essaie d'autres mots-cles en anglais (ex: \"tree\", \"rock\", \"house\", \"door\", \"lamp\", \"fence\", \"sign\", \"wall\")." end return true, "Boite a outils - resultats gratuits pour \"" .. query .. "\" (tries par popularite):\n" .. table.concat(results, "\n") .. "\n\nPrefere les assets avec le plus de \u{2764} et utilise roblox_toolbox_insert avec l'id pour inserer." end -- --------------------------------------------------------------------------- -- Test de la map (Play Solo automatique + capture des erreurs) -- --------------------------------------------------------------------------- local LogService = game:GetService("LogService") local function testPlayCommand(args) local seconds = math.clamp(tonumber(args.seconds) or 8, 3, 30) local okSvc, sts = pcall(function() return game:GetService("StudioTestService") end) if not okSvc or not sts or not sts.ExecutePlayModeAsync then return false, "StudioTestService indisponible (Roblox Studio trop ancien). Mets a jour Roblox Studio." end if isGameplayActive() then return false, "Une simulation est deja en cours. Arrete le Play en cours puis reessaie." end local before = #LogService:GetLogHistory() -- Script temporaire injecte dans la session de test : il attend, collecte -- les erreurs/avertissements, puis termine la session (EndTest). local runner = Instance.new("Script") runner.Name = "XGPTPRO_TestRunner_" .. tostring(os.time()) runner.Source = string.format([==[ local StudioTestService = game:GetService("StudioTestService") local LogService = game:GetService("LogService") local startIndex = #LogService:GetLogHistory() task.wait(%d) local history = LogService:GetLogHistory() local problems = {} for i = startIndex + 1, #history do local entry = history[i] if entry and (entry.messageType == Enum.MessageType.OutputError or entry.messageType == Enum.MessageType.OutputWarning) then table.insert(problems, tostring(entry.message or "")) end end StudioTestService:EndTest(table.concat(problems, "\n")) ]==], seconds) runner.Parent = game:GetService("ServerScriptService") local okRun, result = pcall(function() return sts:ExecutePlayModeAsync("xgpt-pro-test") end) runner:Destroy() -- Cote plugin (mode edition) : ce que le script de test n'a pas vu (ex. erreurs client) local history = LogService:GetLogHistory() local pluginProblems = {} for i = before + 1, #history do local entry = history[i] if entry and (entry.messageType == Enum.MessageType.OutputError or entry.messageType == Enum.MessageType.OutputWarning) then table.insert(pluginProblems, tostring(entry.message or "")) end end -- Fusion + dedoublonnage local seen = {} local merged = {} for _, message in ipairs({ tostring(result or ""), table.concat(pluginProblems, "\n") }) do if message ~= "" then for line in string.gmatch(message, "[^\r\n]+") do if not seen[line] then seen[line] = true table.insert(merged, line) end end end end if not okRun then return false, "Echec du lancement de la map: " .. tostring(result) end if #merged == 0 then return true, "Test termine sans erreur ni avertissement sur " .. seconds .. "s. La map se lance correctement." end local lines = {} for i = 1, math.min(30, #merged) do table.insert(lines, " - " .. merged[i]) end if #merged > 30 then table.insert(lines, " ... et " .. (#merged - 30) .. " autre(s)") end return true, "Test termine avec " .. #merged .. " erreur(s)/avertissement(s) sur " .. seconds .. "s:\n" .. table.concat(lines, "\n") .. "\n\nCorrige avec roblox_update_script puis reteste." end local function toolboxInsertCommand(args) local assetId = tonumber(tostring(args.assetId or ""):match("%d+")) if not assetId then return false, "Donne un assetId numerique (ex: 12109814819)." end local okObjects, objects = pcall(function() return game:GetObjects("rbxassetid://" .. assetId) end) if not okObjects then return false, "Insertion impossible (asset payant, supprime, ou non accessible): " .. tostring(objects) end if type(objects) ~= "table" or #objects == 0 then return false, "L'asset " .. assetId .. " ne contient rien d'inserable." end local parent = getWorkspaceParent(args.parent) local recording = beginRecording("X.GPT PRO: inserer depuis la boite a outils") local names = {} for _, obj in ipairs(objects) do obj.Parent = parent table.insert(names, obj:GetFullName()) end commitRecording(recording) return true, "Insere depuis la Boite a outils: " .. table.concat(names, ", ") end -- --------------------------------------------------------------------------- -- Edition des objets existants : focus, suppression, renommage, proprietes, -- terrain -- --------------------------------------------------------------------------- local Selection = game:GetService("Selection") local function objectPosition(instance) if instance:IsA("BasePart") then return instance.Position end local okPivot, pivot = pcall(function() return instance:GetPivot().Position end) if okPivot and pivot then return pivot end local part = instance:FindFirstChildWhichIsA("BasePart", true) if part then return part.Position end return nil end local function focusCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end pcall(function() Selection:Set({ instance }) end) local camera = workspace.CurrentCamera local position = objectPosition(instance) if camera and position then pcall(function() camera.CFrame = CFrame.lookAt(position + Vector3.new(0, 20, 40), position) end) end return true, "Selectionne et centre la camera sur: " .. instance:GetFullName() end local function deleteCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end if instance == game or instance.Parent == game then return false, "Refuse de supprimer un service de base (" .. instance:GetFullName() .. ")." end local fullName = instance:GetFullName() local recording = beginRecording("X.GPT PRO: supprimer " .. instance.Name) instance:Destroy() commitRecording(recording) return true, "Supprime: " .. fullName end local function renameCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end local newName = tostring(args.newName or ""):gsub("[^%w%p%s]", "") if newName == "" then return false, "Donne un nouveau nom (newName)." end local oldName = instance.Name local recording = beginRecording("X.GPT PRO: renommer " .. oldName) instance.Name = newName commitRecording(recording) return true, "Renomme: " .. oldName .. " -> " .. instance:GetFullName() end local function setPropertiesCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end local recording = beginRecording("X.GPT PRO: modifier proprietes") applyProperties(instance, args.properties) commitRecording(recording) return true, "Proprietes modifiees sur: " .. instance:GetFullName() end local function terrainCommand(args) local materialName = tostring(args.material or "Grass") local material = Enum.Material[materialName] if not material then return false, "Materiau inconnu: " .. materialName .. " (ex: Grass, Water, Sand, Rock, Ground, Slate, Snow, Ice, Concrete)." end local pos = args.position or {} local size = args.size or {} local center = Vector3.new(pos.x or 0, pos.y or 0, pos.z or 0) local sizeVec = Vector3.new(size.x or 100, size.y or 4, size.z or 100) pcall(function() workspace.Terrain:FillBlock(CFrame.new(center), sizeVec, material) end) return true, "Terrain applique: " .. materialName .. " (" .. tostring(sizeVec) .. ") centre sur " .. tostring(center) end -- Parent accepte un chemin complet ("StarterGui.MonGui") ou un nom de dossier -- sous Workspace (cree si absent). local function getParentFromArg(parentArg) if not parentArg or parentArg == "" then return nil end if parentArg:find("%.") then local resolved = resolveInstance(parentArg) if resolved then return resolved end end local knownServices = { ServerScriptService = true, ServerStorage = true, ReplicatedStorage = true, Workspace = true, StarterPlayer = true, StarterPack = true, StarterGui = true, Lighting = true, SoundService = true, } if knownServices[parentArg] then local okSvc, svc = pcall(function() return game:GetService(parentArg) end) if okSvc and svc then return svc end end return getWorkspaceParent(parentArg) end -- Cree n'importe quelle classe d'objet (ScreenGui, Tool, Sound, SpawnLocation, -- TextLabel, Model, ...) avec un dossier parent intelligent. local function createInstance(args) local className = tostring(args.className or "") if className == "" then return nil, "Donne un className (ex: ScreenGui, Tool, Sound, SpawnLocation, TextLabel, BillboardGui, Model...)." end local okNew, instance = pcall(function() return Instance.new(className) end) if not okNew or not instance then return nil, "Classe impossible a creer ici: " .. className .. " (" .. tostring(instance) .. ")" end local recording = beginRecording("X.GPT PRO: creer " .. className) instance.Name = args.name or className applyProperties(instance, args.properties) local container = getParentFromArg(args.parent) if not container then if instance:IsA("GuiObject") or instance:IsA("LayerCollector") then container = game:GetService("StarterGui") elseif instance:IsA("Tool") then container = game:GetService("StarterPack") else container = workspace end end instance.Parent = container commitRecording(recording) return instance:GetFullName(), nil end local function describeObject(instance) local parts = {} local function prop(name, value) table.insert(parts, " " .. name .. " = " .. tostring(value)) end table.insert(parts, instance:GetFullName() .. " (" .. instance.ClassName .. ")") if instance:IsA("BasePart") then prop("Position", instance.Position) prop("Size", instance.Size) prop("Color", instance.Color) prop("Material", instance.Material.Name) prop("Anchored", instance.Anchored) prop("Transparency", instance.Transparency) elseif instance:IsA("LuaSourceContainer") then local source = tostring(instance.Source) if #source > 1500 then source = source:sub(1, 1500) .. "\n... (tronque)" end table.insert(parts, " Source:\n" .. source) elseif instance:IsA("ValueBase") then prop("Value", instance.Value) elseif instance:IsA("Model") then prop("Pivot", instance:GetPivot().Position) end local children = instance:GetChildren() if #children > 0 then table.insert(parts, " Enfants:") for i = 1, math.min(15, #children) do table.insert(parts, " " .. children[i].Name .. " (" .. children[i].ClassName .. ")") end if #children > 15 then table.insert(parts, " ... et " .. (#children - 15) .. " autre(s)") end end return table.concat(parts, "\n") end local function readObjectCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end return true, describeObject(instance) end local function cloneCommand(args) local instance = resolveInstance(args.path) if not instance then return false, "Objet introuvable: " .. tostring(args.path) .. ". Utilise roblox_inspect pour voir les chemins." end if instance == game or instance.Parent == game then return false, "Refuse de cloner un service de base." end local count = math.clamp(tonumber(args.count) or 1, 1, 50) local offset = args.offset or {} local parent = getParentFromArg(args.parent) or instance.Parent local basePos = objectPosition(instance) local recording = beginRecording("X.GPT PRO: cloner " .. instance.Name) local created = {} for i = 0, count - 1 do local clone = instance:Clone() clone.Name = instance.Name .. "_" .. (i + 1) clone.Parent = parent if basePos and (offset.x or offset.y or offset.z) then local target = basePos + Vector3.new((offset.x or 0) * i, (offset.y or 0) * i, (offset.z or 0) * i) pcall(function() if clone:IsA("BasePart") then clone.Position = target else clone:PivotTo(CFrame.new(target)) end end) end table.insert(created, clone:GetFullName()) end commitRecording(recording) return true, "Clone(s) cree(s): " .. table.concat(created, ", ") end local SCENE_PRESETS = { Day = { clock = 14, brightness = 2, ambient = Color3.fromRGB(200, 205, 215), outdoor = Color3.fromRGB(220, 225, 235), fog = Color3.fromRGB(180, 195, 210), fogStart = 300, fogEnd = 800 }, Sunset = { clock = 18.2, brightness = 1.6, ambient = Color3.fromRGB(140, 90, 70), outdoor = Color3.fromRGB(230, 150, 90), fog = Color3.fromRGB(255, 160, 100), fogStart = 100, fogEnd = 400 }, Night = { clock = 0, brightness = 0.7, ambient = Color3.fromRGB(25, 30, 60), outdoor = Color3.fromRGB(30, 35, 70), fog = Color3.fromRGB(10, 12, 30), fogStart = 40, fogEnd = 250 }, Horror = { clock = 0.2, brightness = 0.5, ambient = Color3.fromRGB(20, 15, 15), outdoor = Color3.fromRGB(25, 18, 18), fog = Color3.fromRGB(8, 8, 8), fogStart = 20, fogEnd = 180 }, Space = { clock = 0, brightness = 0.4, ambient = Color3.fromRGB(10, 10, 25), outdoor = Color3.fromRGB(15, 15, 40), fog = Color3.fromRGB(0, 0, 10), fogStart = 10, fogEnd = 120 }, Tropical = { clock = 11, brightness = 2.2, ambient = Color3.fromRGB(210, 225, 230), outdoor = Color3.fromRGB(240, 250, 255), fog = Color3.fromRGB(200, 230, 240), fogStart = 250, fogEnd = 700 }, Neon = { clock = 0, brightness = 0.9, ambient = Color3.fromRGB(60, 20, 90), outdoor = Color3.fromRGB(80, 30, 120), fog = Color3.fromRGB(30, 5, 50), fogStart = 60, fogEnd = 300 }, } local function sceneCommand(args) local presetName = tostring(args.preset or "Day") local preset = SCENE_PRESETS[presetName] if not preset then local names = {} for name in pairs(SCENE_PRESETS) do table.insert(names, name) end table.sort(names) return false, "Preset inconnu: " .. presetName .. " (dispo: " .. table.concat(names, ", ") .. ")" end local lighting = game:GetService("Lighting") local recording = beginRecording("X.GPT PRO: ambiance " .. presetName) lighting.ClockTime = tonumber(args.clock) or preset.clock lighting.Brightness = tonumber(args.brightness) or preset.brightness lighting.Ambient = preset.ambient lighting.OutdoorAmbient = preset.outdoor lighting.FogColor = preset.fog lighting.FogStart = preset.fogStart lighting.FogEnd = preset.fogEnd commitRecording(recording) return true, "Ambiance appliquee: " .. presetName .. " (heure " .. lighting.ClockTime .. ", luminosite " .. lighting.Brightness .. ")" end function executeCommand(command) local args = command.args or {} if command.type == "create" then local objectType = args.objectType or "part" if objectType == "part" then return true, "Cree: " .. createPart(args) elseif objectType == "folder" then return true, "Cree: " .. createFolder(args) elseif objectType == "model" then return true, "Cree: " .. createModel(args) elseif objectType == "script" or objectType == "localscript" then args.client = objectType == "localscript" local full, err = createScript(args) if not full then return false, err end return true, "Cree: " .. full elseif objectType == "instance" then local full, err = createInstance(args) if not full then return false, err end return true, "Cree: " .. full end return false, "Type inconnu: " .. tostring(objectType) elseif command.type == "run_code" then local full, err = createScript({ code = args.code, name = args.name, client = args.client, container = args.container }) if not full then return false, err end return true, "Cree: " .. full elseif command.type == "inspect" then return inspectCommand() elseif command.type == "read_script" then return readScriptCommand(args) elseif command.type == "update_script" then return updateScriptCommand(args) elseif command.type == "toolbox_search" then return toolboxSearchCommand(args) elseif command.type == "test_play" then return testPlayCommand(args) elseif command.type == "focus" then return focusCommand(args) elseif command.type == "delete" then return deleteCommand(args) elseif command.type == "rename" then return renameCommand(args) elseif command.type == "set_properties" then return setPropertiesCommand(args) elseif command.type == "terrain" then return terrainCommand(args) elseif command.type == "read_object" then return readObjectCommand(args) elseif command.type == "clone" then return cloneCommand(args) elseif command.type == "scene" then return sceneCommand(args) elseif command.type == "toolbox_insert" then return toolboxInsertCommand(args) elseif command.type == "disconnect" then disconnect() return true, "Plugin deconnecte par l'IA" end return false, "Commande inconnue: " .. tostring(command.type) end -- --------------------------------------------------------------------------- -- Evenements -- --------------------------------------------------------------------------- connectBtn.MouseButton1Click:Connect(function() if running then disconnect() else connect() end end) toggleBtn.Click:Connect(function() pcall(function() gui.Enabled = not gui.Enabled end) end) pcall(function() gui.Enabled = true end) updateUI() print("[X.GPT PRO] OK - Plugin charge") end) -- fin pcall if not success then print("[X.GPT PRO] ERREUR:", err) warn("[X.GPT PRO] ERREUR:", err) end