-- MainPluginScript.lua

local plugin = plugin

local UI = require(script.Parent.UI)
local Serializer = require(script.Parent.Serializer)
local Rechecker = require(script.Parent.Rechecker) -- Require the Rechecker module

-- Create the UI
local uiElements = UI.createWidget(plugin)

-- Handle the button click to open/close the widget
uiElements.button.Click:Connect(function()
	uiElements.widget.Enabled = not uiElements.widget.Enabled
end)

-- Function to collect selected objects from the UI
local function getSelectedObjects()
	local selectedObjects = {}
	for _, obj in ipairs(uiElements.objectList or {}) do
		local checkboxInfo = uiElements.objectCheckboxes[obj]
		if checkboxInfo and checkboxInfo.isSelected() then
			table.insert(selectedObjects, obj)
		end
	end
	return selectedObjects
end

-- Function to collect all game objects for serialization
local function getAllGameObjects()
	local allObjects = {}

	local servicesToInclude = {
		"Workspace",
		"Lighting",
		"ReplicatedFirst",
		"ReplicatedStorage",
		"ServerScriptService",
		"ServerStorage",
		"StarterGui",
		"StarterPack",
		"StarterPlayer",
		-- Add other services as needed
	}

	for _, serviceName in ipairs(servicesToInclude) do
		local success, service = pcall(function()
			return game:GetService(serviceName)
		end)
		if success and service then
			table.insert(allObjects, service)
		else
			warn("Failed to get service:", serviceName)
		end
	end

	return allObjects
end

