Eventos e chamadas remotas

*Este conteúdo é traduzido por IA (Beta) e pode conter erros. Para ver a página em inglês, clique aqui.

As experiências do Roblox são multijogador por padrão, então todas as experiências são intrinsicamente comunicadas entre o servidor e os clientes conectados dos jogadores.No caso mais simples, à medida que os jogadores movem seus personagens, certas propriedades Humanoid específicas, como estados, são comunicadas ao servidor, que passa essas informações para outros clientes conectados.

Eventos e chamadas remotas permitem que você se comunique através da fronteira cliente-servidor:

  • RemoteEvents habilitar comunicação de um caminho (enviar um pedido e não ceder para uma resposta).
  • UnreliableRemoteEvents habilitar comunicação de um caminho para dados que mudam continuamente ou não são críticos para o estado do jogo.Esses eventos trocam ordem de negociação e confiabilidade para melhorar o performancerede.
  • RemoteFunctions habilitar comunicação de duas vias (enviar um pedido e esperar até que uma resposta seja recebida do destinatário).

Ao contrário de eventos vinculáveis, que têm utilidade mais limitada, os casos de uso para eventos e funções remotas são demasiados para serem listados:

  • Jogabilidade - jogabilidadebásica, como um jogador chegar ao fim de um nível, pode exigir um evento remoto.Um script de cliente notifica o servidor e os scripts do servidor redefinem a posição do jogador.
  • Verificação do servidor - Se um jogador tentar beber uma poção, eles realmente têm aquela poção? Para garantir a imparcialidade, o servidor deve ser a fonte da verdade para uma experiência.Um script de cliente pode usar um evento remoto para notificar o servidor que o jogador está bebendo uma poção, e então os scripts do servidor podem decidir se o jogador realmente tem essa poção e se deve conferir quaisquer benefícios.
  • Atualizações da interface do usuário - À medida que o estado do jogo muda, os scripts do servidor podem usar eventos remotos para notificar os clientes de mudanças em pontuações, objetivos, etc.
  • Compras no Mercado na Experiência - Para uma implementação de exemplo que usa funções remotas, veja Compras de subscrição rápidas.

Referência rápida

As seguintes tabelas servem como referência rápida para como usar RemoteEvents e RemoteFunctions para se comunicar entre o cliente e o servidor.

Cliente → Servidor >
ClienteRemoteEvent:FireServer(args)
ServidorRemoteEvent.OnServerEvent:Connect(function(player, args))
Servidor → Cliente >
ServidorRemoteEvent:FireClient(player, args)
ClienteRemoteEvent.OnClientEvent:Connect(function(args))
Servidor → Todos os Clientes >
ServidorRemoteEvent:FireAllClients(args)
ClienteRemoteEvent.OnClientEvent:Connect(function(args))

Eventos remotos

Um objeto assíncrono facilita a comunicação de uma maneira para a outra através da fronteira cliente-servidor sem renunciar a uma resposta.

Para criar um novo RemoteEvent via a janela Explorer no Studio:

  1. Passe o mouse sobre o contêiner no qual você deseja inserir o RemoteEvent .Para garantir o acesso tanto do servidor quanto do cliente, deve estar em um local onde ambas as partes possam vê-lo, como ReplicatedStorage, embora, em alguns casos, seja apropriado armazená-lo em Workspace ou dentro de um Tool.
  2. Clique no botão que aparece à direita do nome do contêiner e insira uma instância Evento Remoto .
  3. Renomeie a instância para descrever seu propósito.

Uma vez que você criou um RemoteEvent, ele pode facilitar a comunicação de um caminho de cliente para servidor , de servidor para cliente ou de servidor para todos os clientes.

Cliente → Servidor
>

Servidor → Cliente
>

Servidor → Todos os Clientes
>

Cliente → servidor

Você pode usar um para disparar um evento no servidor chamando o método em um .Se você passar argumentos para FireServer() , eles passam para o manipulador de eventos no servidor com certas limitações .Observe que o primeiro parâmetro do manipulador de eventos no servidor é sempre o objeto Player do cliente que o chama, e os parâmetros adicionais seguir.

ClienteRemoteEvent:FireServer(args)
ServidorRemoteEvent.OnServerEvent:Connect(function(player, args))

O seguinte Script conecta um manipulador de eventos a OnServerEvent que cria um novo Part no servidor.O acompanhante LocalScript então chama FireServer() na instância RemoteEvent com o desejado Color e Position para a parte.

Conexão de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " fired the RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- Função de conexão ao evento
remoteEvent.OnServerEvent:Connect(onCreatePart)
Disparo de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Dispare o evento remoto e passe argumentos adicionais
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))

