Eventos remotos y callbacks

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

Los juegos de Roblox son multijugador por defecto, por lo que todos los juegos 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 de Humanoid, como los estados, se comunican al servidor, que pasa esta información a otros clientes conectados.

Los eventos remotos y los callbacks te permiten comunicarte a través del límite cliente-servidor:

  • RemoteEvents permiten la comunicación unidireccional (enviando una solicitud y sin esperar una respuesta).
  • UnreliableRemoteEvents permiten la comunicación unidireccional para datos que cambian continuamente o que no son críticos para el estado del juego. Estos eventos intercambian el orden y la confiabilidad a favor de un mejor rendimiento de red.
  • RemoteFunctions permiten la comunicación bidireccional (enviando una solicitud y esperando hasta recibir una respuesta del destinatario).

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

  • Jugabilidad - La jugabilidad básica, como un jugador alcanzando el final de un nivel, puede requerir un evento remoto. Un script del cliente notifica al servidor, y los scripts del servidor restablecen la posición del jugador.
  • Verificación en el servidor - Si un jugador intenta beber una poción, ¿realmente tiene esa poción? Para garantizar la equidad, el servidor debe ser la fuente de verdad para un juego. Un script del 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 otorgar 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 sobre cambios en puntajes, objetivos, etc.
  • Compras en el mercado del juego - Para una implementación de ejemplo que usa funciones remotas, consulta Compras por suscripción con aviso.

Referencia rápida

Las siguientes tablas sirven como una referencia rápida sobre cómo usar RemoteEvents y RemoteFunctions para comunicarte 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 facilita la comunicación asíncrona, unidireccional a través del límite cliente-servidor sin esperar una respuesta.

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

  1. Pasa el mouse sobre el contenedor en el que deseas insertar el RemoteEvent. Para asegurar el acceso tanto del servidor como del cliente, debe estar en un lugar donde ambos lados puedan verlo, como ReplicatedStorage, aunque en algunos casos es apropiado almacenarlo en Workspace o dentro de un Tool.
  2. Haz clic en el botón que aparece a la derecha del nombre del contenedor e inserta una instancia de RemoteEvent.
  3. Cambia el nombre de la instancia para describir su propósito.

Una vez que hayas creado un RemoteEvent, puede facilitar la comunicación unidireccional 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 FireServer(), se pasarán al controlador de eventos en el servidor con ciertas limitaciones. Ten en cuenta que el primer parámetro del controlador de eventos en el servidor es siempre el objeto Player del cliente que lo llama, y los parámetros adicionales siguen.

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

El siguiente Script conecta un controlador de eventos a OnServerEvent que crea una nueva Part en el servidor. El LocalScript correspondiente luego llama a FireServer() en la instancia de RemoteEvent con el deseado Color y Position para la pieza.

Conexión del Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtener referencia a la instancia del evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " activó el RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- Conectar función al evento
remoteEvent.OnServerEvent:Connect(onCreatePart)
Activación del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia del evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Activar el evento remoto y pasar 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 FireClient() es el objeto Player del cliente al que deseas responder al evento, y los argumentos adicionales se pasarán al cliente con ciertas limitaciones. Ten en cuenta que el controlador de eventos no necesita incluir el objeto Player como su primer argumento porque puedes determinar el jugador en el cliente con Players.LocalPlayer.

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

El siguiente LocalScript conecta un controlador de eventos al evento OnClientEvent. El Script correspondiente luego escucha a los jugadores entrantes al servidor y llama a FireClient() para cada uno con datos arbitrarios.

