Binary Serialization using Cereal

Versioning Serialized Game Save Files

I'm working on a game and want to ensure that save files from older versions can still be loaded in newer versions. How can I handle this using cereal's versioning features?

Abstract art representing computer programming

To handle backward compatibility for serialized game save files using cereal's versioning features:

Step 1: Define a version number for your serializable classes and increment it whenever you make changes that affect serialization:

class Player {
  // ...
};
CEREAL_CLASS_VERSION(Player, 1);

class GameState {
  // ...
};
CEREAL_CLASS_VERSION(GameState, 2);

Step 2: In your serialization functions, use the versioned save/load or serialize function signatures:

template <class Archive>
void Player::serialize(Archive& ar,
  std::uint32_t version) {
  ar(name, level);

  if (version >= 1) {
    ar(health);
  }
}

template <class Archive>
void GameState::serialize(Archive& ar,
  std::uint32_t version) {
  ar(players, score);

  if (version >= 2) {
    ar(difficulty);
  }
}

Step 3: When deserializing, check the version number and handle missing or added fields accordingly. Provide default values for fields that may not exist in older save files:

template <class Archive>
void Player::serialize(Archive& ar,
  std::uint32_t version) {
  ar(name, level);

  if (version >= 1) {
    ar(health);
  } else {
    // Default value for older versions
    health = 100;
  }
}

template <class Archive>
void GameState::serialize(Archive& ar,
  std::uint32_t version) {
  ar(players, score);

  if (version >= 2) {
    ar(difficulty);
  } else {
    // Default value for older versions
    difficulty = 1;
  }
}

Step 4: When loading a save file, cereal will automatically detect and pass the appropriate version number to your serialization functions. Your deserialization logic will handle the version differences.

By following this approach, newer versions of your game will be able to load and handle save files from older versions gracefully. Remember to increment the version number whenever you make changes to the serialization layout of your classes.

A complete example is provided below:

#include <cereal/archives/binary.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/string.hpp>
#include <fstream>
#include <iostream>
#include <vector>

class Player {
 public:
  std::string name;
  int level;
  int health;

 private:
  friend class cereal::access;

  template <class Archive>
  void serialize(Archive& ar,
    std::uint32_t version) {
    ar(name, level);

    if (version >= 1) {
      ar(health);
    } else {
      // Default value for older versions
      health = 100;
    }
  }
};

CEREAL_CLASS_VERSION(Player, 1);

class GameState {
 public:
  std::vector<Player> players;
  int score;
  int difficulty;

 private:
  friend class cereal::access;

  template <class Archive>
  void serialize(Archive& ar,
    std::uint32_t version) {
    ar(players, score);

    if (version >= 2) {
      ar(difficulty);
    } else {
      // Default value for older versions
      difficulty = 1;
    }
  }
};

CEREAL_CLASS_VERSION(GameState, 2);

int main() {
  GameState gameState;
  gameState.players.emplace_back(Player{
    "Alice", 10, 80});
  gameState.players.emplace_back(Player{
    "Bob", 20, 70});
  gameState.score = 1000;
  gameState.difficulty = 2;

  {
    std::ofstream file("savegame.dat");
    cereal::BinaryOutputArchive archive(file);
    archive(gameState);
  }

  GameState loadedGameState;

  {
    std::ifstream file("savegame.dat");
    cereal::BinaryInputArchive archive(file);
    archive(loadedGameState);
  }

  std::cout << "Loaded Game State:\n";
  std::cout << "Score: "
    << loadedGameState.score << "\n";
  std::cout << "Difficulty: "
    << loadedGameState.difficulty << "\n";
  std::cout << "Players:\n";
  for (const auto& player :
    loadedGameState.players) {
    std::cout << "  " << player.name
      << " (Level " << player.level
      << ", Health " << player.health << ")\n";
  }
}
Loaded Game State:
Score: 1000
Difficulty: 2
Players:
  Alice (Level 10, Health 80)
  Bob (Level 20, Health 70)

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved