Update game nhưng đừng reset người chơi: Migrate Save Data trong Unity
Minh Khoa
Tác giả
Giả sử phiên bản đầu tiên của game lưu dữ liệu như sau:
{
"schemaVersion": 1,
"level": 8,
"coins": 120,
"items": ["potion", "potion"]
}
Sau vài lần update, phiên bản hiện tại đã:
- Thêm
gems. - Đổi
levelthànhhighestUnlockedLevel. - Gom Coins và Gems vào
Wallet. - Đổi Inventory từ danh sách ID thành các
ItemStack.
Save cũ không có những dữ liệu này. Vậy làm sao update mà không làm mất progress của người chơi?
Chỉ thêm field mới có đủ không?
Trong Unity 6 hiện tại, JsonUtility.FromJson sẽ chạy field initializer và constructor trước, sau đó ghi đè những field có trong JSON. Field bị thiếu sẽ giữ giá trị mặc định mình đã khởi tạo. FromJsonOverwrite cũng giữ nguyên field trên object nếu JSON không chứa field đó.
Ví dụ:
[Serializable]
public class SaveData
{
public int level;
public int coins;
// Save cũ không có field này
public int stamina = 100;
}
Save cũ có thể nhận stamina = 100.
Cách này ổn nếu thay đổi duy nhất là thêm một field đơn giản. Nhưng nó không giải quyết được các trường hợp:
- Đổi tên field.
- Tách hoặc gộp dữ liệu.
- Đổi kiểu dữ liệu.
- Thay ID item.
- Thay đổi ý nghĩa của một giá trị.
Muốn xử lý an toàn, save cần có version riêng.
Đừng dùng phiên bản game làm phiên bản save
Nên lưu một field:
public int schemaVersion;
schemaVersion mô tả phiên bản cấu trúc save, không phải phiên bản game.
Game có thể update từ 1.2.0 lên 1.2.1 nhưng save không đổi. Ngược lại, chỉ một bản update cũng có thể migrate save qua nhiều cấu trúc.
Game Version: 1.0 → 1.1 → 1.2 → 2.0
Save Version: V1 ──────→ V2 ──→ V3
Migrate từng phiên bản
Giả sử save hiện tại là V3. Người chơi vẫn có thể mang save V1 lên thẳng phiên bản mới.
Thay vì viết một hàm lớn V1ToV3, mình nên chạy tuần tự:
V1 → V2 → V3
Mỗi bước chỉ chịu trách nhiệm cho một thay đổi cụ thể.
V1 → V2
- Đổi
levelthànhhighestUnlockedLevel.