Paint Gui Server Help

So, i have a paint gui and everything, but when a player finishes painting, how do i put the frame for others to see, now i tried to fire every single paint piece info, but it takes to much time and i want to save that, save memory, and reduce lag. so please is there a way for that?

Could you show your code?

maybe you could just clone the painting and then distribute them to all players??

client:

--Variables
local uis = game:GetService("UserInputService")

local lastMoves = 0

local mouse = game.Players.LocalPlayer:GetMouse()
local down = false

local canvas = script.Parent.PaintingFrame
local brushSettings = script.Parent.Frame

function sendDataToServer(data)
	game.ReplicatedStorage.ReturnPainting:InvokeServer(data)
end

local cursor = canvas.Cursor

local canRedo = false

local erasing = false
local currentSize = 10
local currentColor = Color3.fromRGB(0, 0, 0)

brushSettings.SizeBox.Text = "Current Width: "..currentSize

local toDelete = {}
local history = {}
local Colorpieces = {}

--Make sure the mouse is on the canvas
canvas.MouseEnter:Connect(function()
	uis.MouseIconEnabled = false
	cursor.Visible = true
end)

canvas.InputBegan:Connect(function(input, bool)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then

		paintContainer = Instance.new("Folder")
		paintContainer.Parent = script.Parent.Parent.Layers.CurrentLayer.Value
		lastMoves = lastMoves + 1
		paintContainer.Name = "LastMove"..lastMoves
		table.insert(toDelete, paintContainer)

		down = true
		
		wait(8)
		
		down = false
	end
	
	if input.UserInputType == Enum.UserInputType.Touch  then
		repeat
			workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
			wait()
		until workspace.CurrentCamera.CameraType == Enum.CameraType.Scriptable
		down = true
		
		paintContainer = Instance.new("Folder")
		paintContainer.Parent = script.Parent.Parent.Layers.CurrentLayer.Value
		lastMoves = lastMoves + 1
		paintContainer.Name = "LastMove"..lastMoves
		table.insert(toDelete, paintContainer)
		
		workspace.CurrentCamera.CFrame = workspace.Camera.CFrame
		wait(8)
		down = false
	end
end)

canvas.InputEnded:Connect(function(input, bool)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		down = false
		sendDataToServer(Colorpieces)
	end
	
	if input.UserInputType == Enum.UserInputType.Touch  then
		repeat
			workspace.CurrentCamera.CameraType = Enum.CameraType.Custom
		until workspace.CurrentCamera.CameraType == Enum.CameraType.Custom
		down = false
		sendDataToServer(Colorpieces)
	end
end)

canvas.MouseLeave:Connect(function()
	uis.MouseIconEnabled = true
	cursor.Visible = false
	down = false
end)


--Make brush cursor follow mouse and put paint where the player clicks
game:GetService("RunService").Stepped:Connect(function()

	local color = script.Parent.Parent.Paint.Bottom.ColorPickerFrame.ColorShower.BackgroundColor3
	currentColor = color

	local x = math.abs(mouse.X - canvas.AbsolutePosition.X)
	local y = math.abs(mouse.Y - canvas.AbsolutePosition.Y)

	cursor.Position = UDim2.new(x/canvas.AbsoluteSize.X, 0, y/canvas.AbsoluteSize.Y, 0)
	cursor.Size = UDim2.new(0, currentSize, 0, currentSize)

	if down then

		local paint = canvas.Coloring.ColorPiece:Clone()

		canRedo = false

		table.clear(history)

		paint.Position = UDim2.new(x/canvas.AbsoluteSize.X, 0, y/canvas.AbsoluteSize.Y, 0)
		paint.Size = UDim2.new(0, currentSize, 0, currentSize)

		paint.BackgroundColor3 = erasing and Color3.fromRGB(255, 255, 255) or currentColor

		paint.Visible = true

		paint.Parent = paintContainer
		
		paint.ZIndex = script.Parent.Parent.Layers.CurrentLayerCount.Value
		
		table.insert(Colorpieces, {paint.Position, UDim2.new(0, currentSize, 0, currentSize), currentColor, paint.ZIndex})
	end
end)

brushSettings.Delete.MouseButton1Click:Connect(function()
	for i,v in pairs(toDelete) do
		if v:IsA("Folder") then
			v:Destroy()
		end
	end
end)

