<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: netcell</title>
    <description>The latest articles on DEV Community by netcell (@netcell).</description>
    <link>https://dev.to/netcell</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F64324%2F575124c3-3f29-48d6-938f-30d9b9889566.jpg</url>
      <title>DEV Community: netcell</title>
      <link>https://dev.to/netcell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/netcell"/>
    <language>en</language>
    <item>
      <title>An look into using Firebase for Multiplayer Game</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Tue, 12 Mar 2019 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/an-look-into-using-firebase-for-multiplayer-game-hd2</link>
      <guid>https://dev.to/netcell/an-look-into-using-firebase-for-multiplayer-game-hd2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Firebase is awesome, unless you choose the wrong product for the wrong job. A theoretical analysis of Firebase pricing for powering multiplayer games.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Cloud Firestore vs Realtime Database
&lt;/h1&gt;

&lt;p&gt;In &lt;a href="https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html" rel="noopener noreferrer"&gt;October 2017&lt;/a&gt;, Firebase launched &lt;a href="https://firebase.google.com/products/firestore/" rel="noopener noreferrer"&gt;Cloud Firestore&lt;/a&gt; as a new fancy hot cloud database. This new service is operated side by side with &lt;a href="https://firebase.google.com/products/realtime-database/" rel="noopener noreferrer"&gt;Realtime Database&lt;/a&gt; and can confuse new user of which to use for their purpose. Firebase’s effort of driving user to the new service makes it even more confusing, delivering an impression that Firestore is there to replace Realtime Database. When you go to any page of Firebase documentation site on &lt;a href="https://firebase.google.com/docs/database/" rel="noopener noreferrer"&gt;Realtime Database&lt;/a&gt;, you will see a highlight section on the top of the page encouraging you to explore Firestore.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/img/firestore-promo-docs.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fnetcell.netlify.com%2Fassets%2Fimg%2Ffirestore-promo-docs.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Features, Firestore is in fact far better than Realtime Database: &lt;em&gt;better structure, better querying, better rules writing and more concurrent connection&lt;/em&gt;. The only downside: &lt;em&gt;its pricing&lt;/em&gt;. While Realtime Database is mainly priced by the amount of &lt;em&gt;data you are using and transferring&lt;/em&gt;, Firestore is priced by the amount of &lt;em&gt;read/write operations&lt;/em&gt; you are making on the database. This makes using Firestore awkward for realtime applications since each client will react and issue read operations on database changes and that costs money.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who would have thought that Realtime Database is better for realtime applications right?&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Of course no one is using database synchronization for realtime multiplayer games, but turn-based or asynchronous multiplayer games can benefit greatly with Firebase approach. However, one game session can easily invoke 1000 operations, meaning you can support 20 game sessions daily with free plan and 100 game sessions daily with $25/month plan. Realtime Database on the other hand can support 100 CCUs for free plan and 100,000 CCUs for $25/month.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/img/firebase-database-plans.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fnetcell.netlify.com%2Fassets%2Fimg%2Ffirebase-database-plans.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is the best to use both of these database, Realtime Database for game sessions and Firestore for anything else. With this, you can open connections to realtime database only when the game session starts and close it with &lt;a href="https://stackoverflow.com/questions/40186819/firebase-web-close-connection-to-the-realtime-database" rel="noopener noreferrer"&gt;&lt;code&gt;firebaseRef.off()&lt;/code&gt;&lt;/a&gt; when it ends to optimize the simultaneous connections count.&lt;/p&gt;

&lt;p&gt;Furthermore, if you are only using realtime database for game sessions, scaling with multiple databases becomes pretty easy since you don’t have to share any data between these database. While Firestore is supposed to be able to automatically scale indefinitely, I don’t think its benefit outweights the cost in this case.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cloud Functions HTTP Triggers
&lt;/h1&gt;

&lt;p&gt;Since you are making changes to database, you probably want to make some logic not dependent on the client. Cloud Functions provides you with the ability to create &lt;a href="https://cloud.google.com/functions/docs/calling/http" rel="noopener noreferrer"&gt;HTTP endpoints&lt;/a&gt;. However, the functions are &lt;em&gt;billed by invocations&lt;/em&gt;, which is really really bad since there is no protection available for the endpoints if you are using it with CORS.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/img/cloud-function-pricing.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fnetcell.netlify.com%2Fassets%2Fimg%2Fcloud-function-pricing.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;People can make mass requests to these endpoints and you will be billed accordingly. Rejecting from inside cloud functions code doesn’t work since the invocation is already counted. This is not the end of the world though since you can setup CloudFlare and use &lt;a href="https://www.cloudflare.com/rate-limiting/" rel="noopener noreferrer"&gt;rate limiting&lt;/a&gt; feature to protect your endpoints. This service is only &lt;a href="https://support.cloudflare.com/hc/en-us/articles/115000272247-Billing-for-Cloudflare-Rate-Limiting" rel="noopener noreferrer"&gt;billed by good requests&lt;/a&gt; - requests that are allowed to reach to your endpoints.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/img/cloudfare-rate-limit-pricing.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fnetcell.netlify.com%2Fassets%2Fimg%2Fcloudfare-rate-limit-pricing.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, there is another aspect you need to consider: pricing. Free plan gives you 125,000 invocations monthly and $25/month gives you 2 million. This is far less than the amount of write operations you are allowed on Firestore. If you don’t want to use CloudFlare or if you think this limitation might cause trouble, you may want to explore the option to migrate to your own server.&lt;/p&gt;