Servidor → cliente

Você pode usar um Script para disparar um evento em um cliente chamando o método FireClient() em um RemoteEvent.O primeiro argumento para é o objeto do cliente que você deseja responder ao evento e os argumentos adicionais passam ao cliente com certas limitações .Observe que o manipulador de eventos não precisa incluir o objeto Player como seu primeiro argumento porque você pode determinar o jogador no cliente com Players.LocalPlayer .

ServidorRemoteEvent:FireClient(player, args)
ClienteRemoteEvent.OnClientEvent:Connect(function(args))

O seguinte LocalScript conecta um manipulador de eventos ao evento OnClientEvent.O acompanhante Script então ouve os jogadores entrantes para o servidor e chama FireClient() para cada um com dados arbitrários.

Conexão de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[Client] Event received by player", player.Name)
print(maxPlayers, respawnTime)
end
-- Função de conexão ao evento
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
Disparo de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Ouça os jogadores recebidos e envie um evento remoto para cada
local function onPlayerAdded(player)
print("[Server] Firing event to player", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Servidor → todos os clientes

Você pode usar um Script para disparar um evento em todos os clientes chamando o método FireAllClients() em um RemoteEvent.Ao contrário de FireClient() , o método FireAllClients() não requer um objeto Player porque ele dispara o RemoteEvent para todos os clientes.

ServidorRemoteEvent:FireAllClients(args)
ClienteRemoteEvent.OnClientEvent:Connect(function(args))

O seguinte LocalScript conecta um manipulador de eventos ao evento OnClientEvent que produz um tempo de contagem regressiva restante.O acompanhante Script então chama FireAllClients() em um loop a cada segundo para disparar o RemoteEvent para todos os clientes.

Conexão de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- Função de conexão ao evento
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
Disparo de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtenha referência à instância de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- Dispare o Evento Remoto a cada segundo até o tempo expirar
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
end

Chamadas de retorno remoto

Um objeto RemoteFunction facilita a comunicação sincrona, de duas vias, através da fronteira cliente-servidor.O remetente de uma função remota vai renderizar até receber uma resposta do destinatário.

Para criar um novo RemoteFunction via a janela Explorer no Studio:

  1. Passe o mouse sobre o contêiner no qual você deseja inserir o RemoteFunction .Para garantir o acesso tanto do servidor quanto do cliente, deve estar em um local onde ambas as partes possam vê-lo, como ReplicatedStorage, embora, em alguns casos, seja apropriado armazená-lo em Workspace ou dentro de um Tool.
  2. Clique no botão que aparece à direita do nome do contêiner e insira uma instância RemoteFunction .
  3. Renomeie a instância para descrever seu propósito.

Uma vez que você criou um RemoteFunction, ele pode facilitar a comunicação de duas vias entre cliente e servidor ou entre servidor e cliente.

Cliente → Servidor → Cliente
>

Servidor → Cliente → Servidor

Cliente → servidor → cliente

Você pode usar um para chamar uma função no servidor por meio do método em um .Ao contrário de um evento remoto remoto, o LocalScript que invoca o RemoteFunction rende até que o retorno de chamada retorne.Argumentos que você passe para passem para o retorno de chamada do com certas limitações .Observe que se você definir vários retornos de chamada para o mesmo RemoteFunction, apenas a última definição será executada.

ClienteRemoteFunction:InvokeServer(args)
ServidorRemoteFunction.OnServerInvoke = function(player, args)

O seguinte Script define a função de retorno via OnServerInvoke e retorna o solicitado Part através de seu valor return.O acompanhante LocalScript então chama InvokeServer() com argumentos extras definindo a cor e a posição da parte solicitada.

Conexão de retorno de chamada - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtenha referência à instância de função remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Função de retorno
local function createPart(player, partColor, partPosition)
print(player.Name .. " requested a new part")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- Defina a função como o retorno de chamada de função remota
remoteFunction.OnServerInvoke = createPart
Invocação de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtenha referência à instância de função remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Passe uma cor e posição ao invocar o retorno de chamada
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- Saia a referência da peça retornada
print("The server created the requested part:", newPart)

Servidor → cliente → servidor

Você pode usar um Script para chamar uma função no cliente ao chamar o método InvokeClient() em um RemoteFunction, mas tem sérios riscos como segue:

  • Se o cliente lançar um erro, o servidor lança o erro também.
  • Se o cliente se desconectar enquanto estiver sendo invocado, InvokeClient() lança um erro.
  • Se o cliente não retornar um valor, o servidor permanece para sempre.

Para ações que não requerem comunicações de duas vias, como atualizar uma Interface gráfica do usuário, use um RemoteEvent e se comunicar de servidor para cliente.

Limitações de argumento

Quando você dispara um RemoteEvent ou invoca um RemoteFunction , ele encaminha quaisquer argumentos que você passe com o evento ou para a função de retorno de chamada.Qualquer tipo de objeto do Roblox, como um Enum, Instance ou outros, pode ser passado, assim como tipos Luau, como números, strings e booleanos, embora você deva explorar com cuidado as seguintes limitações.

Índices não stringentes

Se algum índice de uma tabela passada for de tipos não-string, como um Instance, dados do usuário ou função, o Roblox converte automaticamente esses índices em strings.

Conexão de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> string / cadeia / texto
end
end
-- Função de conexão ao evento
remoteEvent.OnClientEvent:Connect(onEventFire)
Disparo de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Ouça os jogadores recebidos e envie um evento remoto para cada
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Funções passadas

Funções incluídas como argumentos para um RemoteEvent ou RemoteFunction serão não replicadas através da fronteira cliente-servidor, tornando impossível passar funções remotamente.Em vez disso, o argumento resultante no lado de recepção será nil .

Conexão de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nil
end
remoteEvent.OnClientEvent:Connect(onClientEvent)
Disparo de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Hello world!")
end
-- Disparar evento remoto com função como argumento
remoteEvent:FireAllClients(testFunction)

Índice de tabela

Se você passar uma tabela de dados, não passe uma tabela mista de chaves numéricas e de texto.Em vez disso, passe uma tabela que consiste inteiramente de pares de chave-valor ( dicionário ) ou inteiramente de índices numéricos.

Conexão de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(player, passedTable)
for k, v in passedTable do
print(k .. " = " .. v)
--> 1 = Espada
--> 2 = Arço
--> CharName = Dragão Diva Assassino
--> CharClass = Inimigo
end
end
-- Função de conexão ao evento
remoteEvent.OnServerEvent:Connect(onEventFire)
Disparo de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Tabela numericamente indexada
local inventoryData = {
"Sword", "Bow"
}
-- Tabela de dicionário
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)

