<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[mira1e.dev]]></title><description><![CDATA[Periodically updates useful things.]]></description><link>https://magickaichen.com/</link><image><url>https://magickaichen.com/favicon.png</url><title>mira1e.dev</title><link>https://magickaichen.com/</link></image><generator>Ghost 5.36</generator><lastBuildDate>Mon, 06 Apr 2026 14:05:15 GMT</lastBuildDate><atom:link href="https://magickaichen.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[AWS Serverless: Enable API Versioning via API Gateway + Lambda Aliases]]></title><description><![CDATA[<p>After exposing the lambda function as an API for your serverless application, it is also necessary to keep the API manageable through version control.</p><h2 id="why-versioning">Why Versioning?</h2><!--kg-card-begin: markdown--><ul>
<li><strong>Consistent</strong>: Versioning gives developers the ability to continuously work on the API without breaking or changing its delivered functionality by creating a separate version.</li></ul>]]></description><link>https://magickaichen.com/aws-practices-create-versioning-for/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a57</guid><category><![CDATA[AWS]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Wed, 03 Jul 2019 05:17:02 GMT</pubDate><content:encoded><![CDATA[<p>After exposing the lambda function as an API for your serverless application, it is also necessary to keep the API manageable through version control.</p><h2 id="why-versioning">Why Versioning?</h2><!--kg-card-begin: markdown--><ul>
<li><strong>Consistent</strong>: Versioning gives developers the ability to continuously work on the API without breaking or changing its delivered functionality by creating a separate version. For example, for a simple API <code>/getreport</code>, it would be benificial to have two endpoints: <code>api.example.com/prod/getreport</code> and <code>api.example.com/dev/getreport</code>. Which <code>prod</code> is the production stable release which should always be up and working, while developers will use <code>dev</code> version to develop and test new features.</li>
<li><strong>Backup/Rollback</strong>: Although the latest stable version should always be up and working, however sometimes it does break unexpectedly. With the power of versioning, when this happens, the API is always able to rollback to its previous stable version to get everything back online again.</li>
</ul>
<!--kg-card-end: markdown--><h2 id="create-api-versioning">Create API Versioning</h2><!--kg-card-begin: markdown--><p>If you exposed a lambda function as an API in API Gateway, creating versioning of it requires 2 steps:</p>
<ul>
<li>Create aliases on the lambda function for different version</li>
<li>Deploy the lambda function aliases to different API stages</li>
</ul>
<!--kg-card-end: markdown--><h3 id="create-aliases-for-lambda-function">Create aliases for Lambda Function</h3><!--kg-card-begin: markdown--><p>In AWS Console, open Lambda Management Console, in the top menu, click <code>Actions &gt; Publish new version</code>.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-2.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>In the pop-up dialog, fill in the version description, this can be anything (like <code>v0.1</code>, <code>dev</code>, <code>stable</code>, etc.).<br>
Click &quot;Finish&quot;, then you should see the new published version under <code>Qualifiers &gt; Versions</code>.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-1.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Note that under &quot;Versions&quot; tab, you will see there are two available version:</p>
<ul>
<li>The version you just published (which is version 1)</li>
<li><code>$LATEST</code></li>
</ul>
<p>The version <code>$LATEST</code> points to the latest changes of the lambda function, every time we modify the function, <code>$LATEST</code> will save that change.</p>
<p>The version we published earlier keeps the change at the time we published it, once the version has been published, it is not modifiable, but it can be deleted.</p>
<p>Once the new version has been published, create an alias called &quot;prod&quot; for version 1 (which is the most recent stable release by far) by clicking <code>Actions &gt; Create alias</code>.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image.png" class="kg-image" alt loading="lazy"></figure><p>Fill in the name, description, and version number (which is 1 in our case) in the dialog.</p><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-3.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Repeat this for another alias called <code>dev</code> (which is the latest development version that will be worked on and not stable).</p>
<p>Once done, now we should have two alias for our lambda function: <code>prod</code> and <code>dev</code>, pointing to the version <code>1</code> and version <code>$LATEST</code>, respectively.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="deployamultistageapiviaapigateway">Deploy a multi-stage API via API Gateway</h3>
<p>Since we already have multiple versions of the lambda function, the next step is to add additional stages to the API.<br>
Let&apos;s take the previous example <code>/getreport</code>, in this case, the API should have two stages:</p>
<ul>
<li>Development stage (endpoint: <code>&lt;API_URI&gt;/dev/getreport</code>)</li>
<li>Production stage (endpoint: <code>&lt;API_URI&gt;/prod/getreport</code>)</li>
</ul>
<p>Go to API Gateway console, and click the API we want to modify (<code>/getreport</code>), then go to <code>Resources</code> Tab.</p>
<p>Under <code>Resources</code>, click <code>Actions &gt; Deploy API</code> to deploy the production stage of the API <code>/getreport</code>:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-5.png" class="kg-image" alt loading="lazy"></figure><p>Do the same thing to deploy the development version.</p><!--kg-card-begin: markdown--><p>After that, go to <code>Stages</code> tab, click on <code>prod</code> stage, add a stage variable under <code>Stage Variables</code> tab with following value:</p>
<pre><code class="language-javascript">{
    Name: lambdaAlias,
    Value: stable
}
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-6.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Create a stage variable for <code>dev</code> stage as well:</p>
<pre><code class="language-javascript">{
    Name: lambdaAlias,
    Value: dev
}</code></pre>
<!--kg-card-end: markdown--><p>The name and value for stage variables can be anything, but the name for two stages should be consistent, if the name is <code>lambdaAlias</code> in stage <code>prod</code>, in stage <code>dev</code> the variable name should be <code>lambdaAlias</code> as well.</p><!--kg-card-begin: markdown--><p>Then, click the method we want to add the versioning, on the right panel, click <code>Integration Request</code>.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://magickaichen.com/content/images/2019/07/image-4.png" class="kg-image" alt loading="lazy"><figcaption><code>ANY</code> means all method</figcaption></figure><!--kg-card-begin: markdown--><p>In the right panel, configure the lambda function as</p>
<pre><code class="language-javascript">&lt;lambda&gt;:${stageVariable.lambdaAlias}
</code></pre>
<p>Replace <code>&lt;lambda&gt;</code> with the lambda function we configured the versioning before.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/07/image-7.png" class="kg-image" alt loading="lazy"></figure><!--kg-card-begin: markdown--><p>Click the checkmark, then add the appropriate permission using <a href="https://aws.amazon.com/cli/?ref=mira1e-dev">AWSCLI</a> for the Lambda Function by copying the command in the pop-up dialog.<br>
The command should be something looks like the following:</p>
<pre><code class="language-bash">aws lambda add-permission
    --function-name &quot;arn:aws:lambda:&lt;AWS_REGION&gt;:&lt;ARN_NUMBER&gt;:function:&lt;lambda&gt;:${stageVariables.lambdaAlias}&quot;
    --source-arn &quot;arn:aws:execute-api:&lt;AWS_REGION&gt;:&lt;ARN_NUMBER&gt;:&lt;ENDPOINT&gt;&quot;
    --principal apigateway.amazonaws.com
    --statement-id 5cce4d58-29eb-4e72-88b2-72df38c38f0f
    --action lambda:InvokeFunction
