Roblox GuidebookWissensbibliothek
Deutsch ⌄

Entwicklung / ROBLOX

Fortschritt in Roblox erstmals speichern: Laden, Ändern und erneut beitreten

Wir planen eine kleine Lernübung mit einem einzigen gespeicherten Zähler. Dabei unterscheiden wir Spielerdaten von der Studio-Projektdatei, richten eine getrennte Test-Experience ein und verhindern, dass ein fehlgeschlagener Ladevorgang als neuer leerer Datensatz behandelt wird. Diese Einführung ist noch kein fertiges Speichersystem für eine produktive Spielwirtschaft.

Aktualisiert:

Was soll nach dem Verlassen erhalten bleiben? #

Stell dir eine kleine Werkstatt vor. Ein Spieler erledigt drei Aufträge, beendet das Spiel und kommt am Abend zurück. Das Gebäude gehört zum Projekt. Die Zahl der erledigten Aufträge gehört hingegen zu diesem Spieler. Das Speichern der Leveldatei bewahrt nicht automatisch den persönlichen Fortschritt aller Besucher.

Beginne mit einer einzigen Ganzzahl. Füge nicht gleichzeitig Währung, Gegenstände, Aufgaben und Handel hinzu: Bei einem unerwarteten Ergebnis wäre die Ursache schwer zu finden. Als Übungsnamen kannst du TestCompletedOrders verwenden. Die Anzeige soll den Wert zeigen, den der Server tatsächlich geladen hat, und keine vorher eingesetzte Zahl. Beschreibe vor dem ersten Test, welches Ergebnis nach einem erneuten Beitritt erwartet wird.

Eine getrennte Test-Experience vorbereiten #

Erstelle eine eigene Experience für die Übung, veröffentliche sie und beschränke den Zugang passend. Ein zusätzlicher Place innerhalb einer laufenden Experience bietet nicht dieselbe Trennung: Places derselben Experience können auf deren Data Stores zugreifen. Prüfe im Creator Hub, welches Projekt geöffnet ist, bevor du Einstellungen änderst.

Roblox beschreibt den Studio-Zugriff auf APIs im Bereich Security der Experience Settings. Aktiviere ihn ausschließlich für die getrennte Test-Experience. Die Position von Menüpunkten kann sich verändern; vergleiche bei Abweichungen die aktuelle Dokumentation. Schalte den Zugriff auf echte Spielerdaten nicht nur deshalb ein, weil du einen Versuch schneller starten möchtest. Ein unbekannter produktiver Datensatz darf nicht zum Übungsobjekt werden.

Die Speicherlogik gehört auf den Server #

DataStore-Aufrufe werden in einem serverseitigen Script ausgeführt. Für diese Übung eignet sich ServerScriptService. Ein LocalScript kann Ladezustand und Ergebnis anzeigen, darf aber nicht selbst den gespeicherten Zähler bestimmen oder eine erfolgreiche Speicherung behaupten.

Trenne drei Aufgaben: beim Beitritt einen Wert laden, eine vom Server erlaubte Änderung anwenden und diese Änderung speichern. Werden alle Aufgaben in einem Klick-Handler vermischt, gilt leicht jeder Klick als Erfolg. In der Werkstatt bedeutet „Auftrag abgeschlossen“, dass der Server die Erfüllung geprüft hat. Ein sichtbarer Tastendruck beweist für sich allein keinen verdienten Fortschritt.

Speichername und Spielerschlüssel festlegen #

Wähle einen stabilen Namen für den Testspeicher und bilde den Schlüssel mit Player.UserId. Unser vorgeschlagenes Schema verwendet GuidebookOrdersTest_v1 als Speichernamen und User_ gefolgt von der Benutzerkennung als Schlüssel. Diese Namen sind eine Übungsentscheidung und kein von Roblox vorgeschriebenes Format.

Verwende nicht den Display Name als Identität: Mehrere Personen können denselben Anzeigenamen besitzen. Ändere den Speichernamen zwischen den beiden Testsitzungen nicht. Sonst liest du möglicherweise aus einem anderen Speicher und hältst eine erfolgreiche frühere Speicherung irrtümlich für verloren. Notiere Speichername, Schlüsselbildung und Experience in deinem Testprotokoll, damit spätere Nachforschungen einen eindeutigen Ausgangspunkt haben.

Fehlende Daten sind kein Ladefehler #

Ein erfolgreicher erster Lesevorgang kann nil zurückgeben, wenn unter dem Schlüssel noch kein Wert existiert. Initialisiere den Zähler in dieser Übung erst, nachdem ein erfolgreicher Aufruf das Fehlen des Datensatzes festgestellt hat. Schlägt der Aufruf fehl, sagt ein fehlendes Ergebnis nichts darüber aus, ob bereits ein Profil gespeichert ist.

Nutze ausdrückliche Zustände wie Loading, Ready und LoadFailed. Während Loading bleiben Aktionen gesperrt, die den Fortschritt verändern. Zeige bei LoadFailed eine verständliche Meldung und überschreibe unbekannte Daten nicht mit null. Für die erste Übung reicht es, Änderungen anzuhalten und den Test zu beenden. Eine Wiederholungsstrategie ist eine eigene Entwurfsaufgabe; sie rechtfertigt keinen stillen Ersatz durch ein neues Profil.