&lt;p&gt;A very interesting point about Cloud Functions endpoints is that you can use frameworks like &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;&lt;code&gt;express.js&lt;/code&gt;&lt;/a&gt; to &lt;a href="https://firebase.google.com/docs/functions/http-events#using_existing_express_apps" rel="noopener noreferrer"&gt;wrap these endpoints&lt;/a&gt; into a single Cloud Functions HTTP trigger. Since the Firebase admin library can be initialized on any server, you can bring your entire &lt;code&gt;express.js&lt;/code&gt; section of your code to another server and it should work just fine. This is important because you can start developing your application with Cloud Function which makes your life much easier, knowing that you can migrate anytime you want.&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>multiplayergame</category>
      <category>firestore</category>
      <category>realtimedatabase</category>
    </item>
    <item>
      <title>Programatically Run Motive.io Script in Unity 3D</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Tue, 20 Mar 2018 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/programatically-run-motiveio-script-in-unity-3d-5hie</link>
      <guid>https://dev.to/netcell/programatically-run-motiveio-script-in-unity-3d-5hie</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.motive.io"&gt;Motive.io&lt;/a&gt; is a professional platform that allows you to integrate cutting-edge AR technology into compelling location-AR games and experiences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.motive.io"&gt;Motive.io&lt;/a&gt; is like &lt;strong&gt;Wordpress&lt;/strong&gt; for geolocation game for Unity 3D featuring a set of tools that allow &lt;strong&gt;authoring scripts&lt;/strong&gt; on their web-based interface and activate them on client.&lt;/p&gt;



&lt;p&gt;The thing is, &lt;a href="https://www.motive.io"&gt;Motive.io&lt;/a&gt; is only responsible for &lt;strong&gt;hosting&lt;/strong&gt; the scripts, all the logics are actually ran offline on client based on conditions setup on authouring tool. That is fine for simple single-player games, but for more complex features like multiplayer, you need to be able to control your scripts &lt;strong&gt;programmatically&lt;/strong&gt; , to be aware of their &lt;strong&gt;events&lt;/strong&gt; and feeding them &lt;strong&gt;parameters&lt;/strong&gt; from your own server.&lt;/p&gt;

&lt;p&gt;Unfortunately, the service is currently in beta, &lt;em&gt;“launching public access to the platform on March 21st.”,&lt;/em&gt; the manual is lacking a lot of contents, the examples only scratch the surface, and there are &lt;strong&gt;no SDK documenation&lt;/strong&gt;. Luckyly, their support is really fast and helpful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this series, I will explain how to launch a script programmatically with dyanmic variables.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Anatomy of a Motive Script
&lt;/h1&gt;

&lt;p&gt;Motive script is created on &lt;a href="https://www.motive.io"&gt;Motive.io&lt;/a&gt; Authoring tool.&lt;/p&gt;



&lt;p&gt;Normally, you will be using a &lt;code&gt;Main&lt;/code&gt; script to launch other scripts, and in example projects, there is a Scripts panel where you can manually activate them. However, if you are programmatically launching a script, you will need it’s &lt;strong&gt;unique identifier&lt;/strong&gt;. Each script has one that can be found on the address bar at &lt;code&gt;scriptId&lt;/code&gt; parameter.&lt;/p&gt;



&lt;p&gt;I think the term &lt;em&gt;“launching a script”&lt;/em&gt; is a little bit misleading. In fact, you will be creating instances of that script, each with an unique &lt;code&gt;runId&lt;/code&gt; specified by you. Each instance has its own memory. For example: If you create instances of a &lt;code&gt;Location Task&lt;/code&gt;, each instance will have its own location, status of completion, etc.&lt;/p&gt;




&lt;h1&gt;
  
  
  Operations on Motive Script
&lt;/h1&gt;

&lt;p&gt;There are 3 operation on a script instance you can do: &lt;strong&gt;Launch, Stop and Reset.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Launch:&lt;/strong&gt; creates a new script instance or resume the instance if it is already created&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reset:&lt;/strong&gt; halt the script and reset the original state of the script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop:&lt;/strong&gt; halt the script, hide any location marker, but does not reset anything.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To understand the difference between &lt;strong&gt;Reset&lt;/strong&gt; and &lt;strong&gt;Stop&lt;/strong&gt; , consider this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An instance of a script that contains &lt;strong&gt;two location tasks&lt;/strong&gt; is launched.&lt;/li&gt;
&lt;li&gt;The player has already &lt;strong&gt;completed one task&lt;/strong&gt; in that instance.&lt;/li&gt;
&lt;li&gt;If you &lt;strong&gt;Stop&lt;/strong&gt; and then &lt;strong&gt;Launch&lt;/strong&gt; the instance again, you will only see &lt;strong&gt;the task that is not completed.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If you &lt;strong&gt;Reset&lt;/strong&gt; and then &lt;strong&gt;Launch&lt;/strong&gt; the instance again, you will see &lt;strong&gt;both tasks.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  ScriptManager Singleton
&lt;/h1&gt;

&lt;p&gt;Script managing and operation is handle by a &lt;code&gt;ScriptManager&lt;/code&gt; singleton with two main methods &lt;code&gt;LaunchScript&lt;/code&gt; and &lt;code&gt;StopRunningScript&lt;/code&gt;. Their most basic signatures are as follow:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void LaunchScript(
  string scriptId, string runId, Action&amp;lt;bool&amp;gt; onComplete
);

