Eventos y llamadas de devolución remotos

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

Las experiencias de Roblox son multijugador por defecto, por lo que todas las experiencias se comunican inherentemente entre el servidor y los clientes conectados de los jugadores.En el caso más simple, a medida que los jugadores mueven sus personajes, ciertas propiedades Humanoid determinadas, como estados, se comunican al servidor, que transmite esta información a otros clientes conectados.

Los eventos y las llamadas de devolución remotos te permiten comunicarte a través de el límite cliente-servidor:

  • RemoteEvents habilitar la comunicación de un solo sentido (enviar una solicitud y no rendirse por una respuesta).
  • UnreliableRemoteEvents habilitar la comunicación de un solo sentido para los datos que cambian continuamente o no son críticos para el estado del juego.Estos eventos intercambian la orden de comercio y la fiabilidad para una mejora del ejecuciónde la red.
  • RemoteFunctions habilitar la comunicación de ida y vuelta (enviar una solicitud y rendir hasta que se reciba una respuesta del destinatario).

A diferencia de eventos vinculables, que tienen una utilidad más limitada, los casos de uso para eventos y funciones remotos son demasiado numerosos como para enumerarlos:

  • Juego - El juego básico, como un jugador que llega al final de un nivel, puede requerir un evento remoto.Un script de client notifica al servidor, y los scripts del servidor restablecen la posición del jugador.
  • Verificación del servidor - Si un jugador intenta beber una poción, ¿realmente tiene esa poción? Para garantizar la imparcialidad, el servidor debe ser la fuente de la verdad para una experienciaUn script de cliente puede usar un evento remoto para notificar al servidor que el jugador está bebiendo una poción, y luego los scripts del servidor pueden decidir si el jugador realmente tiene esa poción y si debe conferir algún beneficio.
  • Actualizaciones de la interfaz de usuario - A medida que cambia el estado del juego, los scripts del servidor pueden usar eventos remotos para notificar a los clientes de cambios en las puntuaciones, objetivos, etc.
  • Compras en el mercado en experiencia - Para un ejemplo de implementación que utiliza funciones remotas, vea Compras de suscripción inmediatas.

Referencia rápida

Las siguientes tablas sirven como referencia rápida para cómo usar RemoteEvents y RemoteFunctions para comunicarse entre el cliente y el 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 los clientes
ServidorRemoteEvent:FireAllClients(args)
ClienteRemoteEvent.OnClientEvent:Connect(function(args))

Eventos remotos

Un objeto RemoteEvent asincroniza la comunicación de un solo sentido a través de la frontera cliente-servidor sin renunciar a una respuesta.

Para crear un nuevo RemoteEvent a través de la ventana Explorador en Studio:

  1. Pase el mouse sobre el contenedor en el que desea insertar el RemoteEvent .Para garantizar el acceso tanto del servidor como del cliente, debe estar en un lugar donde ambas partes puedan verlo, como ReplicatedStorage , aunque en algunos casos es apropiado almacenarlo en Workspace o dentro de un Tool .
  2. Haga clic en el botón que aparece a la derecha del nombre del contenedor e insira una instancia de Evento remoto .
  3. Renombra la instancia para describir su propósito.

Una vez que hayas creado un RemoteEvent, puede facilitar la comunicación de ida y vuelta desde cliente a servidor , desde servidor a cliente o desde el servidor a todos los clientes .

Cliente → Servidor
Servidor → Cliente

Servidor → Todos los clientes
>

Cliente → servidor

Puedes usar un LocalScript para activar un evento en el servidor llamando al método FireServer() en un RemoteEvent.Si pasas argumentos a , se envían al gestor de eventos en el servidor con ciertas limitaciones .Tenga en cuenta que el primer parámetro del manipulador de eventos en el servidor siempre es el objeto Player del cliente que lo llama, y se seguirlos parámetros adicionales.

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

El siguiente Script conecta un manejador de eventos a OnServerEvent que crea un nuevo Part en el servidor.El acompañante LocalScript entonces llama a FireServer() en la instancia RemoteEvent con el deseado Color y Position para la parte.

Conexión de evento - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtener referencia a la instancia 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
-- Función de conexión al evento
remoteEvent.OnServerEvent:Connect(onCreatePart)
Disparo de eventos - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Dispara el evento remoto y pasa argumentos adicionales
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))