-- Function to handle serialization
local function onSerializeButtonClicked()
	local isAllGameConversionEnabled = uiElements.isAllGameConversionEnabled()

	local objectsToSerialize = {}

	if isAllGameConversionEnabled then
		-- Get all objects in the game
		objectsToSerialize = getAllGameObjects()
	else
		-- Get selected objects
		objectsToSerialize = getSelectedObjects()
		if #objectsToSerialize == 0 then
			warn("No objects selected for serialization.")
			uiElements.progressLabel.Text = "No objects selected for serialization."
			return
		end
	end

	print("Number of initial objects to serialize:", #objectsToSerialize)

	-- Prepare the serialization queue
	local instancesQueue = {}
	for _, obj in ipairs(objectsToSerialize) do
		table.insert(instancesQueue, obj)
	end

	local instanceMap = {}        -- Map to store instance references
	local serializedData = {}     -- List to keep serialized data
	local skippedInstances = 0    -- Count of instances that were skipped due to errors
	local totalObjectsProcessed = 0  -- We will increment this as we process instances
	local totalObjectsToProcess = #instancesQueue

	uiElements.progressLabel.Text = "Serialization in progress..."
	uiElements.progressBar.Size = UDim2.new(0, 0, 1, 0)  -- Reset progress bar

	local RunService = game:GetService("RunService")
	local startTime = tick()

	-- Function to proceed to generating reconstruction scripts
	local function proceedToGenerateScripts()
		if #serializedData == 0 then
			warn("No data was serialized. Serialization aborted.")
			uiElements.progressLabel.Text = "Serialization aborted. No data was serialized."
			return
		end

		-- Generate reconstruction scripts (multiple scripts if necessary)
		local maxScriptSize = 199000  -- Adjust as needed (Roblox's script size limit is around 200,000 characters)
		local reconstructionScriptsData = Serializer.generateReconstructionScripts(serializedData, maxScriptSize)

		-- Create the reconstruction scripts within the Plugin's parent (e.g., ServerScriptService)
		local scriptsFolder = Instance.new("Folder")
		scriptsFolder.Name = "ReconstructionScripts"
		scriptsFolder.Parent = game:GetService("ServerScriptService")  -- Placing in ServerScriptService to run on server

		-- Create a BoolValue to signal when reconstruction is complete
		local reconstructionCompleteSignal = Instance.new("BoolValue")
		reconstructionCompleteSignal.Name = "ReconstructionComplete"
		reconstructionCompleteSignal.Value = false
		reconstructionCompleteSignal.Parent = scriptsFolder

		-- Create and parent each reconstruction script
		for i, scriptData in ipairs(reconstructionScriptsData) do
			local reconstructionScript = Instance.new("Script")
			reconstructionScript.Name = "ReconstructionScript_" .. tostring(i)
			reconstructionScript.Source = scriptData.Source
			reconstructionScript.Disabled = false  -- Enable script
			reconstructionScript.Parent = scriptsFolder
		end

		-- Wait for deserialization to complete
		local deserializationStartTime = tick()
		local maxWaitTime = 600  -- Maximum wait time in seconds (adjust as needed)
		local deserializationComplete = false

		while not deserializationComplete and (tick() - deserializationStartTime) < maxWaitTime do
			RunService.Heartbeat:Wait()
			deserializationComplete = reconstructionCompleteSignal.Value
		end

		if deserializationComplete then
			print("Deserialization complete. Game is ready to load.")
		else
			warn("Deserialization did not complete within the expected time.")
		end

		-- Display time taken
		local endTime = tick()
		local duration = endTime - startTime
		local minutes = math.floor(duration / 60)
		local seconds = duration % 60
		uiElements.progressLabel.Text = string.format("Serialization complete in %d minutes, %.2f seconds.", minutes, seconds)
		uiElements.progressBar.Size = UDim2.new(1, 0, 1, 0)  -- Fill progress bar

		-- Notify user that serialization is complete
		print("Serialization complete. Reconstruction scripts have been generated.")
		if skippedInstances > 0 then
			print(skippedInstances .. " instances were skipped due to errors.")
		end
	end

	-- Serialize instances
	local function serializeNextInstance(onComplete)
		if #instancesQueue == 0 then
			-- Serialization complete
			if onComplete then
				onComplete()
			end
		else
			local instancesPerFrame = 100  -- Adjust this number as needed
			local count = 0

			while count < instancesPerFrame and #instancesQueue > 0 do
				count = count + 1
				local instance = table.remove(instancesQueue, 1)

				-- Serialize the instance
				local success, errorMsg = pcall(function()
					Serializer.serializeInstance(instance, instanceMap, serializedData, instancesQueue)
				end)

				if not success then
					skippedInstances = skippedInstances + 1
					warn("Failed to serialize instance: " .. tostring(instance:GetFullName()) .. ". Error: " .. tostring(errorMsg))
				end

				totalObjectsProcessed = totalObjectsProcessed + 1

				-- Update progress in UI
				local progressPercentage = math.floor((totalObjectsProcessed / totalObjectsToProcess) * 100)
				uiElements.progressLabel.Text = string.format("Serializing... %d%% complete", progressPercentage)
				uiElements.progressBar.Size = UDim2.new(totalObjectsProcessed / totalObjectsToProcess, 0, 1, 0)
			end

			-- Schedule next batch after yielding
			RunService.Heartbeat:Wait()
			serializeNextInstance(onComplete)
		end
	end

	-- Start the serialization process
	serializeNextInstance(function()
		-- After serialization is complete
		-- Perform recheck to find any missing instances
		local missingInstances = Rechecker.verifySerialization(objectsToSerialize, instanceMap)
		if #missingInstances > 0 then
			warn("Some instances were not serialized. Attempting to serialize missing instances.")

			-- Attempt to serialize missing instances
			Serializer.handleMissingInstances(missingInstances, instanceMap, serializedData, instancesQueue)

			-- Re-run serialization if there are instances left in the queue
			if #instancesQueue > 0 then
				totalObjectsToProcess = totalObjectsToProcess + #instancesQueue
				serializeNextInstance(function()
					-- After re-serialization, check again for missing instances
					missingInstances = Rechecker.verifySerialization(objectsToSerialize, instanceMap)
					if #missingInstances > 0 then
						warn("Could not serialize all instances after retries.")
					else
						print("All instances have been successfully serialized after retries.")
					end

					-- Proceed to generate reconstruction scripts
					proceedToGenerateScripts()
				end)
			else
				-- Proceed to generate reconstruction scripts even if some instances are missing
				proceedToGenerateScripts()
			end
		else
			print("All instances have been successfully serialized.")
			-- Proceed to generate reconstruction scripts
			proceedToGenerateScripts()
		end
	end)
end

-- Connect the serialize button in the UI to the function
uiElements.serializeButton.MouseButton1Click:Connect(onSerializeButtonClicked)
MainPluginScript -- ScriptGenerator.lua

local ScriptGenerator = {}
local HttpService = game:GetService("HttpService")

function ScriptGenerator.getScriptTemplate()
	local scriptTemplate = [[
-- Reconstruction Script - Part CHUNK_INDEX of TOTAL_CHUNKS

local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")

_G.instanceRegistry = _G.instanceRegistry or {}
_G.parentDataMap = _G.parentDataMap or {}
local instanceRegistry = _G.instanceRegistry
local parentDataMap = _G.parentDataMap

local propertiesToSkip = {
    ["ClassName"] = true,
    ["Parent"] = true,
    ["Archivable"] = true,
}

local function recreateValue(value)
    if type(value) == "table" and value.__type then
        local valueType = value.__type
        if valueType == "EnumItem" then
            local enumFullName = value.Value
            local enumTypeName, enumName = enumFullName:match("Enum%.(%w+)%.(.+)")
            if enumTypeName and enumName then
                return Enum[enumTypeName][enumName]
            else
                warn("Failed to reconstruct EnumItem:", value.Value)
                return nil
            end
        elseif valueType == "BrickColor" then
            return BrickColor.new(value.Number)
        elseif valueType == "Color3" then
            return Color3.new(value.R, value.G, value.B)
        elseif valueType == "Vector3" then
            return Vector3.new(value.X, value.Y, value.Z)
        elseif valueType == "Vector2" then
            return Vector2.new(value.X, value.Y)
        elseif valueType == "CFrame" then
            return CFrame.new(unpack(value.Components))
        elseif valueType == "UDim2" then
            return UDim2.new(value.XScale, value.XOffset, value.YScale, value.YOffset)
        elseif valueType == "UDim" then
            return UDim.new(value.Scale, value.Offset)
        elseif valueType == "NumberRange" then
            return NumberRange.new(value.Min, value.Max)
        elseif valueType == "NumberSequence" then
            local keypoints = {}
            for _, kp in ipairs(value.Keypoints) do
                table.insert(keypoints, NumberSequenceKeypoint.new(kp.Time, kp.Value, kp.Envelope))
            end
            return NumberSequence.new(keypoints)
        elseif valueType == "ColorSequence" then
            local keypoints = {}
            for _, kp in ipairs(value.Keypoints) do
                local color = Color3.new(kp.Value.R, kp.Value.G, kp.Value.B)
                table.insert(keypoints, ColorSequenceKeypoint.new(kp.Time, color))
            end
            return ColorSequence.new(keypoints)
        elseif valueType == "Rect" then
            return Rect.new(value.Min.X, value.Min.Y, value.Max.X, value.Max.Y)
        elseif valueType == "PhysicalProperties" then
            return PhysicalProperties.new(value.Density, value.Friction, value.Elasticity, value.FrictionWeight, value.ElasticityWeight)
        elseif valueType == "Font" then
            return Font.new(value.Family, Enum.FontWeight[value.Weight], Enum.FontStyle[value.Style])
        elseif valueType == "Faces" then
            -- Reconstruct Faces from table of booleans
            local faces = {}
            for face, included in pairs(value) do
                if included then
                    table.insert(faces, Enum.NormalId[face])
                end
            end
            return Faces.new(unpack(faces))
        elseif valueType == "Axes" then
            -- Reconstruct Axes from table of booleans
            local axes = {}
            for axis, included in pairs(value) do
                if included then
                    table.insert(axes, Enum.Axis[axis])
                end
            end
            return Axes.new(unpack(axes))
        elseif valueType == "Instance" then
            return instanceRegistry[value.__ref]
        else
            return nil
        end
    else
        return value
    end
end

local function deserializeInstance(data)
    local instance

    -- Handle non-creatable classes
    local nonCreatableClasses = {
        Workspace = function() return game:GetService("Workspace") end,
        Terrain = function() return workspace.Terrain end,
        Lighting = function() return game:GetService("Lighting") end,
        Players = function() return game:GetService("Players") end,
        ReplicatedFirst = function() return game:GetService("ReplicatedFirst") end,
        ReplicatedStorage = function() return game:GetService("ReplicatedStorage") end,
        ServerScriptService = function() return game:GetService("ServerScriptService") end,
        ServerStorage = function() return game:GetService("ServerStorage") end,
        StarterGui = function() return game:GetService("StarterGui") end,
        StarterPack = function() return game:GetService("StarterPack") end,
        StarterPlayer = function() return game:GetService("StarterPlayer") end,
        -- Add other non-creatable classes as needed
    }

    local getInstanceFunction = nonCreatableClasses[data.ClassName]
    if getInstanceFunction then
        instance = getInstanceFunction()
    else
        local success, result = pcall(function()
            return Instance.new(data.ClassName)
        end)
        if success then
            instance = result
        else
            warn("Failed to create instance of class:", data.ClassName, "-", result)
            return nil
        end
    end

    instanceRegistry[data.__id] = instance

    -- Set properties (excluding Parent)
    for property, value in pairs(data.Properties or {}) do
        if not propertiesToSkip[property] then
            local recreatedValue = recreateValue(value)
            local successProp, errorMsg = pcall(function()
                instance[property] = recreatedValue
            end)
            if not successProp then
                warn("Failed to set property:", property, "on instance:", instance:GetFullName(), "-", errorMsg)
            end
        end
    end

    -- Set attributes
    if data.Attributes then
        for attribute, value in pairs(data.Attributes) do
            local recreatedValue = recreateValue(value)
            local successAttr, errorMsg = pcall(function()
                instance:SetAttribute(attribute, recreatedValue)
            end)
            if not successAttr then
                warn("Failed to set attribute:", attribute, "on instance:", instance:GetFullName(), "-", errorMsg)
            end
        end
    end

    -- Store parent data for later parenting
    parentDataMap[instance] = data
end

local function attemptToSetParents()
    local unresolved = {}
    for instance, data in pairs(parentDataMap) do
        local parentInstance = nil
        local canSetParent = true

        if data.ParentId then
            parentInstance = instanceRegistry[data.ParentId]
            if parentInstance then
                -- Avoid setting Parent of non-parentable instances
                if instance == workspace.Terrain or instance:IsA("Terrain") then
                    canSetParent = false
                end
                if canSetParent then
                    instance.Parent = parentInstance
                else
                    unresolved[instance] = data
                end
            else
                unresolved[instance] = data  -- Parent not yet available
            end
        elseif data.ParentIsGame then
            if instance == workspace.Terrain or instance:IsA("Terrain") then
                canSetParent = false
            end
            if canSetParent then
                instance.Parent = game
            end
        elseif data.ParentIsService and data.ParentClassName then
            parentInstance = game:GetService(data.ParentClassName)
            if parentInstance then
                -- Avoid setting Parent of non-parentable instances
                if instance == workspace.Terrain or instance:IsA("Terrain") then
                    canSetParent = false
                end
                if canSetParent then
                    instance.Parent = parentInstance
                end
            else
                warn("Service not found:", data.ParentClassName)
            end
        elseif data.ParentName and data.ParentClassName then
            local service = game:GetService(data.ParentClassName)
            if service then
                parentInstance = service:FindFirstChild(data.ParentName)
                if parentInstance then
                    -- Avoid setting Parent of non-parentable instances
                    if instance == workspace.Terrain or instance:IsA("Terrain") then
                        canSetParent = false
                    end
                    if canSetParent then
                        instance.Parent = parentInstance
                    else
                        unresolved[instance] = data
                    end
                else
                    unresolved[instance] = data  -- Parent not found yet
                end
            else
                warn("Service not found:", data.ParentClassName)
            end
        else
            -- Default parent
            if instance == workspace.Terrain or instance:IsA("Terrain") then
                canSetParent = false
            end
            if canSetParent then
                instance.Parent = workspace
            end
        end
    end
    parentDataMap = unresolved
end

-- Data string assignment
DATA_STRING_ASSIGNMENT

local data = HttpService:JSONDecode(dataString)

-- Deserialize instances
local totalInstances = #data
local currentIndex = 1

local function deserializeBatch()
    local batchSize = 100  -- Adjust as needed
    local endIndex = math.min(currentIndex + batchSize - 1, totalInstances)
    for i = currentIndex, endIndex do
        local instanceData = data[i]
        deserializeInstance(instanceData)
    end
    currentIndex = endIndex + 1
    if currentIndex <= totalInstances then
        RunService.Heartbeat:Wait()
        deserializeBatch()
    else
        -- All instances created, now set parents
        attemptToSetParents()
        -- Retry setting parents for unresolved instances
        for attempt = 1, 10 do
            if next(parentDataMap) then
                RunService.Heartbeat:Wait()
                attemptToSetParents()
            else
                break
            end
        end
        if next(parentDataMap) then
            for instance, data in pairs(parentDataMap) do
                warn("Unresolved parent for instance:", instance:GetFullName())
                -- Avoid setting Parent of non-parentable instances
                if instance ~= workspace.Terrain and not instance:IsA("Terrain") then
                    instance.Parent = workspace  -- Assign to workspace as fallback
                end
            end
        end
        -- Clean up shared data
        _G.instanceRegistry = nil
        _G.parentDataMap = nil
        print("Deserialization complete.")

        -- Signal that deserialization is complete
        local reconstructionCompleteSignal = script.Parent:FindFirstChild("ReconstructionComplete")
        if reconstructionCompleteSignal then
            reconstructionCompleteSignal.Value = true
        end
    end
end

-- Start deserialization
deserializeBatch()
]]

	return scriptTemplate
end

function ScriptGenerator.generateScript(chunkIndex, totalChunks, dataChunk)
	local scriptTemplate = ScriptGenerator.getScriptTemplate()

	-- Prepare the data string assignment
	local dataStringAssignment = 'local dataString = ' .. string.format('%q', dataChunk)
	-- Escape any '%' in dataStringAssignment
	dataStringAssignment = dataStringAssignment:gsub("%%", "%%%%")

	-- Replace placeholders in the script template
	scriptTemplate = scriptTemplate:gsub("CHUNK_INDEX", tostring(chunkIndex))
	scriptTemplate = scriptTemplate:gsub("TOTAL_CHUNKS", tostring(totalChunks))
	scriptTemplate = scriptTemplate:gsub("DATA_STRING_ASSIGNMENT", dataStringAssignment)

	return scriptTemplate
end

function ScriptGenerator.generateReconstructionScripts(serializedData, maxScriptSize)
	local scripts = {}

	local dataSet = serializedData

	local dataChunks = {}
	local totalInstances = #dataSet
	local index = 1

	-- Get the script template for size estimation
	local emptyDataString = 'local dataString = ""'
	local scriptTemplateWithoutData = ScriptGenerator.getScriptTemplate()
	-- Replace placeholders with sample values
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("DATA_STRING_ASSIGNMENT", emptyDataString)
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("CHUNK_INDEX", "1")
	scriptTemplateWithoutData = scriptTemplateWithoutData:gsub("TOTAL_CHUNKS", "1")

	-- Estimate base script size
	local baseScriptSize = #scriptTemplateWithoutData

	local dataChunk = {}
	local dataSize = 0

	while index <= totalInstances do
		local instanceData = dataSet[index]
		local instanceDataString = HttpService:JSONEncode(instanceData)
		local instanceDataSize = #instanceDataString

		local tempDataChunk = { table.unpack(dataChunk) }
		table.insert(tempDataChunk, instanceData)
		local dataStringAssignmentSize = #('local dataString = ' .. string.format('%q', HttpService:JSONEncode(tempDataChunk)))

		local estimatedScriptSize = baseScriptSize - #('local dataString = ""') + dataStringAssignmentSize

		if estimatedScriptSize > maxScriptSize then
			if #dataChunk == 0 then
				-- Single instance too large to fit into a script, skip it
				warn("Instance at index " .. index .. " is too large to fit into a script and will be skipped.")
				index = index + 1
			else
				-- Finalize current dataChunk
				table.insert(dataChunks, dataChunk)
				-- Reset dataChunk and dataSize
				dataChunk = {}
				dataSize = 0
			end
		else
			-- Add instanceData to dataChunk
			dataChunk = tempDataChunk
			dataSize = dataSize + instanceDataSize
			index = index + 1
		end
	end

	-- Add any remaining dataChunk
	if #dataChunk > 0 then
		table.insert(dataChunks, dataChunk)
	end

	local totalChunks = #dataChunks

	-- Now generate scripts
	for chunkIndex, dataChunk in ipairs(dataChunks) do
		local dataString = HttpService:JSONEncode(dataChunk)
		local scriptSource = ScriptGenerator.generateScript(chunkIndex, totalChunks, dataString)
		table.insert(scripts, { Source = scriptSource })
	end

	return scripts
end

return ScriptGenerator
ScriptGenerator Module -- Serializer.lua

local Serializer = {}

local HttpService = game:GetService("HttpService")
local ScriptGenerator = require(script.Parent.ScriptGenerator)
local RobloxApiDump = require(script.Parent.RobloxApiDump)

-- Function to serialize a value
function Serializer.serializeValue(value, instanceMap, serializedData, instancesQueue)
	local valueType = typeof(value)

	-- Handle unsupported types
	local unsupportedTypes = {
		["function"] = true,
		["userdata"] = true,
		["RBXScriptConnection"] = true,
		["RBXScriptSignal"] = true,
		["thread"] = true,
	}

	if unsupportedTypes[valueType] then
		return nil
	end

	-- Handle specific types
	if valueType == "EnumItem" then
		return { __type = "EnumItem", Value = tostring(value) }
	elseif valueType == "BrickColor" then
		return { __type = "BrickColor", Number = value.Number }
	elseif valueType == "Color3" then
		return { __type = "Color3", R = value.R, G = value.G, B = value.B }
	elseif valueType == "Vector3" then
		return { __type = "Vector3", X = value.X, Y = value.Y, Z = value.Z }
	elseif valueType == "Vector2" then
		return { __type = "Vector2", X = value.X, Y = value.Y }
	elseif valueType == "CFrame" then
		return { __type = "CFrame", Components = { value:GetComponents() } }
	elseif valueType == "UDim2" then
		return { __type = "UDim2", XScale = value.X.Scale, XOffset = value.X.Offset, YScale = value.Y.Scale, YOffset = value.Y.Offset }
	elseif valueType == "UDim" then
		return { __type = "UDim", Scale = value.Scale, Offset = value.Offset }
	elseif valueType == "NumberRange" then
		return { __type = "NumberRange", Min = value.Min, Max = value.Max }
	elseif valueType == "NumberSequence" then
		local keypoints = {}
		for _, keypoint in ipairs(value.Keypoints) do
			table.insert(keypoints, { Time = keypoint.Time, Value = keypoint.Value, Envelope = keypoint.Envelope })
		end
		return { __type = "NumberSequence", Keypoints = keypoints }
	elseif valueType == "ColorSequence" then
		local keypoints = {}
		for _, keypoint in ipairs(value.Keypoints) do
			table.insert(keypoints, {
				Time = keypoint.Time,
				Value = { R = keypoint.Value.R, G = keypoint.Value.G, B = keypoint.Value.B },
			})
		end
		return { __type = "ColorSequence", Keypoints = keypoints }
	elseif valueType == "Rect" then
		return { __type = "Rect", Min = { X = value.Min.X, Y = value.Min.Y }, Max = { X = value.Max.X, Y = value.Max.Y } }
	elseif valueType == "PhysicalProperties" then
		return {
			__type = "PhysicalProperties",
			Density = value.Density,
			Friction = value.Friction,
			Elasticity = value.Elasticity,
			FrictionWeight = value.FrictionWeight,
			ElasticityWeight = value.ElasticityWeight,
		}
	elseif valueType == "Font" then
		return {
			__type = "Font",
			Family = value.Family,
			Weight = tostring(value.Weight),
			Style = tostring(value.Style),
		}
	elseif valueType == "Faces" then
		-- Serialize Faces as a table of booleans
		return {
			__type = "Faces",
			Top = value.Top,
			Bottom = value.Bottom,
			Left = value.Left,
			Right = value.Right,
			Front = value.Front,
			Back = value.Back,
		}
	elseif valueType == "Axes" then
		-- Serialize Axes as a table of booleans
		return {
			__type = "Axes",
			X = value.X,
			Y = value.Y,
			Z = value.Z,
		}
	elseif valueType == "Instance" then
		-- Handle instance references
		if instanceMap[value] then
			-- Reference to a serialized instance
			return { __type = "Instance", __ref = instanceMap[value] }
		else
			-- The instance has not been serialized yet
			-- We need to serialize it now
			local success, err = pcall(function()
				Serializer.serializeInstance(value, instanceMap, serializedData, instancesQueue)
			end)
			if success then
				return { __type = "Instance", __ref = instanceMap[value] }
			else
				-- Could not serialize the instance; return nil or handle appropriately
				warn("Failed to serialize instance reference:", tostring(value), "-", err)
				return nil
			end
		end
	else
		-- For basic types like string, number, boolean, Content, etc.
		return value
	end
end

-- Function to serialize an instance
function Serializer.serializeInstance(instance, instanceMap, serializedData, instancesQueue)
	-- Early exit if instance is already processed
	if instanceMap[instance] then
		return
	end

	-- Exclude instances that should not be serialized
	if instance == game or instance:IsA("CoreScript") then
		return
	end

	local success, className = pcall(function()
		return instance.ClassName
	end)

	if not success then
		warn("Failed to get ClassName for instance:", tostring(instance))
		return
	end

	-- Generate a unique ID for the instance
	local instanceId = HttpService:GenerateGUID(false)
	instanceMap[instance] = instanceId

	local serialized = {
		ClassName = className,
		__id = instanceId,
		Properties = {},
		Attributes = {},
	}

	-- Serialize properties
	local properties = Serializer.getSerializableProperties(instance)
	for _, propertyData in ipairs(properties) do
		local propertyName = propertyData.Name

		if propertyName ~= "Parent" then
			local successProp, value = pcall(function()
				return instance[propertyName]
			end)
			if successProp then
				local serializedValue = Serializer.serializeValue(value, instanceMap, serializedData, instancesQueue)
				if serializedValue ~= nil then
					serialized.Properties[propertyName] = serializedValue
				else
					-- Handle serialization failure of property value
					warn("Property value could not be serialized:", propertyName, "on instance:", instance:GetFullName())
				end
			else
				-- Handle property get errors gracefully
				warn("Failed to get property:", propertyName, "on instance:", tostring(instance))
			end
		end
	end

	-- Serialize attributes
	local successAttr, attributes = pcall(function()
		return instance:GetAttributes()
	end)
	if successAttr and attributes then
		for attributeName, attributeValue in pairs(attributes) do
			local serializedAttributeValue = Serializer.serializeValue(attributeValue, instanceMap, serializedData, instancesQueue)
			if serializedAttributeValue ~= nil then
				serialized.Attributes[attributeName] = serializedAttributeValue
			end
		end
	else
		warn("Failed to get attributes for instance:", tostring(instance))
	end

	-- Store ParentId to reconstruct the hierarchy
	local successParent, parent = pcall(function()
		return instance.Parent
	end)
	if successParent and parent then
		if instanceMap[parent] then
			-- Parent is a serialized instance
			serialized.ParentId = instanceMap[parent]
		else
			-- Parent is an external instance or service
			if parent == game then
				serialized.ParentIsGame = true
			else
				-- Attempt to get service if parent is a service
				local successService, parentService = pcall(game.GetService, game, parent.ClassName)
				if successService and parentService == parent then
					serialized.ParentIsService = true
					serialized.ParentClassName = parent.ClassName
				else
					serialized.ParentName = parent.Name
					serialized.ParentClassName = parent.ClassName
				end
			end
		end
	else
		-- Instance has no parent; default to game during deserialization
		serialized.ParentIsGame = true
	end

	-- Add serialized data to the list
	table.insert(serializedData, serialized)

	-- Add immediate children to the queue to process, if any
	local canAccess, children = pcall(function()
		return instance:GetChildren()
	end)
	if canAccess and children then
		for _, child in ipairs(children) do
			if not instanceMap[child] then
				table.insert(instancesQueue, child)
			end
		end
	end
end

-- Function to get serializable properties of an instance
function Serializer.getSerializableProperties(instance)
	local properties = {}
	local className = instance.ClassName
	local classData = RobloxApiDump.Classes[className]

	-- Define collectProperties function
	local function collectProperties(clsData)
		if not clsData then
			-- No class data provided
			return
		end

		-- Recursively collect properties from superclass
		if clsData.Superclass and RobloxApiDump.Classes[clsData.Superclass] then
			collectProperties(RobloxApiDump.Classes[clsData.Superclass])
		end

		-- Process properties
		if clsData.Properties then
			for _, propertyData in ipairs(clsData.Properties) do
				local propertyName = propertyData.Name

				-- Filter out properties based on security and attributes
				local isNotBrowsable = false
				local deprecated = false
				local attributes = propertyData.Attributes or {}

				for _, attribute in ipairs(attributes) do
					if attribute == "NotBrowsable" then
						isNotBrowsable = true
					elseif attribute == "Deprecated" then
						deprecated = true
					end
				end

				-- Include specific properties for UnionOperation
				local isUnionOperationSpecialProperty = false
				if instance:IsA("UnionOperation") then
					if propertyName == "Material" or propertyName == "RenderFidelity" or propertyName == "CenterOfMass" or propertyName == "AssemblyCenterOfMass" then
						isUnionOperationSpecialProperty = true
					end
				end

				-- Include properties that are readable at script security level or special UnionOperation properties
				local canRead = propertyData.Security and (propertyData.Security.Read == "None" or propertyData.Security.Read == "PluginSecurity")
				if (canRead and not isNotBrowsable and not deprecated) or isUnionOperationSpecialProperty then
					table.insert(properties, propertyData)
				end
			end
		end
	end

	if classData then
		collectProperties(classData)
	else
		-- If class data is not available, use default properties
		properties = {
			{ Name = "Name", Security = { Read = "None" } },
			{ Name = "Archivable", Security = { Read = "None" } },
			-- Add other common properties if needed
		}
	end

	return properties
end

-- Function to generate reconstruction scripts
function Serializer.generateReconstructionScripts(serializedData, maxScriptSize)
	-- Use the ScriptGenerator to generate the scripts
	local scripts = ScriptGenerator.generateReconstructionScripts(serializedData, maxScriptSize)
	return scripts
end

-- Function to handle missing instances during serialization
function Serializer.handleMissingInstances(missingInstances, instanceMap, serializedData, instancesQueue)
	for _, instance in ipairs(missingInstances) do
		if not instanceMap[instance] then
			table.insert(instancesQueue, instance)
		end
	end
end

return Serializer
serializer module  i meant make the plugin collects all meshparts to the replicated storage in the serializing process and after they have a position on the game right? i want that position to be randomized anywhere in the game when they move to replicatedstorage and when i join the game [runtime] the reconstructionscripts run right?  the recconstructionscripts moves back the collected meshparts into workspace with their original position and location in Roblox

and send full code