Identidades de tabela

Tabelas passadas como argumentos para eventos/callbacks remotos são copiadas, o que significa que elas não serão exatamente equivalentes às fornecidas ao disparar o evento ou invocar o callback.Nem as tabelas retornadas ao invocador serão exatamente equivalentes às fornecidas.Você pode demonstrar isso executando o seguinte script em um RemoteFunction e observando como as identidades da tabela diferem.

Conexão de retorno de chamada - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Função de retorno
local function returnTable(player, passedTable)
-- Saída da identidade da tabela na invocação
print(tostring(passedTable)) --> tabela: 0x48eb7aead27563d9
return passedTable
end
-- Defina a função como o retorno de chamada de função remota
remoteFunction.OnServerInvoke = returnTable
Invocação de Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Sword", "Bow"
}
-- Saia a identidade original da tabela
print(tostring(inventoryData)) --> tabela: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- Identidade da tabela de saída ao retornar
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9

Metatábles

Se uma tabela tiver um metatable, toda a informação metatable é perdida na transferência.No seguinte exemplo de código, a propriedade NumWheels é parte do Car metadado.Quando o servidor recebe a tabela a seguir, a tabela truck tem a propriedade Name mas não a propriedade NumWheels.

Conexão de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> { ["Nome"] = "MyTruck"]
end
-- Função de conexão ao evento
remoteEvent.OnServerEvent:Connect(onEvent)
Disparo de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local Car = {}
Car.NumWheels = 4
Car.__index = Car
local truck = {}
truck.Name = "MyTruck"
setmetatable(truck, Car)
-- Evento de fogo com tabela que inclui um metatable
remoteEvent:FireServer(truck)

Instâncias não replicadas

Se um RemoteEvent ou RemoteFunction passar um valor que só é visível para o remetente, o Roblox não o replica através da fronteira cliente-servidor e passa nil em vez do valor.Por exemplo, se um Script passa um descendente de ServerStorage , o cliente que está ouvindo o evento receberá um valor nil porque esse objeto não é replicável para o cliente.

Disparo de Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Será recebido como "零" porque o cliente não pode acessar o Armazenamento do Servidor
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Da mesma forma, se você criar uma peça em um LocalScript e tentar passá-la para um Script , o servidor verá nil porque a peça não é replicável para o servidor.

Disparo de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Será recebido como "零" porque o servidor não conhece essa parte
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)