Servidor → cliente

Puedes usar un Script para activar un evento en un cliente llamando al método FireClient() en un RemoteEvent.El primer argumento para es el objeto del cliente al que quieres responder al evento, y los argumentos adicionales se pasan al cliente con ciertas limitaciones .Tenga en cuenta que el manipulador de eventos no necesita incluir el objeto Player como su primer argumento porque puede determinar al jugador en el cliente con Players.LocalPlayer .

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

El siguiente LocalScript conecta un manipulador de eventos al evento OnClientEvent.El acompañante Script entonces escucha a los jugadores entrantes al servidor y llama FireClient() para cada uno con datos arbitrarios.

Conexión de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtener referencia a la instancia 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
-- Función de conexión al evento
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
Disparo de eventos - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtener referencia a la instancia de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Escuchar a los jugadores entrantes y enviar un evento remoto a cada uno
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 los clientes

Puedes usar un Script para activar un evento en todos los clientes llamando al método FireAllClients() en un RemoteEvent.A diferencia de FireClient() , el método FireAllClients() no requiere un objeto Player porque dispara el RemoteEvent a todos los clientes.

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

El siguiente LocalScript conecta un manejador de eventos a el evento OnClientEvent que produce un tiempo de cuenta regresiva restante.El acompañante Script entonces llama FireAllClients() en un bucle cada segundo para disparar el RemoteEvent para todos los clientes.

Conexión de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- Función de conexión al evento
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
Disparo de eventos - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- Dispara el evento remoto cada segundo hasta que expire el tiempo
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
end

Devoluciones de llamadas remotas

Un objeto RemoteFunction facilita la comunicación sincronizada de ida y vuelta a través de la frontera cliente-servidor.El remitente de una función remota rendirá hasta que reciba una respuesta del destinatario.

Para crear un nuevo RemoteFunction a través de la ventana Explorador en Studio:

  1. Pase el mouse sobre el contenedor en el que desea insertar el RemoteFunction .Para garantizar el acceso tanto del servidor como del cliente, debe estar en un lugar donde ambas partes puedan verlo, como ReplicatedStorage , aunque en algunos casos es apropiado almacenarlo en Workspace o dentro de un Tool .
  2. Haga clic en el botón que aparece a la derecha del nombre del contenedor e insira una instancia de Función remota .
  3. Renombra la instancia para describir su propósito.

Una vez que hayas creado un RemoteFunction, puede facilitar la comunicación de ida y vuelta entre cliente y servidor o entre servidor y cliente.

Cliente → Servidor → Cliente
>

Servidor → Cliente → Servidor
>

Cliente → servidor → cliente

Puedes usar un LocalScript para llamar a una función en el servidor llamando el método InvokeServer() en un RemoteFunction .A diferencia de un evento remoto remoto, el LocalScript que invoca el RemoteFunction devuelve hasta que se devuelva la llamada de devolución.Los argumentos que pasas a pasan al llamado de devolución de la con ciertas limitaciones .Tenga en cuenta que si define múltiples llamadas de devolución a la misma RemoteFunction, solo se ejecuta la última definición.

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

La siguiente Script define la función de llamada de devolución a través de OnServerInvoke y devuelve el solicitado Part a través de su valor return.El acompañante LocalScript entonces llama a InvokeServer() con argumentos adicionales que definen el color y la posición de la parte solicitada.

Conexión de devolución - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtener referencia a la instancia de función remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Función de devolución de llamada
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
-- Establecer la función como llamada de devolución de la función remota
remoteFunction.OnServerInvoke = createPart
Invocación de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de función remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Pasar un color y una posición al invocar el llamado de devolución
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- Exportar la referencia de parte devuelta
print("The server created the requested part:", newPart)

Servidor → cliente → servidor

Puedes usar un Script para llamar una función en el cliente llamando el método InvokeClient() en un RemoteFunction, pero tiene riesgos serios como sigue:

  • Si el cliente lanza un error, el servidor también lanza el error.
  • Si el cliente se desconecta mientras se invoca, InvokeClient() lanza un error.
  • Si el cliente no devuelve un valor, el servidor se rinde para siempre.

Para acciones que no requieren comunicaciones de ida y vuelta, como actualizar una Interfaz gráfica (o GUI), use un RemoteEvent y comunicarse desde el servidor al cliente .