Leseergebnisse und erlaubte AktionBild in voller Größe öffnen ↗
Eigene Grafik: Lesefehler bedeutet nicht fehlender Datensatz.
ZustandErwartetes Verhalten
LoadingFortschrittsänderung gesperrt
ReadyServerseitig erlaubte Aktionen verfügbar
LoadFailedKein Anfangsprofil schreiben

Fehler behandeln, ohne Erfolg vorzutäuschen #

DataStore-Aufrufe können fehlschlagen. Die Roblox-Dokumentation zeigt dafür pcall. Die Verwendung von pcall allein macht das Speichern aber nicht zuverlässig: Entscheidend ist, das Ergebnis zu prüfen und eine Reaktion für den Fehlerfall festzulegen.

„Versuch gesendet“ und „Speicherung bestätigt“ sind unterschiedliche Zustände. Verwende in Output getrennte Meldungen für Laden, Ändern und Speichern. Die Oberfläche darf erst nach einem erfolgreichen Serverergebnis „gespeichert“ anzeigen. Gib in Fehlermeldungen für Spieler keine vollständigen Profile oder persönlichen Informationen aus. Für die Übung reichen eine kurze Erklärung und der betroffene Schritt. Ausführliche Diagnoseinformationen gehören in die kontrollierte Testumgebung.

Die Arten der Aktualisierung verstehen #

Vergleiche SetAsync und UpdateAsync vor der Wahl einer Schreibstrategie. SetAsync setzt einen übergebenen Wert. UpdateAsync verarbeitet den aktuellen gespeicherten Wert durch eine Funktion. Wenn mehrere Server schreiben, kann ein alter lokaler Wert bei einer einfachen Zuweisung eine andere Änderung überschreiben.

Der Callback von UpdateAsync darf nicht warten, beispielsweise mit task.wait. Vergib innerhalb dieser Umwandlung keine externe Belohnung in der Annahme, die Funktion werde immer genau einmal ausgeführt. Beschreibe zunächst die Änderung der Daten und melde ein bestätigtes Ergebnis anschließend getrennt. Eine vollständige Lösung für gleichzeitige Profilzugriffe benötigt zusätzliche Regeln. Sitzungsbesitz und Kaufabwicklung sind nicht Bestandteil dieser Einführung.

Lege den folgenden Lerncode als ModuleScript namens StoreExperiment in ServerScriptService ab. Ein serverseitiges Script erhält mit DataStoreService:GetDataStore("GuidebookOrdersTest_v1") den Testspeicher, lädt das Modul mit require und erstellt über StoreExperiment.new(store) den Adapter. Lies mit adapter:Load(player.UserId). Rufe nach einer serverseitig geprüften Übungsaktion adapter:CompleteTestOrder(player.UserId) auf. Das ist weder ein Klick-Handler noch eine automatische Beitrittsbelohnung. Erfolg liefert true und eine Zahl; Fehler liefern false und LoadFailed oder SaveFailed. Vergleiche die Tabelle. Erlaubt sind Ganzzahlen von 0 bis 1.000.000; am gewählten Übungslimit stoppt die Änderung. Ein weiterer separater Aufruf erhöht erneut: Schutz vor doppelter Belohnung fehlt. Lokale Luau-Prüfungen verwendeten einen simulierten Speicher, nicht Studio oder echte API-Aufrufe.

-- ModuleScript: StoreExperiment (ServerScriptService).
-- Learning adapter only; no sessions, receipts, retries or production economy.
local StoreExperiment = {}

local function keyFor(userId)
    assert(type(userId) == "number" and userId > 0
        and userId < math.huge and userId == math.floor(userId), "Invalid UserId")
    return "User_" .. tostring(userId)
end

local function counter(value)
    if value == nil then return 0 end
    assert(type(value) == "number" and value >= 0 and value <= 1000000
        and value == math.floor(value), "Unexpected counter format")
    return value
end

function StoreExperiment.new(store)
    local adapter = {}

    function adapter:Load(userId)
        local key = keyFor(userId)
        local ok, result = pcall(function()
            return counter(store:GetAsync(key))
        end)
        if not ok then return false, "LoadFailed" end
        return true, result
    end

    function adapter:CompleteTestOrder(userId)
        -- Call only after the server verifies the exercise action.
        -- A failed read never authorizes a write of initial data.
        local loaded = self:Load(userId)
        if not loaded then return false, "LoadFailed" end
        local key = keyFor(userId)
        local ok, result = pcall(function()
            return store:UpdateAsync(key, function(current)
                local value = counter(current)
                assert(value < 1000000, "Exercise counter limit reached")
                return value + 1
            end)
        end)
        if not ok then return false, "SaveFailed" end
        return true, result
    end

    return adapter
end

return StoreExperiment

Grenzen der Übung sichtbar halten #

