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