I giochi Roblox sono multiplayer per impostazione predefinita, quindi tutti i giochi comunicano intrinsecamente tra il server e i client connessi dei giocatori. Nel caso più semplice, mentre i giocatori muovono i loro personaggi, alcune proprietà di Humanoid, come gli stati, vengono comunicate al server, che passa queste informazioni agli altri client connessi.
Gli eventi remoti e i callback ti consentono di comunicare attraverso il confine client-server:
- RemoteEvents abilitano la comunicazione unidirezionale (inviare una richiesta e non attendere una risposta).
- UnreliableRemoteEvents abilitano la comunicazione unidirezionale per i dati che cambiano continuamente o non sono critici per lo stato del gioco. Questi eventi scambiano ordinamento e affidabilità per migliorare le prestazioni di rete.
- RemoteFunctions abilitano la comunicazione bidirezionale (inviare una richiesta e attendere fino a ricevere una risposta dal destinatario).
A differenza degli eventi bindabili, che hanno un'utilità più limitata, i casi d'uso per eventi e funzioni remoti sono troppo numerosi per essere elencati:
- Gameplay - Il gameplay di base, come un giocatore che raggiunge la fine di un livello, può richiedere un evento remoto. Uno script client notifica il server e gli script del server ripristinano la posizione del giocatore.
- Verifica del server - Se un giocatore prova a bere una pozione, ha davvero quella pozione? Per garantire equità, il server deve essere la fonte di verità per un gioco. Uno script client può utilizzare un evento remoto per notificare il server che il giocatore sta bevendo una pozione, e poi gli script del server possono decidere se il giocatore ha effettivamente quella pozione e se conferire eventuali benefici.
- Aggiornamenti dell'interfaccia utente - Man mano che lo stato del gioco cambia, gli script del server possono utilizzare eventi remoti per notificare ai client le modifiche ai punteggi, agli obiettivi, ecc.
- Acquisti nel Marketplace di gioco - Per un'implementazione di esempio che utilizza funzioni remote, vedere Acquisti di abbonamento con prompt.
Riferimento rapido
Le seguenti tabelle servono come riferimento rapido su come utilizzare RemoteEvents e RemoteFunctions per comunicare tra client e server.
| Client → Server | |
|---|---|
| Client | RemoteEvent:FireServer(args) |
| Server | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
| Server → Client | |
| Server | RemoteEvent:FireClient(player, args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
| Server → Tutti i Client | |
| Server | RemoteEvent:FireAllClients(args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Eventi remoti
Un oggetto RemoteEvent facilita la comunicazione asincrona, unidirezionale attraverso il confine client-server senza attendere una risposta.
Per creare un nuovo RemoteEvent tramite la finestra Explorer in Studio:
- Passa sopra il contenitore in cui desideri inserire il RemoteEvent. Per garantire l'accesso sia al server che al client, deve trovarsi in un luogo visibile da entrambi i lati, come ReplicatedStorage, anche se in alcuni casi è appropriato memorizzarlo in Workspace o all'interno di un Tool.
- Fai clic sul pulsante ⊕ che appare a destra del nome del contenitore e inserisci un'istanza di RemoteEvent.
- Rinomina l'istanza per descriverne lo scopo.
Una volta creato un RemoteEvent, può facilitare la comunicazione unidirezionale da client a server, da server a client o dal server a tutti i client.



Client → server
Puoi utilizzare un LocalScript per attivare un evento sul server chiamando il metodo FireServer() su un RemoteEvent. Se passi argomenti a FireServer(), questi vengono passati al gestore dell'evento sul server con alcune limitazioni. Nota che il primo parametro del gestore dell'evento sul server è sempre l'oggetto Player del client che lo chiama, e i parametri aggiuntivi seguono.
| Client | RemoteEvent:FireServer(args) |
| Server | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
Il seguente Script collega un gestore di eventi a OnServerEvent che crea un nuovo Part sul server. Lo script LocalScript corrispondente chiama quindi FireServer() sull'istanza di RemoteEvent con il Color e il Position desiderati per la parte.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " ha attivato il RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- Collega la funzione all'evento
remoteEvent.OnServerEvent:Connect(onCreatePart)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Attiva l'evento remoto e passa argomenti aggiuntivi
remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))Server → client
Puoi utilizzare un Script per attivare un evento su un client chiamando il metodo FireClient() su un RemoteEvent. Il primo argomento per FireClient() è l'oggetto Player del client a cui desideri rispondere all'evento, e gli argomenti aggiuntivi vengono passati al client con alcune limitazioni. Nota che il gestore dell'evento non deve includere l'oggetto Player come primo argomento perché puoi determinare il giocatore sul client con Players.LocalPlayer.
| Server | RemoteEvent:FireClient(player, args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Il seguente LocalScript collega un gestore di eventi all'evento OnClientEvent. Lo script Script corrispondente ascolta quindi i giocatori in arrivo sul server e chiama FireClient() per ciascuno con dati arbitrari.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[Client] Evento ricevuto dal giocatore", player.Name)
print(maxPlayers, respawnTime)
end
-- Collega la funzione all'evento
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Ascolta i giocatori in arrivo e invia l'evento remoto a ciascuno
local function onPlayerAdded(player)
print("[Server] Attivazione evento per il giocatore", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)Server → tutti i client
Puoi utilizzare un Script per attivare un evento su tutti i client chiamando il metodo FireAllClients() su un RemoteEvent. A differenza di FireClient(), il metodo FireAllClients() non richiede un oggetto Player perché attiva l'RemoteEvent per tutti i client.
| Server | RemoteEvent:FireAllClients(args) |
| Client | RemoteEvent.OnClientEvent:Connect(function(args)) |
Il seguente LocalScript collega un gestore di eventi all'evento OnClientEvent che visualizza un tempo di conto alla rovescia rimanente. Lo script Script corrispondente chiama quindi FireAllClients() in un ciclo ogni secondo per attivare l'RemoteEvent per tutti i client.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- Collega la funzione all'evento
remoteEvent.OnClientEvent:Connect(onTimerUpdate)local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Ottieni riferimento all'istanza dell'evento remoto
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local countdown = 5
-- Attiva il RemoteEvent ogni secondo fino alla scadenza
for timeRemaining = -1, countdown do
remoteEvent:FireAllClients(countdown - timeRemaining)
task.wait(1)
endCallback remoti
Un oggetto RemoteFunction facilita la comunicazione sincrona, bidirezionale attraverso il confine client-server. Il mittente di una funzione remota attenderà fino a ricevere una risposta dal destinatario.
Per creare una nuova RemoteFunction tramite la finestra Explorer in Studio:
- Passa sopra il contenitore in cui desideri inserire il RemoteFunction. Per garantire l'accesso sia al server che al client, deve trovarsi in un luogo visibile da entrambi i lati, come ReplicatedStorage, anche se in alcuni casi è appropriato memorizzarlo in Workspace o all'interno di un Tool.
- Fai clic sul pulsante ⊕ che appare a destra del nome del contenitore e inserisci un'istanza di RemoteFunction.
- Rinomina l'istanza per descriverne lo scopo.
Una volta creata una RemoteFunction, può facilitare la comunicazione bidirezionale tra client e server o tra server e client.


Client → server → client
Puoi utilizzare un LocalScript per chiamare una funzione sul server chiamando il metodo InvokeServer() su un RemoteFunction. A differenza di un evento remoto, il LocalScript che invoca il RemoteFunction attende fino al ritorno del callback. Gli argomenti che passi a InvokeServer() vengono passati al callback OnServerInvoke della RemoteFunction con alcune limitazioni. Nota che se definisci più callback per la stessa RemoteFunction, solo l'ultima definizione verrà eseguita.
| Client | RemoteFunction:InvokeServer(args) |
| Server | RemoteFunction.OnServerInvoke = function(player, args) |
Il seguente Script definisce la funzione di callback tramite OnServerInvoke e restituisce la Part richiesta attraverso il suo valore di return. Lo script LocalScript corrispondente chiama quindi InvokeServer() con argomenti extra che definiscono il colore e la posizione della parte richiesta.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- Ottieni riferimento all'istanza della funzione remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Funzione di callback
local function createPart(player, partColor, partPosition)
print(player.Name .. " ha richiesto una nuova parte")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- Imposta la funzione come callback della funzione remota
remoteFunction.OnServerInvoke = createPartlocal ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Ottieni riferimento all'istanza della funzione remota
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Passa un colore e una posizione quando invochi il callback
local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
-- Visualizza il riferimento alla parte restituita
print("Il server ha creato la parte richiesta:", newPart)Server → client → server
Puoi utilizzare un Script per chiamare una funzione sul client chiamando il metodo InvokeClient() su un RemoteFunction, ma presenta seri rischi come segue:
- Se il client genera un errore, anche il server genera l'errore.
- Se il client si disconnette mentre viene invocato, InvokeClient() genera un errore.
- Se il client non restituisce un valore, il server attende per sempre.
Per azioni che non richiedono comunicazioni bidirezionali, come l'aggiornamento di un'interfaccia utente, utilizza un RemoteEvent e comunica dal server al client.
Garanzie di consegna
Ogni tipo remoto fa promesse diverse su se un messaggio arrivi e in quale ordine. Queste promesse si applicano solo a una singola connessione in una singola direzione, cioè dal server a un client specifico, o da un client specifico al server.
RemoteEvents
RemoteEvents sono affidabili e ordinati:
- Se un messaggio viene perso durante il transito, Roblox lo ritrasmette fino a quando non arriva, purché il destinatario rimanga connesso.
- I messaggi arrivano nell'ordine in cui li attivi, incluso attraverso diverse istanze di RemoteEvent. Ad esempio, se il server attiva l'evento A, poi B, poi A di nuovo per lo stesso client, quel client riceve A, B, A. Questo si applica sia che tu utilizzi FireClient() o FireAllClients().
- Se un client attiva eventi più velocemente del limite di throttling, il server elabora gli eventi in eccesso in seguito invece di scartarli, e mantengono il loro ordine.
Un messaggio affidabile e ordinato può comunque non raggiungere il tuo codice nei seguenti casi:
- Nessun gestore è connesso. Se nulla è connesso a OnServerEvent o OnClientEvent quando un messaggio arriva, Roblox lo mette in coda e lo consegna, in ordine, non appena un gestore si connette. La coda è limitata sia nel conteggio che nella memoria. Una volta piena, Roblox scarta ulteriori messaggi e registra un errore Remote event invocation nella finestra Output.
- Il destinatario si disconnette. I messaggi che non sono stati consegnati quando un client lascia vengono persi.
L'ordinamento si applica a quando ogni gestore inizia, non quando termina. Se un gestore attende, ad esempio chiamando task.wait() o WaitForChild(), Roblox può iniziare a gestire il messaggio successivo prima che il gestore precedente riprenda.
RemoteFunctions
RemoteFunctions inviano invocazioni e risposte in modo affidabile, quindi Roblox ritrasmette i messaggi persi finché entrambi i lati rimangono connessi. Poiché InvokeServer() e InvokeClient() attendono fino a quando non arriva una risposta, un singolo thread non può avere più di un'invocazione in volo. Thread separati possono invocare contemporaneamente, però, e se un callback attende, le risposte possono tornare in un ordine diverso rispetto a quello in cui sono state inviate le invocazioni.
Se non è assegnato alcun callback a OnServerInvoke o OnClientInvoke, Roblox mette in coda le invocazioni fino a quando non ce n'è uno. Questa coda ha gli stessi limiti della coda di RemoteEvent.
UnreliableRemoteEvents
UnreliableRemoteEvents non garantiscono né la consegna né l'ordine. Non hanno nemmeno alcuna relazione di ordinamento con RemoteEvents o RemoteFunctions. Roblox potrebbe scartare un messaggio in uno dei seguenti casi, senza ritrasmetterlo:
- Il messaggio viene perso durante il transito.
- La rete è congestionata e il messaggio aspetta troppo a lungo per essere inviato.
- Il payload è più grande di 1.000 byte.
- Il client attiva più velocemente del limite di throttling. A differenza di un RemoteEvent, il server scarta i messaggi in eccesso invece di ritardarli.
- Nulla è connesso a OnServerEvent o OnClientEvent quando il messaggio arriva. A differenza di un RemoteEvent, Roblox scarta immediatamente il messaggio invece di metterlo in coda.
Roblox non aspetta nemmeno che un messaggio precedente arrivi prima di elaborare uno successivo, quindi i messaggi possono arrivare fuori ordine. Se l'ordine è importante, includi un timestamp o un numero di sequenza in ogni messaggio e ignora i messaggi più vecchi dell'ultimo che hai gestito.
Limiti di throttling e dimensione
I messaggi dal client al server sono soggetti a un limite di velocità che ogni tipo remoto condivide tra tutte le sue istanze. Per i limiti attuali, vedere la sezione Throttling di RemoteEvent e i limiti di payload in UnreliableRemoteEvent.
Limitazioni degli argomenti
Quando attivi un RemoteEvent o invochi un RemoteFunction, esso inoltra qualsiasi argomento che passi con l'evento o alla funzione di callback. Qualsiasi tipo di oggetto Roblox come un Enum, Instance, o altri può essere passato, così come tipi Luau come numeri, stringhe e booleani, anche se dovresti esplorare attentamente le seguenti limitazioni.
Indici non stringa
Se qualsiasi indice di una tabella passata è di tipi non stringa come un Instance, userdata, o funzione, Roblox converte automaticamente quegli indici in stringhe.
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
-- Collega la funzione all'evento
remoteEvent.OnClientEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Ascolta i giocatori in arrivo e invia l'evento remoto a ciascuno
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)Funzioni passate
Le funzioni incluse come argomenti per un RemoteEvent o RemoteFunction non verranno replicate attraverso il confine client-server, rendendo impossibile passare funzioni a distanza. Invece, l'argomento risultante sul lato ricevente sarà nil.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nil
end
remoteEvent.OnClientEvent:Connect(onClientEvent)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Ciao mondo!")
end
-- Attiva l'evento remoto con una funzione come argomento
remoteEvent:FireAllClients(testFunction)Indicizzazione delle tabelle
Se passi una tabella di dati, non passare una tabella mista di chiavi numeriche e stringa. Invece, passa una tabella che consiste interamente di coppie chiave-valore (dizionario) o interamente di indici numerici.
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 = Spada
--> 2 = Arco
--> CharName = Diva Dragonslayer
--> CharClass = Rogue
end
end
-- Collega la funzione all'evento
remoteEvent.OnServerEvent:Connect(onEventFire)local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Tabella indicizzata numericamente
local inventoryData = {
"Spada", "Arco"
}
-- Tabella dizionario
local characterData = {
CharName = "Diva Dragonslayer",
CharClass = "Rogue"
}
remoteEvent:FireServer(inventoryData)
remoteEvent:FireServer(characterData)Identità delle tabelle
Le tabelle passate come argomenti agli eventi/callback remoti vengono copiate, il che significa che non saranno esattamente equivalenti a quelle fornite quando attivi l'evento o invochi il callback. Né le tabelle restituite all'invocatore saranno esattamente equivalenti a quelle fornite. Puoi dimostrarlo eseguendo il seguente script su un RemoteFunction e osservando come le identità delle tabelle differiscano.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- Funzione di callback
local function returnTable(player, passedTable)
-- Visualizza l'identità della tabella all'invocazione
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- Imposta la funzione come callback della funzione remota
remoteFunction.OnServerInvoke = returnTablelocal ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
local inventoryData = {
"Spada", "Arco"
}
-- Visualizza l'identità della tabella originale
print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549
local invokeReturn = remoteFunction:InvokeServer(inventoryData)
-- Visualizza l'identità della tabella al ritorno
print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9Metatabelle
Se una tabella ha una metatabella, tutte le informazioni della metatabella vengono perse durante il trasferimento. Nel seguente esempio di codice, la proprietà NumWheels fa parte della metatabella Car. Quando il server riceve la seguente tabella, la tabella truck ha la proprietà Name ma non la proprietà NumWheels.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- Collega la funzione all'evento
remoteEvent.OnServerEvent:Connect(onEvent)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)
-- Attiva l'evento con una tabella che include una metatabella
remoteEvent:FireServer(truck)Istanze non replicate
Se un RemoteEvent o RemoteFunction passa un valore che è visibile solo al mittente, Roblox non lo replica attraverso il confine client-server e passa nil invece del valore. Ad esempio, se un Script passa un discendente di ServerStorage, il client che ascolta l'evento riceverà un valore nil perché quell'oggetto non è replicabile per il client.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Sarà ricevuto come "nil" perché il client non può accedere a ServerStorage
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)Allo stesso modo, se crei una parte in un LocalScript e provi a passarla a un Script, il server vedrà nil perché la parte non è replicabile per il server.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- Sarà ricevuto come "nil" perché il server non conosce questa parte
local clientPart = Instance.new("Part")
clientPart.Parent = Workspace
remoteEvent:FireServer(clientPart)