퍼시스턴스 데이터를 사용하면 플레이 세션 간에 플레이어별 데이터를 추적하고 저장할 수 있습니다. 퍼시스턴스 데이터는 Verse에서 개별 플레이어마다 프로필이나 통계 등의 데이터를 저장하는 방식으로 작동합니다. 그런 다음 이 데이터를 데이터 값이 변경되는 횟수만큼 업데이트할 수 있습니다. 퍼시스턴스 데이터이므로 여러 게임 세션에 걸쳐 유지되며, 플레이어가 게임에서 온라인 상태인 경우라면 언제든지 사용할 수 있습니다. 자세한 내용은 Verse에서 퍼시스턴스 데이터 사용하기를 참고하세요.
이 페이지에서는 Verse에서 퍼시스턴스 데이터로 작업할 때의 몇 가지 모범 사례를 다룹니다.
추후 새 필드를 추가할 수 있도록 클래스 사용하기
현재 섬 퍼블리싱 후 변경할 수 있는 유일한 퍼시스턴스 데이터 타입은 class 타입이며, 새 필드가 기본값을 가져야 합니다. 이는 이전 버전에서 저장된 데이터를 로드하면 새 필드 및 새 필드의 기본값이 포함된다는 뜻입니다.
다음과 같은 퍼시스턴스 데이터로 프로젝트를 퍼블리싱하는 예시를 살펴보겠습니다.
player_profile_data := class<final><persistable>:
Class:player_class = player_class.Villager
XP:int = 0
Rank:int = 0프로젝트가 퍼블리싱되었고 라이브 상태이므로, 게임을 플레이한 플레이어는 자신과 연관된 이 퍼시스턴스 데이터를 보유하게 됩니다. 플레이어 프로필 데이터에 퀘스트 수와 히스토리 등 더 많은 필드를 추가했다면, 퍼시스턴스 데이터는 업데이트된 프로젝트에서 다음과 같이 보일 것입니다.
player_profile_data := class<final><persistable>:
Class:player_class = player_class.Villager
XP:int = 0
Rank:int = 0
CompletedQuestCount:int = 0
QuestHistory:[]string = array{}player_profile_data 클래스의 첫 번째 버전으로 플레이한 모든 플레이어의 퍼시스턴스 데이터에는 이제 다음과 같은 새 필드가 포함됩니다.
지정된 기본값인
0값이 있는CompletedQuestCount지정된 기본값인 빈 string 배열이 있는
QuestHistory
이는 새 필드가 이전 버전의 데이터를 업데이트할 수 있도록 기본값이 제공되었기 때문에 작동합니다.
프로젝트를 퍼블리싱한 후 클래스만 업데이트될 수 있기 때문에, 모듈 스코프 weak_map 변수의 값 타입으로 클래스를 사용할 것을 적극 권장합니다.
퍼시스턴스 클래스를 생성하는 방법에 대한 자세한 내용은 퍼시스턴스 타입을 참고하세요.
부분 업데이트에 생성자 사용하기
클래스를 사용 중인 경우, 업데이트된 상태가 포함된 클래스의 새 인스턴스 생성에 생성자를 사용하는 것이 좋습니다. 생성자를 통해 클래스의 부분 업데이트가 가능하기 때문입니다.
다음 예시는 PlayerProfileDataMap을 업데이트하는 방법을 보여줍니다. GrantXP() 함수는 주어진 플레이어의 현재 데이터를 얻은 다음 프로필 데이터의 신규 버전을 만들기 위해 MakePlayerProfileData() 생성자를 호출합니다. 플레이어의 소스 데이터가 새 XP 값과 함께 생성자에 전달되므로, 플레이어의 다른 데이터는 모두 동일하게 유지되는 반면 XP 값만 업데이트됩니다.
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:
이전 예시는 하나의 필드를 업데이트하는 방법을 보여주었지만, 다음과 같은 방법으로 필요한 수만큼 업데이트할 수 있습니다.
set PlayerProfileDataMap[Player] = player_profile_data:
QuestHistory := UpdatedSaveData.QuestHistory
CompletedQuestCount := OldData.CompletedQuestCount + 1
MakePlayerProfileData<constructor>(OldData)퍼시스턴스 데이터 버전 관리
이전에 저장된 플레이어 데이터의 인스턴스 버전을 탐지하기 위해 퍼시스턴스 클래스에서 버전 관리를 사용하는 것이 좋습니다. 버전을 사용하면 퍼시스턴스 클래스 정의 또는 게임플레이 로직이 시간 경과에 따라 변경되는 경우 마이그레이션을 탐지하고 적용할 수 있습니다.
integer 또는 string 값을 사용하여 퍼시스턴스 클래스의 버전을 나타낼 수 있지만, option 값을 사용하여 데이터의 현재와 과거 버전에 대한 레퍼런스를 저장하는 것이 좋습니다. 다음과 같은 구성을 고려해 보세요.
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.
여기에서 player_data 클래스에는 연관된 데이터 클래스의 첫 번째와 두 번째 버전 둘 모두에 대한 option 값이 포함되어 있으며,이는 v1_player_data 및 v2_player_data 클래스로 표현됩니다. V1이나 V2 중 하나만 플레이어가 자신과 연관된 여러 버전의 데이터를 보유하지 못하도록 설정해야 합니다.
원본 V1 플레이어 데이터에는 세 개의 int 필드가 포함되어 있습니다. 이 데이터의 V2 버전은 Playtime 필드를 float로 변경할 뿐만 아니라, 두 개의 새 필드를 추가합니다. Playtime 필드의 타입이 V2 버전에서 변경되었기 때문에, 기존의 V1 데이터를 아직 보유한 모든 플레이어를 대상으로 해당 타입을 변환해야 합니다. 기존의 V1 데이터가 있는 플레이어가 경험에 합류하면, 다음과 같이 헬퍼 생성자 함수를 사용하여 기존 데이터에 기반한 새 V2 데이터 클래스를 빌드할 수 있습니다.
# 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
섬에 합류하는 플레이어의 데이터를 강제로 리셋해야 하는 경우가 있습니다. 이는 모든 플레이어의 'weak_map' 내 퍼시스턴스 데이터의 기본값을 재할당하고 클래스의 Version 필드를 변경하는 방식으로 가능합니다. 선택적 버전 데이터를 사용하는 경우, 선택적 필드를 false로 설정하여 데이터를 리셋할 수 있습니다.
플레이어의 데이터가 이미 리셋되었는지 여부를 파악하려면, 플레이어의 퍼시스턴스 데이터 내 Version 값을 확인하여 최신 상태인지 확인하면 됩니다.
퍼시스턴스 데이터가 한도 내인지 테스트하기
업데이트로 인해 퍼시스턴스 데이터의 총 크기가 영향을 받을 수 있는 경우, 퍼시스턴스 데이터가 여전히 Verse의 퍼시스턴스 시스템 한도 내에 있는지 확인해야 합니다. 퍼시스턴스 데이터를 업데이트하려고 하는데 크기 한도를 초과한다면 Verse 런타임 오류가 발생합니다. 자세한 내용은 최대 퍼시스턴스 오브젝트 크기를 참고하세요.
FitsInPlayerMap() 함수를 사용하여 업데이트가 총 크기에 미치는 영향을 확인할 수 있습니다.
다음 예시에서는 퍼시스턴스 데이터에 스트링 배열이 포함됩니다. FitsInPlayerMap()이 실패하여 해당 배열이 weak_map에 저장하기에 너무 커지는 경우, 예시에서는 배열을 비우고 가장 최근에 저장된 엘리먼트만 추가합니다.
# 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]
섬에 합류하는 플레이어에게 반응하기
신규 플레이어가 섬에 합류할 때 신규 플레이어에게는 퍼시스턴스 weak_map에 자동 추가되는 항목이 없습니다. Verse에서 해당 항목을 추가해야 합니다.
이를 추가하려면, 액세스할 때마다 플레이어가 이미 weak_map에 있는지 확인하거나, 플레이어가 합류할 때마다 weak_map에 기본 데이터를 추가하면 됩니다. 플레이어 합류는 게임의 PlayerAddedEvent() 이벤트에 등록하여 알 수 있습니다.
GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded)
# Later in your file
OnPlayerAdded(Player:player):void=
if:
not PlayerProfileDataMap[Player]
set PlayerProfileDataMap[Player] = player_profile_data{}