Beheers externe gebeurtenissen in Roblox-scripting: bouw veilige multiplayerfuncties.
Met Remote Events in Roblox-scripting kunnen een client en de server berichten naar elkaar sturen zonder te hoeven wachten op een antwoord. Gebruik ze voor verzoeken zoals "probeer dit item te kopen" of voor door de server goedgekeurde updates zoals "toon dit effect aan spelers in de buurt". De belangrijkste ontwerpregel is dat een RemoteEvent een bericht bevat; het maakt het verzoek niet betrouwbaar. De server moet zelf bepalen of een actie is toegestaan en belangrijke spelstatus bijwerken.
Wat een RemoteEvent doet
Een RemoteEventRemoteEvent is een asynchroon, eenrichtingscommunicatieobject. De zender roept een methode aan om het te activeren, en de ontvanger voert een bijbehorende gebeurtenishandler uit. Een RemoteEvent-aanroep retourneert geen waarde. Het is betrouwbaar en geordend zolang de ontvanger verbonden blijft, maar het is geen verzoek-antwoordmechanisme.
Voor een gedeelde gebeurtenis is een gemeenschappelijke locatie ReplicatedStoragede server, waartoe zowel de server als de clients toegang hebben. De server kan zich elders bevinden als het ontwerp dit vereist, bijvoorbeeld binnen een tool, maar beide eindpunten moeten de instantie kunnen zien. Clients kunnen geen berichten rechtstreeks naar andere clients verzenden: een client kan de server op de hoogte stellen, waarna de server kan kiezen welke clients een vervolggebeurtenis ontvangen.
| Richting | Verzendmethode | Ontvanger | Typisch gebruik |
| Client naar server | FireServer(...) | OnServerEvent | Verzoek om een actie of geef spelersinvoer door |
| Server naar één client | FireClient(player, ...) | OnClientEvent | Verzend een privémelding of update |
| Server naar elke verbonden client | FireAllClients(...) | OnClientEvent | Zend een gedeeld effect of een aankondiging uit. |
Wanneer een client een RemoteEvent activeert, geeft Roblox het Playerobject van die speler door als eerste argument aan de OnServerEventcallbackfunctie van de server. Probeer dit argument niet zelf door te geven of te kiezen.
Bouw een veilige gebeurtenis voor de aankoop van artikelen.
Dit vierdelige voorbeeld verbindt een GUI-knop met de aankooplogica van de server. Maak in Verkenner een RemoteEventobject aan ReplicatedStorageen geef het de naam PurchaseItem. Voeg een LocalScript toe onder een TextButton of ImageButton. Voeg een normaal Script toe in ServerScriptService. Als u ook het onderstaande effectvoorbeeld gebruikt, maak dan een tweede RemoteEvent aan met de naam EffectEventin ReplicatedStorage. Het voorbeeld gaat ervan uit dat uw spel al een door de server beheerde leaderstats.Cashwaarde aanmaakt en zijn eigen code heeft voor het toekennen van inventarisitems.
Stap 1: Verstuur alleen de intentie van de speler.
De klant vraagt om een artikel te kopen door de catalogus-ID te verzenden. De platformonafhankelijke Activatedfunctie werkt voor muis-, touch- en gamepad-input op een GUI-knop.
-- LocalScript parented to a TextButton or ImageButton
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local purchaseItem = ReplicatedStorage:WaitForChild("PurchaseItem")
local button = script.Parent
button.Activated:Connect(function()
purchaseItem:FireServer("SmallHealthPotion")
end)
De klant stuurt niet de prijs, zijn kassaldo of een instructie om zichzelf een artikel toe te kennen. Die waarden en beslissingen behoren toe aan de server.
Stap 2: Valideer en verwerk het verzoek op de server.
Bewaar de itemlijst en prijzen in een serverscript of een module die alleen op de server draait. De volgende handler controleert het type verzoek, accepteert alleen een bekende catalogusvermelding, past een afkoelperiode per speler toe en controleert de waarde van het servergeld voordat er iets wordt afgetrokken.
-- Script in ServerScriptService
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local purchaseItem = ReplicatedStorage:WaitForChild("PurchaseItem")
local catalog = {
SmallHealthPotion = { price = 25 },
}
local lastRequestAt = {}
local COOLDOWN_SECONDS = 0.25
purchaseItem.OnServerEvent:Connect(function(player, itemId)
if typeof(itemId) ~= "string" or #itemId > 40 then
return
end
local item = catalog[itemId]
if not item then
return
end
local now = os.clock()
local previous = lastRequestAt[player.UserId] or 0
if now - previous < COOLDOWN_SECONDS then
return
end
lastRequestAt[player.UserId] = now
local leaderstats = player:FindFirstChild("leaderstats")
local cash = leaderstats and leaderstats:FindFirstChild("Cash")
if not cash or not cash:IsA("IntValue") or cash.Value < item.price then
return
end
cash.Value = cash.Value - item.price
-- Grant the item through your server-owned inventory system here.
end)
Players.PlayerRemoving:Connect(function(player)
lastRequestAt[player.UserId] = nil
end)
Pas de waardecontrole aan aan het waardeobject of valutasysteem dat je spel gebruikt. Als een aankoop afhankelijk is van de locatie van een winkel, de levensstatus van de speler, een missie of een ontgrendeling, controleer die voorwaarde dan ook op de server. Houd de validatie en de statuswijziging bij elkaar en vermijd onderbrekingen tussen het controleren van het saldo en het aftrekken van de prijs.
Stap 3: Laat de server de uitkomst kiezen.
Voor acties anders dan aankopen geldt hetzelfde patroon: de client rapporteert invoer en de server valideert deze voordat de gedeelde status wordt gewijzigd. Nadat een serverscript bijvoorbeeld heeft bevestigd dat een spreuk is ontgrendeld en de doelpositie geldig is, kan het de effectpositie uitzenden:
-- Server Script, after validating the action
local effectEvent = ReplicatedStorage:WaitForChild("EffectEvent")
effectEvent:FireAllClients(serverApprovedPosition)
Gebruik deze methode FireClient(player, ...)wanneer slechts één speler een update moet ontvangen. Gebruik deze methode FireAllClients(...)wanneer alle verbonden clients de update nodig hebben. Om een specifieke speler over te slaan, moet u de update expliciet naar de beoogde ontvangers verzenden; FireAllClientsExcept()dit is geen RemoteEvent-methode.
Stap 4: Feedback weergeven die alleen voor de client bestemd is
Een LocalScript kan luisteren naar de goedgekeurde update en een deeltjesexplosie, geluid of andere tijdelijke presentatie weergeven. Houd visuele effecten op de client wanneer ze geen invloed hoeven te hebben op de gameplay.
-- LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local effectEvent = ReplicatedStorage:WaitForChild("EffectEvent")
effectEvent.OnClientEvent:Connect(function(position)
if typeof(position) ~= "Vector3" then
return
end
-- Play a local visual effect at the server-approved position.
end)
Dit voorbeeld controleert het ontvangen type op een defensieve manier. De client mag niet beslissen of de spreuk raak is, schade heeft toegebracht of een beloning heeft gegenereerd; dat zijn beslissingen van de server.
RemoteEvent, RemoteFunction of UnreliableRemoteEvent?
| Voorwerp | Mededeling | Kies het wanneer |
RemoteEvent | Asynchroon, eenrichtingsverkeer; er wordt geen reactie geretourneerd. | Je moet een actieverzoek, melding of update verzenden. |
RemoteFunction | Tweewegsgesprek; de beller wacht tot hij een reactie krijgt. | De beller heeft echt een retourwaarde nodig voordat hij verder kan gaan. |
UnreliableRemoteEvent | Asynchroon, eenrichtingsverkeer, zonder leverings- of ordergarantie. | Regelmatig terugkerende, niet-kritieke gegevens kunnen worden weggelaten zonder de spelstatus te beïnvloeden. |
Gebruik bij voorkeur een RemoteEvent wanneer de afzender geen reactie nodig heeft. Een RemoteFunction kan de aanroepende thread blokkeren tijdens het wachten, en het aanroepen van een client vanaf de server brengt risico's met zich mee als die client een fout geeft, de verbinding verbreekt of nooit een reactie terugstuurt. UnreliableRemoteEvents zijn geschikt voor tijdelijke updates, zoals snel veranderende visuele of richtgegevens, maar niet voor aankopen, voorraad of andere statusinformatie die in een vaste volgorde moet binnenkomen.
RemoteEvent-beveiligingschecklist
- Valideer elk argument van de client op de server. Controleer het type, de grootte, het bereik en de structuur voordat u de gegevens gebruikt.
- Gebruik een whitelist. Koppel een kort item- of actie-ID aan serverinstellingen. Sta niet toe dat een client een prijs, assetpad, willekeurige instantie of uit te voeren code opgeeft.
- Controleer de machtigingen en de context. Verifieer de afstand tot een winkel, de status van het personage, de afkoeltijd, de beschikbare grondstoffen en eventuele vereiste ontgrendelingen op de server.
- Beperk de serverprestaties. Een client-side debounce kan de interface verbeteren, maar aanvallers kunnen deze omzeilen. Stel een serverlimiet in voor bewerkingen die kunnen worden overmatig gebruikt of die veel resources verbruiken.
- Maak van de server een poortwachter. Valideer een door de client geactiveerd effect voordat je het doorgeeft aan andere spelers; zend geen door de client aangeleverde posities klakkeloos uit.
Volgens de beveiligingsrichtlijnen van Roblox wordt invoer van derden als onbetrouwbaar beschouwd. Servervalidatie is essentieel, zelfs als uw LocalScript dezelfde waarden al controleert. Gebruik voor aankopen van hoge waarde of permanente inventaris dezelfde servercontroles in uw logica voor gegevensopslag en transacties.
Test en los problemen op met RemoteEvents.
- “RemoteEvent niet gevonden”: Controleer de naam en het bovenliggende element in Verkenner en gebruik dit
WaitForChild()wanneer een script moet wachten op replicatie.
- De handler wordt nooit uitgevoerd: controleer of de code die de gebeurtenis activeert zich in een LocalScript bevindt, de ontvangende code in een serverscript staat en beide verwijzen naar dezelfde RemoteEvent-instantie.
- De server weigert een aankoop: controleer de item-ID aan de serverzijde, het valutaobject en de toegangsrechten. Los een discrepantie niet op door te vertrouwen op een door de client aangeleverde prijs.
- De effecten verschijnen slechts voor één speler: controleer of je
FireClient()in plaats van hebt gebruikt FireAllClients(), of dat elke client een OnClientEventlistener heeft.
- Berichten gedragen zich onverwacht: verbind de listener voordat je het bericht verzendt. Roblox plaatst berichten kort in een wachtrij wanneer er geen listener is verbonden, maar die wachtrij is beperkt. Als de correctheid afhangt van de volgorde van RemoteEvent- en RemoteFunction-aanroepen, voeg dan je eigen volgorde toe; Roblox garandeert deze volgorde niet.
Gebruik de server- en clienttestmodus van Studio om een server met meerdere gesimuleerde spelers te draaien. Controleer het uitvoervenster aan beide kanten, test vervolgens het gedrag bij het deelnemen en verlaten van een sessie en probeer ongeldige invoer. De client-servertest van Studio is een betere manier om het gedrag in multiplayer-sessies te controleren dan alleen te vertrouwen op een solo-speelsessie.
Officiële Roblox-referenties