{"id":72537,"date":"2019-11-06T04:17:50","date_gmt":"2019-11-06T11:17:50","guid":{"rendered":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/"},"modified":"2019-11-06T04:17:50","modified_gmt":"2019-11-06T11:17:50","slug":"writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4","status":"publish","type":"post","link":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/","title":{"rendered":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)"},"content":{"rendered":"<link rel=\"canonical\" href=\"https:\/\/www.smashingmagazine.com\/2019\/11\/multiplayer-text-adventure-engine-node-js-part-4\/\"><title>Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)<\/title><\/p>\n<article>\n<header>\n<h1>Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)<\/h1>\n<address>Fernando Doglio<\/address>\n<p>                  <time datetime=\"2019-11-06T11:00:00+02:00\">2019-11-06T11:00:00+02:00<\/time><time datetime=\"2019-11-06T11:00:00+02:00\">2019-11-06T11:06:58+00:00<\/time><\/header>\n<p>Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow) talk to each other. That is exactly why our text-adventure engine built in Node.js would not be complete without a way for the party members to be able to communicate with each other. And because this is indeed a <em>text<\/em> adventure, that form of communication will be presented in the form of a chat window.<\/p>\n<p>So in this article, I\u2019m going to explain how I added chat support for the text client as well as how I designed a quick chat server using Node.js.<\/p>\n<div>\n<h4>Previous Parts Of This Series<\/h4>\n<\/p>\n<ul>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2018\/12\/multiplayer-text-adventure-engine-node-js\/\">Part 1<\/a>: The Introduction<\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2019\/10\/multiplayer-text-adventure-engine-node-js-part-2\/\">Part 2<\/a>: Game Engine Server Design<\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2019\/10\/multiplayer-text-adventure-engine-node-js-part-3\/\">Part 3<\/a>: Creating The Terminal Client<\/li>\n<\/ul>\n<\/div>\n<h3>Back To The Original Plan<\/h3>\n<p>Lack of design skills aside, this has been the original wireframe\/mock-up for the text-based client we built in the previous part of the series:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png?ssl=1\"><\/p>\n<p>    <img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"https:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/ui-wireframe.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/ui-wireframe.png?w=900&#038;ssl=1\" sizes=\"100vw\" alt=\"\"><\/a><figcaption>\n      (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05bd43e7-5f3c-48aa-b837-fad3bd2d9001\/ui-wireframe.png\">Large preview<\/a>)<br \/>\n    <\/figcaption><\/figure>\n<p>The right side of that image is meant for inter-player communications, and it\u2019s been planned as a chat since the beginning. Then, during the development of this particular module (the text client), I managed to simplify it into the following:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png?ssl=1\"><\/p>\n<p>    <img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"https:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/client-ss2.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/client-ss2.png?w=900&#038;ssl=1\" sizes=\"100vw\" alt=\"\"><\/a><figcaption>\n      (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/05b17fad-3c2c-46e1-9a86-bf5782fcad70\/client-ss2.png\">Large preview<\/a>)<br \/>\n    <\/figcaption><\/figure>\n<p>Yes, we already covered this image in the previous installment but our focus was the left half. Today, however, our focus will be on the right half of what you\u2019re seeing there. In other words:<\/p>\n<ul>\n<li>Adding the ability to reactively pull data from a third-party service and update a content window.<\/li>\n<li>Adding support to the command interface for chat commands. Essentially changing the way commands work out of the box and adding support for things, such as \u201csending a message to the rest of the team\u201d.<\/li>\n<li>Create a basic chat server on the back-end that can facilitate team communication.<\/li>\n<\/ul>\n<p>Let me start with the last one before moving on to how to modify our existing code.<\/p>\n<div data-component=\"FeaturePanel\" data-audience=\"non-subscriber\" data-remove=\"true\"><\/div>\n<h3>Creating The Chat Server<\/h3>\n<p>Before even looking at any code, one of the first things one should do is to quickly define the scope of any new project. Particularly with this one, we need to make sure we don\u2019t spend a  lot of time working on features we might not need for our particular use case.<\/p>\n<p>You see, all we need is for the party members to be able to send messages with each others, but when one thinks of a \u201cchat server\u201d, other features often come in mind (such as chat rooms, private messages, emojis and so on).<\/p>\n<p>So in order to keep our work manageable and get something out that works, here is what the chat server module will actually do:<\/p>\n<ul>\n<li>Allow for a single room per party. Meaning, the actual room for a party will be auto-created when the game itself is created and the first player starts playing. All subsequent party members will join the same room, automatically and without a choice.<\/li>\n<li>There will not be support for private messages. There is no need to be secretive in your party. At least not in this first version.<br \/>\nUsers will only be able to send messages through the chat, nothing else.<\/li>\n<li>And to make sure everyone is aware, the only notification sent to the entire party, will be when new players join the game. That\u2019s all.<\/li>\n<\/ul>\n<p>The following diagram shows the communication between servers and clients. As I mentioned, the mechanics are quite simple, so the most important bit to highlight here is the fact that we\u2019re keeping conversations contained within the same party members:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png?ssl=1\"><\/p>\n<p>    <img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"https:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/chat-comms.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/chat-comms.png?w=900&#038;ssl=1\" sizes=\"100vw\" alt=\"\"><\/a><figcaption>\n      (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/8cd1a12e-3541-48d8-ba84-b5b08169ae0d\/chat-comms.png\">Large preview<\/a>)<br \/>\n    <\/figcaption><\/figure>\n<h3>The Tools For The Job<\/h3>\n<p>Given the above restrictions and the fact that all we need is a direct connection between the clients and the chat server, we\u2019ll solve this problem with an old fashion socket. Or in other words, the main tool we\u2019ll be using is <a href=\"https:\/\/socket.io\/\">socket.io<\/a> (note that there are 3rd party services providing managed chat servers, for instance, but for the purposes of this, going there would the equivalent of killing a mosquito with a shotgun).<\/p>\n<p>With <em>socket.io<\/em> we can establish a bidirectional, real-time,  event-based communication between the server and the clients. Unlike what we did with the game engine, where we published a REST API, the socket connection provides a faster way of communication.<\/p>\n<p>Which is exactly what we need, a quick way to connect clients and server, exchanging messages and sending broadcasts between them.<\/p>\n<div><\/div>\n<h4>Designing A Chat Server<\/h4>\n<p>Although socket.io is quite magical when it comes to socket management, it\u2019s not a full chat server, we still need to define some logic to use it.<\/p>\n<p>For our particularly small list of features, the design of our server\u2019s internal logic should look something like this:<\/p>\n<ul>\n<li>The server will need to support at least two different event types:\n<ol>\n<li><strong>New message<\/strong><br \/>This one is obvious, we need to know when a new message from a client is received, so we\u2019ll need support for this type of event.<\/li>\n<li><strong>New user joined<\/strong><br \/>We\u2019ll need this one just to make sure we can notify the entire party when a new user joins the chat room.<\/li>\n<\/ol>\n<\/li>\n<li>Internally, we\u2019ll handle chat rooms, even though that concept will not be something public to clients. Instead, all they will send is the game ID (the ID players use to join the game). With this ID we\u2019ll use socket.io\u2019s rooms feature which handles individual rooms for us.<\/li>\n<li>Because of how socket.io works, it keeps an in-memory session open that is automatically assigned to the socket created for each client. In other words, we have a variable automatically assigned to each individual client where we can store information, such as player names, and room assigned. We\u2019ll be using this socket-session to handle some internal client-room associations.<\/li>\n<\/ul>\n<h5>A Note About In-Memory Sessions<\/h5>\n<p>In-memory storage is not always the best solution. For this particular example, I\u2019m going with it because it simplifies the job. That being said, a good and easy improvement you could implement if you wanted to take this into a production-ready product would be to substitute it with a <a href=\"http:\/\/www.redis.io\/\">Redis<\/a> instance. That way you keep the in-memory performance but add an extra layer of reliability in case something goes wrong and your process dies.<\/p>\n<p>With all of that being said, let me show you the actual implementation.<\/p>\n<h4>The Implementation<\/h4>\n<p>Although the full project can be seen on <a href=\"https:\/\/github.com\/deleteman\/tardis-project-chatserver\">GitHub<\/a>, the most relevant code lies in the main file (<em>index.js<\/em>):<\/p>\n<div>\n<pre><code>\/\/ Setup basic express server\nlet express = require('express');\nlet config = require(\"config\")\nlet app = express();\nlet server = require('http').createServer(app);\nlet io = require('socket.io')(server);\nlet port = process.env.PORT || config.get('app.port');\n\nserver.listen(port, () => {\n  console.log('Server listening at port %d', port);\n});\n\nlet numUsers = 0;\n\n\nio.on('connection', (socket) => {\n  let addedUser = false;\n\n  \/\/ when the client emits 'new message', this listens and executes\n  socket.on(config.get('chat.events.NEWMSG'), (data, done) => {\n    let room = socket.roomname\n    if(!socket.roomname) {\n        socket.emit(config.get('chat.events.NEWMSG'), \"You're not part of a room yet\")\n        return done()\n    }\n\n    \/\/ we tell the client to execute 'new message'\n    socket.to(socket.roomname).emit(config.get('chat.events.NEWMSG'), {\n      room: room,\n      username: socket.username,\n      message: data\n    });\n    done()\n  });\n\n  socket.on(config.get('chat.events.JOINROOM'), (data, done) => {\n      console.log(\"Requesting to join a room: \", data)\n\n      socket.roomname = data.roomname\n      socket.username = data.username\n      socket.join(data.roomname, _ => {\n          socket.to(data.roomname).emit(config.get('chat.events.NEWMSG'), {\n            username: 'Game server',\n            message: socket.username + ' has joined the party!'\n          })\n          done(null, {joined: true})\n      })\n  })\n\n  \/\/ when the user disconnects.. perform this\n  socket.on('disconnect', () => {\n    if (addedUser) {\n      --numUsers;\n\n      \/\/ echo globally that this client has left\n      socket.to(socket.roomname).emit('user left', {\n        username: socket.username,\n        numUsers: numUsers\n      });\n    }\n  });\n});<\/code><\/pre>\n<\/div>\n<p>That is all there is for this particular server. Simple right? A couple of notes:<\/p>\n<ol>\n<li>I\u2019m using the <a href=\"https:\/\/www.npmjs.com\/package\/config\">config module<\/a> to handle all my constants. I personally love this module, it simplifies my life every time I need to keep \u201cmagic numbers\u201d out of my code. So everything from the list of accepted messages to the port the server will listen to are stored and accessed through it.<\/li>\n<li>There are two main events to pay attention to, just like I said before.\n<ul>\n<li>When a new message is received, which can be seen when we listen for <code>config.get('chat.events.NEWMSG')<\/code>. This code also makes sure you don\u2019t accidentally try to send a message before joining a room. This shouldn\u2019t happen if you implement the chat client correctly, but just in case these type of checks are always helpful when others are writing the clients for your services.<\/li>\n<li>When a new user joins a room. You can see that event on the <code>config.get('chat.events.JOINROOM')<\/code> listener. In that case, all we do is add the user to the room (again, this is handled by socket.io, so all it takes is a single line of code) and then we broadcast to the room a message notifying who just joined. The key here is that by using the socket instance of the player joining, the broadcast will be sent to everyone in the room <em>except<\/em> the player. Again, behavior provided by <em>socket.io<\/em>, so  we don\u2019t have to add this in.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>That is all there is to the server code, let\u2019s now review how I integrated the client-side code into the text-client project.<\/p>\n<div><\/div>\n<h3>Updating The Client Code<\/h3>\n<p>In order to integrate both, chat commands and game commands, the input box at the bottom of the screen will have to parse the player\u2019s input and decide on what they\u2019re trying to do.<\/p>\n<p>The rule is simple: If the player is trying to send a message to the party, they\u2019ll start the command with the word \u201cchat\u201d, otherwise, they won\u2019t.<\/p>\n<h4>What Happens When Sending A Chat Message?<\/h4>\n<p>The following list of actions takes place when the user hits the ENTER key:<\/p>\n<ol>\n<li>Once a chat command is found, the code will trigger a new branch, where a chat client library will be used and a new message will be sent (emitted through the active socket connection) to the server.<\/li>\n<li>The server will emit the same message to all other players in the room.<\/li>\n<li>A callback (setup during boot-time) listening for new events from the server will be triggered. Depending on the event type (either a player sent a message, or a player just joined), we\u2019ll display a message on the chat box (i.e the text box on the right).<\/li>\n<\/ol>\n<p>The following diagram presents a graphic representation of the above steps; ideally, it should help visualize which components are involved in this process:<\/p>\n<figure><a href=\"https:\/\/i0.wp.com\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png?ssl=1\"><\/p>\n<p>    <img data-recalc-dims=\"1\" decoding=\"async\" srcset=\"https:\/\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/client-chat.png 400w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_800\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png 800w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1200\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png 1200w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_1600\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png 1600w,\n\t\t\t        https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_auto\/w_2000\/https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png 2000w\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/client-chat.png?w=900&#038;ssl=1\" sizes=\"100vw\" alt=\"\"><\/a><figcaption>\n      (<a href=\"https:\/\/cloud.netlifyusercontent.com\/assets\/344dbf88-fdf9-42bb-adb4-46f01eedd629\/68c9b316-d791-4a1d-bfd6-c018e58658bf\/client-chat.png\">Large preview<\/a>)<br \/>\n    <\/figcaption><\/figure>\n<h4>Reviewing The Code Changes<\/h4>\n<p>For a full list of changes and the entire code working, you should check the full <a href=\"https:\/\/github.com\/deleteman\/tardis-project-client\">repository on Github<\/a>. Here, I\u2019m quickly going to glance over some of the most relevant bits of code.<\/p>\n<p>For example, setting up the main screen is where we now trigger the connection with the chat server and where we configure the callback for updating the chat box (red box on the top from the diagram above).<\/p>\n<div>\n<pre><code>setUpChatBox: function() {\n        let handler = require(this.elements[\"chatbox\"].meta.handlerPath)\n        handler.handle(this.UI.gamestate, (err, evt) => {\n            if(err) {\n                this.UI.setUpAlert(err)    \n                return this.UI.renderScreen()\n            }\n\n            if(evt.event == config.get('chatserver.commands.JOINROOM')) {\n                this.elements[\"chatbox\"].obj.insertBottom([\"::You've joined the party chat room::\"])\n                this.elements[\"chatbox\"].obj.scroll((config.get(\"screens.main-ui.elements.gamebox.autoscrollspeed\") ) + 1)\n            }\n            if(evt.event == config.get('chatserver.commands.SENDMSG')) {\n                this.elements[\"chatbox\"].obj.insertBottom([evt.msg.username + ' said :> ' + evt.msg.message])\n                this.elements[\"chatbox\"].obj.scroll((config.get(\"screens.main-ui.elements.gamebox.autoscrollspeed\") ) + 1)\n            }\n            this.UI.renderScreen()\n        })\n\n    },<\/code><\/pre>\n<\/div>\n<p>This method gets called from the init method, just like everything else. The main function for this code is to use the assigned handler (the chatbox handler) and call it\u2019s <em>handle<\/em> method, which will connect to the chat server, and afterwards, setup the callback (which is also defined here) to be triggered when something happens (one of the two events we support).<\/p>\n<p>The interesting logic from the above snippet is inside the callback, because it\u2019s the logic used to update the chat box.<\/p>\n<p>For completeness sake, the code that connects to the server and configures the callback shown above is the following:<\/p>\n<div>\n<pre><code>const io = require('socket.io-client'),\n    config = require(\"config\"),\n    logger = require(\"..\/utils\/logger\")\n\n\n\/\/ Use https or wss in production.\nlet url = config.get(\"chatserver.url\") \nlet socket = io(url)\n\n\nmodule.exports = {\n\n    connect2Room: function(gamestate, done) {\n        socket.on(config.get('chatserver.commands.SENDMSG'), msg => {\n            done(null, {\n                event: config.get('chatserver.commands.SENDMSG'),\n                msg: msg\n            })     \n        })\n        socket.emit(config.get(\"chatserver.commands.JOINROOM\") , {\n            roomname: gamestate.gameID,\n            username: gamestate.playername\n        }, _ => {\n            logger.info(\"Room joined!\")\n            gamestate.inroom = true\n            done(null, {\n                event: config.get('chatserver.commands.JOINROOM')\n            })\n        })\n        \n    },\n\n   handleCommand: function(command, gamestate, done) {\n        logger.info(\"Sending command to chatserver!\")\n        \n        let message = command.split(\" \").splice(1).join(\" \")\n\n        logger.info(\"Message to send: \", message)\n\n        if(!gamestate.inroom) { \/\/first time sending the message, so join the room first\n            logger.info(\"Joining a room\")\n            let gameId = gamestate.game\n            \n    socket.emit(config.get(\"chatserver.commands.JOINROOM\") , {\n                roomname: gamestate.gameID,\n                username: gamestate.playername\n            }, _ => {\n                logger.info(\"Room joined!\")\n                gamestate.inroom = true\n                updateGameState = true\n\n                logger.info(\"Updating game state ...\")\n                socket.emit(config.get(\"chatserver.commands.SENDMSG\"), message, done)\n            })\n        } else {\n            logger.info(\"Sending message to chat server: \", message  )\n            socket.emit(config.get(\"chatserver.commands.SENDMSG\"), message, done)\n        }\n            \n    }\n}<\/code><\/pre>\n<\/div>\n<p>The <code>connect2room<\/code> method is the one called during setup of the main screen as I mentioned, you can see how we set up the handler for new messages and emit the event related to joining a room (which then triggers the same event being broadcasted to other players on the server-side).<\/p>\n<p>The other method, <code>handleCommand<\/code> is the one that takes care of sending the chat message to the server (and it does so with a simple <code>socket.emit<\/code>). This one is executed when the <code>commandHandler<\/code> realizes a chat message is being sent. Here is the code for that logic:<\/p>\n<div>\n<pre><code>module.exports = {\n    handle: function(gamestate, text, done) {\n        let command = text.trim()\n        if(command.indexOf(\"chat\") === 0) { \/\/chat command\n            chatServerClient.handleCommand(command, gamestate, done)\n        } else {\n            sendGameCommand(gamestate, text, done)\n        }     \n    }\n}<\/code><\/pre>\n<\/div>\n<p>That is the new code for the commandHandler, the sendGameCommand function is where the old code now is encapsulated (nothing changed there).<\/p>\n<p>And that is it for the integration, again, fully working code can be downloaded and tested from the <a href=\"https:\/\/github.com\/deleteman\/tardis-project-client\">full repository<\/a>.<\/p>\n<h3>Final Thoughts<\/h3>\n<p>This marks the end of the road for this project. If you stuck to it until the end, thanks for reading! The code is ready to be tested and played with, and if you happen to do so, please reach out and let me know what you thought about it.<\/p>\n<p>Hopefully with this project, many old-time fans of the genre can get back to it and experience it in a way they never did.<\/p>\n<p>Have fun playing (and coding)!<\/p>\n<h4><span>Further Reading<\/span> on SmashingMag:<\/h4>\n<ul>\n<li><a title=\"Read 'Building A Pub\/Sub Service In-House Using Node.js And Redis'\" href=\"https:\/\/www.smashingmagazine.com\/2018\/06\/pub-sub-service-in-house-node-js-redis\/\" rel=\"bookmark\">Building A Pub\/Sub Service In-House Using Node.js And Redis<\/a><\/li>\n<li><a title=\"Read 'Building A Node.js Express API To Convert Markdown To HTML'\" href=\"https:\/\/www.smashingmagazine.com\/2019\/04\/nodejs-express-api-markdown-html\/\" rel=\"bookmark\">Building A Node.js Express API To Convert Markdown To HTML<\/a><\/li>\n<li><a title=\"Read 'Get Started With Node: An Introduction To APIs, HTTP And ES6+ JavaScript'\" href=\"https:\/\/www.smashingmagazine.com\/2019\/02\/node-api-http-es6-javascript\/\" rel=\"bookmark\">Get Started With Node: An Introduction To APIs, HTTP And ES6+ JavaScript<\/a><\/li>\n<li><a title=\"Read 'Keeping Node.js Fast: Tools, Techniques, And Tips For Making High-Performance Node.js Servers'\" href=\"https:\/\/www.smashingmagazine.com\/2018\/06\/nodejs-tools-techniques-performance-servers\/\" rel=\"bookmark\">Keeping Node.js Fast: Tools, Techniques, And Tips For Making High-Performance Node.js Servers<\/a><\/li>\n<\/ul>\n<div>\n  <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/logo-red-5.png?w=900&#038;ssl=1\" alt=\"Smashing Editorial\"><span>(dm, yk, il)<\/span>\n<\/div>\n<\/article>\n<p class=\"wpematico_credit\"><small>Powered by <a href=\"http:\/\/www.wpematico.com\" target=\"_blank\" rel=\"noopener noreferrer\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00 Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players&#8230;<a class=\"moretag\" href=\"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/\"> Read the full article&#8230;<\/a><\/p>\n","protected":false},"author":4,"featured_media":72538,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[371],"tags":[],"class_list":["post-72537","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-user-experience"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Guest Contribution\"\/>\n\t<meta name=\"keywords\" content=\"user experience\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Design for Immersive Technologies | User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies\" \/>\n\t\t<meta property=\"og:description\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-06T11:17:50+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-11-06T11:17:50+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#article\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies\",\"headline\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)\",\"author\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/www.taterboy.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/11\\\/ui-wireframe.png?fit=400%2C283&ssl=1\",\"width\":400,\"height\":283},\"datePublished\":\"2019-11-06T04:17:50-07:00\",\"dateModified\":\"2019-11-06T04:17:50-07:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#webpage\"},\"articleSection\":\"User Experience\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.taterboy.com\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"name\":\"User Experience\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"position\":2,\"name\":\"User Experience\",\"item\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#listItem\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#listItem\",\"position\":3,\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/category\\\/user-experience\\\/#listItem\",\"name\":\"User Experience\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\",\"name\":\"Design for Immersive Technologies\",\"description\":\"User Experience for Games, Virtual Reality (VR) and Augmented\\\/Mixed Reality (AR\\\/MR)\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/\",\"name\":\"Guest Contribution\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d2aad73eb0f48c67b141e9fc978a0e498969791ed623346e361d02d19775b0bb?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Guest Contribution\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#webpage\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies\",\"description\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/author\\\/guestcontribution\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/www.taterboy.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/11\\\/ui-wireframe.png?fit=400%2C283&ssl=1\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#mainImage\",\"width\":400,\"height\":283},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/11\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\\\/#mainImage\"},\"datePublished\":\"2019-11-06T04:17:50-07:00\",\"dateModified\":\"2019-11-06T04:17:50-07:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/\",\"name\":\"Design for Immersive Technologies\",\"description\":\"User Experience for Games, Virtual Reality (VR) and Augmented\\\/Mixed Reality (AR\\\/MR)\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies","description":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)","canonical_url":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/","robots":"max-image-preview:large","keywords":"user experience","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#article","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies","headline":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)","author":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"publisher":{"@id":"https:\/\/www.taterboy.com\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/ui-wireframe.png?fit=400%2C283&ssl=1","width":400,"height":283},"datePublished":"2019-11-06T04:17:50-07:00","dateModified":"2019-11-06T04:17:50-07:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#webpage"},"isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#webpage"},"articleSection":"User Experience"},{"@type":"BreadcrumbList","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog#listItem","position":1,"name":"Home","item":"https:\/\/www.taterboy.com\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","name":"User Experience"}},{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","position":2,"name":"User Experience","item":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#listItem","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#listItem","position":3,"name":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)","previousItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/#listItem","name":"User Experience"}}]},{"@type":"Organization","@id":"https:\/\/www.taterboy.com\/blog\/#organization","name":"Design for Immersive Technologies","description":"User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","url":"https:\/\/www.taterboy.com\/blog\/"},{"@type":"Person","@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author","url":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/","name":"Guest Contribution","image":{"@type":"ImageObject","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/d2aad73eb0f48c67b141e9fc978a0e498969791ed623346e361d02d19775b0bb?s=96&d=mm&r=g","width":96,"height":96,"caption":"Guest Contribution"}},{"@type":"WebPage","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#webpage","url":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies","description":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#breadcrumblist"},"author":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"creator":{"@id":"https:\/\/www.taterboy.com\/blog\/author\/guestcontribution\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/ui-wireframe.png?fit=400%2C283&ssl=1","@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#mainImage","width":400,"height":283},"primaryImageOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/#mainImage"},"datePublished":"2019-11-06T04:17:50-07:00","dateModified":"2019-11-06T04:17:50-07:00"},{"@type":"WebSite","@id":"https:\/\/www.taterboy.com\/blog\/#website","url":"https:\/\/www.taterboy.com\/blog\/","name":"Design for Immersive Technologies","description":"User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","inLanguage":"en-US","publisher":{"@id":"https:\/\/www.taterboy.com\/blog\/#organization"}}]},"og:locale":"en_US","og:site_name":"Design for Immersive Technologies | User Experience for Games, Virtual Reality (VR) and Augmented\/Mixed Reality (AR\/MR)","og:type":"article","og:title":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies","og:description":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)","og:url":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/","article:published_time":"2019-11-06T11:17:50+00:00","article:modified_time":"2019-11-06T11:17:50+00:00","twitter:card":"summary","twitter:title":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) | Design for Immersive Technologies","twitter:description":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4) Fernando Doglio 2019-11-06T11:00:00+02:002019-11-06T11:06:58+00:00Any platform that allows for collaborative play between people will be required to have one very particular characteristic: the ability for players to (somehow)"},"aioseo_meta_data":{"post_id":"72537","title":null,"description":null,"keywords":null,"keyphrases":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_custom_image_width":null,"og_custom_image_height":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"created":"2021-02-07 16:59:12","updated":"2026-09-02 10:29:30","focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"primary_term":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"twitter_image_url":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"limit_modified_date":false,"ai":null,"breadcrumb_settings":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.taterboy.com\/blog\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/\" title=\"User Experience\">User Experience<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tWriting A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.taterboy.com\/blog"},{"label":"User Experience","link":"https:\/\/www.taterboy.com\/blog\/category\/user-experience\/"},{"label":"Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 4)","link":"https:\/\/www.taterboy.com\/blog\/2019\/11\/writing-a-multiplayer-text-adventure-engine-in-node-js-adding-chat-into-our-game-part-4\/"}],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8wzr5-iRX","jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/11\/ui-wireframe.png?fit=400%2C283&ssl=1","_links":{"self":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/72537","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/comments?post=72537"}],"version-history":[{"count":0,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/72537\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media\/72538"}],"wp:attachment":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media?parent=72537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/categories?post=72537"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/tags?post=72537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}