Storing Dispatched Codes/Data

{
Hi,

I am trying to store dispatched codes and data during a match. When a player wants to switch back into any match, the aim is to have the player receive all match state updates and basically the game will play out automatically up to the point where the game was left off (this may sound weird - but it’s how I hope this will work).

In the matchLoop code in the server TS file, whenever a message is sent (i.e. dispatcher.broadcastMessage), I also call another function: saveDispatchedMessages

let matchLoop: nkruntime.MatchLoopFunction = function (context: nkruntime.Context, logger: nkruntime.Logger, nakama: nkruntime.Nakama, dispatcher: nkruntime.MatchDispatcher, tick: number, state: nkruntime.MatchState, messages: nkruntime.MatchMessage[]) {
    let gameState = state as GameState;
    for (let message of messages) {
        dispatcher.broadcastMessage(message.opCode, message.data, null, message.sender);
        saveDispatchedMessages(message.opCode, message.data, context.userId);
    }
    return gameState.endMatch ? null : { state: gameState };
}

The code for the saveDispatchedMessages function is as follows:

function saveDispatchedMessages(code: number, data: ArrayBuffer, userID: string) {

    const matchState = [
        {
            code: code,
            data: data,
        },
]

    var write: nkruntime.StorageWriteRequest = {
        collection: "MatchStates",
        key: "Dispatched",
        value: matchState,
        userId: userID,
        permissionRead: 1,
        permissionWrite: 0,
    }
}

If I want to receive the match states to bring a match up to the point where I left it off. I use this:

let reloadMatchStates: nkruntime.RpcFunction = function (context: nkruntime.Context, logger: nkruntime.Logger, nakama: nkruntime.Nakama, dispatcher: nkruntime.MatchDispatcher, userID: string): string {
    let storageReadReq: nkruntime.StorageReadRequest = {
        collection: "MatchStates",
        key: "Dispatched",
        userId: userID,
    }

    let objects: nkruntime.StorageObject[] = nakama.storageRead([storageReadReq]);

    //goal is to use dispatcher.broadcastMessage for each object
}

And basically I want the server to dispatch.broadcastMessage each of the objects (containing the code and data).

It’s not quite working yet, and I am not 100% sure if this is going to work or if I am on the right track.

It would be awesome to have so advice on this. If there is an example showing how to save each dispatched message and then retrieve this data to resend each previously dispatched message, that would be great.

Once a match ends, I will then delete this saved data.
}

  1. Versions: Nakama {3.5}, {Windows, Mac, Linux binary or Docker}, {client library (SDK) and version}
  2. Server Framework Runtime language (If relevant) {Go, TS/JS, Lua}
{code or log snippet}

:tv: Media:

I actually had same idea for reconnect implementation and went over trying to implement it without the usage of database…
But it failed as soon it hit over 1500 bytes limit per packet, i mean i could have changed that that limitation in match handler is more but didnt want to mess with it.
Instead i am going with different approach…And that is it, since in my case game is server authorative, that means server in its state has “game state”
My job is to make sure data for game state fits in those 1500 bytes, I can represent everything and then upon reconnection send just state and do recreation in the client.
Client syncs up → game proceeds…

Hi, don’t know how I missed this reply many months ago. I wouldn’t mind giving it a crack still noting I may hit the size limitations. Do you have any examples codes of how to correctly save match data and reload?

Hello @Rob161, I think that recreating the state of the game on the client by replaying all of the messages in sequence may be very inefficient, unless there’s not that many messages exchanged. If possible, I’d suggest you create a snapshot state of the game that allows the client to recreate it without having to go through all the messages.

If you really wish to do it that way, then I suggest you go through all the messages and send them one-by-one to the client through a websocket connection.

Also in your snippet:

function saveDispatchedMessages(code: number, data: ArrayBuffer, userID: string) {

    const matchState = [
        {
            code: code,
            data: data,
        },
]

    var write: nkruntime.StorageWriteRequest = {
        collection: "MatchStates",
        key: "Dispatched",
        value: matchState,
        userId: userID,
        permissionRead: 1,
        permissionWrite: 0,
    }
}

If the key, collection and user_id are always the same, you’re only really storing the most recent message.

The storage engine also does not guarantee ordering of the read objects when using the listing API, you’d need to store the messages all within the same object in an array to ensure that the ordering is kept, otherwise you’d need some sort of seq number in the object/message and the client would be responsible for buffering and ordering the messages in-memory before applying them.

Hope this helps

Thanks for your answer on this and my other related thread. Looks like I will start looking into storing the game state as is rather than replay all raised events.