local Players = game:GetService("Players") local HttpService = game:GetService("HttpService") local StarterGui = game:GetService("StarterGui") local player = Players.LocalPlayer -- ===== CRÉATION DE L'UI ===== local gui = Instance.new("ScreenGui") gui.Name = "MapExporterUI" gui.ResetOnSpawn = false gui.Parent = player:WaitForChild("PlayerGui") local frame = Instance.new("Frame") frame.Parent = gui frame.Size = UDim2.fromScale(0.7, 0.75) frame.Position = UDim2.fromScale(0.15, 0.125) frame.BackgroundColor3 = Color3.fromRGB(30, 30, 30) local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 16) corner.Parent = frame local title = Instance.new("TextLabel") title.Parent = frame title.Size = UDim2.fromScale(1, 0.07) title.Text = "Map & GUI Exporter / Importer + Position Saver" title.TextScaled = true title.TextColor3 = Color3.new(1,1,1) title.BackgroundTransparency = 1 local statusLabel = Instance.new("TextLabel") statusLabel.Parent = frame statusLabel.Size = UDim2.fromScale(0.95, 0.07) statusLabel.Position = UDim2.fromScale(0.025, 0.08) statusLabel.Text = "Prêt - Cliquez sur Exporter pour commencer" statusLabel.TextScaled = true statusLabel.TextColor3 = Color3.fromRGB(100, 255, 100) statusLabel.BackgroundColor3 = Color3.fromRGB(20, 20, 20) statusLabel.TextWrapped = true local box = Instance.new("TextBox") box.Parent = frame box.Name = "DataBox" box.Size = UDim2.fromScale(0.95, 0.5) box.Position = UDim2.fromScale(0.025, 0.16) box.ClearTextOnFocus = false box.MultiLine = true box.TextWrapped = true box.TextYAlignment = Enum.TextYAlignment.Top box.TextXAlignment = Enum.TextXAlignment.Left box.TextSize = 12 box.Text = "" box.BackgroundColor3 = Color3.fromRGB(20,20,20) box.TextColor3 = Color3.new(1,1,1) box.Font = Enum.Font.Code local boxCorner = Instance.new("UICorner") boxCorner.CornerRadius = UDim.new(0, 8) boxCorner.Parent = box local exportBtn = Instance.new("TextButton") exportBtn.Parent = frame exportBtn.Text = "📤 EXPORTER MAP" exportBtn.Size = UDim2.fromScale(0.3, 0.065) exportBtn.Position = UDim2.fromScale(0.025, 0.68) exportBtn.BackgroundColor3 = Color3.fromRGB(50,150,50) exportBtn.TextColor3 = Color3.new(1,1,1) exportBtn.TextScaled = true exportBtn.Font = Enum.Font.GothamBold local selectBtn = Instance.new("TextButton") selectBtn.Parent = frame selectBtn.Text = "📋 TOUT SÉLECT" selectBtn.Size = UDim2.fromScale(0.3, 0.065) selectBtn.Position = UDim2.fromScale(0.35, 0.68) selectBtn.BackgroundColor3 = Color3.fromRGB(50,100,200) selectBtn.TextColor3 = Color3.new(1,1,1) selectBtn.TextScaled = true selectBtn.Font = Enum.Font.GothamBold local importBtn = Instance.new("TextButton") importBtn.Parent = frame importBtn.Text = "📥 IMPORTER MAP" importBtn.Size = UDim2.fromScale(0.3, 0.065) importBtn.Position = UDim2.fromScale(0.675, 0.68) importBtn.BackgroundColor3 = Color3.fromRGB(200,100,50) importBtn.TextColor3 = Color3.new(1,1,1) importBtn.TextScaled = true importBtn.Font = Enum.Font.GothamBold -- Nouveaux boutons pour positions local savePoBtn = Instance.new("TextButton") savePoBtn.Parent = frame savePoBtn.Text = "💾 SAVE POSITIONS" savePoBtn.Size = UDim2.fromScale(0.3, 0.065) savePoBtn.Position = UDim2.fromScale(0.025, 0.76) savePoBtn.BackgroundColor3 = Color3.fromRGB(100,150,200) savePoBtn.TextColor3 = Color3.new(1,1,1) savePoBtn.TextScaled = true savePoBtn.Font = Enum.Font.GothamBold local loadPoBtn = Instance.new("TextButton") loadPoBtn.Parent = frame loadPoBtn.Text = "📍 LOAD POSITIONS" loadPoBtn.Size = UDim2.fromScale(0.3, 0.065) loadPoBtn.Position = UDim2.fromScale(0.35, 0.76) loadPoBtn.BackgroundColor3 = Color3.fromRGB(150,100,200) loadPoBtn.TextColor3 = Color3.new(1,1,1) loadPoBtn.TextScaled = true loadPoBtn.Font = Enum.Font.GothamBold local clearBtn = Instance.new("TextButton") clearBtn.Parent = frame clearBtn.Text = "🗑️ EFFACER" clearBtn.Size = UDim2.fromScale(0.3, 0.065) clearBtn.Position = UDim2.fromScale(0.675, 0.76) clearBtn.BackgroundColor3 = Color3.fromRGB(150,50,50) clearBtn.TextColor3 = Color3.new(1,1,1) clearBtn.TextScaled = true clearBtn.Font = Enum.Font.Gotham local closeBtn = Instance.new("TextButton") closeBtn.Parent = frame closeBtn.Text = "❌ FERMER" closeBtn.Size = UDim2.fromScale(0.95, 0.06) closeBtn.Position = UDim2.fromScale(0.025, 0.84) closeBtn.BackgroundColor3 = Color3.fromRGB(80,80,80) closeBtn.TextColor3 = Color3.new(1,1,1) closeBtn.TextScaled = true closeBtn.Font = Enum.Font.Gotham local infoLabel = Instance.new("TextLabel") infoLabel.Parent = frame infoLabel.Size = UDim2.fromScale(0.95, 0.04) infoLabel.Position = UDim2.fromScale(0.025, 0.91) infoLabel.Text = "💡 Save Positions = Sauvegarde uniquement les positions | Load = Restaure les positions" infoLabel.TextSize = 10 infoLabel.TextColor3 = Color3.fromRGB(200, 200, 100) infoLabel.BackgroundTransparency = 1 infoLabel.TextWrapped = true infoLabel.Font = Enum.Font.Gotham -- ===== PROPRIÉTÉS À SAUVEGARDER ===== local PROPERTIES_TO_SAVE = { BasePart = { "Size", "Position", "Orientation", "Color", "Material", "Transparency", "Reflectance", "CanCollide", "Anchored", "CastShadow", "TopSurface", "BottomSurface", "LeftSurface", "RightSurface", "FrontSurface", "BackSurface" }, GuiObject = { "Size", "Position", "BackgroundColor3", "BackgroundTransparency", "BorderColor3", "BorderSizePixel", "Rotation", "Visible", "ZIndex", "AnchorPoint" }, TextLabel = { "Text", "TextColor3", "TextSize", "TextScaled", "TextWrapped", "TextXAlignment", "TextYAlignment", "Font" }, TextButton = { "Text", "TextColor3", "TextSize", "TextScaled", "Font", "AutoButtonColor" }, TextBox = { "Text", "TextColor3", "TextSize", "PlaceholderText", "ClearTextOnFocus", "MultiLine", "TextEditable" }, ImageLabel = { "Image", "ImageColor3", "ImageTransparency", "ScaleType" }, ImageButton = { "Image", "ImageColor3", "ImageTransparency" }, Frame = {}, ScreenGui = { "ResetOnSpawn", "DisplayOrder", "Enabled" } } -- ===== SÉRIALISATION ===== local function serializeValue(value) local t = typeof(value) if t == "Vector3" then return {value.X, value.Y, value.Z} elseif t == "Vector2" then return {value.X, value.Y} elseif t == "Color3" then return {value.R, value.G, value.B} elseif t == "UDim2" then return {value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset} elseif t == "EnumItem" then return tostring(value) end return value end local function serialize(obj, parentId, data, ignoreList) ignoreList = ignoreList or {} if obj:IsA("Terrain") or ignoreList[obj] then return end local objData = { ClassName = obj.ClassName, Name = obj.Name, Parent = parentId, Properties = {} } for className, props in pairs(PROPERTIES_TO_SAVE) do if obj:IsA(className) then for _, propName in ipairs(props) do local success, value = pcall(function() return obj[propName] end) if success then objData.Properties[propName] = serializeValue(value) end end end end table.insert(data, objData) local myId = #data for _, child in ipairs(obj:GetChildren()) do serialize(child, myId, data, ignoreList) end end -- ===== SAUVEGARDE POSITIONS ===== local function getFullPath(obj) local path = {} local current = obj while current and current ~= workspace and current ~= game do table.insert(path, 1, current.Name) current = current.Parent end return table.concat(path, ".") end local function savePositions(parent, positions) for _, obj in ipairs(parent:GetChildren()) do if obj:IsA("BasePart") then local path = getFullPath(obj) positions[path] = { Position = {obj.Position.X, obj.Position.Y, obj.Position.Z}, Orientation = {obj.Orientation.X, obj.Orientation.Y, obj.Orientation.Z}, CFrame = {obj.CFrame:GetComponents()} } end if obj:IsA("Model") or obj:IsA("Folder") then savePositions(obj, positions) end end end savePoBtn.MouseButton1Click:Connect(function() statusLabel.Text = "⏳ Sauvegarde des positions en cours..." statusLabel.TextColor3 = Color3.fromRGB(255, 200, 100) wait() local positions = {} savePositions(workspace, positions) local jsonData = HttpService:JSONEncode(positions) box.Text = jsonData statusLabel.Text = "✅ Positions sauvegardées ! " .. #positions .. " parts | Cliquez TOUT SÉLECT puis Ctrl+C" statusLabel.TextColor3 = Color3.fromRGB(100, 255, 100) print("✅ Positions sauvegardées:", #jsonData, "caractères") end) -- ===== CHARGEMENT POSITIONS ===== local function findByPath(parent, path) local parts = {} for part in path:gmatch("[^.]+") do table.insert(parts, part) end local current = parent for _, name in ipairs(parts) do local found = current:FindFirstChild(name) if not found then return nil end current = found end return current end loadPoBtn.MouseButton1Click:Connect(function() if box.Text == "" then statusLabel.Text = "❌ Collez d'abord les données de positions (Ctrl+V)" statusLabel.TextColor3 = Color3.fromRGB(255, 100, 100) return end statusLabel.Text = "⏳ Restauration des positions..." statusLabel.TextColor3 = Color3.fromRGB(255, 200, 100) wait() local success, positions = pcall(function() return HttpService:JSONDecode(box.Text) end) if not success then statusLabel.Text = "❌ Données invalides" statusLabel.TextColor3 = Color3.fromRGB(255, 100, 100) return end local restored = 0 local notFound = 0 for path, data in pairs(positions) do local obj = findByPath(workspace, path) if obj and obj:IsA("BasePart") then pcall(function() if data.CFrame then obj.CFrame = CFrame.new(unpack(data.CFrame)) else obj.Position = Vector3.new(unpack(data.Position)) obj.Orientation = Vector3.new(unpack(data.Orientation)) end restored = restored + 1 end) else notFound = notFound + 1 end end statusLabel.Text = "✅ Positions restaurées ! " .. restored .. " parts | " .. notFound .. " non trouvées" statusLabel.TextColor3 = Color3.fromRGB(100, 255, 100) print("✅ Restauration:", restored, "parts,", notFound, "non trouvées") end) -- ===== EXPORT MAP ===== exportBtn.MouseButton1Click:Connect(function() statusLabel.Text = "⏳ Export en cours..." statusLabel.TextColor3 = Color3.fromRGB(255, 200, 100) box.Text = "Génération des données..." wait() local exportData = { Workspace = {}, StarterGui = {} } local ignoreList = { [workspace.Terrain] = true, [gui] = true } serialize(workspace, 0, exportData.Workspace, ignoreList) for _, child in ipairs(StarterGui:GetChildren()) do serialize(child, 0, exportData.StarterGui, {}) end local jsonData = HttpService:JSONEncode(exportData) if #jsonData > 190000 then local chunkSize = 190000 local chunks = {} for i = 1, #jsonData, chunkSize do table.insert(chunks, jsonData:sub(i, i + chunkSize - 1)) end box.Text = chunks[1] statusLabel.Text = "⚠️ Données trop grandes ! Partie 1/" .. #chunks statusLabel.TextColor3 = Color3.fromRGB(255, 150, 50) print("DONNÉES COMPLÈTES:") print(jsonData) else box.Text = jsonData statusLabel.Text = "✅ Export terminé ! " .. #exportData.Workspace .. " objets" statusLabel.TextColor3 = Color3.fromRGB(100, 255, 100) end end) -- ===== TOUT SÉLECTIONNER ===== selectBtn.MouseButton1Click:Connect(function() box:CaptureFocus() box.CursorPosition = 1 box.SelectionStart = 1 task.wait(0.1) box.CursorPosition = #box.Text + 1 statusLabel.Text = "✅ Texte sélectionné ! Ctrl+C pour copier" statusLabel.TextColor3 = Color3.fromRGB(100, 200, 255) end) -- ===== EFFACER ===== clearBtn.MouseButton1Click:Connect(function() box.Text = "" statusLabel.Text = "🗑️ Zone effacée" statusLabel.TextColor3 = Color3.fromRGB(150, 150, 150) end) -- ===== FERMER ===== closeBtn.MouseButton1Click:Connect(function() gui:Destroy() end) -- ===== DÉSÉRIALISATION ===== local function deserializeValue(value, propType) if type(value) == "table" then if #value == 3 and (propType == "Vector3" or propType == "Color3") then if propType == "Color3" then return Color3.new(value[1], value[2], value[3]) end return Vector3.new(value[1], value[2], value[3]) elseif #value == 2 then return Vector2.new(value[1], value[2]) elseif #value == 4 then return UDim2.new(value[1], value[2], value[3], value[4]) end end return value end local function applyProperties(obj, props) for propName, value in pairs(props) do pcall(function() local propType = typeof(obj[propName]) obj[propName] = deserializeValue(value, propType) end) end end -- ===== IMPORT MAP ===== importBtn.MouseButton1Click:Connect(function() if box.Text == "" then statusLabel.Text = "❌ Collez les données (Ctrl+V) avant d'importer" statusLabel.TextColor3 = Color3.fromRGB(255, 100, 100) return end statusLabel.Text = "⏳ Import en cours..." statusLabel.TextColor3 = Color3.fromRGB(255, 200, 100) wait() local success, importData = pcall(function() return HttpService:JSONDecode(box.Text) end) if not success then statusLabel.Text = "❌ Données invalides" statusLabel.TextColor3 = Color3.fromRGB(255, 100, 100) return end if importData.StarterGui then for _, guiData in ipairs(importData.StarterGui) do local existing = StarterGui:FindFirstChild(guiData.Name) if existing and existing.Name ~= "MapExporterUI" then existing:Destroy() end end end local wsCount = 0 if importData.Workspace then local created = {[0] = workspace} for i, objData in ipairs(importData.Workspace) do pcall(function() local newObj = Instance.new(objData.ClassName) newObj.Name = objData.Name applyProperties(newObj, objData.Properties) newObj.Parent = created[objData.Parent] or workspace created[i] = newObj wsCount = wsCount + 1 end) end end local guiCount = 0 if importData.StarterGui then local created = {[0] = StarterGui} for i, objData in ipairs(importData.StarterGui) do if objData.Name ~= "MapExporterUI" then pcall(function() local newObj = Instance.new(objData.ClassName) newObj.Name = objData.Name applyProperties(newObj, objData.Properties) newObj.Parent = created[objData.Parent] or StarterGui created[i] = newObj guiCount = guiCount + 1 end) end end end statusLabel.Text = "✅ Import réussi ! " .. wsCount .. " objets, " .. guiCount .. " GUIs" statusLabel.TextColor3 = Color3.fromRGB(100, 255, 100) end)