</code></pre>
<p>Run the command twice, replace <strong><code>${stageVariables.lambdaAlias}</code></strong> with each <code>lambdaAlias</code> stage variable that created earlier (<code>stable</code> and <code>dev</code>).</p>
<p>When done, the API <code>/getreport</code> should have two endpoint available:</p>
<ul>
<li><code>&lt;API_URI&gt;/prod/getreport</code>: The production stage, this should always be up and stable.</li>
<li><code>&lt;API_URI&gt;/dev/getreport</code>: Developers can use this endpoint for development and testing.</li>
</ul>
<!--kg-card-end: markdown--><p>Creating versioning for API is important, especially for large-scaled applications, in the future there might be more versions rather than just two, and it is always welcome to reference this article as a guide to publish additional version of Lambda Function and APIs.</p>]]></content:encoded></item><item><title><![CDATA[Create Your First Mod in Cities: Skylines]]></title><description><![CDATA[<p>In the recent days I was playing a popular city builder simulation game <a href="https://store.steampowered.com/app/255710/Cities_Skylines/?ref=mira1e-dev">Cities: Skylines</a> and I spent a lot of time on it. This is a game that not only great by itself, but also has a large community on the steam workshop with hundreds of thousands of mod</p>]]></description><link>https://magickaichen.com/create-your-first-mod-in-cities-skylines/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a56</guid><category><![CDATA[GameDev]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Thu, 10 Jan 2019 07:33:27 GMT</pubDate><media:content url="https://magickaichen.com/content/images/2026/04/Cities-Skylines-Wallpaper.webp" medium="image"/><content:encoded><![CDATA[<img src="https://magickaichen.com/content/images/2026/04/Cities-Skylines-Wallpaper.webp" alt="Create Your First Mod in Cities: Skylines"><p>In the recent days I was playing a popular city builder simulation game <a href="https://store.steampowered.com/app/255710/Cities_Skylines/?ref=mira1e-dev">Cities: Skylines</a> and I spent a lot of time on it. This is a game that not only great by itself, but also has a large community on the steam workshop with hundreds of thousands of mod authors that are keep providing stunning additional custom contents to the game. In this article I will show you how to get started on your first mod if you are thinking of being a mod author to this game.</p><p>This tutorial is for PC only, the project hierarchy may be different and you may need alternate developing tools to create mods on Mac or Linux machines.</p><h3 id="recommended-tools">Recommended Tools</h3><ul><li>Visual Studio 2015 (and Above) *</li><li><a href="https://steamcommunity.com/sharedfiles/filedetails/?id=450877484&amp;searchtext=modtool&amp;ref=mira1e-dev">ModTools</a> by BloodPenguin (For debug purposes)</li></ul><p>*You are more than welcome to use other IDEs and text editors</p><h3 id="special-thanks">Special Thanks</h3><p>I would like to take some time to thank <a href="https://community.simtropolis.com/profile/678517-boformer/?ref=mira1e-dev">boformer</a> and his awesome <a href="https://community.simtropolis.com/forums/topic/73388-mod-development-tutorialsdocumentation/?ref=mira1e-dev">modding tutorial series</a>, most of the content in this tutorial is originally created by him.</p><!--kg-card-begin: markdown--><h2 id="getstarted">Get Started</h2>
<p>Let&apos;s get started by creating a simple mod which shows the detailed zone demand (Residential, Commercial, Workplace) by numbers when you pressed a hotkey, it is not something really useful, but enough to get your hands dirty to start.</p>
<h3 id="projecthierarchy">Project Hierarchy</h3>
<p>Generally, in Cities: Skylines, all mods will be placed at <code>%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods</code> with a folder structure like following:</p>
<pre><code class="language-bash">\Mods
&#x2514;-- ModName
    |-- ModName.dll(Automatically Compiled)
    &#x2514;-- \source
        &#x2514;-- ModName.cs(source code)
</code></pre>
<p>However, it is not necessary to create structures in advance like this, since we will configure Visual Studios to do it automatically in the later steps.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="codeyourfirstmod">Code Your First Mod</h3>
<p>Now, let&apos;s jump into Visual Studio start coding.</p>
<h4 id="createyourfirstclass">Create your first class</h4>
<p>Once VS is opened, create a new project, select <code>Visual C# &gt; Class Library (.Net Framework)</code> as the template. Give it a name like &quot;RCWDemand&quot; or any name you like, and choose a location to place your source code (note: the source code does not need to be placed inside <code>\Mod</code> folder as previously listed, we will configure Visual Studio to automatically copy the compiled <code>.dll</code> file to that folder, which will be mentioned later).</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://magickaichen.com/content/images/2019/01/image-1.png" class="kg-image" alt="Create Your First Mod in Cities: Skylines" loading="lazy"><figcaption>Create Project</figcaption></figure><!--kg-card-begin: markdown--><h4 id="adddependenciestotheproject">Add dependencies to the project</h4>
<p>Once we created a class, we need to add all of supported Cities: Skylines APIs to our dependency list:</p>
<ul>
<li>ICities (<code>ICities.dll</code>)</li>
<li>UnityEngine (<code>UnityEngine.dll</code>)</li>
<li>ColossalFramework (<code>ColossalManaged.dll</code>)</li>
<li>Assembly-CSharp(<code>Assembly-CSharp.dll</code>)</li>
</ul>
<p>Let&apos;s do it by right click the reference in Solution Manager (The tab on the upper right corner), then select &quot;Add Reference&quot;, on the popup menu, use &quot;Browse...&quot; button  to select those <code>.dll</code> files, which located at <code>Steam\steamapps\common\Cities_Skylines\Cities_Data\Managed</code>.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://magickaichen.com/content/images/2019/01/image-2.png" class="kg-image" alt="Create Your First Mod in Cities: Skylines" loading="lazy"><figcaption>Your Reference Manager will looks like this, make sure all of them are checked and click OK to continue</figcaption></figure><!--kg-card-begin: markdown--><h4 id="automateddeployment">Automated Deployment</h4>
<p>To speed through the development process, we will configure Visual Studio to do two things:</p>
<ol>
<li>Automatically copy the compiled <code>.dll</code> file to the mod directory in Cities: Skylines.</li>
<li>Make the game to auto hot-reload the mod while running after every rebuild.</li>
</ol>
<p>To auto copy, right click the project node in the solution explorer, and choose &quot;Properties&quot;, select &quot;Build Events&quot; in the left panel, then paste the following command in the &quot;Post-build&quot; event:</p>
<pre><code class="language-bash">mkdir &quot;%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods\$(SolutionName)&quot;
del &quot;%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods\$(SolutionName)\$(TargetFileName)&quot;
xcopy /y &quot;$(TargetPath)&quot; &quot;%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods\$(SolutionName)&quot;
</code></pre>
<p>Save (<code>Ctrl + S</code>) and close the tab.</p>
<p>Then simply change the bottom two lines in <code>AssemblyInfo.cs</code> to make the game auto hot-reload our mod while running:</p>
<pre><code class="language-csharp">[assembly: AssemblyVersion(&quot;1.0.*&quot;)]
//[assembly: AssemblyFileVersion(&quot;1.0.0.0&quot;)]
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="workingonthemodfinally">Working on the Mod (Finally)</h4>
<p>After finishing all of the above steps, we can start working on the project.<br>
(Note: everytime you start a brand new project, you need to repeat these steps to get it working.)</p>
<p>double click on <code>Class1.cs</code> and replace the code with this:</p>
<pre><code class="language-csharp">using UnityEngine;
using ICities;