public void StopRunningScript(
  string scriptId, string runId, bool resetState, Action onComplete
);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Both of them recieves &lt;code&gt;scriptId&lt;/code&gt; for identifying the script, &lt;code&gt;runId&lt;/code&gt; for identifying the script instance and &lt;code&gt;onComplete&lt;/code&gt; Action for callback on completion.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For &lt;strong&gt;launching a new instance&lt;/strong&gt; of a script with &lt;code&gt;runId&lt;/code&gt; as unique identifier, or &lt;strong&gt;resuming an instance&lt;/strong&gt; with that id, we use:&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ScriptManager.Instance.LaunchScript(scriptId, runId, onComplete);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To &lt;strong&gt;stop an instance&lt;/strong&gt; with id &lt;code&gt;runId&lt;/code&gt;, we call &lt;code&gt;StopRunningScript&lt;/code&gt; with &lt;code&gt;resetState = false&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ScriptManager.Instance.StopRunningScript(scriptId, runId, false, onComplete);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To &lt;strong&gt;reset an instance&lt;/strong&gt; with id &lt;code&gt;runId&lt;/code&gt;, we call &lt;code&gt;StopRunningScript&lt;/code&gt; with &lt;code&gt;resetState = true&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ScriptManager.Instance.StopRunningScript(scriptId, runId, true, onComplete);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Try in Example
&lt;/h1&gt;

&lt;p&gt;Start with the GhostHunter Unity template provided by &lt;a href="https://www.motive.io"&gt;Motive.io&lt;/a&gt;, we will be editting the script launcher to &lt;strong&gt;launch new instance everytime&lt;/strong&gt;.&lt;/p&gt;



&lt;p&gt;By default, the script launcher of the template only &lt;strong&gt;launch and manage one instance&lt;/strong&gt; with &lt;code&gt;runId="test"&lt;/code&gt; for each script.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// TestScriptsPanel.cs
ScriptManager.Instance.LaunchScript(e.Script.Id, "test", null);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you run the project, each time you launch a script, the &lt;code&gt;Launch&lt;/code&gt; button is turned in to a red &lt;code&gt;Stop&lt;/code&gt; button. You can remove this behaviour by changing the logic of &lt;code&gt;TestScriptItem.cs&lt;/code&gt; like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// TestScriptItem.cs
public void UpdateState()
{
  var isRunning = false; // Previously = ScriptManager.Instance.IsScriptRunning(m_script, "test");

  LaunchButton.gameObject.SetActive(!isRunning);
  StopButton.gameObject.SetActive(isRunning);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;However, this only keep the &lt;code&gt;Launch&lt;/code&gt; button, but this button wouldn’t create new script instance and &lt;strong&gt;no new location marker&lt;/strong&gt; will be added. Instead, you would want to replace &lt;code&gt;"test"&lt;/code&gt; with a &lt;strong&gt;random identifier&lt;/strong&gt; like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// TestScriptsPanel.cs
var runId = System.Guid.NewGuid().ToString();

ScriptManager.Instance.LaunchScript(e.Script.Id, runId, null);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, you can run the project and launch any script and new instance of it would be initiated. Managing all of these instances would requires more coding since &lt;code&gt;TestScriptItem.cs&lt;/code&gt; only track &lt;code&gt;runId = test&lt;/code&gt; instances. We wouldn’t discuss that here, instead, let’s explore how to &lt;strong&gt;add dynamic varibable&lt;/strong&gt; to our scripts.&lt;/p&gt;




&lt;h1&gt;
  
  
  What’s next?
&lt;/h1&gt;

&lt;p&gt;In the next post in this series, I will explain how to create dynamic variables in &lt;a href="https://motive.io"&gt;Motive.io&lt;/a&gt; Authoring Tool and passing values to those variables when launching script instance in Unity 3D.&lt;/p&gt;


</description>
      <category>ar</category>
      <category>geolocation</category>
      <category>motiveio</category>
      <category>unity</category>
    </item>
    <item>
      <title>Wordpress development with Docker</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Sat, 17 Mar 2018 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/wordpress-development-with-docker-2jk9</link>
      <guid>https://dev.to/netcell/wordpress-development-with-docker-2jk9</guid>
      <description>

&lt;p&gt;One of my obsessions lately is keeping my operating system as clean as possible. In order to do that, I perfer to install as few as possible anything on it.&lt;/p&gt;

&lt;p&gt;Node.js makes that quest so easy as I only need &lt;code&gt;node&lt;/code&gt; installed globally and everything else can be installed locally inside project directory. However, for many other languages, such as &lt;code&gt;Python&lt;/code&gt; and &lt;code&gt;PHP&lt;/code&gt;, it’s often not the case. Furthermore, when each project requires different environemnt setup, it quickly becomes a painful job managing everything and sometime you break the whole system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Docker to the rescue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While mostly used for controlling production and teamwork environments, Docker is also very useful for encapsulating development environment and providing a “clean slate” to make sure nothing breaks unintentionally.&lt;/p&gt;






&lt;h1&gt;
  
  
  Goals
&lt;/h1&gt;

&lt;p&gt;When building a docker development system, I often consider the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimum volume mounting:&lt;/strong&gt; File IO operations on mounted host volumes are slow (on Windows and Mac) so you would only want to mount the very sourcecode files you are going to edit. Others should be copied when builing the image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No runtime installation:&lt;/strong&gt; Dependencies and 3rd-party plugins should not be installed at container run time, especially if they require internet connection, to ensure fastest booting time when you resume the development. They should be installed when building the image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimum 3rd-party on host:&lt;/strong&gt; If possible, dependencies and 3rd-party plugins should be fetched from the internet (via a configuration file like &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;Gemfile&lt;/code&gt; or even listed inside &lt;code&gt;Dockerfile&lt;/code&gt;). Otherwise they should be kept as zip files and copied/extracted when building the image. There are two reasons for this: 

&lt;ul&gt;
&lt;li&gt;Copying a big amount of files from host to image is very slow.&lt;/li&gt;
&lt;li&gt;Keeping a big amount of 3rd-party files in your git directory is messy.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trackable snapshot:&lt;/strong&gt; You should be able to take snapshots of your current development progress (especially in Wordpress case as explained below), and the they should be able to be tracked in git repository.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Base Docker Image
&lt;/h1&gt;

&lt;p&gt;For Wordpress development, I use &lt;a href="https://hub.docker.com/r/chriszarate/wordpress/"&gt;&lt;code&gt;chriszarate/wordpress&lt;/code&gt;&lt;/a&gt; since it provides a bunch of useful features via envinronment varaibles including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically &lt;strong&gt;activate plugins&lt;/strong&gt; when container starts. Because no one wants to activate theme manually every single time. However, this becomes irrelevant once you start using database snapshots.&lt;/li&gt;
&lt;li&gt;Automatically &lt;strong&gt;activate a theme&lt;/strong&gt; when container starts. Similarly, this becomes irrelevant once you start using database snapshots.&lt;/li&gt;
&lt;li&gt;Append additional PHP to &lt;code&gt;wp-config.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Preconfigure admin user, admin password, admin email and site url to skip the boring welcome setup screen.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The magic behind this docker image is a set of &lt;code&gt;wp-cli&lt;/code&gt; scripts appended into the default entrypoint &lt;code&gt;docker-entrypoint.sh&lt;/code&gt; of the official &lt;code&gt;wordpress&lt;/code&gt; docker image.&lt;/p&gt;




&lt;h1&gt;
  
  
  Folder Structure
&lt;/h1&gt;

&lt;p&gt;Here is the folder structure of my Wordpress development directory, there are 3 main sections (which are poorly named in the screenshot but explained nicely in the picture below):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sourcecodes:&lt;/strong&gt; The plugins and themes you are currently developing. They are text files (&lt;code&gt;.php&lt;/code&gt;, &lt;code&gt;.css&lt;/code&gt;, &lt;code&gt;.xml&lt;/code&gt;, etc.) that you are going to create and change during most of your project timeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3rd-parties:&lt;/strong&gt; They are the 3rd-party plugins that your site needs, the dependencies of your project or the parent theme for which you are creating child theme. They should be kept as zip files in these folders or specified as urls in &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshots:&lt;/strong&gt; Including the sql dump from wordpress database and the compressed file of &lt;code&gt;wp-content/uploads&lt;/code&gt; folder (in case you are building contents or starting with demo content of a theme).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this structure, 3rd-parties and Snapshots will be built into the image, while sourcecodes are mounted to allow changes in development.&lt;/p&gt;



&lt;p&gt;&lt;code&gt;docker-entrypoint.sh&lt;/code&gt; is the default entrypoint &lt;code&gt;docker-entrypoint.sh&lt;/code&gt; of the original docker image and will be modified (see below) to fit our needs.&lt;/p&gt;




&lt;h1&gt;
  
  
  Dockerfile
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;For a sample &lt;code&gt;Dockerfile&lt;/code&gt;, checkout &lt;strong&gt;&lt;a href="https://gist.github.com/netcell/fbbd178b027ad411c8082a606f530718#file-dockerfile"&gt;this gist.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Packages
&lt;/h2&gt;

&lt;p&gt;For Dockerfile configuration, I install the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;unzip&lt;/code&gt;: As noted above, snapshots and 3rd-parties are saved as zip files (and in the case of remotely fetched, also in zip format). We would need this utility to &lt;strong&gt;decompress&lt;/strong&gt; them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mysql-client&lt;/code&gt;: This package provides neccessary commands required by &lt;code&gt;wp db&lt;/code&gt; to &lt;strong&gt;export and import wordpress database&lt;/strong&gt; as &lt;code&gt;.sql&lt;/code&gt; snapshot.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;[Optional]&lt;/em&gt; &lt;code&gt;wget&lt;/code&gt;: In the case where dependencires are remotely fetched, we use &lt;code&gt;wget&lt;/code&gt; to &lt;strong&gt;download&lt;/strong&gt; them from specified urls.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM chriszarate/wordpress:4.9.1

RUN \
    apt-get update &amp;amp;&amp;amp; \
    apt-get install unzip wget mysql-client -y &amp;amp;&amp;amp; \
    rm -rf /var/lib/apt/lists/*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  3rd-parties and Snapshots
&lt;/h2&gt;

&lt;p&gt;We copy each 3rd-party directory of zip files to a temporary folder on the image (or download via &lt;code&gt;wget&lt;/code&gt;), extract and delete all zip files. The content of these folders will be copied to real target directories at runtime by &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The reason we are not copying them directly to the real target folders is that they would be overwritten by commands in official wordpress image’s &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# If copied from folder
COPY ./plugins/ /temp/plugins
# If downloaded via url
wget -P /temp/plugins/ https://downloads.wordpress.org/plugin/jetpack.5.9.zip
# Extract and delete zip files
RUN unzip '/temp/plugins/*.zip' -d /temp/plugins &amp;amp;&amp;amp; rm /temp/plugins/*.zip || true;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;|| true&lt;/code&gt; is added to make sure that when there are no zip file the script would not fail and terminate image build process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Similarly we copy snapshot files (if available) to the image. The &lt;code&gt;uploads.zip&lt;/code&gt; file should be decompressed like above, while &lt;code&gt;wordpress.sql&lt;/code&gt; would later be processed by &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Entrypoint and Configurations
&lt;/h2&gt;

&lt;p&gt;We need to replace the default &lt;code&gt;docker-entrypoint.sh&lt;/code&gt; with our modified script. We don’t have to specify &lt;code&gt;ENTRYPOINT&lt;/code&gt; since it is already declared in the official docker image.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is also useful to have your own php uploads configuration as &lt;code&gt;uploads.ini&lt;/code&gt; in your repository and insert into the image. Obviously you can config other internal system files using the same method: copy a custom file to the absolute path inside the image.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY ./uploads.ini /usr/local/etc/php/conf.d/uploads.ini
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Entrypoint Script
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;For a sample &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;, checkout &lt;strong&gt;&lt;a href="https://gist.github.com/netcell/fbbd178b027ad411c8082a606f530718#file-docker-entrypoint-sh"&gt;this gist.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s time to modify &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;. Starting with a clone of the script from &lt;a href="https://hub.docker.com/r/chriszarate/wordpress/"&gt;&lt;code&gt;chriszarate/wordpress&lt;/code&gt;&lt;/a&gt;, we would need to copy all files in &lt;code&gt;/temp/&lt;/code&gt; directory to where they need to be. These lines need to be placed before plugins and themes activation.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONTENT_DIR=$ROOT_DIR/wp-content
THEME_DIR=$CONTENT_DIR/themes
PLUGIN_DIR=$CONTENT_DIR/plugins

cp -r /temp/themes/* $THEME_DIR || true
cp -r /temp/plugins/* $PLUGIN_DIR || true
cp -r /temp/base/* $CONTENT_DIR || true

# Activate plugins. Install if it cannot be found locally.
# ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One thing to notice here is that, all these files and folders are owned by &lt;code&gt;root&lt;/code&gt; user, hence will not be writable by Wordpress. If you need to give Wordpress permission over these directories, you need to insert something like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chown -R $WEB_USER:$WEB_USER $ROOT_DIR/wp-content/uploads
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;Finally, when everything is done, at the end of &lt;code&gt;docker-entrypoint.sh&lt;/code&gt;, we would want to import &lt;code&gt;wordpress.sql&lt;/code&gt; file. We place this line at the end of the file, just before &lt;code&gt;exec "$@"&lt;/code&gt;, to ensure our database would not be overwritten by anything.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;runuser $WEB_USER -s /bin/sh -c "wp db import $CONTENT_DIR/wordpress.sql"

exec "$@"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;h1&gt;
  
  
  Docker Compose
&lt;/h1&gt;

&lt;p&gt;For &lt;code&gt;docker-compose&lt;/code&gt; configuration, you can find an example at &lt;a href="https://github.com/chriszarate/docker-compose-wordpress/blob/master/docker-compose.yml"&gt;chriszarate’s repository&lt;/a&gt;. It’s a combination of 2 services: &lt;code&gt;wordpress&lt;/code&gt; for PHP wordpress installation and &lt;code&gt;mysql&lt;/code&gt; for database. There are only a few things to change here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build your Dockerfile:&lt;/strong&gt; instead of using &lt;code&gt;chriszarate/wordpress&lt;/code&gt; image directly&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  wordpress:
    build: .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mount your sourcecodes&lt;/strong&gt; according to your project, one by one. &lt;strong&gt;Do not&lt;/strong&gt; mount the entire &lt;code&gt;themes&lt;/code&gt; or &lt;code&gt;plugins&lt;/code&gt; directory since their versions inside the container are already populated with other files.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;volumes:
  - "./src/themes/my-custom-theme:/var/www/html/wp-content/themes/my-custom-theme"
  - "./src/plugins/my-custom-plugin:/var/www/html/wp-content/plugins/my-custom-plugin"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local only:&lt;/strong&gt; Only list plugins and themes that are installed inside docker image on &lt;code&gt;WORDPRESS_ACTIVATE_PLUGINS&lt;/code&gt; and &lt;code&gt;WORDPRESS_ACTIVATE_THEME&lt;/code&gt; environment variables. Otherwise, the entrypoint script will attempt to download them from the internet and prolong the startup time.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Now we are set. Let’s go and clean off any XAMPP or MAMP stack, or just delete everything and reinstall your operating system, or even better throw your machine away for a brand new computer. Have fun.&lt;/p&gt;


</description>
      <category>docker</category>
      <category>dockercompose</category>
      <category>container</category>
      <category>wordpress</category>
    </item>
    <item>
      <title>Developing GameClosure with Docker and Gitlab CI</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Sun, 24 Dec 2017 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/developing-gameclosure-with-docker-and-gitlab-ci-5em</link>
      <guid>https://dev.to/netcell/developing-gameclosure-with-docker-and-gitlab-ci-5em</guid>
      <description>&lt;p&gt;Develop games with HTML5 game framework GameClosure using Docker and Gitlab CI.&lt;/p&gt;



&lt;h2&gt;
  
  
  Docker for Development
&lt;/h2&gt;

&lt;p&gt;Following the guide of GameClosure, I made a Dockerfile that has &lt;code&gt;gameclosure/devkit&lt;/code&gt; &lt;strong&gt;installed&lt;/strong&gt; where I copied &lt;code&gt;manifest.json, package.json&lt;/code&gt; and run the commands to &lt;strong&gt;install dependencies&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COPY --chown=node manifest.json package.json ./
    RUN devkit install
    COPY --chown=node ./package.json ./
    RUN npm install
    CMD ["devkit", "serve"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;My project&lt;/strong&gt; only needs &lt;strong&gt;2 folders:&lt;/strong&gt; &lt;code&gt;src&lt;/code&gt; for source codes and &lt;code&gt;resources&lt;/code&gt; for assets. These are the folders required by GameClosure, everything else are dependencies and installed in the docker image. Using &lt;code&gt;docker-compose&lt;/code&gt;, I &lt;strong&gt;mount these folders&lt;/strong&gt; to the container and &lt;strong&gt;expose port&lt;/strong&gt; &lt;code&gt;9200&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;volumes:
        - ./src:/home/node/game/src
        - ./resources:/home/node/game/resources
    ports:
        - 9200:9200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the host machine, I can access devkit page via browser at &lt;code&gt;localhost:9200&lt;/code&gt; as normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continous Deployment
&lt;/h2&gt;

&lt;p&gt;In order to build the project, I need another &lt;code&gt;docker-compose&lt;/code&gt; configuration to &lt;strong&gt;mount&lt;/strong&gt; a &lt;code&gt;build&lt;/code&gt; folder and &lt;strong&gt;run the build command&lt;/strong&gt; instead of &lt;code&gt;serve&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;volumes:
        - ./build:/home/node/game/build
    command: devkit debug browser-mobile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn’t want to build the game manually, so I used Gitlab CI/CD service to have it &lt;strong&gt;runs&lt;/strong&gt; the container, &lt;strong&gt;builds&lt;/strong&gt; the game and &lt;strong&gt;deploys&lt;/strong&gt; to Gitlab Pages for me. I create this &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file with &lt;code&gt;pages&lt;/code&gt; job that &lt;em&gt;build the game into&lt;/em&gt; &lt;code&gt;*public*&lt;/code&gt; &lt;em&gt;artifacts&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unlike Github Pages which can only build Jekyll, Gitlab Pages can automatically build almost anything with its CI/CD service.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pages:
        stage: deploy
        script:
            - docker-compose -f docker-compose.yml -f docker-compose.browser-mobile.yml up
            - cp -a build/debug/browser-mobile/. public/
        artifacts:
            paths:
                - public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, everytime I push to my Gitlab repository, the game will be built and served at Gitlab Pages.&lt;/p&gt;

</description>
      <category>gameclosure</category>
      <category>docker</category>
      <category>cicd</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>Geolocation in Mobile Game</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Thu, 19 Oct 2017 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/geolocation-in-mobile-game-j02</link>
      <guid>https://dev.to/netcell/geolocation-in-mobile-game-j02</guid>
      <description>

&lt;h1&gt;
  
  
  🖼️ Overview
&lt;/h1&gt;

&lt;p&gt;The general problem is as follow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Provides the game a context of player being inside a certain area in a set of predefined records, allowing the game to affect player’s process accordingly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;🗒️ Here, a &lt;code&gt;location&lt;/code&gt; is understand as a set of two value &lt;code&gt;(latitude, longitude&lt;/code&gt;) which refers to a position on the surface of the Earth.&lt;/p&gt;

&lt;h1&gt;
  
  
  🛒 What’s on the market?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  🎮 Geolocation Games
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔴 🌐&lt;/strong&gt; &lt;a href="https://www.geocaching.com/play"&gt;&lt;strong&gt;Geocaching&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Launched in 2000 and is still kicking well, the game allows players to go find real boxes 📦 hidden around the world. While being more of an outdoor game ⚽ than a video game 🎮 , this is probably one of the longest running geolocation mobile game ever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴 🏙️&lt;/strong&gt; &lt;a href="https://www.ingress.com/"&gt;&lt;strong&gt;Ingress&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before the widely successful &lt;strong&gt;Pokemon Go&lt;/strong&gt; 👎 , Niantic created &lt;strong&gt;Ingress&lt;/strong&gt; with a futuristic theme 🚀 and so many more features: location capturing, structure building, PvP actions, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴 📈&lt;/strong&gt; &lt;a href="https://landlordgame.com/"&gt;&lt;strong&gt;Landlord&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Landlord allows player to buy venues 🏯 that they visits and earn rent 💵 as people check in 📍 at those location in real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴🕵️‍♀️&lt;/strong&gt; &lt;a href="https://mobile-italia.com/works/rog/"&gt;&lt;strong&gt;Revenge of the Gang&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this game, the players create gangs 👨‍👦‍👦 to fight each other for territories 🗺️ . The aim of the game is to try to conquer as many cells as possible on a grid map (see more at Grid section).&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ Location as a Services
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔴 🏖️&lt;/strong&gt; &lt;a href="https://developers.google.com/places"&gt;&lt;strong&gt;Google Places API&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This service is discussed below 👇 in Marker section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🔴 🔪&lt;/strong&gt; &lt;a href="https://www.motive.io/"&gt;&lt;strong&gt;Motive.io&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;🌟&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A location backend with Vuforia AR integration for Unity.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;The service provides quite a &lt;strong&gt;complete backend solution for location-based game&lt;/strong&gt; 👍 development with places matching, user location tracking, narrative designs and quest management.&lt;/p&gt;

&lt;p&gt;They also promote AR integration with Vuforia but I believe with ARKit and ARCore insight, the modern AR approach implementation is in due.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sadly, &lt;strong&gt;Motive.io is currently still in closed beta.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🔴 ⛓️&lt;/strong&gt; &lt;a href="https://backendless.com/products/geolocation/"&gt;&lt;strong&gt;Backendless.com&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;🌟&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The geolocation feature of this service seems to cover most 👍 of the backend features you need. However, there are no 🚫 Backendless SDK for game engines right now &lt;em&gt;(though about one year ago, it is said to be under development)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴 🗺️&lt;/strong&gt; &lt;a href="https://www.mapbox.com/"&gt;&lt;strong&gt;Mapbox&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌟 Mapbox is a toolbox of geo-related tools. It even has mobile SDKs and Unity SDK for displaying maps. Mapbox analysis tool Turf.js allows complicated geo calculation and estimation.&lt;/p&gt;

&lt;h1&gt;
  
  
  🤖 Technical Patterns
&lt;/h1&gt;

&lt;h2&gt;
  
  
  🏁 Grid - Area-based method
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Grid map&lt;/strong&gt; is really popular in games. A grid &lt;em&gt;split the map into multiple consecutive regions called&lt;/em&gt; &lt;strong&gt;&lt;em&gt;cells&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;with identical shapes&lt;/em&gt; (square or hexagon in most cases).&lt;/p&gt;



&lt;p&gt;🌟 By using &lt;strong&gt;grid method&lt;/strong&gt; in geolocation, the game can find out &lt;em&gt;which cell player is currently in and affect the player’s process accordingly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Considering the world map 🗺️ as a &lt;strong&gt;2D plane&lt;/strong&gt; , &lt;code&gt;latitude&lt;/code&gt; and &lt;code&gt;longitude&lt;/code&gt; are the coordinates, this problem is similar to &lt;em&gt;checking if a point is within a polygon.&lt;/em&gt; ☝️ However, there are cases where the area &lt;strong&gt;overlaps&lt;/strong&gt; where the map wrap around, &lt;em&gt;but&lt;/em&gt; these cases can be solved with relatively simple algorithms.&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 Markers - Distance-based method
&lt;/h2&gt;

&lt;p&gt;🌟 In this method, given a database of locations, the game need to figure out which of those locations are &lt;strong&gt;within a certain radius&lt;/strong&gt; around and &lt;strong&gt;nearest&lt;/strong&gt; to player’s current location.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴&lt;/strong&gt;  &lt;strong&gt;🏖️&lt;/strong&gt; &lt;a href="https://developers.google.com/places"&gt;&lt;strong&gt;Google Places API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;- The third-party way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🌟 With this method, the database doesn’t save the location but &lt;strong&gt;ID of the places available on Google Places API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🌟 Google Places has a very good 🛢️ &lt;strong&gt;location database&lt;/strong&gt; of &lt;strong&gt;real-life places.&lt;/strong&gt; The &lt;a href="https://developers.google.com/places/web-service/search#PlaceSearchRequests"&gt;nearby search-request API&lt;/a&gt; 🔎 allows &lt;strong&gt;searching&lt;/strong&gt; places &lt;strong&gt;near&lt;/strong&gt; player’s current location within a &lt;strong&gt;radius&lt;/strong&gt; 👉 &lt;em&gt;which is the problem we are looking into.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  - &lt;strong&gt;Notice 1:&lt;/strong&gt; It was &lt;em&gt;possible&lt;/em&gt; to &lt;strong&gt;add places&lt;/strong&gt; that doesn’t exist on Google Places. &lt;strong&gt;However,&lt;/strong&gt; &lt;a href="https://developers.google.com/places/web-service/add-place"&gt;&lt;strong&gt;that API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;has been deprecated&lt;/strong&gt; ⛔ &lt;strong&gt;since June 2017.&lt;/strong&gt; Therefore, if we use Google Places API, our markers will be &lt;strong&gt;limited to what exists on Google Places&lt;/strong&gt; only. On the bright side 🔅, its database is really huge so this may not be that big of a problem.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Notice 2&lt;/strong&gt; The Google Places API for iOS enforces a default ⚠️ &lt;strong&gt;limit of 1,000 requests per 24 hour&lt;/strong&gt; period. However, it is possible to request an increase by following a simple review process.&lt;/p&gt;

&lt;p&gt;With this method, the &lt;strong&gt;database&lt;/strong&gt; structures and operations would be &lt;strong&gt;much simple&lt;/strong&gt; , delicate the most notable features to the Google’s service. The game backend only needs to &lt;strong&gt;map places to desired behaviours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴&lt;/strong&gt;  &lt;strong&gt;⚗️ Formulas for Spherical distance - The first-party way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are three formulas for this including: &lt;strong&gt;&lt;em&gt;Haversine&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;formula&lt;/em&gt;, &lt;em&gt;Spherical&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Law of Cosines&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;Equirectangular&lt;/em&gt;&lt;/strong&gt; approximation. These are listed in the &lt;a href="https://www.movable-type.co.uk/scripts/latlong.html"&gt;document&lt;/a&gt; that is &lt;a href="https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#creating-a-table-in-mysql"&gt;referred&lt;/a&gt; by Google Maps 🗺️ team.&lt;/p&gt;

&lt;p&gt;👉 According to the document:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Spherical&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Law of Cosines -&lt;/em&gt;&lt;/strong&gt; provided the 👍 &lt;strong&gt;best accuracy&lt;/strong&gt; &lt;em&gt;for small distances&lt;/em&gt; and the 👎 &lt;strong&gt;worst performance&lt;/strong&gt; overall.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Haversine&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;formula&lt;/em&gt; &lt;strong&gt;-&lt;/strong&gt; is the most &lt;strong&gt;popular in the past&lt;/strong&gt; ⏳ since it avoids large round-off errors in computations in the era where computers 🖥️ did not exist or were very primitive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Equirectangular&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;approximation&lt;/em&gt; &lt;strong&gt;-&lt;/strong&gt;  &lt;strong&gt;has the 👍 **best performance&lt;/strong&gt; while provides the 👎 &lt;strong&gt;worst accuracy&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌟 With the current technology, &lt;em&gt;Spherical&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Law of Cosines&lt;/em&gt;&lt;/strong&gt; became &lt;strong&gt;widely used&lt;/strong&gt; for spherical distance calculation. The Google Maps 🗺️ documentation, &lt;em&gt;regarding this matter&lt;/em&gt;, also gave the &lt;a href="https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#finding-locations-with-mysql"&gt;&lt;strong&gt;example SQL query&lt;/strong&gt;&lt;/a&gt; based on &lt;em&gt;Spherical&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Law of Cosines&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;.&lt;/em&gt; 👍&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔴&lt;/strong&gt;  &lt;strong&gt;🔬 Optimization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For whichever formula selected&lt;/em&gt;, the problem with these techniques is that the formula requires a lot of trigonometric operations, &lt;strong&gt;which are very CPU-intensive&lt;/strong&gt; 🤖. It is important to ✂️ &lt;strong&gt;trim down the records&lt;/strong&gt; to a small subset prior to use the formula.&lt;/p&gt;

&lt;p&gt;🌟 &lt;strong&gt;A method&lt;/strong&gt; for trimming process would be using &lt;strong&gt;a square with player’s location at center&lt;/strong&gt; and only &lt;strong&gt;select locations&lt;/strong&gt; in the database that lies &lt;strong&gt;within this square&lt;/strong&gt;. The calculation, as mentioned in Grid section 👆, is relatively simple.&lt;/p&gt;






&lt;h2&gt;
  
  
  🚚 Distribution
&lt;/h2&gt;

&lt;p&gt;There are 2 ways to &lt;strong&gt;distribute bonuses&lt;/strong&gt; 💰 to real-life locations 📍 where players can visit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;✋ Manually:&lt;/strong&gt; By creating location manually, we can &lt;strong&gt;establish partnerships&lt;/strong&gt; 🤝 by putting &lt;strong&gt;special bonuses&lt;/strong&gt; 💰 at partner’s location 📍 .&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🤖&lt;/strong&gt;  &lt;strong&gt;Automatically&lt;/strong&gt;** : &lt;strong&gt;Even with partnerships, we still need to&lt;/strong&gt; populate &lt;strong&gt;🌧️ the map with&lt;/strong&gt; many regular bonus places &lt;strong&gt;to keep players interests inside&lt;/strong&gt; the geo-game-loop**.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  📁 General Distribution
&lt;/h3&gt;

&lt;p&gt;🌟 For seeding 🌱 , in the beginning, we would be distributing bonuses around &lt;strong&gt;famous places&lt;/strong&gt; 🏯 in selective &lt;em&gt;(or all)&lt;/em&gt; cities 🏙️ around the world &lt;em&gt;(or in selected countries)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;🌟 Using &lt;a href="https://developers.google.com/places/web-service/search#TextSearchRequests"&gt;&lt;strong&gt;Text Search Requests&lt;/strong&gt;&lt;/a&gt; in Google Places API, we can search for &lt;strong&gt;point of interest&lt;/strong&gt; places &lt;em&gt;(tourist attraction)&lt;/em&gt; by querying:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${cityName}+point+of+interest

    # Example requesting famous places in New York City
    https://maps.googleapis.com/maps/api/place/textsearch/json?query=new+york+city+point+of+interest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The response returns 20 places object along with a &lt;code&gt;next_page_token&lt;/code&gt; string which can be used to fetch more places.&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 Markers Distribution
&lt;/h2&gt;

&lt;p&gt;Markers distribution pretty simple: For each famous, we only need to directly assign &lt;strong&gt;bonuses&lt;/strong&gt; 💰 to its &lt;strong&gt;location&lt;/strong&gt; 📍.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏁 Grid Distribution
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I will only cover &lt;strong&gt;square grid only&lt;/strong&gt;. Hexagon grid is more complicated and other than game visual requirement, there is actually no perk over square grid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Here I use the term &lt;strong&gt;subgrid&lt;/strong&gt; which means a set of cells in the grid that forms a square.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First we decide the &lt;strong&gt;size&lt;/strong&gt; &lt;code&gt;S&lt;/code&gt; of a square grid cell &lt;code&gt;S x S&lt;/code&gt; and put this grid over the world map 🗺️. There are two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The grid cover the whole map 🗺️ 

&lt;ul&gt;
&lt;li&gt;For each city, we find the &lt;strong&gt;smallest subgrid that fully cover that city&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;A custom grid for each city 🏙️ 

&lt;ul&gt;
&lt;li&gt;For each city, find &lt;strong&gt;a square with the size is a multiple of&lt;/strong&gt; &lt;code&gt;S&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Divide the square into a grid of &lt;code&gt;S x S&lt;/code&gt; cells.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After establishing a grid for each city, assign &lt;strong&gt;bonuses&lt;/strong&gt; 💰 to cells that &lt;strong&gt;contains famous places&lt;/strong&gt; 🏯.&lt;/p&gt;


</description>
      <category>mobilegame</category>
      <category>geolocation</category>
    </item>
    <item>
      <title>Webhook notification from Netlify to Discord</title>
      <dc:creator>netcell</dc:creator>
      <pubDate>Fri, 11 Aug 2017 17:00:00 +0000</pubDate>
      <link>https://dev.to/netcell/webhook-notification-from-netlify-to-discord-39ol</link>
      <guid>https://dev.to/netcell/webhook-notification-from-netlify-to-discord-39ol</guid>
      <description>&lt;p&gt;Moving from Slack to Discord is a huge pleasure. Sure it lack some functionalities that Slack has to offer, but Discord clients are super fast and smooth and comes with voice chat. At the end of the day, performance is what matters the most.&lt;/p&gt;

&lt;p&gt;One of the problem I had to deal with is moving the Netlify notifications from Slack to Discord. Here in this post, I will talk about the process of me figuring it out. However, if you are just looking for a solution just like I was, jump forward to TLDR;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I thought
&lt;/h2&gt;

&lt;p&gt;At first, I thought that I only need to create a incoming webhook on Discord to get a webhook url.&lt;/p&gt;



&lt;p&gt;Afterward, create a outgoing webhook on Netlify.&lt;/p&gt;



&lt;p&gt;Copy the webhook url from Discord and paste into Netlify.&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;You know what? It doesn’t work!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What’s wrong?
&lt;/h2&gt;

&lt;p&gt;The problem is that the JSON format sent from Netlify isn’t compatible with Discord. After searching around, I found this part &lt;a href="https://discordapp.com/developers/docs/resources/webhook"&gt;inside Discord Developer Documentation&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  TLDR;
&lt;/h2&gt;

&lt;p&gt;In Netlify, create a &lt;strong&gt;Slack intergration&lt;/strong&gt; webhook (&lt;em&gt;yeah, Slack&lt;/em&gt;), paste your &lt;strong&gt;Discord webhook url&lt;/strong&gt; and append &lt;code&gt;/slack&lt;/code&gt;&lt;/p&gt;



&lt;blockquote&gt;
&lt;p&gt;Have fun :)&lt;/p&gt;
&lt;/blockquote&gt;



</description>
      <category>netlify</category>
      <category>slack</category>
      <category>discord</category>
      <category>webhook</category>
    </item>
  </channel>
</rss>