Conexión del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtener referencia a la instancia del evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[Cliente] Evento recibido por el jugador", player.Name)
print(maxPlayers, respawnTime)
end
-- Conectar función al evento
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
Activación del Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtener referencia a la instancia del evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Escuchar a los jugadores entrantes y despachar evento remoto a cada uno
local function onPlayerAdded(player)
print("[Servidor] Activando evento para el jugador", 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 activa el RemoteEvent para todos los clientes.

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

El siguiente LocalScript conecta un controlador de eventos al evento OnClientEvent que muestra un tiempo de cuenta regresiva restante. El Script correspondiente luego llama a FireAllClients() en un bucle cada segundo para activar el RemoteEvent para todos los clientes.

Conexión del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia del evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- Conectar función al evento
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
Activación del Evento - Script

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

Callbacks remotos

Un objeto RemoteFunction facilita la comunicación sincrónica, bidireccional a través del límite cliente-servidor. El remitente de una función remota espera hasta que recibe una respuesta del destinatario.

Para crear una nueva RemoteFunction a través de la ventana Explorer en Studio:

  1. Pasa el mouse sobre el contenedor en el que deseas insertar el RemoteFunction. Para asegurar el acceso tanto del servidor como del cliente, debe estar en un lugar donde ambos lados puedan verlo, como ReplicatedStorage, aunque en algunos casos es apropiado almacenarlo en Workspace o dentro de un Tool.
  2. Haz clic en el botón que aparece a la derecha del nombre del contenedor e inserta una instancia de RemoteFunction.
  3. Cambia el nombre de la instancia para describir su propósito.

Una vez que hayas creado un RemoteFunction, puede facilitar la comunicación bidireccional 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 al método InvokeServer() en un RemoteFunction. A diferencia de un evento remoto, el LocalScript que invoca el RemoteFunction espera hasta que el callback regresa. Los argumentos que pasas a InvokeServer() se pasan al callback OnServerInvoke de la RemoteFunction con ciertas limitaciones. Ten en cuenta que si defines múltiples callbacks para el mismo RemoteFunction, solo se ejecutará la última definición.

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

El siguiente Script define la función de callback a través de OnServerInvoke y devuelve la Part solicitada a través de su valor de return. El LocalScript correspondiente luego llama a InvokeServer() con argumentos adicionales que definen el color y la posición de la parte solicitada.

Conexión de Callback - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Obtener referencia a la instancia de la función remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Función de callback
local function createPart(player, partColor, partPosition)
print(player.Name .. " solicitó una nueva parte")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- Establecer la función como callback de la función remota
remoteFunction.OnServerInvoke = createPart
Invocación del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de la función remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Pasar un color y posición al invocar el callback
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- Salida de la referencia de la parte devuelta
print("El servidor creó la parte solicitada:", newPart)

Servidor → cliente → servidor

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

  • Si el cliente lanza un error, el servidor también lanza el error.
  • Si el cliente se desconecta mientras se está invocando, InvokeClient() lanza un error.
  • Si el cliente no devuelve un valor, el servidor espera indefinidamente.

Para acciones que no requieren comunicaciones bidireccionales, como actualizar una GUI, usa un RemoteEvent y comunícate desde servidor a cliente.

Limitaciones de argumentos

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

Índices no string

Si algún índice de una tabla pasada tiene tipos no string, como un Instance, userdata, o function, Roblox convierte automáticamente esos índices a strings.

Conexión del 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
end
end
-- Conectar función al evento
remoteEvent.OnClientEvent:Connect(onEventFire)
Activación del Evento - Script

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 despachar evento remoto a cada uno
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)

Funcionas pasadas

Las funciones incluidas como argumentos para un RemoteEvent o RemoteFunction no se replicarán a través del límite cliente-servidor, lo que hace imposible pasar funciones de forma remota. En su lugar, el argumento resultante del lado receptor será nil.

Conexión del Evento - LocalScript

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

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("¡Hola mundo!")
end
-- Activar evento remoto 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 string. En su lugar, pasa una tabla que consista entera de pares clave-valor (diccionario) o entera de índices numéricos.

Conexión del 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 = Arco
--> CharName = Diva Dragonslayer
--> CharClass = Rogue
end
end
-- Conectar función al evento
remoteEvent.OnServerEvent:Connect(onEventFire)
Activación del Evento - LocalScript

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

Identidades de tablas

Las tablas pasadas como argumentos a eventos/callbacks remotos se copian, lo que significa que no serán exactamente equivalentes a las proporcionadas al activar el evento o invocar el callback. 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 las identidades de las tablas difieren.

Conexión de Callback - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Función de callback
local function returnTable(player, passedTable)
-- Salida de la identidad de la tabla en la invocación
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- Establecer función como callback de la función remota
remoteFunction.OnServerInvoke = returnTable
Invocación del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Espada", "Arco"
}
-- Salida de la identidad de la tabla original
print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- Salida de la identidad de la tabla al regresar
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9

Metatables

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

Conexión del Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- Conectar función al evento
remoteEvent.OnServerEvent:Connect(onEvent)
Activación del 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)
-- Activar evento con tabla que incluye una metatable
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 del límite 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 nil porque ese objeto no es replicable para el cliente.

Activación del Evento - Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Se recibirá como "nil" 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)

De igual manera, si creas una parte en un LocalScript y intentas pasarla a un Script, el servidor verá nil porque la parte no es replicable para el servidor.

Activación del Evento - LocalScript

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Se recibirá como "nil" porque el servidor no conoce esta parte
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)
©2026 Roblox Corporation. Roblox, el logotipo de Roblox y "Powering Imagination" son algunas de nuestras marcas registradas y no registradas en los Estados Unidos y otros países.