How can I accept :InvokeClient in a Modual Script?
By running the Code on the Server, and not the Client.
If you are using it for Both, Check if the Current Environment is on the Server using RunService:IsServer()
, or if on the Client using RunService:IsClient()
:InvokeClient()
poses a great risk for the server.
Example (server script, 'RemoteFunction' in Replicated storage) > server yields indefinitely
local remFunction = game:GetService("ReplicatedStorage").RemoteFunction
local response = nil
task.spawn(function()
while not response do
print("No response yet.")
task.wait(1)
end
end)
game:GetService("Players").PlayerAdded:Connect(function(player)
player.CharacterAppearanceLoaded:Connect(function(character)
response = remFunction:InvokeClient(player)
end)
end)
Much better to use remote events. A very basic example?
Server fires the remote event and continues with the code. Elsewhere, it listens for the response.
|> ‘RemoteEvent’ in Replicated storage.
Server script
local Players = game:GetService("Players")
local remoteEvent = game:GetService("ReplicatedStorage").RemoteEvent
local invokedPlayers = {}
INVOKE_EXPIRY_TIME = 5 -- seconds
remoteEvent.OnServerEvent:Connect(function(player, response) -- "response"
-- If player is not in invokedPlayers, server didn't ask
-- for the reponse.
if invokedPlayers[player] then
invokedPlayers[player] = nil
print(response) --> 'Echo'
end
end)
Players.PlayerAdded:Connect(function(player)
player.CharacterAppearanceLoaded:Connect(function(character)
invokedPlayers[player] = os.clock()
remoteEvent:FireClient(player) -- "invoke"
-- What if player didn't respond in the next 5 seconds?
task.wait(INVOKE_EXPIRY_TIME)
if invokedPlayers[player] and os.clock() - invokedPlayers[player] > INVOKE_EXPIRY_TIME then
invokedPlayers[player] = nil
print("Invoke expired.")
end
end)
end)
-- Clear the player from invokedPlayers.
Players.PlayerRemoving:Connect(function(player)
invokedPlayers[player] = nil
end)
Local script
local remoteEvent = game:GetService("ReplicatedStorage"):WaitForChild("RemoteEvent")
remoteEvent.OnClientEvent:Connect(function()
-- task.wait(6)
remoteEvent:FireServer("Echo")
end)
If we were to halt the response on client, the server would abandon the invocation after five seconds.
Important caveat: This is AN EXAMPLE and has its limits, e.g. it wouldn’t work well with rapid invocations by the server. There’s normally no need for frequent invocations, however.
Same as in the local script.
Update.
Around the Dev Forum, you can find some good implementations of a timeout for remote calls.