Reload Match Events

Hi,
I have a 2 player PvP turnbased game with which I plan to save any match events to the cloud storage and then reload these events when a player leaves and rejoins the same match.

Within the MatchLoop function, I save the OpCode and Data as per below:

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);

        var matchStateCode = message.opCode
        var matchStateData = message.data

        saveDispatchedCode(matchStateCode, context.matchId, context.userId);
        saveDispatchedData(matchStateData, context.matchId, context.userId);
        };
    return gameState.endMatch ? null : { state: gameState };
}

The SaveDispatchedCode & SaveDispatchedData functions are written as follows:

function saveDispatchedCode(code: number, matchID: string, userID: string) {

    var value = { code };

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

function saveDispatchedData(data: ArrayBuffer, matchID: string, userID: string) {

    var value = { data };

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

No errors so far on the above, but I am struggling on how to write the code for reloading and broadcasting these match OpCodes and Data. This is what I have so far:

let reloadMatchState: nkruntime.RpcFunction = function (context: nkruntime.Context, logger: nkruntime.Logger, nakama: nkruntime.Nakama, dispatcher: nkruntime.MatchDispatcher, userID: string): string { 
    let storageReadCode: nkruntime.StorageReadRequest = {
        key: "MatchStates",
        collection: "Code",
        userId: userID,
    }
    let storageReadData: nkruntime.StorageReadRequest = {
        key: "MatchStates",
        collection: "Data",
        userId: userID,
    }

    let eventCode: nkruntime.StorageObject[] = nakama.storageRead([storageReadCode]);
    let eventData: nkruntime.StorageObject[] = nakama.storageRead([storageReadData]);

    for (let i = 0; i < eventCode.length; i++) {
        dispatcher.broadcastMessage(eventCode[i],eventData[i]);
    }

    logger.info("Receiving Event Code: " + eventCode + "and Event Data: " + eventData);
}

Regarding the ‘dispatcher.broadcastMessage(eventCode[i],eventData[i])’ code, I get the error: “StorageObject is not assignable to parameter of type ‘number’” which I understand because ‘eventCode[i]’ is meant to be a number and not a StorageObject.

Can you please provide any advice on how to convert a StorageObject to a number? Are there any examples of saving and reloading match events I can look at and is what I have written so far on the right track?

Any help would be appreciated.

Thanks

  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 am getting back into developing my game. Wondering if anyone is able to help with my query I made a few months ago. Thanks.

Hey @Rob161, please see my response here.

This approach has some potential issues - storing every message individually within a tick may slow your match loop down, since your game is turn-based I suppose the tickrate will be low, so this may be fine if there’s only a few players, but at scale (or if under-provisioned) the DB may not keep up and drag the game loop, causing it to fall behind the set tick rate.

You’d at least want to batch the messages into a single storageWrite operation every few ticks, but usually db operations should be avoided within your main loop, and be delegated to execution flows outside of it. The best would be to buffer them in memory and store them whenever the match is stopped.

As mentioned in the other thread, you’re not storing a list of messages, but a single one. You need to either store an array of messages within your storage object, or use different ‘key’ values within the same collection and user_id to list the with the storageList api.

Hope this clarifies.