Mit dauerhaften Daten kannst du Daten pro Spieler zwischen den Spielsitzungen verfolgen und speichern. Für dauerhafte Daten werden Daten wie das Profil oder Statistiken in Verse für jeden einzelnen Spieler gespeichert. Diese Daten können dann jedes Mal aktualisiert werden, wenn sich der Wert der Daten ändert. Da diese Daten dauerhaft sind, bleiben sie über Spielsitzungen hinweg erhalten und sind jedes Mal verfügbar, wenn sich der Spieler online im Spiel befindet. Weitere Informationen findest du unter Verwendung dauerhafter Daten in Verse.
Diese Seite beinhaltet einige Best Practices für die Arbeit mit dauerhaften Daten in Verse.
Verwende Klassen, um später neue Felder hinzuzufügen
Derzeit ist der einzige Typ dauerhafter Daten, den du nach dem Veröffentlichen deiner Insel ändern kannst, der Typ class, solange neue Felder Standardwerte haben. Das bedeutet, dass das Laden gespeicherter Daten aus einer vorherigen Version dann die neuen Felder und ihre Standardwerte umfasst.
Sehen wir uns ein Beispiel für die Veröffentlichung eines Projekts mit den folgenden dauerhaften Daten an:
player_profile_data := class<final><persistable>:
Class:player_class = player_class.Villager
XP:int = 0
Rank:int = 0Da das Projekt veröffentlicht wurde und live ist, sind diese dauerhaften Daten den Spielern zugeordnet, die das Spiel gespielt haben. Wenn wir weitere Felder zu den Spielerprofildaten hinzufügen, wie Auftragsanzahl und Verlauf, könnten die dauerhaften Daten im aktualisierten Projekt ungefähr wie folgt aussehen:
player_profile_data := class<final><persistable>:
Class:player_class = player_class.Villager
XP:int = 0
Rank:int = 0
CompletedQuestCount:int = 0
QuestHistory:[]string = array{}Die dauerhaften Daten für alle Spieler, die mit der ersten Version der Klasse player_profile_data gespielt haben, umfassen nun die neuen Felder:
CompletedQuestCountmit dem Wert0, dem festgelegten Standardwert.QuestHistorymit einem leeren String-Array, dem festgelegten Standardwert.
Das funktioniert, weil ein Standardwert für die neuen Felder festgelegt wurde, damit die ältere Version der Daten aktualisiert werden kann.
Da nur Klassen nach der Veröffentlichung eines Projekts aktualisiert werden können, empfehlen wir die Verwendung einer Klasse als Werttyp jeder modulbereichsbezogenen weak_map-Variable.
Weitere Details zum Erstellen einer dauerhaften Klasse findest du unter Dauerhafte Typen.
Verwenden von Constructors für Teilaktualisierungen
Wenn du Klassen verwendest, empfehlen wir dir, einen Constructor zu verwenden, um eine neue Instanz deiner Klasse zu erstellen, die den aktualisierten Status enthält, da Constructors dir Teilaktualisierungen von Klassen ermöglichen.
Das folgende Beispiel zeigt, wie du PlayerProfileDataMap aktualisieren kannst. Die Funktion GrantXP() holt die aktuellen Daten des angegebenen Spielers ab und ruft dann den Constructor MakePlayerProfileData() auf, um eine neue Version der Profildaten zu erstellen. Da die Spieler-Quelldaten zusammen mit dem neuen EP-Wert an den Constructor übergeben werden, wird nur der EP-Wert aktualisiert, während alle anderen Daten des Spielers identisch bleiben.
MakePlayerProfileData<constructor>(Src:player_profile_data)<transacts> := player_profile_data:
Version := Src.Version
Class := Src.Class
XP := Src.XP
Rank := Src.Rank
CompletedQuestCount := Src.CompletedQuestCount
QuestHistory := Src.QuestHistory
GrantXP(Agent:agent, GrantedXP:int):void=
if:
Das vorangegangene Beispiel zeigt, wie ein Feld aktualisiert wird. Auf diese Art kannst du aber auch beliebig viele Felder aktualisieren:
set PlayerProfileDataMap[Player] = player_profile_data:
QuestHistory := UpdatedSaveData.QuestHistory
CompletedQuestCount := OldData.CompletedQuestCount + 1
MakePlayerProfileData<constructor>(OldData)Versionierung dauerhafter Daten
Wir empfehlen, die Versionsverwaltung in dauerhaften Klassen zu verwenden, um die Version der Instanz für zuvor für einen Spieler gespeicherte Daten zu ermitteln. Durch die Verwendung von Versionen kannst du Migrationen erkennen und anwenden, wenn sich deine dauerhafte Klassendefinition oder Gameplay-Logik im Laufe der Zeit ändert.
Obwohl du die Version deiner dauerhaften Klasse mit Ganzzahl- oder String-Werten angeben kannst, empfehlen wir dir, option-Werte zu verwenden, um Verweise auf aktuelle und frühere Versionen deiner Daten zu speichern. Überlege dir die folgende Einrichtung:
var SavedPlayerData:weak_map(player, player_data) = map{}
# A player data class containing optional fields of versioned player data. Only one of these
# optional values should contain a real value at any given time.
player_data := class<final><persistable>:
V1:?v1_player_data = false
V2:?v2_player_data = false
# Original version of player data.
Hier enthält die Klasse player_data die Werte option sowohl für die erste als auch für die zweite Version der zugehörigen Datenklasse, die durch die Klassen v1_player_data und v2_player_data dargestellt werden. Es sollte immer nur entweder V1 oder V2 festgelegt werden, um zu verhindern, dass Spieler mehrere Versionen von Daten zugeordnet bekommen.
Die ursprünglichen V1-Spielerdaten enthalten drei int-Felder. Die Version V2 der Daten ändert das Feld Playtime in einen float und fügt zwei neue Felder hinzu. Da sich der Typ des Feldes Playtime in der Version V2 geändert hat, muss er für jeden Spieler konvertiert werden, der noch über die alten V1-Daten verfügt. Wenn ein Spieler mit alten V1-Daten an einem Erlebnis teilnimmt, kannst du Helfer-Constructor-Funktionen verwenden, um eine neue V2-Datenklasse basierend auf seinen alten Daten wie folgt erstellen:
# Create v1_player_data using existing v1_player_data.
MakeV1PlayerData<constructor>(SourceData:v1_player_data)<transacts> := v1_player_data:
XP := SourceData.XP
Rank := SourceData.Rank
Playtime := SourceData.Playtime
# Create v2_player_data using existing v2_player_data.
MakeV2PlayerData<constructor>(SourceData:v2_player_data)<transacts> := v2_player_data:
XP := SourceData.XP
Rank := SourceData.Rank
Es kann vorkommen, dass du das Zurücksetzen von Daten für Spieler erzwingen möchtest, die deiner Insel beitreten. Dies kann erreicht werden, indem für alle Spieler ein Standardwert für die dauerhaften Daten in der ‚weak_map‘ neu zugewiesen und das Feld Version der Klasse geändert wird. Wenn du optionale versionierte Daten verwendest, kannst du die Daten zurücksetzen, indem du die optionalen Felder auf False setzt.
Um festzustellen, ob die Daten des Spielers bereits zurückgesetzt wurden, kannst du den Wert Version in den dauerhaften Daten des Spielers überprüfen, um zu sehen, ob es sich um die neueste Version handelt.
Testen, ob dauerhafte Daten innerhalb der Begrenzungen liegen
Wenn sich deine Aktualisierung auf die Gesamtgröße der Persistenzdaten auswirken kann, solltest du verifizieren, dass die dauerhaften Daten noch den Beschränkungen für das Verse-Persistenzsystem entsprechen. Wenn du versuchst, die dauerhaften Daten zu aktualisieren und das die Größenbeschränkungen übersteigt, wird ein Verse-Laufzeitfehler erzeugt. Weitere Informationen findest du unter Maximale Größe von dauerhaften Objekten.
Du kannst überprüfen, wie sich deine Aktualisierungen auf die Gesamtgröße auswirken, indem du die Funktion FitsInPlayerMap() verwendest.
Im folgenden Beispiel enthalten die dauerhaften Daten ein String-Array. Wenn dieses Array jemals zu groß wird, um es in der weak_map zu speichern, was passiert, wenn FitsInPlayerMap() fehlschlägt, leert das Beispiel das Array und fügt nur das zuletzt gespeicherte Element hinzu.
# Construct and return a new player_profile_data with updated quest history.
SetQuestHistory(Src:player_profile_data, NewQuestHistory:[]string)<transacts>:player_profile_data =
NewData:player_profile_data = player_profile_data:
MakePlayerProfileData<constructor>(Src)
QuestHistory := NewQuestHistory
# Set a player's quest history in the PlayerProfileDataMap.
RecordQuestHistory(Agent:agent, QuestHistory:string):void=
if:
CheckSaveDataForPlayer[Agent]
Reaktion auf Spieler, die deiner Insel beitreten
Wenn ein neuer Spieler deiner Insel beitritt, wird er nicht automatisch zur dauerhaften weak_map hinzugefügt. Du musst diesen Eintrag in Verse hinzufügen.
Dazu kannst du entweder bei jedem Zugriff auf die weak_map überprüfen, ob ein Spieler bereits darin enthalten ist, oder du kannst der weak_map bei jedem Beitritt eines Spielers Standarddaten hinzufügen, was du durch Abonnieren des Event PlayerAddedEvent() des Spiels erfahren kannst.
GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded)
# Later in your file
OnPlayerAdded(Player:player):void=
if:
not PlayerProfileDataMap[Player]
set PlayerProfileDataMap[Player] = player_profile_data{}