namespace RCWDemand
{
	public class RCWDemandMod : IUserMod {
		public string Name =&gt; &quot;RCW Demand&quot;;

		public string Description =&gt; &quot;Show actual RCW Demands in numbers.&quot;;
	}
}
</code></pre>
<p>Here we created a new class called <code>RCWDemandMod</code> and make it extends the base class <code>IUserMod</code>, then implemented the two virtual funtions <code>Name()</code> and <code>Description()</code>, the <code>=&gt;</code> symbol is equivalent to <code>get { return ... }</code>.</p>
<p>If you are not really familiar with Object Oriented Programming(OOP) or Polymorphism, you need to study that as soon as possible, but what this does is to let our newly created class to be a mod class so it can be recognized by the game, and give it a name and description.</p>
<p>Before we make any further development, let&apos;s see if everything we configured works.</p>
<p>Build the entire solution (<code>Build &gt; Build Solution</code> or <code>CTRL + SHIFT + B</code>), then go to the mods directory of the game (<code>%LOCALAPPDATA%\Colossal Order\Cities_Skylines\Addons\Mods</code>), you should see a folder named as the project you created (<code>RCWDemand</code> in our case) with a compiled <code>.dll</code> file that has the same name inside.</p>
<p>Now start the game, in your content mamager, you should see the mod appears in the &quot;Mods&quot; tab, enable it if it&apos;s not, although it doesn&apos;t have any functionality yet.</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://magickaichen.com/content/images/2019/01/image-3.png" class="kg-image" alt="Create Your First Mod in Cities: Skylines" loading="lazy"><figcaption>You should see the mod appears in the game (My game uses Simplified Chinese instead of English)</figcaption></figure><!--kg-card-begin: markdown--><h4 id="addfunctionalitiestothemod">Add Functionalities to the Mod</h4>
<p>Let&apos;s finish up this mod, now it&apos;s time to test your auto hot-reloading! Enter a savegame or create a brand new scene in the game, then leave it for right now and back to Visual Studio.</p>
<p>We will use threading hook to check if the player is pressing the hotkeys (let&apos;s use <code>CTRL + D</code> in this project), the <code>IThreadingExtension/ThreadingExtensionBase</code> is a hook provided by the official modding API. Classes implementing them are invoked before, during and after every simulation tick. Since it will be executed many times per second in game, make sure your implementation does not contain jobs that are heavy-workloaded (like I/O Operations or instantiating new game objects), or it may slow down the game.</p>
<p>Create a new class called <code>ShowDemand</code> below <code>Name()</code> and <code>Description()</code>:</p>
<pre><code class="language-csharp">public class ShowDemand : ThreadingExtensionBase {

		private bool _processed = false;
		public override void OnUpdate(float realTimeDelta, float simulationTimeDelta) {
			Debug.Log(_processed);

			if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) &amp;&amp; Input.GetKey(KeyCode.D)) {
				if (_processed)
					return;

				_processed = true;
				int rDemand = ZoneManager.instance.m_actualResidentialDemand;
				int cDemand = ZoneManager.instance.m_actualCommercialDemand;
				int wDemand = ZoneManager.instance.m_actualWorkplaceDemand;

				string message = $&quot;Residential: {rDemand}\nCommercial: {cDemand}\nWorkplace: {wDemand}&quot;;

				ExceptionPanel panel = UIView.library.ShowModal&lt;ExceptionPanel&gt;(&quot;ExceptionPanel&quot;);
				panel.SetMessage(&quot;Detailed RCW Demand&quot;, message, false);
			}

			else {
				_processed = false;
			}
		}
	}
</code></pre>
<p>Make sure to include the UI namespace at the top:</p>
<pre><code class="language-csharp">using ColossalFramework.UI; 
</code></pre>
<p>You can also create the class in the separate folder, I would recommend doing this if our project gets larger, but we will keep this for right now.</p>
<p>Now, your completed code should looks like this:</p>
<pre><code class="language-csharp">using UnityEngine;
using ICities;
using ColossalFramework.UI;

namespace RCWDemand
{
	public class RCWDemandMod : IUserMod {
		public string Name =&gt; &quot;RCW Demand&quot;;

		public string Description =&gt; &quot;Show actual RCW Demands in numbers.&quot;;
	}

	public class ShowDemand : ThreadingExtensionBase {

		private bool _processed = false;
		public override void OnUpdate(float realTimeDelta, float simulationTimeDelta) {
			Debug.Log(_processed);

			if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) &amp;&amp; Input.GetKey(KeyCode.D)) {
				if (_processed)
					return;

				_processed = true;
				int rDemand = ZoneManager.instance.m_actualResidentialDemand;
				int cDemand = ZoneManager.instance.m_actualCommercialDemand;
				int wDemand = ZoneManager.instance.m_actualWorkplaceDemand;

				string message = $&quot;Residential: {rDemand}\nCommercial: {cDemand}\nWorkplace: {wDemand}&quot;;

				ExceptionPanel panel = UIView.library.ShowModal&lt;ExceptionPanel&gt;(&quot;ExceptionPanel&quot;);
				panel.SetMessage(&quot;Detailed RCW Demand&quot;, message, false);
			}

			else {
				_processed = false;
			}
		}
	}
}

