{"id":149,"date":"2015-01-26T13:17:07","date_gmt":"2015-01-26T13:17:07","guid":{"rendered":"http:\/\/smartfoxserver.com\/blog\/?p=149"},"modified":"2015-01-26T13:17:50","modified_gmt":"2015-01-26T13:17:50","slug":"maintaining-game-state-across-multiple-reloads","status":"publish","type":"post","link":"https:\/\/smartfoxserver.com\/blog\/maintaining-game-state-across-multiple-reloads\/","title":{"rendered":"Maintaining game state across multiple reloads"},"content":{"rendered":"<p>Continuing from a <a title=\"The singleton solution\" href=\"http:\/\/smartfoxserver.com\/blog\/?p=144\">previous post about Singletons\u00a0<\/a>\u00a0we are going to discuss a simple strategy to maintain application state across multiple Extension reloads. Before delving into the details, let&#8217;s first analyze the reasons why this may help.<!--more--><\/p>\n<p>The ability to update an Extension at runtime comes at the cost of destroying all of the data managed by the\u00a0Extension itself, which in some cases can be a pain. Whether the\u00a0Zone Extension is handling the global game state or multiple Room game states, it will loose all of the runtime data, which makes re-deployments a critical activity, requiring careful scheduling to avoid too much downtime for players.<\/p>\n<p>Using a\u00a0Singleton class as <a href=\"http:\/\/smartfoxserver.com\/blog\/?p=144\">described in the previous article<\/a>\u00a0we can store all of the necessary game state in a safe memory space, that won&#8217;t be affected by a redeployment of our code.<\/p>\n<h3>\u00bb How does this work?<\/h3>\n<p>In our documentation we have a section dedicated to how <a href=\"http:\/\/docs2x.smartfoxserver.com\/AdvancedTopics\/advanced-extensions#classLoading\" target=\"_blank\">class loading works in the JVM<\/a>. The image below outlines the class loader hierarchy in SFS2X.<\/p>\n<p><a href=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/01\/class-loaders.png\"><img loading=\"lazy\" class=\" wp-image-151 size-full aligncenter\" src=\"http:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/01\/class-loaders.png\" alt=\"class-loaders\" width=\"561\" height=\"259\" srcset=\"https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/01\/class-loaders.png 561w, https:\/\/smartfoxserver.com\/blog\/wp-content\/uploads\/2015\/01\/class-loaders-300x139.png 300w\" sizes=\"(max-width: 561px) 100vw, 561px\" \/><\/a>What is important in this simple diagram is the <strong>Extension Global ClassLoader<\/strong>, which sits on top of all deployed Extensions and whose life cycle is independent from its children. We will therefore exploit this top class loader to maintain state across multiple re-deployments.<\/p>\n<p>As mentioned in the previous article this top class loader manages all jar files under the\u00a0<strong>extensions\/__lib__\/\u00a0<\/strong>folder, so we&#8217;ll deploy our singleton class and its dependencies\u00a0in a separate jar file to this folder.<\/p>\n<h3>\u00bb An example<\/h3>\n<p>Here is a simple pseudo-code of a singleton game model:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class GameSingleton\r\n{\r\n\tprivate static final GameSingleton INSTANCE = new GameSingleton();\r\n\r\n\t\/\/ Here we keep the state for each game in the Zone\r\n\tprivate Map&lt;String, GameState&gt; gamesTable = new ConcurrentHashMap&lt;&gt;();\r\n\r\n\tprivate GameSingleton() {}\r\n\r\n\tpublic static GameSingleton getInstance()\r\n\t{\r\n\t\treturn INSTANCE;\r\n\t}\r\n}\r\n\r\npublic class GameState\r\n{\r\n\tprivate HighScoreTable hsTable;\r\n\tprivate List&lt;Player&gt; players;\r\n\r\n\t\/\/ ... more game data ...\r\n}\r\n\r\npublic class HighScoreTable\r\n{\r\n\t...\r\n}\r\n\r\npublic class Player\r\n{\r\n\t...\r\n}\r\n<\/pre>\n<p>The main singleton class keeps a map of <em>GameState<\/em> objects, one for each game running in the Zone. Each instance will in turn describe all of the runtime data for the game, such as high scores, the players properties and whatever other information is needed.<\/p>\n<div class=\"dottedYellowBox\"><strong>NOTE:\u00a0<\/strong>When deploying the code we will make sure that the main singleton object and all the related game state classes are packed in the same jar file and exported to the <strong>extensions\/__lib__\/<\/strong> folder.<\/div>\n<p>&nbsp;<\/p>\n<p>In our main Extension <strong>init()<\/strong> method we will just need to access the Singleton class, which in turn will either get initialized, if it&#8217;s the very first time this class is loaded, or we&#8217;ll get\u00a0a reference to object already in memory.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npublic class MyGameExtension extends SFSExtension\r\n{\r\n\tprivate GameSingleton gameSingleton;\r\n\r\n\t@Override\r\n\tpublic void init()\r\n\t{\r\n\t\tgameSingleton = GameSingleton.getInstance();\r\n\r\n\t\t\/\/ etc...\r\n\t}\r\n}\r\n<\/pre>\n<p>As a final remark,\u00a0keep in mind that this approach will work\u00a0fine as long as you don&#8217;t need to re-deploy changes to the singleton or related model classes. In that particular case a server restart will be required.<\/p>\n<div class=\"dottedYellowBox\"><strong>NOTE<\/strong>: If during the implementation of this solution you&#8217;re getting a ClassCastException when accessing the global game data, chances are you haven&#8217;t deployed your model classes correctly. In particular the class that has raised the Exception is likely to have been exported in the wrong jar, i.e. in the Extension jar vs the Singleton jar.<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Continuing from a previous post about Singletons\u00a0\u00a0we are going to discuss a simple strategy to maintain application state across multiple Extension reloads. Before delving into the details, let&#8217;s first analyze the reasons why this may help.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[31,7],"_links":{"self":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/149"}],"collection":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/comments?post=149"}],"version-history":[{"count":11,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/149\/revisions"}],"predecessor-version":[{"id":162,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/149\/revisions\/162"}],"wp:attachment":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/media?parent=149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/categories?post=149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/tags?post=149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}