brushSettings.Undo.MouseButton1Click:Connect(function()
	local Layer = script.Parent.Parent.Layers.CurrentLayer.Value
	local quantity = #Layer:GetChildren()
	if quantity > 0 then
		local movingFolder = Layer:GetChildren()[quantity]
		for i,v in pairs(movingFolder:GetChildren()) do
			if v:IsA("Frame") and v.Name == "ColorPiece" then
				table.insert(history, movingFolder)
				canRedo = true
				v.Visible = false
			end
		end
	end
end)

brushSettings.Redo.MouseButton1Click:Connect(function()
	local quantity = #history
	if quantity > 0 then
		local movingfolder = history[quantity]
		for i,v in pairs(movingfolder:GetChildren()) do
			if v:IsA("Frame") and v.Name == "ColorPiece" then
				table.remove(history, quantity)
				v.Visible = true
			end
		end
	end
end)

--Switch between eraser and brush when their respective buttons are pressed
brushSettings.paint.MouseButton1Click:Connect(function()
	erasing = false
end)
brushSettings.eraser.MouseButton1Click:Connect(function()
	erasing = true
end)

--Change the size of the brush when the text box is used
brushSettings.SizeBox.FocusLost:Connect(function(entered)

	if entered then

		local size = brushSettings.SizeBox.Text

		if tonumber(size) then
			currentSize = size
		end

		brushSettings.SizeBox.Text = "Current Width: "..currentSize
	end
end)

server:

game.ReplicatedStorage.ReturnPainting.OnServerInvoke = function(Player, data)
	
	local Part = workspace.PlayerPart:FindFirstChild(Player.Name).Value
	
	for _, Piece in pairs(data) do
		local NewPiece = script.ColorPiece:Clone()
		NewPiece.Visible = true
		NewPiece.Parent = Part.SurfaceGui.PaintingFrame:FindFirstChild("PaintContainer")
		NewPiece.Position = Piece[1]
		NewPiece.Size = Piece[2]
		NewPiece.BackgroundColor3 = Piece[3]
		NewPiece.ZIndex = Piece[4]
		print(Piece[4])
		wait()
	end
end

Change your server code to this:

game.ReplicatedStorage.ReturnPainting.OnServerInvoke = function(Player, data)

	local Part = workspace.PlayerPart:FindFirstChild(Player.Name).Value

	for _, Piece in pairs(data) do
		local NewPiece = script.ColorPiece:Clone()
		NewPiece.Visible = true
		NewPiece.Position = Piece[1]
		NewPiece.Size = Piece[2]
		NewPiece.BackgroundColor3 = Piece[3]
		NewPiece.ZIndex = Piece[4]
		NewPiece.Parent = Part.SurfaceGui.PaintingFrame:FindFirstChild("PaintContainer")
	end
end

Tell me if it performs any quicker.

yes it was faster, but now i need to save memory because when i draw a big drawing it starts lagging now i do clear the children of the PaintContainer for every time a event is fired but it doesn’t seem to work

Try this to clear all children:

game.ReplicatedStorage.ReturnPainting.OnServerInvoke = function(Player, data)
	local PaintContainer = workspace.PlayerPart:WaitForChild(Player.Name).Value.SurfaceGui.PaintingFrame:FindFirstChild("PaintContainer")
	PaintContainer:ClearAllChildren()

	for _, Piece in pairs(data) do
		local NewPiece = script.ColorPiece:Clone()
		NewPiece.Visible = true
		NewPiece.Position = Piece[1]
		NewPiece.Size = Piece[2]
		NewPiece.BackgroundColor3 = Piece[3]
		NewPiece.ZIndex = Piece[4]
		NewPiece.Parent = PaintContainer
	end
end

This one might appear visually smoother (try this after you try the first one):

game.ReplicatedStorage.ReturnPainting.OnServerInvoke = function(Player, data)
	local PaintContainer = workspace.PlayerPart:WaitForChild(Player.Name).Value.SurfaceGui.PaintingFrame:FindFirstChild("PaintContainer")
	local previousChildren = PaintContainer:GetChildren()

	for _, Piece in pairs(data) do
		local NewPiece = script.ColorPiece:Clone()
		NewPiece.Visible = true
		NewPiece.Position = Piece[1]
		NewPiece.Size = Piece[2]
		NewPiece.BackgroundColor3 = Piece[3]
		NewPiece.ZIndex = Piece[4]
		NewPiece.Parent = PaintContainer
	end
	
	for i, piece in ipairs(previousChildren) do
		piece:Destroy()
	end
end

i did clearallchildren, now we have to test, but im not sure, as the painting may contain 100000+ peices, which my lead to so much lag, and there are a some 20+ parts for painting in the game, so imagine 2M+ children in the workspace, thats so much lag and even the remoteEvent well not fire maybe