</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="testing">Testing</h4>
<p>Now it&apos;s time to see if it works! Simply build the project (<code>CTRL + SHIFT + B</code>) and jump back into game, it should auto reload the mod withouy quiting the game.</p>
<p>Press <code>CTRL + D</code> to test the mod, it should show up like below:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://magickaichen.com/content/images/2019/01/image-4.png" class="kg-image" alt="Create Your First Mod in Cities: Skylines" loading="lazy"></figure><!--kg-card-begin: markdown--><h3 id="debugyourmod">Debug Your Mod</h3>
<p>In case of your mod is not working properly, there&apos;s many ways to debug your mod, what I recommend is to look at the <a href="https://skylines.paradoxwikis.com/Debugging_Mods?ref=mira1e-dev">debugging page</a> on official developer wiki to choose the way you feel most confortable with. The way I choose is to use Unity&apos;s debug logging API:</p>
<pre><code class="language-csharp">Debug.Log(...);
</code></pre>
<p>and then subscribe to <a href="https://steamcommunity.com/sharedfiles/filedetails/?id=450877484&amp;ref=mira1e-dev">ModTools</a> to see the debug log.</p>
<!--kg-card-end: markdown--><p>Congrats! You just created your first mod in Cities: Skylines! </p><p>Happy Modding!</p>]]></content:encoded></item><item><title><![CDATA[Use Semantic UI in create-react-app]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Semantic UI a powerful UI framework for front-end development, and few years ago it launched a React integration: <a href="https://react.semantic-ui.com/?ref=mira1e-dev">Semantic UI React</a>. However it does not have any instructions for installing on apps bootstrapped with <code>create-react-app</code>. This blog will be a very short one -- it includes the recipe I used</p>]]></description><link>https://magickaichen.com/installing-semantic-ui-in-create-react-app/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a55</guid><category><![CDATA[WebDev]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Wed, 31 Oct 2018 11:42:55 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Semantic UI a powerful UI framework for front-end development, and few years ago it launched a React integration: <a href="https://react.semantic-ui.com/?ref=mira1e-dev">Semantic UI React</a>. However it does not have any instructions for installing on apps bootstrapped with <code>create-react-app</code>. This blog will be a very short one -- it includes the recipe I used while installing the full Semantic UI package on my <code>create-react-app</code> project, and the problems I was running into.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="installreactpackage">Install React package</h3>
<p>Before we move on, make sure you have the React package for Semantic UI:</p>
<ul>
<li>Install via <code>yarn</code>:</li>
</ul>
<pre><code class="language-bash">&gt; yarn add semantic-ui-react
</code></pre>
<ul>
<li>Install via <code>npm</code>:</li>
</ul>
<pre><code class="language-bash">&gt; npm install semantic-ui-react
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h3 id="installuipackage">Install UI Package</h3>
<p>After that, we can start installing Semantic UI, you can either install the full Semantic UI package (which is what we are going to cover here), or just have the CSS package if you don&apos;t want custom theming support.</p>
<h4 id="issuesontheofficialdocumentation">Issues on the <a href="https://react.semantic-ui.com/usage/?ref=mira1e-dev">official documentation</a>:</h4>
<p>The official documentation recommends to use <code>yarn</code> to install the package:</p>
<pre><code class="language-bash">&gt; yarn add semantic-ui --dev
</code></pre>
<p>However it will freeze at the first step of installing, it has been an <a href="https://github.com/Semantic-Org/Semantic-UI/issues/4801?ref=mira1e-dev">known issue</a> for a while.</p>
<p>To install, we have two methods, each one is relatively short and simple.</p>
<h4 id="method1vianpm">Method 1: Via <code>npm</code></h4>
<p>Instead of using <code>yarn</code>, we can use <code>npm</code> to install:</p>
<pre><code class="language-bash">&gt; npm install semantic-ui --saveDev
</code></pre>
<h4 id="method2viayarn">Method 2: Via <code>yarn</code></h4>
<p>If you think <code>npm</code> is too slow and insist to use <code>yarn</code>...okay I understand, but do this instead (thanks to <a href="https://github.com/Ahmad-Maged?ref=mira1e-dev">@Ahmad-Maged</a>&apos;s <a href="https://github.com/yarnpkg/yarn/issues/976?ref=mira1e-dev#issuecomment-380513970">solution</a> on this issue):</p>
<pre><code class="language-bash">&gt; yarn add semantic-ui --ignore-scripts
&gt; cd ./node_modules/semantic-ui/
&gt; gulp install
</code></pre>
<p>For both methods, choose the desired installation method as you wish when prompted (I choose &quot;Automatic&quot; for the sake of simplicity).<br>
For the installation path, Semantic UI needs to be installed inside the <code>/src</code> since your <code>create-react-app</code> instance will not have permission to navigate outside of it. Make sure you put the <strong>absolute path</strong> here (for example: <code>C:/my-react-app/src</code> if <code>/my-react-app</code> is your project root folder).</p>
<p>After the installation is complete, the UI package will be installed at <code>../project-folder/src/semantic</code>.<br>
Move the file <code>semantic.json</code> to folder <code>/semantic</code>, and edit it:</p>
<pre><code class="language-diff">{
-   &quot;base&quot;: &quot;semantic\\&quot;,
+   &quot;base&quot;: &quot;/&quot;,
    &quot;paths&quot;: {
    &quot;source&quot;: {
      ...
    },
    ...
}
</code></pre>
<h3 id="buildsemanticlibrary">Build Semantic Library</h3>
<pre><code class="language-bash">&gt; cd /project-folder/src/semantic`
&gt; gulp build
</code></pre>
<p>Then, every time before making changes to the theme:</p>
<pre><code class="language-bash">&gt; gulp watch
</code></pre>
<h3 id="makesureeverythingworks">Make sure everything works</h3>
<p>To make Semantic UI works, add the minified CSS to <code>src/index.js</code>:</p>
<pre><code class="language-jsx">import &apos;./semantic/dist/semantic.min.css&apos;;
</code></pre>
<p>To test if the installation is successful, simply add some components from Semantic UI to your site, for example, we can add a button on the top of our <code>App.js</code>:</p>
<pre><code class="language-jsx">import React, { Component } from &apos;react&apos;;
import { Button } from &apos;semantic-ui-react&apos;
...
class App extends Component {
  render() {
    return (
      &lt;div className=&quot;App&quot;&gt;
        &lt;Button&gt;Test&lt;/Button&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          ...
        &lt;/header&gt;
      &lt;/div&gt;
    );
  }
}

export default App;
</code></pre>
<p>If the button shows up on top, cheers! You have succesfully added Semantic UI to your app!</p>
<h3 id="gettingstucknoluck">Getting Stuck? No Luck?</h3>
<p>Make a comment below! Make sure to describle the problems as detailed as possible so I can take a look what&apos;s wrong!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Programming in Unity: Use Singleton Pattern]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I believe at lease some of you have met this situation (or similar) while developing your own games in Unity: There is a <code>GameManager.cs</code> script attached to a <code>gameObject</code>(probably named as &quot;GameManager&quot; as well):</p>
<pre><code class="language-csharp"> public class GameManager : MonoBehaviour {
     
     private const float StartingTime = 60f;
     private int _time;</code></pre>]]></description><link>https://magickaichen.com/use-singleton-how-to-make-your-code-clean-and-make-your-teammate-happy/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a54</guid><category><![CDATA[GameDev]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Wed, 16 May 2018 18:24:23 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I believe at lease some of you have met this situation (or similar) while developing your own games in Unity: There is a <code>GameManager.cs</code> script attached to a <code>gameObject</code>(probably named as &quot;GameManager&quot; as well):</p>
<pre><code class="language-csharp"> public class GameManager : MonoBehaviour {
     
     private const float StartingTime = 60f;
     private int _time;
     ...
     // some other variables and methods
     ...
     
     public void RoundRestart() {
         _time = StartingTime;
         ResetSpawnPoint();
     }
}
</code></pre>
<p>And you need to get it in an another script (<code>Player.cs</code>, for example):</p>
<pre><code class="language-csharp"> public class Player : MonoBehaviour {
     
     private float _health = 100f;
     ...
     // some other variables and methods
     ...
     
     private void Update() {
         if (health &lt;= 0f) {
             // RoundRestart() &lt;- NEED TO CALL THIS METHOD IN GameManager
         }
     }
}
</code></pre>
<p>How to do that? Some of you might tried to create an <code>GameManager</code> variable in the <code>Player.cs</code>, find the <code>GameManager</code> and assign to it:</p>
<pre><code class="language-csharp">GameManager _gm = GameObject.FindGameObjectWithTag(&quot;GameManager&quot;).GetComponent&lt;GameManager&gt;();
_gm.RoundRestart();
</code></pre>
<p>or <s>some lazy bastards</s> will create a serialized field and drag the object to the slot in Unity Editor:</p>
<pre><code class="language-csharp"> public class Player : MonoBehaviour {
     
     [SerializedField] GameManager _gm;
     
     ...
     
     private void Update() {
         if (health &lt;= 0f) {
             _gm.RoundRestart();
         }
     }
}
</code></pre>
<p>Seems like it solves the problem, nice. Now we have another problem: what if there are some other scripts (more than 10) also need the <code>GameManager</code> script?</p>
<p>We can just copy the code we wrote for <code>Player.cs</code>, then we created multiple references to <code>GameManager</code>, which causes a lot of redunancy. To solve this problem without copy and paste the code around, we can use a design pattern: <strong>Singleton</strong>:</p>
<blockquote>
<p>In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton. (from <a href="https://en.wikipedia.org/wiki/Singleton_pattern?ref=mira1e-dev#C#_implementation">Wikipedia - Singleton Pattern</a>)</p>
</blockquote>
<p>To make the <code>GameManager</code> singleton is simple:</p>
<pre><code class="language-csharp"> public class GameManager : MonoBehaviour {
 
     private static GameManager Instance; // **&lt;- reference link to GameManager
     
     ...
     
     private void Awake() {
         if (Instance == null) {
             Instance = this;
         }
         else {
             Destroy(gameObject);
         }
     }
     
     ...
}
</code></pre>
<p>That&apos;s it! The piece of code above creates a static reference of <code>GameManager</code> instance (which is itself) and delete any duplicate instances. With this, getting a reference of your <code>GameManager</code> is much easier, for example, to access a <code>public</code> function in your <code>GameManager</code>, instead of doing:</p>
<pre><code class="language-csharp">GameManager manager;
...
mamager.SomeFunction();
</code></pre>
<p>you can directly access it using:</p>
<pre><code class="language-csharp">GameManager.Instance.SomeFunction();
</code></pre>
<p><em>A note of using Singleton Pattern</em>: <strong>DO NOT</strong> abuse singleton pattern! It is a pattern which usually been used for global configurations and sometimes it is considered as a &quot;anti-pattern&quot; (since it is basically a global variable but nicely written), such as <code>GameManager</code> in our case. Only use singleton if you are sure your game has and only has exactly <strong>One</strong> instance of this object. For example, you should not use singleton pattern on <code>Enemy</code>, or <code>PickupItem</code> since those objects are very likely to have more than one.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Game AI Basics - Patrolling]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Patrolling is the most commonly used movement type while designing enemy AI, it is simple and makes your enemies looks &quot;smarter&quot; than just standing still, also it is easy to implement.</p>
<h3 id="asimplesolutionstaticwaypoints">A simple solution - static waypoints</h3>
<p>Waypoints seems to be the most straight forward solution to come</p>]]></description><link>https://magickaichen.com/game-ai-basics-create-a-wandering-enemy/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a52</guid><category><![CDATA[GameDev]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Sat, 14 Oct 2017 21:00:58 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Patrolling is the most commonly used movement type while designing enemy AI, it is simple and makes your enemies looks &quot;smarter&quot; than just standing still, also it is easy to implement.</p>
<h3 id="asimplesolutionstaticwaypoints">A simple solution - static waypoints</h3>
<p>Waypoints seems to be the most straight forward solution to come up with, the basic idea is to setup an array of waypoint game objects, and let the enemy character move from one to another.<br>
The approach is simple (Use a 2D space in Unity as an example):</p>
<pre><code class="language-csharp">public class EnemyMovement : MonoBehaviour {
    public GameObject[] waypoints;
    public float moveSpeed = 5f;
    
    private GameObject currentWaypoint;
    private int wpIndex = 0; // index of the current waypoint in array
    
    private void Start() {
        wpIndex = 0;
        currentWaypoint = waypoints[wpIndex]; // initialize current waypoint
    }
    
    private void Update() {
        Patrol();
    }
    
    private void Patrol() {
        if (WpReached()) {
            UpdateWp(); // move to next waypoint if reached the current one
        }
        gameObject.transform.position = Vector2.MoveTowards(
            gameObject.transform.position, 
            currentWaypoint.transform.position, 
            moveSpeed * Time.deltaTime
        );  // move towards the current waypoint
    }
    
    private bool WpReached(Vector2 position, Vector2 target, float allowance) {
        return Vector2.Distance(position, target) &lt;= allowance
    }
    
    private void UpdateWp(){
        wpIndex++; // next waypoint
        wpIndex = wpIndex % waypoints.Length; // cycling from 0 to waypoint length
        currentWaypoint = waypoints[wpIndex];
    }
}
</code></pre>
<p>Looks good, but seems like the enemy will always move between the given waypoints, so the player can predict the enemy&apos;s path after few plays. What if I want my enemy patrols randomly?</p>
<h3 id="improvementrandomwaypoints">Improvement - Random waypoints</h3>
<p>To make the enemy move randomly, we have to let enemy chose the waypoint by itself, the idea is to randomly choose a new x location when the enemy reaches its destination, and set the next waypoint location to <code>(newX, currentY)</code>.<br>
Here&apos;s the approach (again, a 2D space in Unity):</p>
<pre><code class="language-csharp">public class EnemyMovement : MonoBehaviour {
    public float moveSpeed = 5f;
    
    private GameObject currentWaypoint;
    
    private void Start() {
        currentWaypoint = SelectRandomPoint(); // initialize current waypoint
    }
    
    private void Update() {
        Patrol();
    }
    
    private void Patrol() {
        if (WpReached()) {
            currentWaypoint = SelectRandomPoint(); // select a new waypoint
        }
        gameObject.transform.position = Vector2.MoveTowards(
            gameObject.transform.position, 
            currentWaypoint.transform.position, 
            moveSpeed * Time.deltaTime
        );  // move towards the current waypoint
    }
    
    private bool WpReached(Vector2 position, Vector2 target, float allowance) {
        return Vector2.Distance(position, target) &lt;= allowance
    }
    
    private Vector2 SelectRandomPoint() {
        // select a random point inside a circle
        var point = Random.insideUnitCircle * wanderingRadius;
        // eliminate the change of Y
        point.y = 0;
        // Add the difference to the current locaton of enemy
        point += (Vector2)gameObject.transform.position;
        return point;
    }
}
</code></pre>
<p>This will make the enemy patrol to random locations, but what about those location which could be inside of a obstacle? We need to take care of that.<br>
Add this member variable to the <code>EnemyMovement</code> class:</p>
<pre><code class="language-csharp">public LayerMask layer; // layer of all obstacles
</code></pre>
<p>And this to the beginning of your <code>Patrol()</code> function:</p>
<pre><code class="language-csharp">if (Physics2D.OverlapCircleAll(wanderWaypoint, 1, layer).Length != 0) {
    currentWaypoint = SelectRandomPoint();
}
</code></pre>
<p>This will detect if the waypoint overlaps with any game objects in obstacle layer, if yes then select a new point.<br>
Of course, you need to set all of your obstacle game objects (such as walls, ground blocks, platforms, etc.) to a new layer, and then attach this code to your enemy game object then select the obstacle layer(s) in the inspector.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Network Programming: Blocking & Non-blocking, Synchronous & Asynchronous]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>This could be one of the concepts that will easily get confused, especially for those ones just get started on network programming.</p>
<h2 id="themajordifference">The Major Difference</h2>
<p>First thing: blocking operation does <strong>NOT</strong> equal to synchronous, also non-blocking operation does <strong>NOT</strong> equal to asynchronous. Actually, they don&apos;t have direct relevant</p>]]></description><link>https://magickaichen.com/unblock-block/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a51</guid><category><![CDATA[Networking]]></category><category><![CDATA[WebDev]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Sat, 26 Aug 2017 02:06:40 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>This could be one of the concepts that will easily get confused, especially for those ones just get started on network programming.</p>
<h2 id="themajordifference">The Major Difference</h2>
<p>First thing: blocking operation does <strong>NOT</strong> equal to synchronous, also non-blocking operation does <strong>NOT</strong> equal to asynchronous. Actually, they don&apos;t have direct relevant with each other.</p>
<h3 id="synchronousasynchronous">Synchronous &amp; Asynchronous</h3>
<p>Synchronous/asynchronous describes the <strong>communication mechanism</strong>.</p>
<p><strong>Synchronous</strong> is, when we started a function call, the call will not return anything until it gets the result, the function needs to finish everything before it can give anything to us.</p>
<p><strong>Asynchronous</strong> does not need to wait for the function completes its operation, once we call it, it returns immediately without any result, the function uses callback function (or other notification method) to &quot;notify&quot; us to get the value after it completes execution.</p>
<h3 id="acommonnoobproblemwhyigetnullfrommygetter">A Common &quot;Noob&quot; Problem: Why I get <code>null</code> from my getter?</h3>
<p>Before we continue, let&apos;s take a look at this getter from an android project:</p>
<pre><code class="language-java">public class CarService {
    public Car getCar() {
        ...
        client.get(&quot;https://car.example/api&quot;, params, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] res) {
                try {
                    String result = new String(res, &quot;utf-8&quot;);
                    Gson gson = new GsonBuilder().create();
                    car = gson.fromJson(result, Car.class);
                } catch (UnsupportedEncodingException e) {
                    Log.e(&quot;Error&quot;, e.getMessage());
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] res, Throwable error) {
                Log.e(&quot;Request Error&quot;, String.valueOf(statusCode));
            }
        });
        return car;
    }
}
</code></pre>
<p>Looks like it has no problem: it establishes an API call to get the car from server, and returns it at the end. However, when this getter gets called in another class:</p>
<pre><code class="language-java">public CarActivity extends Activity {
    private Car myCar;
    private CarService carService;
    //.....
    public void setMyCar() {
        myCar = carService.getCar();    // &lt;- *this will return null*
    }
}
</code></pre>
<p><code>myCar</code> will be <code>null</code>, why? Because the getter starts an async operation <code>AsyncHttpResponseHandler()</code> to establish an API call asynchronously and returns <code>car</code> immediately right after that, the function will not wait for the inside code (<code>onSuccess()</code>, <code>onFailure()</code>, etc) to finish, so <code>car</code> gets returned before it gets the value from the server.</p>
<p>So how to solve it? A straight forward solution is to use a callback to handle the response instead of just return it:</p>
<pre><code class="language-java">public interface CarServiceCallBack {
    void onSuccess(Car car);
}
</code></pre>
<p>In class <code>CarService</code>:</p>
<pre><code class="language-java">public void getCar(final CarServiceCallback callback) {
    client.get(&quot;https://car.example/api&quot;, params, new AsyncHttpResponseHandler() {
        @Override
        public void onSuccess(int statusCode, Header[] headers, byte[] res) {
            try {
                String result = new String(res, &quot;utf-8&quot;);
                Gson gson = new GsonBuilder().create();
                car = gson.fromJson(result, Car.class);
                callback.onSuccess(car); // &lt;- Pass the car object to callback funtion
            } catch (UnsupportedEncodingException e) {
                Log.e(&quot;Error&quot;, e.getMessage());
            }
        }
        ...
    }
}
</code></pre>
<p>And in <code>CarActivity.setMyCar()</code>:</p>
<pre><code class="language-java">public void setMyCar() {
    // Construct a new callback object
    carService.getCar(new CarServiceCallback() {
        @Override
        public void onSuccess(Car car) {
            myCar = car;    // &lt;- pass the received car object to myCar
        }
    });
}
</code></pre>
<p>How this works? When <code>CarActivity.setMyCar()</code> gets called, it will call <code>carSerivce.getCar()</code> and pass in a new callback interface <code>CarServiceCallback</code> to handle the async operation, while the client successfully gets the response, in the handler&apos;s <code>onSuccess()</code> it will ask the callback interface to call its <code>onSuccess()</code> method, which is implemented in <code>CarActivity.setMyCar()</code>:</p>
<pre><code class="language-java">public void onSuccess(Car car) {
    myCar = car;    // &lt;- pass the received car object to myCar
}
</code></pre>
<h3 id="blockingnonblocking">Blocking &amp; Non-blocking</h3>
<p>Unlike synchronous/asynchronous, blocking/non-blocking focuses on the <strong>status of the program</strong> while waiting for the result from the function call.</p>
<p>A <strong>blocking</strong> operation <strong>hangs up</strong> current thread before it gets the result, in other words, a blocking operation will let the current thread wait for the result returns, even if the target function will use a callback function to notify client side to fetch the result, the thread on the client side will still be blocked until it gets the returned result. In opposite way, the <strong>non-blocking</strong> operation <strong>will not hang up</strong> the current thread if no result returned immediately.</p>
<h2 id="asimpleexample">A Simple Example</h2>
<p>You are the customer making the phone call to the hotel to make a reservation.</p>
<p><strong>Synchronous</strong>: The hotel receptionist receives the call and ask you to wait while he/she needs to look up the calendar to see if there is any available time slot. After finished looking up, the receptionist tells you if the requested time slot is available (result returned).</p>
<p><strong>Asynchronous</strong>: The hotel receptionist receives the call and tell you that they have got the information, then he/she hangs up, you will receive a call back from the hotel once they have finished checking (callback).</p>
<p><strong>Blocking</strong>: You make the phone call, before you get any result back, you will sit on the couch and do nothing until the hotel tells you if your reservation can be made.</p>
<p><strong>Non-blocking</strong>: You make the phone call, after telling the information to the hotel, you start to do something else (drink water, eat snacks, take shower, etc.) and check if you get any results every few minutes.</p>
<h2 id="overall">Overall</h2>
<p>The example above should give you a clear understanding of the underlying communication between client (you) and server (hotel). Sync/Async usually describes how the server will deal with incoming requests, and Blocking/Non-blocking describes how the client side will handle the results (wait or do something else).</p>
<p>Further Reading:<br>
<a href="https://www.javatpoint.com/understanding-synchronous-vs-asynchronous?ref=mira1e-dev">Understanding Synchronous vs Asynchronous (AJAX) - JavaTPoint</a><br>
<a href="http://faculty.salina.k-state.edu/tim/ossg/Device/blocking.html?ref=mira1e-dev">Blocking and Nonblocking I/O - Kansas State Polytechnic</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Create a loading scene with a "real" loading bar in Unity]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Transition between scenes in Unity is easy, but how to create an intermediate &quot;loading&quot; scene with a loading bar which displays the current progress? In this article I will talk about how to create a loading bar which actually shows loaded percentage for the upcoming scene.</p>
<p>(Cover Photo</p>]]></description><link>https://magickaichen.com/create-a-loading-scene-with-a-real-loading-bar-in-unity/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a50</guid><category><![CDATA[GameDev]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Sat, 04 Mar 2017 16:30:00 GMT</pubDate><media:content url="https://magickaichen.com/content/images/2026/04/gettyimages-1442799355-640x640.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://magickaichen.com/content/images/2026/04/gettyimages-1442799355-640x640.jpg" alt="Create a loading scene with a &quot;real&quot; loading bar in Unity"><p>Transition between scenes in Unity is easy, but how to create an intermediate &quot;loading&quot; scene with a loading bar which displays the current progress? In this article I will talk about how to create a loading bar which actually shows loaded percentage for the upcoming scene.</p>
<p>(Cover Photo Credit: sgprolab)</p>
<h4 id="thingsyoushouldknowalready">Things You Should Know Already</h4>
<p>Before we get started, let&apos;s look at how to switch between scenes in Unity:</p>
<pre><code class="language-csharp">using UnityEngine;
/*...some other includes...*/
using UnityEngine.SceneManagement;

public class ChangeScene : MonoBehaviour {
    public void ChangeScene(string sceneName) {
        SceneManager.LoadScene(sceneName);
    }
}
</code></pre>
<p>When <code>ChangeScene()</code> gets called, it will trigger <code>SceneManager</code> to load the scene with the specific <code>sceneName</code>.</p>
<p>Well, this might work for most of the cases, but the game will stuck for a bit while the other scene is getting loaded in, especially if it is a large one, it may takes a half to a second to finish loading, which makes your game looks craggy. Also, it is nice to have a loading bar to actually tell the player the game is doing loading operation.</p>
<h4 id="talkischeapshowmethecode">&quot;Talk is cheap, show me the code&quot;</h4>
<p>Okay...okay...well, the basic idea is, while we loading a scene, we want to display the loading UI and let the scene to be loaded in the background, then switch to the scene when the loading process is completed.</p>
<p>Fortunately, Unity has a powerful scripting API library which makes possible for us to finish this job by just few lines of code, you can load your scene asynchronously using <code>SceneManager.LoadSceneAsync()</code>.</p>
<p>Let&apos;s see how can we get this done: to make a &quot;real&quot; loading progress bar, we need to know the data of loading progress to get it shown on our UI (in here I used a <code>Slider</code> to display the current loading progress). In Unity, we can do:</p>
<pre><code class="language-csharp">AsyncOperation sceneAO;
</code></pre>
<p>And assign it in a Coroutine called <code>LoadingSceneRealProgress()</code>:</p>
<pre><code class="language-csharp">IEnumerator LoadingSceneRealProgress(string sceneName) {
    ...
    sceneAO = SceneManager.LoadSceneAsync(sceneName);
    ...
}
</code></pre>
<p>This creates a <code>AsyncOperation</code> called <code>sceneAO</code> which will perform the loading operation in the background while we call <code>ChangeScene()</code> to start the Coroutine, notice here we use <code>LoadSceneAsync()</code> instead of <code>LoadScene()</code> to initialize a Asynchronous Operation.</p>
<p>Then, if you want to do something after the scene is fully loaded but before it brings you to the new scene, you can turn off the scene activation:</p>
<pre><code class="language-csharp">sceneAO.allowSceneActivation = false;
</code></pre>
<p>And turn it back on when you are finished:</p>
<pre><code class="language-csharp">sceneAO.allowSceneActivation = true;
</code></pre>
<p>To get the loading progress shown on the slider, we can simply assign the loading progress data to the value of the slider:</p>
<pre><code class="language-csharp">while(!sceneAO.isDone) {
    loadingProgbar.value = sceneAO.progress;
    // do something else
}
</code></pre>
<p>This will keep assigning the progress data to the value of the progress bar, while the Asynchronous Operation is not complete, which means, before the scene gets fully loaded, the bar will keep updating the loading progress for the upcoming scene, which is exactly what we want.</p>
<p>This is an example in my game <strong><em>Objective: Extraction</em></strong>:</p>
<pre><code class="language-csharp">public class ChangeSceneAsync : MonoBehaviour {

    AsyncOperation sceneAO;
    [SerializeField] GameObject loadingUI;
    [SerializeField] Slider loadingProgbar;
    [SerializeField] Text loadingText;

    // the actual percentage while scene is fully loaded
    private const float LOAD_READY_PERCENTAGE = 0.9f;

    public void ChangeScene(string sceneName){
        loadingUI.SetActive(true);
        loadingText.text = &quot;LOADING...&quot;;
        StartCoroutine(LoadingSceneRealProgress(sceneName));
    }

    IEnumerator LoadingSceneRealProgress(string sceneName) {
        yield return new WaitForSeconds(1);
        sceneAO = SceneManager.LoadSceneAsync(sceneName);

        // disable scene activation while loading to prevent auto load
        sceneAO.allowSceneActivation = false;

        while (!sceneAO.isDone) {
            loadingProgbar.value = sceneAO.progress;

            if (sceneAO.progress &gt;= LOAD_READY_PERCENTAGE) {
                loadingProgbar.value = 1f;
                loadingText.text = &quot;PRESS SPACE TO CONTINUE&quot;;
                if (Input.GetKeyDown(KeyCode.Space)) {
                    sceneAO.allowSceneActivation = true;
                }
            }
            Debug.Log(sceneAO.progress);
            yield return null;
        }
    }
}
</code></pre>
<p>This creates a loading bar which will pause the scene while its fully loaded and ask for user a confirm input, if user confirms to navigate to that scene, the script will direct the player to the target scene. Notice that I have a function</p>
<pre><code class="language-csharp">yield return new WaitForSeconds(1);
</code></pre>
<p>which will stop everything else for a second to give the bar UI have enough time to load (or it will show 100% immediately since the upcoming scene is small).</p>
<p>Another place to pay attention is I set <code>LOAD_READY_PERCENTAGE = 0.9f</code>, the reason I set this value to <code>0.9</code> is <code>sceneAO.progress == 0.9</code> when the upcoming scene is fully loaded (yes, it is 90%, not 100%).</p>
<p>I will leave this code for you to think about, feel free to take this code as a reference while developing your own game, and please leave the comment below if you have any questions.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Deploy git to your Ghost blog]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>It&apos;s been a long time ago since I set up my blog and post the very first article. After coming back to MSU from Hong Kong I was pretty busy in the following spring semester since there are a lot of stuff going on (credit transfer, exams, endless</p>]]></description><link>https://magickaichen.com/deploy-git-to-your-ghost-blog-2/</link><guid isPermaLink="false">6401c6fc2ac610304cb98a4f</guid><category><![CDATA[Git]]></category><dc:creator><![CDATA[Mike Xiao]]></dc:creator><pubDate>Wed, 06 Jul 2016 03:47:55 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1556075798-4825dfaaf498?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fGdpdHxlbnwwfHx8fDE3NzU0NTk4MTB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1556075798-4825dfaaf498?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fGdpdHxlbnwwfHx8fDE3NzU0NTk4MTB8MA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=2000" alt="Deploy git to your Ghost blog"><p>It&apos;s been a long time ago since I set up my blog and post the very first article. After coming back to MSU from Hong Kong I was pretty busy in the following spring semester since there are a lot of stuff going on (credit transfer, exams, endless assignments..etc).</p>
<p>Anyway, I&apos;m back again, let&apos;s back to the business. Today I will talk about how to setup <code>git</code> on your own Ghost blog.</p>
<h5 id="alwayssetupaversioncontrol">Always set up a version control</h5>
<p>After successfully setting up Ghost blog, we might still need to make changes on <code>config</code>. It is <strong>important</strong> to have a version control to keep tracking your change and recover your original files from VPS failure or unexpected error occurs after you make changes. In most cases, we use <code>git</code> as your version control system since it is the most popular system used by developers.</p>
<h5 id="deploygittoyourblog">Deploy <code>git</code> to your blog</h5>
<p>In this article we will use GitHub as an example.</p>
<p>First of all, install <code>git</code> on your VPS:</p>
<pre><code class="language-bash">sudo apt-get install git
</code></pre>
<p>Wait till the installation is done, after you installed <code>git</code>, connect it to your GitHub account:</p>
<pre><code class="language-bash">git config --global user.name &quot;your name&quot;  
git config --global user.email &quot;your email&quot;
</code></pre>
<p>Change <code>your name</code> and <code>your email</code> to your GitHub username and email.</p>
<p>To connect, we need to add a <code>ssh key</code> to your GitHub account.</p>
<pre><code class="language-bash">ssh-keygen -t rsa -C &quot;your_email@example.com&quot;
</code></pre>
<p>As the same from above, substitute <code>your_email@example.com</code> to the email you used on GitHub. When generating keys there will be an option for <code>ssh passphrase</code>, use any password you want or hit <code>Enter</code> to skip (use without password).</p>
<p>When completed, under <code>/root/.ssh</code> there will be two files: <code>id_rsa.pub</code> and <code>id_rsa</code>, they are public key and private key respectively.</p>
<p>Open <code>id_rsa.pub</code> use <code>nano</code> or <code>vi</code>, copy <strong>THE ENTIRE</strong> content to your text editor.</p>
<p>Then open your browser and login to GitHub, under <strong>Settings</strong>, click <strong>SSH and GPG keys</strong>, in the right panel, click <strong>New SSH Key</strong>, add any title and paste your key here.<br>
<img src="http://i.imgur.com/U2Q3lL4.png" alt="Deploy git to your Ghost blog" loading="lazy"></p>
<p>Test your key on VPS, make sure it is working:</p>
<pre><code class="language-bash">ssh -T git@github.com
</code></pre>
<p>When you see the information below, means the key is successfully added.<br>
<img src="http://i.imgur.com/7lrSFpP.png" alt="Deploy git to your Ghost blog" loading="lazy"></p>
<p>Create a repository on GitHub with any name (i.e MyBlog), then back to VPS, go to the path of your Ghost blog and initialize <code>git</code>.</p>
<pre><code class="language-bash">cd /var/www/ghost
git init
</code></pre>
<p>sometimes the path is located at home directory, then we use following instead:</p>
<pre><code class="language-bash">cd ghost
git init
</code></pre>
<p>Bind your local repository with your remote repository on GitHub:</p>
<pre><code class="language-bash">git remote add origin git@github.com:your_name/Blog_Name.git 
</code></pre>
<p>Substitute <code>your_name/Blog_Name.git</code> with your GitHub username and the name of your repository.</p>
<p>After binding, add all files in your local repository into git and commit:</p>
<pre><code class="language-bash">git add .
git commit -m &quot;message&quot;
</code></pre>
<p>Flag <code>-m</code> means add message for this commit, <code>message</code> can be any message (don&apos;t forget quotes!).</p>
<p>When you committed all of your work, push all of your changes to the remote repository:</p>
<pre><code class="language-bash">git push origin master
</code></pre>
<p>Go to your repository, make sure your changes has been submitted.</p>
<p>Good to go! You have successfully setup <code>git</code> for your blog.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>