Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Node.js and Mongodb building blocks for your ne...

mongodb
April 24, 2012
340

Node.js and Mongodb building blocks for your next HTML5 game

MongoDB Stockholm 2012
Christian Kvalhem, Software Engineer, 10gen

Have you always wanted to learn how to rewrite your own HTML5 retro game using Node.js and MongoDB with a multiplayer twist to it. Come play the game, learn how it was made and fork it.

mongodb

April 24, 2012
Tweet

Transcript

  1. Gaming and HTML5 •Space is moving fast •Canvas/WebGL getting better

    and better •Lot’s of libraries but Zynga and Disney keeps buying the good ones Tuesday, April 24, 12
  2. Challenges •Latency, Latency, Latency •Spend minimal time in the Eventloop

    •Process locality on server Tuesday, April 24, 12
  3. Technology •Node.JS •Akihabara for game engine •SoundJS for the audio

    •websocket npm package •Socket.IO was to slow •Binary frames only on Chrome +Firefox 11 •Mongo capped collections •BSON parser in the browser Tuesday, April 24, 12
  4. Akihabara •Retro 2D game engine •“Simple” to adapt example game

    to Mongoman •Uses canvas only so not the fastest game engine out there but plenty good enough :) Tuesday, April 24, 12
  5. Websocket npm package •Pure websocket implementation •No fallback compatibility •Supports

    binary frame protocol for Websockets •Fast Tuesday, April 24, 12
  6. SoundJS •Manages all the complexity of audio in the browser

    •Mixes audio •Simple to use API Tuesday, April 24, 12
  7. Mongo Capped collections •Positives •In memory only •Fifo based limiting

    memory exposure •Predictable time to write/read from collection •Supports Indexes •Tailable (like tail -f) Tuesday, April 24, 12
  8. Mongo Capped collections •Negatives •Documents cannot grow so need to

    prime each document •No single server persistence, server dies game gone. Tuesday, April 24, 12
  9. BSON Parser •Initial version (wait to use) •Supports node.js Buffers

    •Support Browser Uint8Array and Array •Plenty fast deserialization Tuesday, April 24, 12
  10. Node.JS •Express serves up the basic html pages and handles

    the hiscore list. •Organized using the cluster api in Node.js 0.6.X •1 parent process and X child processes handling game •If a child dies get’s restarted Tuesday, April 24, 12
  11. Cluster code // Fork workers (one pr. cpu), the web

    workers handle the websockets for (var i = 0; i < numCPUs; i++) { var worker = cluster.fork(); worker.on('message', function(msg) { if(msg != null && msg['cmd'] == 'online') { console.log("================================ worker online"); console.dir(msg); } }); } // If the worker thread dies just print it to the console and for a new one cluster.on('death', function(worker) { console.log('worker ' + worker.pid + ' died'); cluster.fork(); }); Tuesday, April 24, 12
  12. Session workaround •Could not use express sessions as they don’t

    work with the websocket module •Wrote own session handling using capped collection •A bit HACKY bit works Tuesday, April 24, 12
  13. Websocket session grab code // Parse the cookie var cookie

    = connectUtils.parseCookie(request.httpRequest.headers['cookie']); // Grab the session id var sessionId = cookie['connect.sid']; // Grab the username based on the session id and initialize the board state.sessionsCollection.findOne({id:sessionId}, function(err, session) { if(err) throw err; session = typeof session == 'undefined' || session == null ? {} : session; initializeBoard(state, session, self); }) •Uses connect npm package for nice to have cookie parser functions •Using capped collection aswell Tuesday, April 24, 12
  14. .findAndModify( {number_of_players: {$lt:5}, pid: process.pid}, [], {$inc: {number_of_players: 1}, $push:{players:connection.connectionId}},

    {new:true, upsert:false}, function(err, board) { // Code to deal with the board or the non existance of the board } Initializing a board •Using findAndModify to pick a board •Atomic operation to add player to existing board •Process bound Tuesday, April 24, 12
  15. One for all, all for one •Websocket connections are bound

    to a specific process •Avoids overhead •Would need separate IO queues Tuesday, April 24, 12
  16. Message passing •Non-frequent messages in JSON •intialize •ghost died •mongoman

    dies •game over •Frequent messages in Binary •Movement information Tuesday, April 24, 12
  17. // Binary message update player position state.gameCollection.update({id: self.connectionId}, message.binaryData); //

    Let's grab the record state.gameCollection.findOne({id: self.connectionId, state:'n'}, {raw:true}, function(err, rawDoc) { if(rawDoc) { // Retrieve the board by id from cache var boardId = state.boardIdByConnections[self.connectionId]; var board = state.connectionsByBoardId[boardId]; // Send the data to all the connections expect the originating connection for(var i = 0; i < board.length; i++) { if(board[i] != self.connectionId) { if(state.connections[board[i]] != null) state.connections[board[i]].sendBytes(rawDoc); } } } }); Binary message passing •BSON de/serialization in the browser for movement. Raw mode queries. Tuesday, April 24, 12
  18. Client side processing •Using BSON parser •Available soon, Uint8Array and

    Array support. // Serialize a message BSON.serialize({'$set': {'pos': updateObject}}, false, true, false) // Handle the web socket messages GameCommunication.prototype.handleWebsocketMessage = function(message) { // Let's handle the message, deserializing it as needed if(message.data instanceof ArrayBuffer) { this.callback(BSON.deserialize(new Uint8Array(message.data))); } else { this.callback(JSON.parse(message.data)); } } Tuesday, April 24, 12
  19. Justification •Decrease latency by avoiding •Deserialize BSON on Server •Serialize

    BSON to JSON on Server •Deserialize JSON to Object on Client •Just Deserialize once on client •Less time spent in the EventLoop Tuesday, April 24, 12
  20. Light speed that #@!@#$ •Your max resolution is 2X times

    the ping time to the server •20ms = 40 ms delivery = 25 fps •135 = 270 ms delivery = 4 fps •No you know why it’s a WOW EU server or US server Tuesday, April 24, 12
  21. •Websockets still fresh •Few browsers support binary •Latency is the

    mind killer •If you users are in Germany have a local server for Germany •Hard to test games, time consuming •Anybody know a good test framework tell me :) Tuesday, April 24, 12
  22. What’s coming for you •Finishing up BSON NPM package •Making

    single BSON file both in normal and minified version for browsers •Some way to link directly to the latest one like JQuery. Tuesday, April 24, 12
  23. Demo game •Join in the game, DDOS My laptop point

    your Chrome or Firefox 11+ browser to •165.225.128.82:3000 Tuesday, April 24, 12
  24. @mongodb conferences, appearances, and meetups http://www.10gen.com/events http://bit.ly/mongofb Facebook | Twitter

    | LinkedIn http://linkd.in/joinmongo download at mongodb.org support, training, and this talk brought to you by Tuesday, April 24, 12