Player leaving during remote call causes game to stop

local ChosenPlayers = ChoosePlayers:InvokeClient(Sensei, Settings.ACTIVE_PLAYERS)
if #ChosenPlayers == 2 then
    print('Players have been chosen')
else
    print('Player did not pick')
end

Basically I get a selected player to pick 2 players, so I fire a RemoteFunction and wait for the response from said player. However if that player leaves, that causes entire game to stop. How can I have like a way of checking if the RemoteFunction hasn’t be returned?

You may find this helpful

The solution is to simply wrap your InvokeClient in a pcall and handle the error accordingly if the call failed.

Taken from the developer hub wiki page:


https://developer.roblox.com/en-us/api-reference/function/RemoteFunction/InvokeClient

Please search before posting.

3 Likes

To add on, @NinjoOnline you might as well just not use :InvokeClient at all.

An exploiter can decide to not return anything, which leaves the server yielding indefinitely.

Instead, use RemoteEvent:FireServer since the :Fire family of RemoteEvent methods don’t yield thus making it easier to validate data.

2 Likes

I need to wait for a returned value one way or another.

RemoteFunction works better than RemoteEvent, as then I’d have to do this

local ChosenPlayers = ChoosePlayers:FireClient(Sensei, Settings.ACTIVE_PLAYERS)

ChoosePlayers.OnServerEvent:Wait()

if #ChosenPlayers == 2 then
    print('Players have been chosen')
else
    print('Player did not pick')
end

You have made a mistake. All :Fire methods don’t return anything (or in C++ terms like Roblox uses, void). Thus ChosenPlayers is nil.

The way you would do it is the client would through a :FireServer call send the data. And from there you validate it. Don’t wait for the response, because

  • As said before, exploiter can choose to not return anything
  • Exploiter can send bad info (through :FireServer they can as well, but validating through OnServerEvent listener would be very easy
  • Exploiter can wait(n) before returning, thus making server yield even longer. (i think, if not correct me)

But in what context is the client giving data to the server. Is it like through a GUI or how do you do it.

2 Likes

How can an exploiter prevent anything from being returned?

function remotef.OnClientInvoke(...)
    return 5
end

-- am eval xploytr wach awt 4 mi!!11
function remotef.OnClientInvoke(...)
    while true do
        -- nothing!
        wait(n)
    end
end
3 Likes

If I were you I would put the :Invoke call into a coroutine. Then, after the coroutine has started executing, I’d put this:

local timeWaiting = 0
repeat
wait(1)
timeWaiting = timeWaiting + 1
until gotAnswer or timeWaiting > 3.

gotAnswer would be the result of the Invoke. timeWaiting would be an integer that you increase by 1 inside the loop. You could change 3 to how long you want to wait for the player to choose. Then,once you’re outside of the loop, check if gotAnswer is nil. If it is, get a different player to choose or handle it however you see fit.

Hope this helps

1 Like

Then what’s the use of RemoteFunctions? If they cant be used for anything

1 Like

They can and do have uses. OnClientInvoke/InvokeClient are the ones to be careful with. In fact, client invokes are so unsecure you’re better off not using them.

FireClient <-> InvokeServer
FireServer <-> InvokeClient

While this might work, it’s only a bandaid fix to a player leaving/not returning anything. The fix to the root problem is to not use one in this case.

1 Like

While there’s truth to what you’re saying, I don’t think I would consider it the one and only solution to the problem.

I can’t say I fully understand your hatred for RemoteFunctions and InvokeServer. They are used widely across several major titles on the site and have no negative when used correctly.

I believe thre is misinterpretation going on here.

Invoke server is NOT bad. Invoke client and on client invoke are bad. Remote functions are not bad. Half of them, at least

1 Like

How can I wait for the response then?

ChoosePlayers:FireClient(Sensei, Settings.ACTIVE_PLAYERS)

ChoosePlayers.OnServerEvent:Connect(function(chosenPlayers)
    if #chosenPlayers == 2 then

    else

    end
end

As exploiter could once again just not fire the event back?

1 Like

That is true, it’s a lose-lose situation. You can do a timeout for the event though.

1 Like

Could you provide me with some links on this? Or just a further explanation?

I’m willing to learn here but I’m just unsure if I agree with you.

How tho???

Using this. But instead, of rbxutility, you would swap it out with a BindableEvent.

@ImFarley um sure but what exactly are you looking for.

2 Likes

Seems a little excessive for what I’m trying to do…

No not really, since roblox doesn’t have like a timeout argument for :Wait for events (maybe not yet), this is what we can use for now.

Oh and I modernized this because I actually needed to use it, if you want here is the code

Timeout for event
local function wait_until_timeout(event, timeout)
	if type(timeout) == "number" then
		local signal = Instance.new("BindableEvent")
		local connection 
		connection = event:Connect(function(...)
	    	connection:Disconnect()
	    	signal:Fire(...)
		end)
		
		delay(timeout, function()
	    	if connection then
	        	connection:Disconnect()
	        	connection = nil
	        	signal:Fire()
	    	end
		end)
		return signal.Event:Wait()
	end
	return nil
end

You can make it into a module script so you can use it anywhere in any script.

3 Likes