Limitaciones de argumentos

Cuando disparas un RemoteEvent o invocas un RemoteFunction , envía cualquier argumento que pases con el evento o a la función de llamada de devolución.Cualquier tipo de objeto de Roblox como un Enum, Instance o otros se puede pasar, así como tipos Luau como números, cadenas y booleanos, aunque deberías explorar cuidadosamente las siguientes limitaciones.

Índices no de cadena

Si algún índice de una tabla pasada es de tipo no cadena como un Instance , datos de usuario o función , Roblox convierte automáticamente esos índices a cadenas.

Conexión 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)) --> cadena
end
end
-- Función de conexión al evento
remoteEvent.OnClientEvent:Connect(onEventFire)
Disparo de eventos - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Escuchar a los jugadores entrantes y enviar un evento remoto a cada uno
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Funciones pasadas

Las funciones incluidas como argumentos para un o no se replicarán a través de la frontera cliente-servidor , lo que hace imposible pasar funciones de forma remota.En cambio, el argumento resultante en el lado receptor será nil .

Conexión de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> cero
end
remoteEvent.OnClientEvent:Connect(onClientEvent)
Disparo de eventos - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Hello world!")
end
-- Evento remoto de fuego con función como argumento
remoteEvent:FireAllClients(testFunction)

Indexación de tablas

Si pasas una tabla de datos, no pases una tabla mixta de claves numéricas y de texto.En cambio, pasa una tabla que consiste completamente de pares de clave-valor (diccionario) o completamente de índices numéricos.

Conexión de evento - Guión

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 = Lazo
--> Nombre de personaje = Diva Dragonslayer
--> CharClass = Ladrón
end
end
-- Función de conexión al evento
remoteEvent.OnServerEvent:Connect(onEventFire)
Disparo de eventos - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Tabla indexada numéricamente
local inventoryData = {
"Sword", "Bow"
}
-- Tabla de diccionario
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)

Identidades de tabla

Las tablas pasadas como argumentos a eventos remotos/Callback se copian, lo que significa que no serán exactamente equivalentes a las proporcionadas al disparar el evento o invocar el llamado de devolución.Tampoco las tablas devueltas al invocador serán exactamente equivalentes a las proporcionadas.Puedes demostrar esto ejecutando el siguiente script en un RemoteFunction y observando cómo difieren las identidades de la tabla.

Conexión de devolución - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Función de devolución de llamada
local function returnTable(player, passedTable)
-- Identificación de tabla de salida al invocar
print(tostring(passedTable)) --> tabla: 0x48eb7aead27563d9
return passedTable
end
-- Establecer la función como llamada de devolución de la función remota
remoteFunction.OnServerInvoke = returnTable
Invocación de evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Sword", "Bow"
}
-- Identificación de tabla original de salida
print(tostring(inventoryData)) --> tabla: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- Identificación de tabla de salida al devolver
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9

Tablas metálicas

Si una tabla tiene una información metatable, se pierde toda la información metatable en la transferencia.En el siguiente ejemplo de código, la propiedad NumWheels es parte del Car metatable.Cuando el servidor recibe la siguiente tabla, la tabla truck tiene la propiedad Name pero no la propiedad NumWheels.

Conexión de evento - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> { ["Nombre"] = "MyTruck"}
end
-- Función de conexión al evento
remoteEvent.OnServerEvent:Connect(onEvent)
Disparo de eventos - 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 fuego con tabla que incluye una tabla metálica
remoteEvent:FireServer(truck)

Instancias no replicadas

Si un RemoteEvent o RemoteFunction pasa un valor que solo es visible para el remitente, Roblox no lo replica a través de la frontera cliente-servidor y pasa nil en lugar del valor.Por ejemplo, si un Script pasa un descendiente de ServerStorage , el cliente que escucha el evento recibirá un valor de nil porque ese objeto no es replicable para el cliente.

Disparo de eventos - Guión

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Se recibirá como "nulo" porque el cliente no puede acceder a ServerStorage
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Del mismo modo, si creas una parte en un LocalScript y tratas de pasarla a un Script , el servidor verá nil porque la parte no es replicable para el servidor.

Disparo de eventos - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Se recibirá como "nulo" porque el servidor no sabe de esta parte
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)