1 /* Base class providing common code for game engine implementations. */
5 this.next_client_id = 1;
8 /* Suport for game meta-data.
10 * What we want here is an effectively static field that is
11 * accessible through either the class name (SomeGame.meta) or an
12 * instance (some_game.meta). To pull this off we do keep two copies
13 * of the data. But the game classes can just set SomeGame.meta once
14 * and then reference it either way.
16 static set meta(data) {
17 /* This allows class access (SomeGame.meta) via the get method below. */
20 /* While this allows access via an instance (some_game.meta). */
21 this.prototype.meta = data;
28 add_client(response) {
29 const id = this.next_client_id;
30 this.clients.push({id: id,
32 this.next_client_id++;
38 this.clients = this.clients.filter(client => client.id !== id);
41 /* Send a string to all clients */
42 broadcast_string(str) {
43 this.clients.forEach(client => client.response.write(str + '\n'));
46 /* Send an event to all clients.
48 * An event has both a declared type and a separate data block.
49 * It also ends with two newlines (to mark the end of the event).
51 broadcast_event(type, data) {
52 this.broadcast_string(`event: ${type}\ndata: ${data}\n`);
55 handle_events(request, response) {
56 /* These headers will keep the connection open so we can stream events. */
58 "Content-type": "text/event-stream",
59 "Connection": "keep-alive",
60 "Cache-Control": "no-cache"
62 response.writeHead(200, headers);
64 /* Add this new client to our list of clients. */
65 const id = this.add_client(response);
67 /* And queue up cleanup to be triggered on client close. */
68 request.on('close', () => {
69 this.remove_client(id);
75 module.exports = Game;