Making a 3d draw tool server-sided

  1. What do you want to achieve? Keep it simple and clear!

I want to achieve a server-sided draw tool

  1. What is the issue? Include screenshots / videos if possible!

When I pass the script from a localscript to a normal script (server sided), The server cannot get the player’s mouse, so the script wont work.

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I have tried to get the player’s mouse via remote events, but they are really confusing to me specially in these cases, and I end up messing up the whole script.

Could someone help me? Thanks.

local Player = game:GetService("Players").LocalPlayer;
local Mouse = Player:GetMouse();
local Down = false;
local Size = 0.1;

function WeldParts(Part1, Part2)
	local Weld = Instance.new("Weld")
	Weld.Part0 = Part2
	Weld.Part1 = Part1
	Weld.C0 = Part2.CFrame:toObjectSpace(Part1.CFrame)
	Weld.Parent = Part2
end

function Draw(mouse)
	Down = true;
	coroutine.resume(coroutine.create(function()
		mouse.Button1Up:wait();
		Down = false;
	end))
	local Part = Instance.new("Part", Player.Character);
		Part.Name = "DrawPart";
		Part.Size = Vector3.new(1, 0.5, 0.5);
		Part.Anchored = true;
		Part.TopSurface = 0;
		Part.BottomSurface = 0;
		Part.CanCollide = false;
		Part.BrickColor = BrickColor.new("Really black");
		Part.Locked = true;
	local Mesh = Instance.new("BlockMesh", Part);
	local Target = Mouse.Target;
	local Hit = Mouse.Hit.p;
	
	while Down do
		local Magnitude = (Hit - Mouse.Hit.p).magnitude;
		Mesh.Scale = Vector3.new(Size, 0.4, (Magnitude+(Size/3))*2)
		Part.CFrame = CFrame.new(Hit, Mouse.Hit.p) * CFrame.new(0, 0, -Magnitude/2 - Size/5)
		if Magnitude > Size/2+0.1 then
			Draw(mouse)
			if Target ~= nil then
				if not Target.Anchored then
					Part.Anchored = false;
					WeldParts(Part, Target);
				end
			end
			break;
		end
		wait();
	end
end

Mouse.Button1Down:connect(function() Draw(Mouse) end);

game:GetService("RunService").RenderStepped:connect(function()
	for _,Item in next, Player.Character:children() do
		if Item:IsA("BasePart") and Item.Name ~= "DrawPart" then
			Item.Transparency = 1;
		elseif Item:IsA("Hat") then
			Item:Destroy();
		end
		if Item.Name == "DrawPart" then
			Item.LocalTransparencyModifier = 0;
		end
	end
end)
1 Like

That can’t be done. You can only send objects that exist on both the server and client, and since Mouse objects only exist on the respective clients and not on the server, if you try sending it to the server then nil will be sent instead.

You will have to send some other information instead, such as the points that the player wants to draw between.

Do you know how could I specifically do that?,

2 Likes

I would have a RemoteFunction called “TryDrawing” which gets fired by the client script and which a server script listens to. Calls to TryDrawing should pass the Size and CFrame of the part that the player wants to create. The server then creates those parts so that all players can see them.

The parts still get created by the client initially, which won’t replicate to the server or any other clients. These “temporary” / “fake” parts get deleted when the result comes back from the server.

The server can choose not to create the requested parts, for example if you only want to allow drawing within certain areas.

EDIT: Here’s an example implementation that should show the basic idea:


local RunS = game:GetService("RunService")
local Debris = game:GetService("Debris")

local TryDrawingRemote

local DrawingModule = {}

if RunS:IsServer() then
    TryDrawingRemote = Instance.new("RemoteFunction")
    TryDrawingRemote.Name = "TryDrawing"
    TryDrawingRemote.Parent = game.ReplicatedStorage

    TryDrawingRemote.OnServerInvoke = function(partSize, partCFrame)
        local part = script.DrawingPart:Clone()
        part.Size = partSize
        part.CFrame = partCFrame
        part.Parent = game.Workspace

        return true
    end
else -- IsClient
    TryDrawingRemote = game.ReplicatedStorage:WaitForChild("TryDrawing", math.huge)

    local function Draw()
        -- Bla bla bla

        while Down do
            -- Bla

            if Magnitude > Size/2+0.1 then
                Draw(mouse)
                coroutine.wrap(function()
                    local result = TryDrawingRemote:InvokeServer(Part.Size * Mesh.Scale, Part.CFrame)
                    Debris:AddItem(Part, 0)
                end)
                -- Blah
                break;
            end
            wait();
        end
    end

    --Blablabla
end

return DrawingModule

2 Likes

Thank you so much, will complete it and try it later, for now i’ll mark you as the solution as I bet it will work. Have a nice day.

1 Like

Ok, glad it’s helpful :slight_smile: Just a heads up, I noticed the “welding to unanchored parts” thing just now, you might need to send the necessary information to the server to do taht as well