Skip to content

Instantly share code, notes, and snippets.

@delucis
Last active April 21, 2022 12:24
Show Gist options
  • Save delucis/53803fedb036f778e8a991bb9e07b388 to your computer and use it in GitHub Desktop.
Save delucis/53803fedb036f778e8a991bb9e07b388 to your computer and use it in GitHub Desktop.
Extending boardgame.io storage connectors

You can extend a boardgame.io storage adapter to add custom functionality.

This example wraps the original setState method to accomplish some other task when the game is over — in this case posting the game logs elsewhere via a hypothetical dumpEndOfGameLog function.

(The example uses the FlatFile storage class, but should work with any other boardgame.io storage class.)

import { FlatFile } from 'boardgame.io/server';
import type { LogEntry } from 'boardgame.io';
declare function dumpEndOfGameLog(matchID: string, log: LogEntry[]): void;
export class ExtendedDB extends FlatFile {
async setState(...args: Parameters<FlatFile['setState']>) {
await super.setState(...args);
const [matchID, state] = args;
if (state.ctx.gameover !== undefined) {
const { log } = await this.fetch(matchID, { log: true });
dumpEndOfGameLog(matchID, log);
}
}
}
import { Server } from 'boardgame.io/server';
import { ExtendedDB } from './extended-bgio-storage';
const server = Server({
db: new ExtendedDB(/* Any options you’d usually set */),
// other Server options: games, origins, etc.
});
server.run();
@on3iro
Copy link

on3iro commented Apr 21, 2022

just as reference, here's how you could interact with setMetadata:

export class ExtendedPostgresStore extends PostgresStore {
  async setMetadata(...args: Parameters<PostgresStore['setMetadata']>) {
    await super.setMetadata(...args)

    const [matchID, metadata] = args

    /**
     * We add the current matchID to a field inside the user table, if the user was not
     * present while the game was finished.
     * This allows us to then show a notification to the user...
     */
    if (metadata.gameover?.winner !== undefined && !metadata.gameover.done) {
      const player1Name = metadata.players[PlayerID.player1]?.name
      const player1IsConnected = metadata.players[PlayerID.player1]?.isConnected
      const player2Name = metadata.players[PlayerID.player2]?.name
      const player2IsConnected = metadata.players[PlayerID.player2]?.isConnected

      if (!player1IsConnected && player1Name) {
        addNewlyArchivedPrivateMatch(player1Name, matchID)
      }

      if (!player2IsConnected && player2Name) {
        addNewlyArchivedPrivateMatch(player2Name, matchID)
      }

     // Invoke setMetadata again to set the 'done' flag inside gameover, so the code above won't be triggered again for
     // this match
      await super.setMetadata(matchID, {
        ...metadata,
        gameover: { ...metadata.gameover, done: true },
      })
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment