{"id":329,"date":"2015-09-09T13:28:09","date_gmt":"2015-09-09T13:28:09","guid":{"rendered":"http:\/\/smartfoxserver.com\/blog\/?p=329"},"modified":"2015-09-09T14:32:36","modified_gmt":"2015-09-09T14:32:36","slug":"top-10-common-pitfalls-to-avoid-like-the-plague","status":"publish","type":"post","link":"https:\/\/smartfoxserver.com\/blog\/top-10-common-pitfalls-to-avoid-like-the-plague\/","title":{"rendered":"Top 10 common pitfalls to avoid like the plague"},"content":{"rendered":"<p>This time we&#8217;re going to take a look at the top common errors and pitfalls that can be easily avoided when developing and deploying a multiplayer game with SmartFoxServer 2X. The list is compiled from a selection of topics that are quite popular\u00a0in our support forums.<\/p>\n<p>Knowing about these common pitfalls can possibly save you a significant amount\u00a0of time and head scratching. Let&#8217;s see what they are.<\/p>\n<p><!--more--><\/p>\n<h2>1) Forgetting to use\u00a0the SFSApi class<\/h2>\n<p>When developing server side code the <a title=\"SFSApi\" href=\"http:\/\/docs2x.smartfoxserver.com\/api-docs\/javadoc\/server\/\" target=\"_blank\">SFSApi class<\/a> is your best friend. It contains all of the most important methods you will ever need to implement your game logic: creating and joining rooms, setting variables,\u00a0disconnecting users, sending messages, and tons more.<\/p>\n<p>Additionally all of the SFSApi calls take care of updating clients and generating server-side events.<\/p>\n<p><strong>Bottom line<\/strong>: whenever you need to tell the server to perform an action, check this class before anything else, chances are you will find what you need.<\/p>\n<p>The <a title=\"SFSApi\" href=\"http:\/\/docs2x.smartfoxserver.com\/api-docs\/javadoc\/server\/\" target=\"_blank\">SFSApi class<\/a> is super-easy to use as it is already instantiated behind the scenes in the main Extension class and all ClientRequest and ServerEvent handlers. You can access by calling the <strong>getApi()<\/strong> method in your code.<\/p>\n<p>Additionally you can access the specialized API (<a title=\"BuddList API\" href=\"http:\/\/docs2x.smartfoxserver.com\/AdvancedTopics\/buddy-list-api\" target=\"_blank\">BuddyList API<\/a>, <a title=\"Game API\" href=\"http:\/\/docs2x.smartfoxserver.com\/AdvancedTopics\/game-api\" target=\"_blank\">Game API<\/a>) from this line of code:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nSmartFoxServer.getInstance().getApiManager();\r\n<\/pre>\n<h2>2) Manual database connection handling<\/h2>\n<p>This is likely the most popular problem recurring in the forums. When accessing\u00a0the database connection directly, instead of using the SFSDBManager class, there is extra care required to properly dispose of it at the end of the code.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\ntry\r\n{\r\n    connection = dbManager.getConnection();\r\n    \/\/ Your database code goes here\r\n}\r\ncatch(SQLException sqle)\r\n{\r\n    \/\/ Here we handle the SQL failure\r\n}\r\nfinally\r\n{\r\n    try\r\n    {\r\n        connection.close();\r\n    }\r\n    catch(SQLException sqle)\r\n    {\r\n        \/\/ It shouldn't happen, but if it does it's best to leave a trace in the logs\r\n    }\r\n}<\/pre>\n<p>The example above should serve as a code template for manual connection handling. Inside the <strong>try block<\/strong> we start by obtaining the connection from SFS2X connection pool.<\/p>\n<p>Since connections are reused to improve performance, we must make sure that they are returned to the pool when the operation is complete. Failing to do this will leak the connection, which in turn won&#8217;t be reusable. If this happens too often all available connections will be exhausted causing all sort of problems.<\/p>\n<p>The <strong>finally block<\/strong> is particularly important because it is the last thing that is executed before leaving the method, even when an exception is thrown.<\/p>\n<h2>3)\u00a0Sending data in for loops<\/h2>\n<p>If you find yourself writing code like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nfor (int i = 0; i &lt; 100; i++)\r\n{\r\n\tSFSObject obj = new SFSObject();\r\n\tobj.putParam(&quot;var&quot; + i, i);\r\n\r\n\tsfs.Send(new ExtensionRequest(&quot;cmd&quot;, obj));\r\n}\r\n<\/pre>\n<p>think again.<\/p>\n<p>Writing data to the network inside a for-loop is a bad idea. In this example we&#8217;re generating a deluge of small packets, sent one after the other, while we could have simply packed all of the data in one object and send\u00a0in one shot. Like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nSFSObject obj = new SFSObject();\r\n\r\nfor (int i = 0; i &lt; 100; i++)\r\n{\r\n\tobj.putParam(&quot;var&quot; + i, i);\r\n}\r\n\r\nsfs.Send(new ExtensionRequest(&quot;cmd&quot;, obj));\r\n<\/pre>\n<p>Additionally the first example is creating 100 SFSObjects, each having its 3 byte header and thus wasting an extra 300 bytes.<\/p>\n<p><strong>Bottom line<\/strong>: if your code sends data inside a for-loop, rewrite the code so that the send call is outside the loop and your data is aggregated in one request.<\/p>\n<h2>4) Enormous Room Lists<\/h2>\n<p>High traffic game servers can host tens of thousands of players and thousands of Game Rooms. If you plan to reach these heights it would\u00a0be better to have a strategy for managing very big Room Lists.<\/p>\n<p>If such a strategy is not in place clients will end up receiving ginormous lists of rooms that will waste lots of bandwidth and overwhelm\u00a0the clients with data.\u00a0Fortunately SFS2X provides a simple and efficient mechanism to organize Rooms into Groups and let users decide which of those they are interested in.<\/p>\n<p>For more details on this topic we have a previous blog post, called <a title=\"Fine tuning Room Lists\" href=\"http:\/\/smartfoxserver.com\/blog\/?p=287\" target=\"_blank\">Fine Tuning Room Lists<\/a>.<\/p>\n<h2>5)\u00a0Calling slow remote services<\/h2>\n<p>We have seen a number of projects where existing application API already exist in form of web services, often\u00a0written in PHP and connected to an existing database.\u00a0Typically these API handle a wide range of functionalities, from user profile management,\u00a0credentials, integration with other website features etc..<\/p>\n<p>Integrating these services with a SmartFoxServer 2X is relatively simple. All you need is to perform HTTP calls from your Extension code to the web\u00a0server, wait for a response and finally reply to the client via socket.<\/p>\n<p>On paper this looks like a great way to reuse existing services, without the hassle of\u00a0rewriting them in Java, but\u00a0unfortunately there is also a dark side to this approach which typically manifests in performance bottlenecks for SmartFoxServer: invoking remote HTTP services can be\u00a0slow or even painfully slow, depending on several factors.<\/p>\n<p>We&#8217;ve seen HTTP calls taking between 1000 and 8000 milliseconds to return, while SFS2X was receiving 100-200 calls per second. You can easily do the math and see that this is a scalability nightmare.<\/p>\n<p>The most radical solution to this problem is avoiding it entirely, by accessing the data source (e.g. database) without intermediaries (HTTP server, PHP etc&#8230;) This can provide a speed bump of several orders of magnitude and thus solving the issue altogether.<\/p>\n<p><strong>Bottom line<\/strong>: If you have the option of\u00a0choosing how to implement these services we absolutely positively recommend to access the datasource directly, you won&#8217;t regret it.<\/p>\n<p>On the other hand, if this is not an option then we can only suggest to make sure that every step of the chain is carefully optimized, avoiding excessive lag between servers, improving the PHP performance with a compiler and checking the execution time of each query, optimizing those that don&#8217;t perform well enough.<\/p>\n<h2>6)\u00a0Creating too many Task Schedulers<\/h2>\n<p>The <a title=\"Task Scheduler\" href=\"http:\/\/docs2x.smartfoxserver.com\/GettingStarted\/howtos#item7\" target=\"_blank\">Task Scheduler<\/a> is\u00a0an effective\u00a0tool to run delayed operations such as timers and countdowns or generate interval based events. Schedulers\u00a0are backed by a thread-pool so they can handle a multitude of tasks very efficiently.<\/p>\n<p>It is important to note that these schedulers should be used parsimoniously as every new instance will create a new thread pool. We usually recommend to just create one Scheduler in your Zone and then reference it in all of your code, be it Zone or Room Extension.<\/p>\n<p><strong>Bottom line<\/strong>: the really is no reason to use more than one Task Scheduler per game\/application.\u00a0If you find that the Scheduler is not keeping up with the submitted work it&#8217;s just a matter of resizing its thread pool.<\/p>\n<h2>7)\u00a0Using old, legacy collection classes<\/h2>\n<p>Quite surprisingly we have seen that a number of developers are still struggling with legacy collection classes such as <strong>Vector<\/strong>, <strong>HashTable<\/strong> and <strong>Dictionary<\/strong>. While these classes are not deprecated they are certainly not the first choice when it comes to collections in Java, these days.<\/p>\n<p>The main issues with the\u00a0legacy collection classes\u00a0is their handling of concurrency. For instance,\u00a0the Vector and HashTable classes synchronize every operation, making them unsuitable in multi-threaded environments such as SFS2X.<\/p>\n<p>Since Java 5 there has been a significant progress in the choice of efficient collections, especially in respect\u00a0to concurrency. Classes\u00a0like <strong>ConcurrentHashMap<\/strong>, <strong>CopyOnWriteArrayList<\/strong> and its <strong>Set<\/strong> counterpart offer a much better implementation and performance.<\/p>\n<p>To learn more we highly <a title=\"Java concurrent collections\" href=\"http:\/\/www.ibm.com\/developerworks\/library\/j-jtp07233\/\" target=\"_blank\">recommend this article<\/a>.<\/p>\n<h2>8) Sending an unrealistic number of packets per second (pps)<\/h2>\n<p>While in principle it is tempting to send an update every time a frame is rendered, we must realize that the network poses physical limits to the number of packets per second that can be sent. This value is referred to as <strong>pps<\/strong>\u00a0and it can vary based on the type of transport protocol in use (e.g. TCP vs UDP), the network conditions, the physical distance between client and server etc&#8230;<\/p>\n<p>Under normal network conditions it is usually\u00a0assumed that TCP can send ~15-20 pps while UDP can reach ~30, even 40 pps, although the latter is also subject to packet loss.<\/p>\n<p>With these numbers in mind, and considering that not all players can enjoy a fast internet connection, we can quickly realize that sending an update on every game frame is not going to work, especially if the frame rate runs at 30 or more frames.<\/p>\n<p><strong>Bottom line<\/strong>: there is no need to link the network updates to the frame rate. If the server (or client) is generating updates at a rate faster than the one at which is sending, it is common practice to simply buffer the updates and send them at specific intervals.<\/p>\n<h2><strong>9) Sending XML\/JSON\u00a0json data instead of optimized SFSObjects<\/strong><\/h2>\n<p>Sometimes a game loads data from another resource in a specific format such as text, maybe formatted as JSON or XML. Typical examples are level data, or user data coming from an external data source.<\/p>\n<p>There is nothing bad in sending text data to the client or viceversa if this is not a recurring type of message.\u00a0However, if you find yourself often sending XML\/JSON-type\u00a0data you should keep in mind that this is going to waste bandwidth and it would be best to unpack it from the original format and pack it back into SFSObjects using the specific data types. (short vs int vs long etc&#8230;)<\/p>\n<p>In other words a JSON packet like this:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nSFSObject sfso = new SFSObject();\r\nsfso.putUtfString(&quot;data&quot;, &quot;{'x':15.4456, 'y':81.7099, 'z':-0.0003, 'active':true}&quot;);\r\n<\/pre>\n<p>can be packed more efficiently using native types:<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nSFSObject sfso = new SFSObject();\r\nsfso.putFloat(&quot;x&quot;, 15.4456);\r\nsfso.putFloat(&quot;y&quot;, 81.7099);\r\nsfso.putFloat(&quot;z&quot;, -0.0003);\r\nsfso.putBool(&quot;ac&quot;, false);\r\n<\/pre>\n<p>and the latter will result in roughly 1\/2 the size of the former.<\/p>\n<p>For recurring messages this can make an important difference.<\/p>\n<h2><strong>10) Live testing<\/strong><\/h2>\n<p>Live testing for multiplayer games is fundamental. It is roughly the equivalent of having someone taste your cakes before you open a bakery and start mass production. If there are problems with the recipe or the final results it is best to know in advance, than having angry paying customers at the door complaining for what they have bought.<\/p>\n<p>Developing and testing multiplayer games in a local environment doesn&#8217;t guarantee that the game will behave correctly and doesn&#8217;t take into account all of the variables that exist when the product is finally live.<\/p>\n<p>It may not come as a surprise\u00a0that it is\u00a0highly important\u00a0to allocate enough time for live beta testing, especially using external testers that can try the game from a number of different devices and connection and report back any issue.<\/p>\n<p>While it seems we&#8217;re stating the obvious it has happened many times that clients reported problems with their game because they went from development to production directly.<\/p>\n<h2><span style=\"color: #993300;\"><strong>11) (bonus) Don&#8217;t buy the server license the day your game goes live!<\/strong><\/span><\/h2>\n<p>This is a bonus item that we had to include in this top-10 list, as it is a very simple pitfall to avoid.<\/p>\n<p>As per the title we really recommend to avoid that! If you&#8217;re going to buy a license <strong>don&#8217;t wait just a few hours before the game goes live<\/strong>. Payments sometimes don&#8217;t go through\u00a0and we need a bit of time to process the order and deliver the license(s).<\/p>\n<p>If you&#8217;re doing this you&#8217;ve possibly also fallen in <strong>pitfall #10\u00a0<\/strong>and we can&#8217;t emphasize more how these two are so important to avoid!<\/p>\n<p>Happy coding.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This time we&#8217;re going to take a look at the top common errors and pitfalls that can be easily avoided when developing and deploying a multiplayer game with SmartFoxServer 2X. The list is compiled from a selection of topics that are quite popular\u00a0in our support forums. Knowing about these common pitfalls can possibly save you [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[23],"tags":[40,34,44,7],"_links":{"self":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/329"}],"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=329"}],"version-history":[{"count":22,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/329\/revisions"}],"predecessor-version":[{"id":351,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/posts\/329\/revisions\/351"}],"wp:attachment":[{"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/media?parent=329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/categories?post=329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/smartfoxserver.com\/blog\/wp-json\/wp\/v2\/tags?post=329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}