Ein Lernzähler ist keine produktive Geldbörse. Für eine echte Spielwirtschaft musst du klären, welcher Server das Profil verwaltet, wie wiederholte Vorgänge erkannt werden, wie Netzwerkfehler behandelt werden und was beim Herunterfahren mit ausstehenden Schreibvorgängen geschieht.

Speichere nicht in jedem Frame oder bei jeder Änderung einer Textanzeige. Die Schreibfrequenz richtet sich nach Dienstgrenzen und dem tolerierbaren Fortschrittsverlust. Hier prüfen wir eine bewusste Speicherung und das Lesen in einer neuen Sitzung. Das erklärt den Mechanismus, beweist aber nicht, dass ein einzelner Schreibvorgang für jedes Spiel genügt oder ein erfolgreicher Aufruf alle späteren Fehler ausschließt.

Zwei aufeinanderfolgende Sitzungen prüfen #

Bereite das Protokoll vor dem Start vor. Warte in der ersten Sitzung auf erfolgreiches Laden, führe eine Testaktion aus, erhalte die Bestätigung des Schreibvorgangs und notiere den angezeigten Zähler. Beende die Sitzung. Tritt anschließend derselben Test-Experience mit demselben Konto, Speicher und Schlüssel erneut bei.

Vergleiche den neu geladenen Wert mit der Erwartung. Das Neustarten einer Oberfläche innerhalb der alten Sitzung ersetzt keine Prüfung dauerhafter Speicherung. Bei zusätzlichen Untersuchungen beachte den Cache von GetAsync: Zwei unmittelbar aufeinanderfolgende Lesevorgänge beweisen nicht zwangsläufig zwei unabhängige Zugriffe auf den aktuellen Backend-Zustand. Beschreibe die Beobachtung genau, statt jeden wiederholten Aufruf als frische Prüfung zu bezeichnen.

Ablauf der SpeicherprüfungBild in voller Größe öffnen ↗
Eigene Grafik: Daten zwischen Sitzungen vergleichen.

Fehler und getrennte Spielerdaten prüfen #

Zwei erfolgreiche Beitritte sind nur ein Teil des Tests. Prüfe, dass ein zweiter Benutzer einen eigenen Schlüssel erhält und Änderungen am ersten Zähler den zweiten nicht beeinflussen. Ein Ladefehler darf keine Speicherung von Anfangsdaten auslösen. Ein Schreibfehler darf keine Erfolgsmeldung erzeugen.

Für kontrollierte Tests kannst du den Speicherzugriff von der restlichen Spiellogik trennen und vorübergehend einen Übungsadapter einsetzen, der einen Fehler zurückgibt. Beschädige keine echten Datensätze, um diesen Fall herzustellen. Die Simulation prüft die Verzweigungen deiner Anwendung. Ein zusätzlicher Test mit der echten API bleibt nötig; bezeichne simulierte Antworten nicht als Beleg für einen tatsächlich ausgeführten Roblox-Aufruf.

PrüfungErfolgskriterium
Erneuter BeitrittBestätigter Zähler geladen
Anderer SpielerEigener Schlüssel und Wert
LesefehlerKeine leeren Daten schreiben
SchreibfehlerKeine Erfolgsmeldung

Wenn beim nächsten Beitritt wieder null erscheint #

Gehe die Kette durch: Ist es die richtige Experience? Stimmt der Speichername? Ist die erwartete UserId beigetreten? War der vorherige Schreibvorgang erfolgreich? Hat die Anwendung nach einem Ladefehler Anfangsdaten erstellt? Lies Output-Meldungen in Reihenfolge und betrachte nicht nur die letzte rote Zeile.

Lösche keine Datenbestände auf Verdacht. Sichere das Protokoll und reproduziere die Ursache zuerst an einem getrennten Schlüssel. Hat ein Versuch versehentlich eine laufende Experience erreicht, stoppe experimentelle Schreibvorgänge und untersuche die verfügbaren Werkzeuge zur Datenverwaltung. Wiederholtes Starten derselben fehlerhaften Logik kann den Schaden vergrößern, ohne die Ursache zu klären.

Wann ist die erste Stufe abgeschlossen? #

Die Übung besteht, wenn der Zähler zwischen bestätigten Sitzungen erhalten bleibt, Benutzer getrennte Daten haben, ein Ladefehler nie ein leeres Profil überschreibt und ein Schreibfehler nie als Erfolg erscheint. Notiere tatsächliche Ergebnisse: Konten, Umgebung, Aktionen und beobachtete Werte.

Die nächste Stufe behandelt Zugriffe mehrerer Server, begrenzte Wiederholungen und Profilbesitz. Übertrage die Übung bis zu diesen Prüfungen nicht in eine bestehende Experience mit Käufen und Sammlungen. Für diesen Entwurf wurde Studio nicht ausgeführt. Der Text enthält eine Erklärung und einen Testplan, keinen Bericht über einen abgeschlossenen Spieltest.

Originalquellen

Roblox Creator Hub — Data stores
Roblox Creator Hub — Best practices for data stores