[SOLVED] Save and load multiplayer game progress

For my boardgame I like to create a kind of save and load function. The goal is when one of the two players lost the connection, I can restore the state of the game from the connected player back to the reconnected player.

I have a gameboard with 36 tiles. Every tile has his own name, like Tile24. Every tile has a child entity with also it’s own name, like Piece18. From that I need to save some kind of data with which tile has which piece. Then when the player reconnect the game I need to switch the piece to the correct tile (reparent), using the saved data that I get from the connected player.

How do I handle this?

2 Likes

Maybe it gets a bit more complicated as game pieces can change into another game piece in the game. So I also need to determine which game piece for example Piece18 actual is. (I use tags for this).

It’s not a simple thing to implement unfortunately. At a very high level, you will need:

  • Matchmaking where two players connect to the server play against each other in a ‘room’
  • The state of the game controlled by the server. What the board looks like, whose turn it is, whether a move is valid from the player, etc. This is known as ‘server authoritative’
  • Allow players to reconnect to the room after a disconnection or refresh of the page and the server sends the board state of the game to player.

This needs custom server code of some sort to do and may be easier to use something off the shelf to do like Colyseus. Tanks - Colyseus & Arena Cloud Documentation

I am currently using Photon to create a room. When another player enters the room, I would like to take over the progress of the board from the player already in the room. So if the player has already moved a piece before the other player was present, then I want to transfer the local information from the first player to the other player.

My idea was to go through all the tiles with a loop and see which game pieces the tiles have. Wrapping this in data so that the other player can also apply the information to the tiles with a loop.

I can find many Unity examples and tutorials, but with my knowledge it is impossible to use them with PlayCanvas.

You could store the board state in a json object or similar and past that over. If your pieces are uniquely named, you could store all the pieces XY position on the board by name:

{
  piece1: { x: 0, y: 1 },
  piece2: { x: 0, y: 2 }
}

etc

Storing the positions is not useful with my setup. Every tile entity (Tile tag) has a piece child entity (Piece tag and Empty, Bolt, Nut or Neutral tag). I need to store the tile name together with the piece name and piece tag, to know which tile has which piece.

Ah, when I say position, I mean position on the board. Take Chess for example:

I could have the board state like:

{
  blackRook1: { x: 'a', y '8' }
}

Or have it so that the board says what pieces are on it

{
  'a8': 'blackRook'
}

And configure the board that way

If you have to, you can store the tags in the board state too JSON object too

piece1: { x: 0, y: 1, tags: ['blah', 'foo'] }
1 Like

Another way is that you keep a history of the moves like chess move notation and when the player reconnects, they get a copy of the move history to quickly play back locally to reach the same board state.

I have some progress, but still no logic how to handle this.

image

I probably need to package this information into a single JSON object? For the other player I need to find a way to use this information in a loop to compare it with the tiles of the other player. If the information doesn’t match with the actual tile, I have to replace the piece child with the correct piece child.

Yeah. Basically you need to store this data in some format and for the other side, be able to read that data and setup the board. It could be JSON, or just some text etc. It doesn’t really matter as long as you can write and read from that format

1 Like

Maybe I don’t need all the information I thought. The method below seems to work locally. At least I get the expected result.

GamePhoton.prototype.getProgress = function () {
    var tiles = [];
    this.app.root.findByTag('Tile').forEach(function(entity) {
        tiles.push(entity.findByTag('Piece')[0].tags.list()[1]);
    }.bind(this));
    this.setProgress(tiles);
};
GamePhoton.prototype.setProgress = function (tiles) {
    var number = -1;
    this.app.root.findByTag('Tile').forEach(function(entity) {
        number += 1;
        if (entity.findByTag('Piece')[0].tags.list()[1] === tiles[number]){
            console.log('Correct piece');
        }
        else {
            console.log('Incorrect piece');
        }
    }.bind(this));
};

It seems to work! :partying_face:

Thanks for your help @yaustar!

1 Like

Below my final code that actually replaced the incorrect piece, so the game progress is the same after (re)connecting.

GamePhoton.prototype.getProgress = function () {
    var tiles = [];
    this.app.root.findByTag('Tile').forEach(function(entity) {
        tiles.push(entity.findByTag('Piece')[0].tags.list()[1]);
    }.bind(this));
    this.app.loadBalancing.raiseEvent(3, tiles);
};
GamePhoton.prototype.setProgress = function (tiles) {
    var number = -1;
    this.app.root.findByTag('Tile').forEach(function(entity) {
        number += 1;
        if (entity.findByTag('Piece')[0].tags.list()[1] != tiles[number]){
            replacement = this[tiles[number]].resource.instantiate();
            replacement.name = entity.findByTag('Piece')[0].name;
            entity.findByTag('Piece')[0].destroy();
            entity.addChild(replacement);
        }
    }.bind(this));
};

1 Like