boardgameio / boardgame.io

State Management and Multiplayer Networking for Turn-Based Games
https://boardgame.io
MIT License
10.02k stars 707 forks source link

server-side side-effects for room state changes #680

Open jabza opened 4 years ago

jabza commented 4 years ago

The current lobby and server are somewhat of a black box when it comes to accessing the room state.

It would be nice to allow server to listen to state change events, perhaps the redux store directly, to trigger side-effects when rooms are created, modified and ended. One example being updating user statistics upon game completion.

Right now, server-side, the only option is events hooked up with the various game callbacks, such as onEnd(G, ctx). But these are understandably intended for modifying G only. (and do not provide roomId or player metadata)

I'm not sure what the solution is here, but maybe something like the redux enhancer for client side could exist in server-side as an effective way of triggering side-effects as games progress?

Ideally we'd have access to the RoomId that changed, what changed in it, and the player metadata of those currently involved.

delucis commented 4 years ago

Thanks for laying out the details @jabza.

There are two different states to listen for changes in: metadata (players joining/leaving, room created etc.) and the actual game state.

Game State

For game state, we would probably need to add a hook/callback in the game master. For example, we currently do this to check if the game is over and if we should update the metadata:

https://github.com/boardgameio/boardgame.io/blob/b2d6b067d6d737406484a648b6697c8d1443570e/src/master/master.ts#L293-L303

Room ID, action, old & new state are all available here. It wouldn’t offer fine-grained game events, but it would permit the basic functionality you’re looking for I think.

Metadata

For metadata changes, we might hook something into the REST API code, that could be called for each successful request.


Is this something you’d be interested in working on? I’d be happy to provide pointers and answer any questions you might have.

jabza commented 4 years ago

Hey @delucis

Thanks for the reply.

In haste, I ended up taking a more low-level approach. I created a new StorageAPI.Async db class that includes EventEmitter, effectively acting as a 'man-in-the-middle'. This is great for me, but I've no idea if this a solution wanted for master.

Ideally having StorageAPI.Async inherit EventEmitter would be cleaner, but I'm using composition for now.

Cheers

delucis commented 4 years ago

Nice! I actually thought about something like that too — glad it’s working for you for now.

janKir commented 4 years ago

@jabza I am also interested in this functionality. Could you share your implementation? Maybe we could create a package that would be used as middleware (like the cache storage adapter)?

delucis commented 3 years ago

For reference, if anyone’s looking for a quick solution, here’s an example of extending a database implementation to do some extra work when the game ends: https://gist.github.com/delucis/53803fedb036f778e8a991bb9e07b388

A similar approach would cover many use cases — extend the createMatch method for game start events, setMetadata for match metadata changes, setState for all other types of state changes.