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 se mueven sus personajes, ciertas propiedades de Humanoid se comunican al servidor, que pasa esta información a otros clientes conectados.
Los eventos y llamadas remotos le permiten comunicarse a través de la frontera cliente-servidor:
- RemoteEvents habilita la comunicación unidireccional ( enviar una solicitud y no producir una respuesta).
- UnreliableRemoteEvents habilita la comunicación de un solo camino para los datos que cambian continuamente o no son críticos para el estado del juego. Estos eventos intercambian la orden y la confiabilidad para mejorar el ejecuciónde la red.
- RemoteFunctions habilita la comunicación de dos vías ( enviar una solicitud y esperar 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 para listar:
- Juego en línea - juegoen línea básico, como un jugador que alcanza el final de un nivel, puede requerir un evento remoto. Un script de cliente 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, ¿en realidad tiene esa poción? Para garantizar la justicia, el servidor tiene que ser la fuente de la verdad para una experiencia. Un 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 confiar cualquier beneficio.
- Actualizaciones de la interfaz de usuario - Cuando el estado del juego cambia, los scripts del servidor pueden usar eventos remotos para notificar a los clientes de cambios en las puntuaciones, objetivos, etc.
- Compras de mercado en la experiencia - Para una implementación de ejemplo que usa funciones remotas, see Solicitudes de compras de suscripciones .
Referencia rápida
Las siguientes tablas sirven como una referencia rápida para cómo usar RemoteEvents y RemoteFunctions para comunicarse entre el cliente y el servidor.
Cliente → Servidor | >|
---|---|
Cliente | RemoteEvent:FireServer(args) |
Servidor | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
Servidor → Cliente | |
Servidor | RemoteEvent:FireClient(player, args) |
Cliente | RemoteEvent.OnClientEvent:Connect(function(args)) |
Servidor → Todos los Clientes ” | ”|
Servidor | RemoteEvent:FireAllClients(args) |
Cliente | RemoteEvent.OnClientEvent:Connect(function(args)) |
Eventos remotos
Un objeto RemoteEvent facilita la comunicación asíncrona, de un solo camino, a través de la frontera cliente-servidor sin rendimiento.
Para crear un nuevo RemoteEvent a través de la ventana Explorador en Studio:
- Pase el mouse sobre el contenedor en el que desea insertar el RemoteEvent . Para asegurar tanto el acceso del servidor como del cliente, debe estar en un lugar donde ambos lados puedan verlo, como ReplicatedStorage , aunque en algunos casos es adecuado almacenarlo en Workspace o dentro de un 1> Class.RemoteEvent .
- Haga clic en el botón ⊕ que aparece a la derecha del nombre del contenedor y agregue una instancia RemoteEvent a continuación.
- Renombre la instancia para describir su propósito.
Una vez que hayas creado un RemoteEvent, puede facilitar una comunicación unidireccional desde el cliente al servidor, desde el servidor al cliente o desde el 2> servidor a todos los clientes2>.
Cliente → Servidor
Puedes usar un LocalScript para activar un evento en el servidor 服务器 al llamar el método Class.RemoteEvent:FireServer()|FireServer() 2>
Cliente | RemoteEvent:FireServer(args) |
Servidor | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
El siguiente Script conecta un servidorde eventos a OnServerEvent que crea una nueva Class.Part
Conexión de eventos - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 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
-- Conectar función a evento
remoteEvent.OnServerEvent:Connect(onCreatePart)
Evento de disparo - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Obtener referencia a la instancia de evento remotolocal remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- Activa el evento remoto y pasa argumentos adicionalesremoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
Servidor → Cliente
Puedes usar un Script para
Servidor | RemoteEvent:FireClient(player, args) |
Cliente | RemoteEvent.OnClientEvent:Connect(function(args)) |
El siguiente LocalScript conecta un eventoador de eventos a un evento OnClientEvent . El acompañante Script luego escucha a los jugadores entrantes al servidor y llama a 1> Class.RemoteEvent:FireClient()|FireClient()1> para cada con datos arbitrarios.
Conexión de eventos - 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
-- Conectar función a evento
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
Evento de disparo - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Obtener referencia a la instancia de evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Escúchame para los jugadores entrantes y envía 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 al llamar el método FireAllClients() en un Class.RemoteEvent</
Servidor | RemoteEvent:FireAllClients(args) |
Cliente | RemoteEvent.OnClientEvent:Connect(function(args)) |
El siguiente LocalScript conecta un eventoador de eventos a el evento OnClientEvent que muestra un tiempo de recuenta regresiva restante. El acompañante Script luego llama a 1> Class.RemoteEvent:FireAllClients()|FireAllClients()
Conexión de eventos - 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
-- Conectar función a evento
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
Evento de disparo - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Obtener referencia a la instancia de evento remotolocal remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")local countdown = 5-- Activa el evento remoto cada segundo hasta que el tiempo se acabefor timeRemaining = -1, countdown doremoteEvent:FireAllClients(countdown - timeRemaining)task.wait(1)end
Llamadas remotas
Un objeto RemoteFunction facilita la comunicación sincrona, de dos vías, a través de la frontera cliente-servidor. El remitente de una función remota producirá hasta que reciba una respuesta del destinatario.
Para crear una nueva RemoteFunction a través de la ventana Explorador en Studio:
- Pase el mouse sobre el contenedor en el que desea insertar el RemoteFunction . Para asegurar tanto el acceso del servidor como del cliente, debe estar en un lugar donde ambos lados puedan verlo, como ReplicatedStorage , aunque en algunos casos es adecuado almacenarlo en Workspace o dentro de un 1> Class.RemoteFunction</
- Haga clic en el botón ⊕ que aparece a la derecha del nombre del contenedor y agregue una instancia de RemoteFunction .
- Renombre la instancia para describir su propósito.
Una vez que hayas creado un RemoteFunction, puede facilitar la comunicación de dos vías entre el cliente y el servidor o entre el servidor y el cliente.
Cliente → Servidor → Cliente
Puedes usar un LocalScript para llamar a una función en el servidor Class.RemoteFunction:ExecuteServer() al llamar el método
Cliente | RemoteFunction:InvokeServer(args) |
Servidor | RemoteFunction.OnServerInvoke = function(player, args) |
El siguiente Script define la función de llamada a través de OnServerInvoke y devuelve el solicitado Part a través de su valor de 1> devolver1> . El acompañante 4> Class.LocalScript4> luego
Conexión de llamada - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Obtener referencia a la instancia de función remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Funció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 el retorno de llamada de la función remota
remoteFunction.OnServerInvoke = createPart
Invocación de eventos - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Obtener referencia a la instancia de función remotalocal remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")-- Pasa un color y una posición al invocar el código de llamadalocal newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))-- Output la referencia de la parte devueltaprint("The server created the requested part:", newPart)
Servidor → Cliente → Servidor
Puede usar un Script para llamar a una función en el cliente al llamar el método InvokeClient() en un RemoteFunction, pero tiene riesgos serios como los siguientes:
- Si el cliente muestra un error, el servidor también muestra el error.
- Si el cliente se desconecta mientras se invoca, InvokeClient() lanza un error.
- Si el cliente no devuelve un valor, el servidor muestra siempre.
Para acciones que no requieren comunicaciones de dos vías, como actualizar un Interfaz gráfica (o GUI), use un RemoteEvent y comuníquese desde el servidor al cliente.
Limitaciones de argumentos
Cuando lanzas un RemoteEvent o invocas un RemoteFunction, proyecta cualquier argumento que pases con el evento o a la función de llamada. Cualquier tipo de objeto de Roblox, como un Enum , 1> Class.Instance1> o otros, se pueden proyectar, así como los
Índices no estructurados
Si cualquier índice de una tabla pasada es de tipos no estructurados, como un Instance , userdata o funciones, Roblox convierte automáticamente esos índices en cadenas.
Conexión de eventos - 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
-- Conectar función a evento
remoteEvent.OnClientEvent:Connect(onEventFire)
Evento de disparo - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Escúchame para los jugadores entrantes y envía 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 RemoteEvent o RemoteFunction no se replicarán a través de la frontera del cliente-servidor, lo que imposibilita pasar funciones de forma remota. En cambio, el argumento resultante en el lado del receptor será 4> nil4> .
Conexión de eventos - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nulo
end
remoteEvent.OnClientEvent:Connect(onClientEvent)
Evento de disparo - Script
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)
Índice de tablas
Si pasa una tabla de datos, no pase una tabla mixta de números y cadenas de claves. En cambio, pase una tabla que consiste entero de parejas de valores de clave (diccionario) o entero de índices numéricos.
Conexión de eventos - 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 = Tirador
end
end
-- Conectar función a evento
remoteEvent.OnServerEvent:Connect(onEventFire)
Evento de disparo - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- Tabla numéricamente indexadalocal inventoryData = {"Sword", "Bow"}-- mesa de diccionariolocal characterData = {CharName = "Diva Dragonslayer",CharClass = "Rogue"}remoteEvent:FireServer(inventoryData)remoteEvent:FireServer(characterData)
Identidades de la tabla
Las tablas pasadas como argumentos a eventos/ callbacks remotos se copian, lo que significa que no serán exactamente equivalentes a las proporcionadas cuando se ejecuta el evento o se invoca el devolución de llamada. Las tablas devueltas al invocador no serán exactamente equivalentes a las proporcionadas. Puedes demostrar esto al ejecutar el siguiente script en un RemoteFunction y observar cómo las identidades de las tablas se diferencian.
Conexión de llamada - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Función de llamada
local function returnTable(player, passedTable)
-- Identificación de la tabla de salida al invocar
print(tostring(passedTable)) --> tabla: 0x48eb7aead27563d9
return passedTable
end
-- Establecer la función como el retorno de llamada de la función remota
remoteFunction.OnServerInvoke = returnTable
Invocación de eventos - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")local inventoryData = {"Sword", "Bow"}-- Identificación de la tabla originalprint(tostring(inventoryData)) --> tabla: 0x059bcdbb2b576549local invokeReturn = remoteFunction:InvokeServer(inventoryData)-- Identificación de la tabla de salida al devolverprint(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9
Metatables
Si una tabla tiene una metavertiente, toda la información de la metavertiente se pierde en el transfer. En el ejemplo de código siguiente, la propiedad NumWheels es parte de la metavertiente Car. Cuando el servidor recibe la siguiente tabla, la propiedad truck de la tabla 2>truck2>
Conexión de eventos - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> { ["Nombre"] = "MyTruck" }
end
-- Conectar función a evento
remoteEvent.OnServerEvent:Connect(onEvent)
Evento de disparo - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")local Car = {}Car.NumWheels = 4Car.__index = Carlocal truck = {}truck.Name = "MyTruck"setmetatable(truck, Car)-- Evento de fuego con una tabla que incluye una metaverticalremoteEvent: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 de ese valor. Por ejemplo, si
Evento de disparo - 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)
Del mismo modo, si crea una parte en un LocalScript y trata de pasarla a un Script, el servidor verá nil porque la parte no es replicable para el servidor.
Evento de disparo - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- Se recibirá como "nil" porque el servidor no sabe acerca de esta partelocal clientPart = Instance.new("Part")clientPart.Parent = workspaceremoteEvent:FireServer(clientPart)