Entwicklung / ROBLOX
Anfragelimits in Roblox: Eine Server-Hilfe vor wiederholten Klicks schützen
Ein Übungslimiter für die Werkstatthilfe erlaubt vier sofortige Versuche und füllt anschließend zwei Token pro Sekunde nach. Wir erklären getrennten Spielerzustand, Serverzeit, Schaltflächenverhalten und lokale Prüfungen ohne echten Roblox-Verkehr.
Eine bestimmte Aktion begrenzen #
Stell dir eine Werkstatt vor, in der Anfänger mit „Wo ist die Station?“ einen Hinweis anfordern. Mehrere schnelle Klicks können versehentlich entstehen, eine Reaktion auf verzögerte Antworten sein oder unerwünschte Wiederholungen darstellen. Wenn jeder Aufruf teure Arbeit startet, kann eine kleine Schaltfläche unnötige Last erzeugen. Beschreibe zuerst die Serveroperation hinter dem Klick und den Grund für ihre Begrenzung.
Wir verwenden einen Texthinweis, keine Bestellung, Belohnung oder Profilspeicherung. Das ist ein eigenes Übungsszenario und keine neu hinzugefügte Funktion der Spiele des Website-Autors. Vier Versuche und zwei Token pro Sekunde sind gewählte Erklärungswerte. Sie sind weder Roblox-Quoten noch allgemeine Empfehlungen für jede Aktion. Ein echter Mehrspieler-Lasttest wurde nicht durchgeführt.
Die Client-Schaltfläche bestimmt keine Serverregel #
Eine vorübergehend deaktivierte Schaltfläche kann anzeigen, dass eine Antwort aussteht. Das hilft Spielern zu verstehen, dass ihre Anfrage bereits gesendet wurde. Trotzdem muss der Server unabhängig entscheiden, ob ein weiterer Aufruf erlaubt ist. Roblox weist ausdrücklich darauf hin, dass ein ausschließlich clientseitiges Anfragelimit nicht genügt.
Akzeptiere weder die vom Client gemeldete Anzahl verbleibender Versuche noch dessen behaupteten letzten Klickzeitpunkt als Erlaubnis. Unser Modul verwaltet Guthaben und Zeit auf dem Server. Der Client fragt, der Server entscheidet. Die Häufigkeitsprüfung macht ungültige Parameter nicht gültig: Typprüfung, zulässige Aktion und Spielzustand bleiben eigene Anforderungen.
Ein Token Bucket erlaubt eine kurze Serie #
Jeder Spieler besitzt gedanklich einen Behälter für höchstens vier Token. Ein Versuch kostet ein Token. Pro Sekunde kommen zwei zurück, jedoch nie über die Kapazität hinaus. Damit sind vier sofortige Versuche möglich; eine anhaltende Serie muss auf Nachfüllung warten. Dies ist der von Roblox beschriebene Token-Bucket-Ansatz.
Das bedeutet nicht „vier Aufrufe in jeder Kalendersekunde“. Nach kurzer Wartezeit kann nur ein Bruchteil eines Tokens vorhanden sein. Solange kein ganzes Token verfügbar ist, wird der nächste Versuch abgelehnt. Wir prüfen diesen Bruchteil ausdrücklich, damit die Wartezeit erklärbar bleibt und nicht wie ein zufälliger Schaltflächenfehler wirkt.
| Zeit | Versuch | Ergebnis und Guthaben |
|---|---|---|
| 0 | Erster bis vierter | Erlaubt: 4 → 0 |
| 0 | Fünfter | Abgelehnt: 0 |
| 0.25 s | Neuer Versuch | Abgelehnt: 0,5 |
| 0.5 s | Neuer Versuch | Erlaubt: 0 |
Spielerzustände getrennt halten #
Wenn A seine vier Token ausgibt, darf Bs nächste Anfrage nicht deshalb blockiert werden. Deshalb verwendet die Tabelle den Player aus dem serverseitigen OnServerEvent-Handler als Schlüssel. Ersetze dieses Objekt nicht durch einen zusätzlich vom Client übergebenen Namen oder eine Kennung. Sonst würde die Auswahl eines fremden Behälters von unvertrauenswürdigen Eingaben abhängen.
Getrennte Behälter begrenzen nicht den Gesamtverkehr aller Spieler. Viele Nutzer können ihre erlaubten Versuche gleichzeitig ausgeben. Teure Aktionen oder Backend-Aufrufe erfordern eine getrennte Betrachtung von Gesamtrate, Warteschlangen und Kosten. Das Modul besitzt weder ein gemeinsames Serverbudget noch eine Obergrenze paralleler Aufgaben oder zwischen Servern verteilten Zustand.
Das Übungsmodul verstehen #
Lege HintRequestLimiter in ServerScriptService ab. new(capacity, refillPerSecond, clock) legt Kapazität, Nachfüllrate und Serverzeitfunktion fest. Allow(player) liefert eine Erlaubnis und einen kurzen Ergebniscode. Forget(player) löscht den lokalen Zustand beim Verlassen. Das Modul greift nicht auf DataStore zu, erzeugt kein RemoteEvent und verschickt selbst keinen Hinweis.
Die Kapazität muss eine ganze Zahl von 1 bis 1000 sein. Die Nachfüllrate muss positiv, endlich und höchstens 1000 sein. Diese Grenzen gehören zu unserem Beispiel, nicht zu Plattformquoten. Gebrochene Raten sind erlaubt. Fehlerhafte Zeitwerte führen zur Ablehnung; rückwärtslaufende Zeit fügt keine Token hinzu. Der gesamte Zustand gehört ausschließlich zum aktuellen Server.
os.clock hat keinen festgelegten absoluten Ausgangspunkt. Vergleiche Differenzen statt Kalenderdaten. Das Übungsmodul akzeptiert einen endlichen negativen Ausgangswert; ein eigener lokaler Test prüft die Nachfüllung damit.
-- Original teaching limiter for server-side hint requests.
-- Pass the Player supplied by OnServerEvent, never a client-supplied identity.
-- Frequency control does not validate permissions or grant rewards.
local Limiter = {}
local function finite(value)
return type(value) == "number" and value == value
and value > -math.huge and value < math.huge
end
function Limiter.new(capacity, refillPerSecond, clock)
assert(finite(capacity) and capacity == math.floor(capacity)
and capacity >= 1 and capacity <= 1000, "Invalid capacity")
assert(finite(refillPerSecond) and refillPerSecond > 0
and refillPerSecond <= 1000, "Invalid refill rate")
if clock == nil then clock = os.clock end
assert(type(clock) == "function", "Invalid clock")
local buckets = {}
local adapter = {}
function adapter:Allow(player)
if player == nil then return false, "MissingPlayer" end
local ok, now = pcall(clock)
if not ok or not finite(now) then
return false, "InvalidClock"
end
local bucket = buckets[player]
if not bucket then
bucket = {tokens = capacity, last = now}
buckets[player] = bucket
elseif now < bucket.last then
return false, "ClockWentBackwards"
else
bucket.tokens = math.min(capacity,
bucket.tokens + (now - bucket.last) * refillPerSecond)
bucket.last = now
end
if bucket.tokens < 1 then return false, "RateLimited" end
bucket.tokens -= 1
return true, "Allowed"
end
function adapter:Forget(player)
buckets[player] = nil
end
return adapter
end
return Limiter
Den Server-Handler bewusst anschließen #
Erstelle ein RemoteEvent namens GetHint in ReplicatedStorage und ein Server-Script neben dem Modul. Das Script holt die Dienste, lädt das Modul mit require und erstellt den Limiter mit 4, 2 und os.clock. Der Handler verwendet den von Roblox gelieferten Player, prüft die Anfrage und schickt ausschließlich einen vorgegebenen Hinweis an diesen Spieler.
Das Beispiel erwartet TutorialStep=1 als Attribut aus bereits vorhandener serverseitiger Tutoriallogik. Es beginnt kein Tutorial und ändert das Attribut nicht auf Wunsch des Clients. Ohne diesen Zustand wird kein Hinweis gesendet. Auch die Client-Oberfläche fehlt: Verbinde sie separat mit GetHint und dessen Antwort. Das Script zeigt die Integration, kein geprüftes vollständiges Spiel.
-- Server Script; create ReplicatedStorage.GetHint as a RemoteEvent first.
-- TutorialStep must be maintained by your existing SERVER gameplay logic.
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Limiter = require(
game:GetService("ServerScriptService"):WaitForChild("HintRequestLimiter")
)
local request = ReplicatedStorage:WaitForChild("GetHint")
assert(request:IsA("RemoteEvent"), "GetHint must be a RemoteEvent")
local limiter = Limiter.new(4, 2, os.clock)
request.OnServerEvent:Connect(function(player, hintName)
-- Each attempt consumes quota before further processing.
if not limiter:Allow(player) then return end
if type(hintName) ~= "string" or #hintName > 32 then return end
if hintName ~= "FindWorkshop" then return end
if player:GetAttribute("TutorialStep") ~= 1 then return end
local character = player.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
request:FireClient(player, "Hint", "Look for the workshop sign.")
end)
Players.PlayerRemoving:Connect(function(player)
limiter:Forget(player)
end)
Festlegen, was einen Versuch verbraucht #
Unser Handler ruft Allow vor der Zeichenkettenprüfung auf. Ein Versuch verbraucht daher auch bei ungültigem Hinweisnamen oder falscher Tutorialstufe ein Token. Das ist beabsichtigt: Begrenzt werden Eingänge in den Handler, nicht nur erfolgreich gelieferte Hinweise. Ungültige Eingaben erhalten keinen unbegrenzten kostenlosen Weg in die nachfolgende Verarbeitung.
Erstatte Token nicht nach jeder abgelehnten Anfrage automatisch. Sonst könnte ein Strom ungültiger Eingaben diese Regel umgehen. Die Spielbedeutung braucht dennoch eigene Prüfungen. Ein Token bestätigt weder Belohnungsberechtigung noch Gegenstandsbesitz, Aufgabenabschluss oder Zugriff auf fremde Objekte. Eine andere Aufgabe kann eine andere Reihenfolge oder Kostenregel erfordern, die ausdrücklich definiert werden muss.
Nicht jede abgelehnte Wiederholung beantworten #
Der Übungshandler beendet eine begrenzte Anfrage still. Eine Antwort oder ausführliche Protokollzeile für jede Ablehnung könnte auf diesem Pfad neue Arbeit erzeugen. Lass den Limiter keine endlosen Benachrichtigungen auslösen. Wähle für Beobachtungen eine begrenzte Zusammenfassung der Ablehnungen statt einer Speicherung jedes eingehenden Pakets.
Bei stiller Ablehnung muss die Oberfläche ihre Schaltfläche nach sinnvoller lokaler Wartezeit wieder freigeben und einen erneuten Versuch verständlich machen. Diesen Client-Timer implementieren wir hier nicht. Lass die Schaltfläche niemals dauerhaft auf eine Antwort warten, die der Server absichtlich nicht sendet. Bedienkomfort und serverseitige Erlaubnis sind verschiedene Aufgaben.
Mit kontrollierter Zeit testen #
Der lokale Luau-Test übergibt eine eigene Zeitfunktion. Bei Zeitpunkt 0 darf A vier Versuche ausführen; der fünfte liefert RateLimited. Bei 0,25 ist nur ein halbes Token vorhanden, also bleibt der nächste Versuch abgelehnt. Bei 0,5 ist ein Token verfügbar: Ein Versuch gelingt, der nächste nicht. Diese Zahlen beschreiben einen lokalen Test, keine echten Spielbesuche.
Der Test prüft ebenfalls Bs unabhängigen Behälter. Eine lange Pause stellt höchstens vier Versuche wieder her. Ungültige oder rückwärtslaufende Zeit erzeugt kein zusätzliches Guthaben. Konfiguration, Bereinigung und gebrochene Nachfüllraten werden geprüft. Alle Prüfungen verwenden Ersatzobjekte und kontrollierte Zeit; echte Roblox-Remotes, Spieler und Serverleistungsmessungen fehlen.
| Prüfung | Erwartung |
|---|---|
| Sofortiger fünfter Versuch | RateLimited |
| Anfrage eines anderen Spielers | Getrennter Behälter |
| Lange Pause | Höchstens 4 Token |
| Zeit läuft rückwärts | Keine Nachfüllung |
| Ungültige Zeit | InvalidClock |
| Zustand nach Bereinigung | Neuer voller Behälter |
Beim Verlassen bereinigen #
Verbinde Players.PlayerRemoving mit limiter:Forget(player). Andernfalls hält die Tabelle den Zustand ausgeschiedener Spieler bis zum Serverende fest. Rufe Forget nicht bei einer gewöhnlichen Ablehnung auf: Danach bekäme die nächste Anfrage wieder einen vollen Behälter. Bereinigung gehört zum Spielerlebenszyklus und ist kein Mittel zur Freigabe einer Schaltfläche.
Nach gelöschtem Zustand beginnt ein neuer Eintritt mit einem neuen Behälter. Das ist vorgesehenes lokales Verhalten, kein Schutz gegen erneute Verbindung und kein kontoweites Limit. Zustand bleibt nicht zwischen Servern erhalten. Anforderungen über verschiedene Sitzungen hinweg brauchen ein eigenes Konzept; das Löschen eines Tabelleneintrags beweist keine solche Garantie.
Häufigkeit begrenzt nicht alle Folgearbeit #
Eine erlaubte Anfrage kann an anderer Stelle eine lange Aufgabe starten. Unser Modul wartet nicht auf deren Ende und zählt keine bereits laufenden Aufgaben. Auch die erlaubte Rate kann für eine teure Operation zu hoch sein. Prüfe, was nach der Erlaubnis geschieht: Werden große Modelle kopiert, API-Aufrufe gestartet oder andere Spieler beeinflusst?
Käufe, Datenspeicherung und gemeinsame Wirtschaftssysteme benötigen eigene Regeln, nicht nur Token. Das Beispiel prüft auch keinen Abstand zu einer Station: Sein Texthinweis erfordert das bewusst nicht. Ergänze beim Übertragen auf Objektinteraktionen die benötigten Serverprüfungen für Position, Berechtigung und Zustand. Wir haben keinen vorhandenen Spielcode des Autors verändert.
Die Übergabe vorbereiten #
Bewahre begrenzte Aktion, Bedeutung des Tokenverbrauchs, Kapazität, Nachfüllrate und erforderliche Serverprüfungen zusammen auf. Ergänze lokale Testabläufe und markiere echte Netzwerk- und Lasttests als ausstehend. Übertrage vier nicht als universelle Einstellung für jede Schaltfläche oder Waffe; der Wert gehört nur zu dieser Übung.
Bitte den Entwickler, zwei Spieler, lange Pausen, Verlassen und ungültige Anfragen sowie die Schaltflächenfreigabe nach stiller Ablehnung zu prüfen. Liste fehlende Funktionen getrennt auf: gemeinsames Serverbudget, parallele Operationen, Zustand über Sitzungen hinweg und Client-Oberfläche. So lässt sich die Idee im nächsten Spiel verwenden, ohne den tatsächlichen Fertigstellungsgrad zu verschleiern.
Originalquellen
Roblox Creator Hub — Client-server boundaryLuau — Standard library
Roblox Creator Hub — os