{"id":72155,"date":"2019-10-24T04:15:27","date_gmt":"2019-10-24T11:15:27","guid":{"rendered":"http:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/"},"modified":"2019-10-24T04:15:27","modified_gmt":"2019-10-24T11:15:27","slug":"writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2","status":"publish","type":"post","link":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/","title":{"rendered":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)"},"content":{"rendered":"<link rel=\"canonical\" href=\"https:\/\/www.smashingmagazine.com\/2019\/10\/multiplayer-text-adventure-engine-node-js-part-2\/\"><title>Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)<\/title><\/p>\n<article>\n<header>\n<h1>Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)<\/h1>\n<address>Fernando Doglio<\/address>\n<p>                  <time datetime=\"2019-10-23T14:00:59+02:00\">2019-10-23T14:00:59+02:00<\/time><time datetime=\"2019-10-24T11:06:08+00:00\">2019-10-24T11:06:08+00:00<\/time><\/header>\n<p>After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should be a familiar scene for anyone who has ever worked with an eager client who dreams about an ideal product but needs to be restraint by the development team.<\/p>\n<p>Once features have been implemented and tested, your team will start noticing that some characteristics might differ from the original plan, and that\u2019s alright. Simply notify, adjust, and go on. So, without further ado, allow me to first explain what has changed from the <a href=\"https:\/\/www.smashingmagazine.com\/2018\/12\/multiplayer-text-adventure-engine-node-js\/\">original plan<\/a>.<\/p>\n<h4>Battle Mechanics<\/h4>\n<p>This is probably the biggest change from the original plan. I know I said I was going to go with a D&#038;D-esque implementation in which each PC and NPC involved would get an initiative value and after that, we would run a turn-based combat. It was a nice idea, but implementing it on a REST-based service is a bit complicated since you can\u2019t initiate the communication from the server side, nor maintain status between calls.<\/p>\n<p>So instead, I will take advantage of the simplified mechanics of REST and use that to simplify our battle mechanics. The implemented version will be player-based instead of party-based, and will allow players to attack NPCs (Non-Player Characters). If their attack succeeds, the NPCs will be killed or else they will attack back by either damaging or killing the player.<\/p>\n<p>Whether an attack succeeds or fails will be determined by the type of weapon used and the weaknesses an NPC might have. So basically, if the monster you\u2019re trying to kill is weak against your weapon, it dies. Otherwise, it\u2019ll be unaffected and \u2014 most likely \u2014 very angry.<\/p>\n<h4>Triggers<\/h4>\n<p>If you paid close attention to the JSON game definition from my <a href=\"https:\/\/www.smashingmagazine.com\/2018\/12\/multiplayer-text-adventure-engine-node-js\/\">previous article<\/a>, you might\u2019ve noticed the trigger\u2019s definition found on scene items. A particular one involved updating the game status (<code>statusUpdate<\/code>). During implementation, I realized having it working as a toggle provided limited freedom. You see, in the way it was implemented (from an idiomatic point of view), you were able to set a status but unsetting it wasn\u2019t an option. So instead, I\u2019ve replaced this trigger effect with two new ones: <code>addStatus<\/code> and <code>removeStatus<\/code>. These will allow you to define <em>exactly<\/em> when these effects can take place \u2014 if at all. I feel this is a lot easier to understand and reason about.<\/p>\n<p>This means that the triggers now look like this:<\/p>\n<pre><code>\"triggers\": [\n{\n    \"action\": \"pickup\",\n\"effect\":{\n    \"addStatus\": \"has light\",\n\"target\": \"game\"\n    }\n},\n{\n    \"action\": \"drop\",\n    \"effect\": {\n    \"removeStatus\": \"has light\",\n    \"target\": \"game\"\n    }\n}\n]<\/code><\/pre>\n<p>When picking up the item, we\u2019re setting up a status, and when dropping it, we\u2019re removing it. This way, having multiple game-level status indicators is completely possible and easy to manage.<\/p>\n<div data-component=\"FeaturePanel\" data-audience=\"non-subscriber\" data-remove=\"true\"><\/div>\n<h3>The Implementation<\/h3>\n<p>With those updates out of the way, we can start covering the actual implementation. From an architectural point of view, nothing changed; we\u2019re still building a REST API that will contain the main game engine\u2019s logic.<\/p>\n<h4>The Tech Stack<\/h4>\n<p>For this particular project, the modules I\u2019m going to be using are the following:<\/p>\n<table data-tablesaw-mode=\"swipe\" data-tablesaw-minimap>\n<thead>\n<tr>\n<th data-tablesaw-priority=\"persist\">Module<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/expressjs.com\/\">Express.js<\/a><\/td>\n<td>Obviously, I\u2019ll be using Express to be the base for the entire engine.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/www.npmjs.com\/package\/winston\">Winston<\/a><\/td>\n<td>Everything in regards to logging will be handled by Winston.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/www.npmjs.com\/package\/config\">Config<\/a><\/td>\n<td>Every constant and environment-dependant variable will be handled by the config.js module, which greatly simplifies the task of accessing them.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/www.npmjs.com\/package\/mongoose\">Mongoose<\/a><\/td>\n<td>This will be our ORM. I will model all resources using Mongoose Models and use that to interact directly with the database.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/www.npmjs.com\/package\/uuid\">uuid<\/a><\/td>\n<td>We\u2019ll need to generate some unique IDs \u2014 this module will help us with that task.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As for other technologies used aside from Node.js, we have <strong>MongoDB<\/strong> and <strong>Redis<\/strong>. I like to use Mongo due to the lack of schema required. That simple fact allows me to think about my code and the data formats, without having to worry about updating the structure of my tables, schema migrations or conflicting data types.<\/p>\n<p>Regarding Redis, I tend to use it as a support system as much as I can in my projects and this case is no different. I will be using Redis for everything that can be considered volatile information, such as party member numbers, command requests, and other types of data that are small enough and volatile enough to not merit permanent storage.<\/p>\n<p>I\u2019m also going to be using Redis\u2019 key expiration feature to auto manage some aspects of the flow (more on this shortly).<\/p>\n<h3>API Definition<\/h3>\n<p>Before moving into client-server interaction and data-flow definitions I want to go over the endpoints defined for this API. They aren\u2019t that many, mostly we need to comply with the main features described in <a href=\"https:\/\/www.smashingmagazine.com\/2018\/12\/multiplayer-text-adventure-engine-node-js\/\">Part 1<\/a>:<\/p>\n<table data-tablesaw-mode=\"swipe\" data-tablesaw-minimap>\n<thead>\n<tr>\n<th data-tablesaw-priority=\"persist\">Feature<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Join a game<\/td>\n<td>A player will be able to join a game by specifying the game\u2019s ID.<\/td>\n<\/tr>\n<tr>\n<td>Create a new game<\/td>\n<td>A player can also create a new game instance. The engine should return an ID, so that others can use it to join.<\/td>\n<\/tr>\n<tr>\n<td>Return scene<\/td>\n<td>This feature should return the current scene where the party is located. Basically, it\u2019ll return the description, with all of the associated information (possible actions, objects in it, etc.).<\/td>\n<\/tr>\n<tr>\n<td>Interact with scene<\/td>\n<td>This is going to be one of the most complex ones, because it will take a command from the client and perform that action \u2014 things like move, push, take, look, read, to name just a few.<\/td>\n<\/tr>\n<tr>\n<td>Check inventory<\/td>\n<td>Although this is a way to interact with the game, it does not directly relate to the scene. So, checking the inventory for each player will be considered a different action.<\/td>\n<\/tr>\n<tr>\n<td>Register client application<\/td>\n<td>The above actions require a valid client to execute them. This endpoint will verify the client application and return a Client ID that will be used for authentication purposes on subsequent requests.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The above list translates into the following list of endpoints:<\/p>\n<table data-tablesaw-mode=\"swipe\" data-tablesaw-minimap>\n<thead>\n<tr>\n<th data-tablesaw-priority=\"persist\">Verb<\/th>\n<th>Endpoint<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>POST<\/td>\n<td><code>\/clients<\/code><\/td>\n<td>Client applications will require to get a Client ID key using this endpoint.<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/games<\/code><\/td>\n<td>New game instances are created using this endpoint by the client applications.<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/games\/:id<\/code><\/td>\n<td>Once the game is created, this endpoint will enable party members to join it and start playing.<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/games\/:id\/:playername<\/code><\/td>\n<td>This endpoint will return the current game state for a particular player.<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/games\/:id\/:playername\/commands<\/code><\/td>\n<td>Finally, with this endpoint, the client application will be able to submit commands (in other words, this endpoint will be used to play).<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Let me go into a bit more detail about some of the concepts I described in the previous list.<\/p>\n<h4>Client Apps<\/h4>\n<p>The client applications will need to register into the system to start using it. All endpoints (except for the first one on the list) are secured and will require a valid application key to be sent with the request. In order to obtain that key, client apps need to simply request one. Once provided, they will last for as long as they are used, or will expire after a month of not being used. This behavior is controlled by storing the key in Redis and setting a one-month long TTL to it.<\/p>\n<h4>Game Instance<\/h4>\n<p>Creating a new game basically means creating a new instance of a particular game. This new instance will contain a copy of all of the scenes and their content. Any modifications done to the game will only affect the party. This way, many groups can play the same game on their own individual way.<\/p>\n<h4>Player\u2019s Game State<\/h4>\n<p>This is similar to the previous one, but unique to each player. While the game instance holds the game state for the entire party, the player\u2019s game state holds the current status for one particular player. Mainly, this holds inventory, position, current scene and HP (health points).<\/p>\n<h4>Player Commands<\/h4>\n<p>Once everything is set up and the client application has registered and joined a game, it can start sending commands. The implemented commands in this version of the engine include: <code>move<\/code>, <code>look<\/code>, <code>pickup<\/code> and <code>attack<\/code>.<\/p>\n<ul>\n<li>The <code>move<\/code> command will allow you to traverse the map. You\u2019ll be able to specify the direction you want to move towards and the engine will let you know the result. If you take a quick glimpse at <a href=\"https:\/\/www.smashingmagazine.com\/2018\/12\/multiplayer-text-adventure-engine-node-js\/\">Part 1<\/a>, you can see the approach I took to handle maps. (In short, the map is represented as a graph, where each node represents a room or scene and is only connected to other nodes that represent adjacent rooms.)\n<p>The distance between nodes is also present in the representation and coupled with the standard speed a player has; going from room to room might not be as simple as stating your command, but you\u2019ll also have to traverse the distance. In practice, this means that going from one room to the other might require several move commands). The other interesting aspect of this command comes from the fact that this engine is meant to support multiplayer parties, and the party can\u2019t be split (at least not at this time).<\/p>\n<p>Therefore, the solution for this is similar to a voting system: every party member will send a move command request whenever they want. Once more than half of them have done so, the most requested direction will be used.<\/li>\n<li><code>look<\/code> is quite different from move. It allows the player to specify a direction, an  item or NPC they want to inspect. The key logic behind this command, comes into consideration when you think about status-dependant descriptions.\n<p>For example, let\u2019s say that you enter a new room, but it\u2019s completely dark (you don\u2019t see anything), and you move forward while ignoring it. A few rooms later, you pick up a lit torch from a wall. So now you can go back and re-inspect that dark room. Since you\u2019ve picked up the torch, you now can see inside of it, and be able to interact with any of the items and NPCs you find in there.<\/p>\n<p>This is achieved by maintaining a game wide and player specific set of status attributes and allowing the game creator to specify several descriptions for our status-dependant elements in the JSON file. Every description is then equipped with a default text and a set of conditional ones, depending on the current status. The latter are optional; the only one that is mandatory is the default value.<\/p>\n<p>Additionally, this command has a short-hand version for <code>look at room: look around<\/code>; that is because players will be trying to inspect a room very often, so providing a short-hand (or alias) command that is easier to type makes a lot of sense.<\/li>\n<li>The <code>pickup<\/code> command plays a very important role for the gameplay. This command takes care of adding items into the players inventory or their hands (if they\u2019re free). In order to understand where each item is meant to be stored, their definition has a \u201cdestination\u201d property that specifies if it is meant for the inventory or the player\u2019s hands. Anything that is successfully picked up from the scene is then removed from it, updating the game instance\u2019s version of the game.<\/li>\n<li>The <code>use<\/code> command will allow you to affect the environment using items in your inventory. For instance, picking up a key in a room will allow you to use it to open a locked door in another room.<\/li>\n<li>There is a special command, one that is not gameplay-related, but instead a helper command meant to obtain particular information, such as the current game ID or the player\u2019s name. This command is called <strong>get<\/strong>, and the players can use it to query the game engine. For example: <em>get gameid<\/em>.<\/li>\n<li>Finally, the last command implemented for this version of the engine is the <code>attack<\/code> command. I already covered this one; basically, you\u2019ll have to specify your target and the weapon you\u2019re attacking it with. That way the system will be able to check the target\u2019s weaknesses and determine the output of your attack.<\/li>\n<\/ul>\n<div><\/div>\n<h4>Client-Engine Interaction<\/h4>\n<p>In order to understand how to use the above-listed endpoints, let me show you how any would-be-client can interact with our new API.<\/p>\n<table data-tablesaw-mode=\"swipe\" data-tablesaw-minimap>\n<thead>\n<tr>\n<th data-tablesaw-priority=\"persist\">Step<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Register client<\/td>\n<td>First things first, the client application needs to request an API key to be able to access all other endpoints. In order to get that key, it needs to register on our platform. The only parameter to provide is the name of the app, that\u2019s all.<\/td>\n<\/tr>\n<tr>\n<td>Create a game<\/td>\n<td>After the API key is obtained, the first thing to do (assuming this is a brand new interaction) is to create a brand new game instance. Think about it this way: the JSON file I created in my last post contains the game\u2019s definition, but we need to create an instance of it just for you and your party (think classes and objects, same deal). You can do with that instance whatever you want, and it will not affect other parties.<\/td>\n<\/tr>\n<tr>\n<td>Join the game<\/td>\n<td>After creating the game, you\u2019ll get a game ID back from  the engine. You can then use that game ID to join the instance using your unique username. Unless you join the game, you can\u2019t play, because joining the game will also create a game state instance for you alone. This will be where your inventory, your position and your basic stats are saved in relation to the game you\u2019re playing. You could potentially be playing several games at the same time, and in each one have independent states.<\/td>\n<\/tr>\n<tr>\n<td>Send commands<\/td>\n<td>In other words: play the game. The final step is to start sending commands. The amount of commands available was already covered, and it can be easily extended (more on this in a bit). Everytime you send a command, the game will return the new game state for your client to update your view accordingly.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div><\/div>\n<h3>Let\u2019s Get Our Hands Dirty<\/h3>\n<p>I\u2019ve gone over as much design as I can, in the hopes that that information will help you understand the following part, so let\u2019s get into the nuts and bolts of the game engine.<\/p>\n<p><strong>Note<\/strong>: <em>I will not be showing you the full code in this article since it\u2019s quite big and not all of it is interesting. Instead, I\u2019ll show the more relevant parts and <a href=\"https:\/\/github.com\/deleteman\/tardis-project-engine\">link to the full repository<\/a> in case you want more details.<\/em><\/p>\n<h4>The Main File<\/h4>\n<p>First things first: this is an Express project and it\u2019s based boilerplate code was generated using Express\u2019 own generator, so the <em>app.js<\/em> file should be familiar to you. I just want to go over two tweaks I like to do on that code to simplify my work.<\/p>\n<p>First, I add the following snippet to automate the inclusion of new route files:<\/p>\n<pre><code>const requireDir = require(\"require-dir\")\nconst routes = requireDir(\".\/routes\")\n\n\/\/...\n\nObject.keys(routes).forEach( (file) => {\n    let cnt = routes[file]\n    app.use('\/' + file, cnt)    \n})<\/code><\/pre>\n<p>It\u2019s quite simple really, but it removes the need to manually require each route files you create in the future. By the way, <code>require-dir<\/code> is a simple module that takes care of auto-requiring every file inside a folder. That\u2019s it.<\/p>\n<p>The other change I like to do is to tweak my error handler just a little bit. I should really start using something more robust, but for the needs at hand, I feel like this gets the work done:<\/p>\n<pre><code>\/\/ error handler\napp.use(function(err, req, res, next) {\n  \/\/ render the error page\n  if(typeof err === \"string\") {\n    err = {\n      status: 500,\n      message: err\n    }\n  }\n  res.status(err.status || 500);\n  let errorObj = {\n    error: true,\n    msg: err.message,\n    errCode: err.status || 500\n  }\n  if(err.trace) {\n    errorObj.trace = err.trace\n  }\n\n  res.json(errorObj);\n});<\/code><\/pre>\n<p>The above code takes care of the different types of error messages we might have to deal with \u2014 either full objects, actual error objects thrown by Javascript or simple error messages without any other context. This code will take it all and format it into a standard format.<\/p>\n<h4>Handling Commands<\/h4>\n<p>This is another one of those aspects of the engine that had to be easy to extend. In a project like this one, it makes total sense to assume new commands will pop up in the future. If there is something you want to avoid, then that would probably be avoid making changes on the base code when trying to add something new three or four months in the future.<\/p>\n<p>No amount of code comments will make the task of modifying code you haven\u2019t touched (or even thought about) in several months easy, so the priority is to avoid as many changes as possible. Lucky for us, there are a few patterns we can implement to solve this. In particular, I used a mixture of the Command and the Factory patterns.<\/p>\n<p>I basically encapsulated the behavior of each command inside a single class which inherits from a <code>BaseCommand<\/code> class that contains the generic code to all commands. At the same time, I added a <code>CommandParser<\/code> module that grabs the string sent by the client and returns the actual command to execute.<\/p>\n<p>The parser is very simple since all implemented commands now have the actual command as to their first word (i.e. \u201cmove north\u201d, \u201cpick up knife\u201d, and so on) it\u2019s a simple matter of splitting the string and getting the first part:<\/p>\n<pre><code>const requireDir = require(\"require-dir\")\nconst validCommands = requireDir('.\/commands')\n\nclass CommandParser {\n\n\n    constructor(command) {\n        this.command = command\n    }\n\n\n    normalizeAction(strAct) {\n        strAct = strAct.toLowerCase().split(\" \")[0]\n        return strAct\n    }\n\n\n    verifyCommand() {\n        if(!this.command) return false\n        if(!this.command.action) return false\n        if(!this.command.context) return false\n\n        let action = this.normalizeAction(this.command.action)\n\n        if(validCommands[action]) {\n            return validCommands[action]\n        }\n        return false\n    }\n\n    parse() {\n        let validCommand = this.verifyCommand()\n        if(validCommand) {\n            let cmdObj = new validCommand(this.command)\n            return cmdObj\n        } else {\n            return false\n        }\n    }\n}<\/code><\/pre>\n<p><strong>Note<\/strong>: <em>I\u2019m using the <code>require-dir<\/code> module once again to simplify the inclusion of any existing and new command classes. I simply add it to the folder and the entire system is able to pick it up and use it.<\/em><\/p>\n<p>With that being said, there are many ways this can be improved; for instance, by being able to add synonym support for our commands would be a great feature (so saying \u201cmove north\u201d, \u201cgo north\u201d or even \u201cwalk north\u201d would mean the same). That is something that we could centralize in this class and affect all commands at the same time.<\/p>\n<p>I won\u2019t go into details on any of the commands because, again, that\u2019s too much code to show here, but you can see in the following route code how I managed to generalize that handling of the existing (and any future) commands:<\/p>\n<pre><code>\/**\nInteraction with a particular scene\n*\/\nrouter.post('\/:id\/:playername\/:scene', function(req, res, next) {\n\n    let command = req.body\n    command.context = {\n        gameId: req.params.id,\n        playername: req.params.playername,\n    }\n\n    let parser = new CommandParser(command)\n\n    let commandObj = parser.parse() \/\/return the command instance\n    if(!commandObj) return next({ \/\/error handling\n        status: 400,\n          errorCode: config.get(\"errorCodes.invalidCommand\"),\n        message: \"Unknown command\"\n    })\n\n    commandObj.run((err, result) => { \/\/execute the command\n        if(err) return next(err)\n\n        res.json(result)\n    })\n\n})<\/code><\/pre>\n<p>All commands only require the <code>run<\/code> method \u2014 anything else is extra and meant for internal use.<\/p>\n<p>I encourage you to go and review the <a href=\"https:\/\/github.com\/deleteman\/tardis-project-engine\">entire source code<\/a> (even download it and play with it if you like!). In the next part of this series, I\u2019ll show you the actual client implemention and interaction of this API.<\/p>\n<h3>Closing Thoughts<\/h3>\n<p>I may not have covered a lot of my code here, but I still hope that the article was helpful to show you how I tackle projects \u2014 even after the initial design phase. I feel like a lot of people try to start coding as their first response to a new idea and that sometimes can end up discouraging to a developer since there is no real plan set nor any goals to achieve \u2014 other than having the final product ready (and that is too big of a milestone to tackle from day 1). So again, my hope with these articles is to share a different way to go about working solo (or as part of a small group) on big projects.<\/p>\n<p>I hope you\u2019ve enjoyed the read! Please feel free to leave a comment below with any type of suggestions or recommendations, I\u2019d love to read what you think and if you\u2019re eager to start testing the API with your own client-side code.<\/p>\n<p><em>See you on the next one!<\/em><\/p>\n<div>\n  <img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/10\/logo-red-17.png?w=900\" 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\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00 After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed&#8230;.<a class=\"moretag\" href=\"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/\"> Read the full article&#8230;<\/a><\/p>\n","protected":false},"author":4,"featured_media":72156,"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-72155","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: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should\" \/>\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\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/\" \/>\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: Game Engine Server Design (Part 2) | Design for Immersive Technologies\" \/>\n\t\t<meta property=\"og:description\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-24T11:15:27+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-24T11:15:27+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: Game Engine Server Design (Part 2) | Design for Immersive Technologies\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should\" \/>\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\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#article\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) | Design for Immersive Technologies\",\"headline\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)\",\"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\\\/10\\\/logo-red-17.png?fit=60%2C80&ssl=1\",\"width\":60,\"height\":80},\"datePublished\":\"2019-10-24T04:15:27-07:00\",\"dateModified\":\"2019-10-24T04:15:27-07:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#webpage\"},\"articleSection\":\"User Experience\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#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\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#listItem\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#listItem\",\"position\":3,\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)\",\"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\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#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\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#webpage\",\"url\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/\",\"name\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) | Design for Immersive Technologies\",\"description\":\"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#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\\\/10\\\/logo-red-17.png?fit=60%2C80&ssl=1\",\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#mainImage\",\"width\":60,\"height\":80},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.taterboy.com\\\/blog\\\/2019\\\/10\\\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\\\/#mainImage\"},\"datePublished\":\"2019-10-24T04:15:27-07:00\",\"dateModified\":\"2019-10-24T04:15:27-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: Game Engine Server Design (Part 2) | Design for Immersive Technologies","description":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should","canonical_url":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/","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\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#article","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) | Design for Immersive Technologies","headline":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)","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\/10\/logo-red-17.png?fit=60%2C80&ssl=1","width":60,"height":80},"datePublished":"2019-10-24T04:15:27-07:00","dateModified":"2019-10-24T04:15:27-07:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#webpage"},"isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#webpage"},"articleSection":"User Experience"},{"@type":"BreadcrumbList","@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#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\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#listItem","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#listItem","position":3,"name":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)","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\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#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\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#webpage","url":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/","name":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) | Design for Immersive Technologies","description":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/www.taterboy.com\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#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\/10\/logo-red-17.png?fit=60%2C80&ssl=1","@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#mainImage","width":60,"height":80},"primaryImageOfPage":{"@id":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/#mainImage"},"datePublished":"2019-10-24T04:15:27-07:00","dateModified":"2019-10-24T04:15:27-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: Game Engine Server Design (Part 2) | Design for Immersive Technologies","og:description":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should","og:url":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/","article:published_time":"2019-10-24T11:15:27+00:00","article:modified_time":"2019-10-24T11:15:27+00:00","twitter:card":"summary","twitter:title":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) | Design for Immersive Technologies","twitter:description":"Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2)Writing A Multiplayer Text Adventure Engine In Node.js: Game Engine Server Design (Part 2) Fernando Doglio 2019-10-23T14:00:59+02:002019-10-24T11:06:08+00:00After some careful consideration and actual implementation of the module, some of the definitions I made during the design phase had to be changed. This should"},"aioseo_meta_data":{"post_id":"72155","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 17:06:10","updated":"2026-09-02 08:54:06","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: Game Engine Server Design (Part 2)\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: Game Engine Server Design (Part 2)","link":"https:\/\/www.taterboy.com\/blog\/2019\/10\/writing-a-multiplayer-text-adventure-engine-in-node-js-game-engine-server-design-part-2\/"}],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p8wzr5-iLN","jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.taterboy.com\/blog\/wp-content\/uploads\/2019\/10\/logo-red-17.png?fit=60%2C80&ssl=1","_links":{"self":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/72155","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=72155"}],"version-history":[{"count":0,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/posts\/72155\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media\/72156"}],"wp:attachment":[{"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/media?parent=72155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/categories?post=72155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.taterboy.com\/blog\/wp-json\/wp\/v2\/tags?post=72155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}