Game lags insanely after using remoteFunction?

So im making a winch system for my upcoming game, but when i click a target for the winch, the game and studio entirely freeze… (at the line of the first invoke)

Server script:

local runservice = game:GetService("RunService")
local repstorage = game:GetService("ReplicatedStorage")

local car = workspace.Car
local winch = car.Winch
local detector = winch.ClickDetector
local winchRemoteFunction = repstorage:WaitForChild("Winch")
local inputRemoteFunction = repstorage:WaitForChild("Input")

local pickingtarget = {}

function plrAdded(plr)
	table.insert(pickingtarget, plr.Name, false)
end

function plrRemoving(plr)
	pickingtarget[plr] = nil
end

function winchstart(plr)
	
	pickingtarget[plr.Name] = true
	
	print(plr.Name)
	
	local winchatt = Instance.new("Attachment")
	winchatt.Parent = winch
	
	local otheratt = Instance.new("Attachment")
	otheratt.Parent = plr.Character.RightHand
	
	local rope = Instance.new("RopeConstraint")

	rope.Visible = true
	rope.Attachment0 = winchatt
	rope.Attachment1 = otheratt
	rope.Parent = winch
	
	local length
	
	coroutine.wrap(function()
		while pickingtarget[plr.Name] do
			length = (winch.Position - plr.Character.RightHand.Position).Magnitude
			rope.Length = length + 5
			wait()
		end
	end)()
	
	local target = winchRemoteFunction:InvokeClient(plr) -- freezes here
	pickingtarget[plr] = false
	otheratt.Parent = target
	
	
	local input
	
	coroutine.wrap(function()
		input = inputRemoteFunction:InvokeClient(plr, "R")
	end)()
	
	if input then 
		if input == Enum.KeyCode.R then
			if target.Anchored == false then
				local originallength = rope.Length
				for i = 1, length + 2, .33 do
					rope.Length = originallength - i
					wait(.1)
				end
			else
				rope.Length = (winch.Position - target.Position).Magnitude
			end
		end
	end
	
end


game.Players.PlayerAdded:Connect(plrAdded)
game.Players.PlayerRemoving:Connect(plrRemoving)
detector.MouseClick:Connect(winchstart)


Local script:

local rs = game:GetService("ReplicatedStorage")
local uis = game:GetService("UserInputService")


local winchRemoteFunction = rs:WaitForChild("Winch")
local inputRemoteFunction = rs:WaitForChild("Input")

local plr = game.Players.LocalPlayer
local mouse = plr:GetMouse()

winchRemoteFunction.OnClientInvoke = function() -- freezes at this function, not sure why
	mouse.Button1Up:Wait()
	return mouse.Target
end

inputRemoteFunction.OnClientInvoke = function(var)
	local sendback
	local incorrectvar = true
	while incorrectvar and not sendback do
		uis.InputBegan:Connect(function(input)
			if input.KeyCode == Enum.KeyCode[var] then
				sendback = input.KeyCode
			end
		end)
	end
	return sendback
end

How would I make sure this doesn’t freeze?

Thanks for reading!

1 Like

FYI: Invoking RemoteFunctions on the client is a bad practice because the client (or rather exploiters) can yield them indefinitely and cause issues. This is already presenting an issue in your script as I suspect it might actually be “freezing” at this line:
mouse.Button1Up:Wait()

1 Like

How can I change this without losing its functionality?

1 Like

Could you give me a quick rundown of what behavior you are trying to achieve?

1 Like

I want to wait until the player has clicked, and then send the mouse.Target back to the server script

1 Like

I think there is a bit more to it but based off of what you told me:

Check for user input (ClickDetector) on the client then trigger a RemoteEvent with the mouse.Target
On the server you can do the necessary checks (whether the winch is available, whether player is close enough to click, whether the Target is valid, …)

Also note that this portion:

coroutine.wrap(function()
		input = inputRemoteFunction:InvokeClient(plr, "R")
	end)()
	
	if input then 
		if input == Enum.KeyCode.R then

Would not work because at the time you are checking input it will always be nil due to the delay introduced by the network.

The server is supposed to wait until it gets a callback from the invoke before continuing the script though?

Also, the reason I used a invoke, is because its in a specific moment that a part needs to be clicked; when the rope is held by the player’s hand.

Here is a crude example of what it could look like server side:

WinchTriggeredEvent.OnServerEvent:Connect(function(player, winch)

    -- Checks go here

    pickingtarget[plr.Name] = true

    

    local winchatt = Instance.new("Attachment")

    winchatt.Parent = winch

    

    local otheratt = Instance.new("Attachment")

    otheratt.Parent = plr.Character.RightHand

    

    local rope = Instance.new("RopeConstraint")

    rope.Visible = true

    rope.Attachment0 = winchatt

    rope.Attachment1 = otheratt

    rope.Parent = winch

    

    local length

    coroutine.wrap(function()

        while pickingtarget[plr.Name] do

            length = (winch.Position - plr.Character.RightHand.Position).Magnitude

            rope.Length = length + 5

            wait()

        end

    end)()

    -- Timeout

    delay(10, function()

        warn("Winch timed out")

        pickingtarget[plr] = false    

        -- Reset winch state here

    end)

end)

-- Triggered when the player releases MouseButton1

WinchGotTargetEvent.OnServerEvent:Connect(function(player, mouseTarget)

    

    -- Do checks for target

    usingWinch[player.Name] = true

end)

-- Triggered when player pressed R key

WinchReversingEvent.OnServerEvent:Connect(function(player, mouseTarget))

    if not usingWinch[player.Name] then

        return

    end

    -- handle the rope being pulled in

end)
1 Like

You’re looping without a yield and creating a lot of connections, which may lead to a memory leak. Why not use bindables? e.g:

local inputBindable = Instance.new("BindableEvent")
local var = nil
uis.InputBegan:Connect(function(input)
	if not var then return end
	if input.KeyCode == Enum.KeyCode[var] then
		inputBindable:Fire(input.KeyCode)
	end
end)
inputRemoteFunction.OnClientInvoke = function(v)
	var = v
	local result = inputBindable.Event:Wait()
	var = nil
	return result
end
1 Like