@gameroom-js/server
Overview
A simple library for Node.JS that allows you to rapidly develop stateful, socketed multiplayer games and web applications. For use in conjunction with the client library @gameroom-js/client.
The three main classes in the gameroom-js server library are GameRoom
, ConnectionController
, and ClientController
.
Quickstart
Server.ts
import express from "express";
import { ConnectionController } from "@gameroom-js/server";
import { MyGameRoom } from './MyGameRoom'
const app = express();
const server = app.listen(3000);
const connection = new ConnectionController(server);
const defaultGameRoom = new MyGameRoom({ gameRoomID: "Lobby" });
connection.registerGameRoom(defaultGameRoom);
GameRoom
GameRoom
is defined as an abstract class. In order to use it in your game or application, you need to extend it by writing your own subclass which extends it. In doing so, you'll include your own custom logic by adding class properties, methods, and registering listeners.
Extending GameRoom
MyGameRoom.ts
import { GameRoom, GameRoomOptions } from "@gameroom-js/server";
export interface MyGameRoomOptions extends GameRoomOptions {}
export interface MyRoomState {}
export interface MyGameState {}
export class MyGameRoom extends GameRoom {
constructor(options: MyGameRoomOptions) {
super(options)
}
async onCreate(): Promise<void> {
this.onProtocol(protocolType, listener);
this.onAction(actionType, listener);
this.onTransfer(transferType, listener);
this.onEvent(eventName, listener);
}
async onAuth(): Promise<void> {}
async onJoin(): Promise<void> {}
async onJoined(): Promise<void> {}
async onLeave(): Promise<void> {}
async onDispose(): Promise<void> {}
getRoomState(): MyRoomState {}
getGameState(): MyGameState {}
The GameRoomOptions
interface is defined as follows:
export interface GameRoomOptions {
gameRoomID?: string;
autoDispose?: boolean;
}
Events and Listeners
There are four types of events that your GameRoom
class can listen for. Protocol
, Action
, and Transfer
are sent by the client. Event
is used internally within the GameRoom
and can also be accessed by other parts of the application. (For example, a REST API that also needs to make changes to or access the state of the game.)
All of these listeners should be registered during the onCreate
lifecycle method, implemented in your custom GameRoom
class:
MyGameRoom.ts
async onCreate(): Promise<void> {
this.onProtocol(protocolType, listener);
this.onAction(actionType, listener);
this.onTransfer(transferType, listener);
this.onEvent(eventName, listener);
}
Events from the client
The gameroom-js client can send three types of event: Protocol
, Action
, and Transfer
.
Protocol
is an event meant to communicate with the server for purposes of handshaking,authentication, or information requests that are separate from game logic. Event includes a protocolType
string. Protocol
event listeners are registered via the onProtocol(protocolType, listener)
method.Action
is an event meant to communicate user interactions to the server. Button presses, clicks, and other interactions with the game or application should be sent as action events. Event includes a actionType
string. Action
event listeners are registered via the onAction(actionType, listener)
method.Transfer
is an event that communicates a piece of information (serialized as a string) to the server. Event includes a transferType
string as well as a payload
string. Transfer
event listeners are registered via the onTransfer(transferType, listener)
method.
When handling the events via their respective methods, the clientController
which initiated the event is always sent to the listener as the first argument. This can be used to validate the event or to associate information with a particular client.
this.onProtocol("REQUEST_CLIENT_STATE", (client: ClientController) => {
client.send("updateClientState", client.getClientState());
});
this.onAction("nextTurnPressed", (client: ClientController) => {
if (client.getClientID() === this.playerWithTurn) {
this.advanceTurn();
}
});
this.onTransfer("updateClientName", (client: ClientController, newName: string) => {
this.updateClientName(client, newName);
});
Events from the server
The gameroom-js server communicates internally via an Event
system. Listeners are registered with the onEvent(eventName, listener)
method. Events
can be emitted via the emitEvent(eventName, ...args)
method.
Logic outside of the GameRoom
can also access these events. A good example of this might be if your game or application has a REST API that might need to send events to the GameRoom
:
const app = express();
const server = app.listen(3000);
const connection = new ConnectionController(server);
app.post("/nextTurn", (req, res) => {
const gameRoomID = req.body.gameRoomID;
const gameRoom = connection.getGameRoom(gameRoomID);
gameRoom.emitEvent("advanceTurn");
})
ConnectionController
The ConncectionController
class handles communication between sockets and game rooms. When instantiated, it requires a reference to an http server (such as one created by Express.JS or Koa). gameroom.js uses Socket.IO for websocket communication, so ConnectionController
optionally receives the Socket.IO ServerOptions
object.
Server.ts
import express from "express";
import { ConnectionController } from "@gameroom-js/server";
const app = express();
const server = app.listen(3000);
const connection = new ConnectionController(server, {pingTimeout: 10000});
The most important method of ConnectionController
is registerGameRoom(gameRoom)
, which registers a new GameRoom
and allows clients to connect to it.
Server.ts
const defaultGameRoom = new MyGameRoom({ gameRoomID: "Lobby" });
connection.registerGameRoom(defaultGameRoom);
ConnectionController
also has methods for getting references to game rooms that have already been registered.
getGameRooms()
returns an array of the gameRoomID
s of all registered game rooms.getGameRoom(gameRoomID)
returns the reference to the game room that matches the provided gameRoomID
. Returns undefined
if no matching game room is registered.
ClientController
The ClientController
class is an abstraction on top of the Socket.IO socket
instance. It can be extended if you wish to store state or add custom game/application logic, although this is not recommended. (We recommend finding a way to store individual player state with the rest of the GameState, and using an authentication system to reconnect new sockets to previous state.)
To send an event to an individual client, use the send(message, args, cb)
method.
You can get a client's id via the getClientID()
method.
If you are storing state in the ClientController
, you can get this information by extending and calling the getClientState()
method.