<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Independent Dev Log</title><description>Build, learn, share.</description><link>https://blog.coding1024.com/</link><language>en</language><item><title>Reflections on Programming with AI</title><link>https://blog.coding1024.com/en/posts/e958102a/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/e958102a/</guid><description>How AI changed my approach to localization, game combat systems, code reuse, and software architecture.</description><pubDate>Wed, 10 Jun 2026 10:52:18 GMT</pubDate><content:encoded>&lt;p&gt;Since 2022, AI has been part of the everyday programmer&apos;s workflow for four years. It has now completely changed how we work: productivity, coding conventions, and even architecture have all been turned upside down. Some approaches we once considered foolish suddenly make a great deal of sense.&lt;/p&gt;
&lt;p&gt;Localization is a simple example. Previously, we would look for plugins, or call translation APIs to automate the process. Now I can ask AI to generate the translations and keep one text file per language. It is that straightforward, with no plugin required. Maintaining those files by hand once seemed almost impossible; with AI, it barely feels like a problem.&lt;/p&gt;
&lt;p&gt;Game combat systems are another example. We used to dislike implementing every ability as a separate script: maintenance was difficult, development was slow, and bugs were easy to introduce. I implemented all combat logic—abilities, projectiles, and buffs—with behavior trees, in a setup somewhat like visual scripting. I even built a dedicated behavior-tree editor. It worked reasonably well in practice. Looking back, though, if I were writing that combat system again today, I would not choose behavior trees or visual scripting. I would have AI write the scripts directly.&lt;/p&gt;
&lt;p&gt;I work on an SLG game. Recently, a designer brought us a particularly demanding requirement. We already had a large SLG world map with very complex business logic. The designer wanted a smaller SLG map mode that reused fundamental systems such as marching and combat, but differed substantially in gameplay. Architecturally, I had three choices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reuse the existing code directly and accommodate the differences in the business layer.&lt;/li&gt;
&lt;li&gt;Abstract the shared logic out of the existing code and use it for the new mode.&lt;/li&gt;
&lt;li&gt;Copy the existing code and modify the copy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the past, judged on elegance, I would have ranked option 2 above option 1, with option 3 far behind. Option 3 was an architectural taboo: copying and pasting code was a recipe for a maintenance nightmare. If every new mode meant another copy, how could anyone maintain it?&lt;/p&gt;
&lt;p&gt;Today, I would choose option 3 without hesitation. I would maintain the main gameplay implementation, then have AI adapt the derivative implementations to follow changes in that primary codebase.&lt;/p&gt;
&lt;p&gt;My takeaway is that many clever techniques I once felt proud of now look far less impressive next to AI.&lt;/p&gt;
</content:encoded></item><item><title>A Pragmatic Game Programmer’s Approach to Optimization</title><link>https://blog.coding1024.com/en/posts/9dfa69e1/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/9dfa69e1/</guid><description>Prioritize delivery and maintainability, understand client and server bottlenecks, and optimize around a measured workload.</description><pubDate>Thu, 16 Oct 2025 09:24:42 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I recently interviewed several backend programmers and asked about optimization. Many struggled to give a good answer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, what makes a programmer pragmatic? On a game project, schedule matters enormously. A pragmatic programmer should solve problems quickly and deliver stable code promptly, while keeping it maintainable enough to accommodate changing design requirements.&lt;/p&gt;
&lt;p&gt;One interviewee described optimizing an inventory system. Items had originally been represented as dictionaries, such as &lt;code&gt;{name:&quot;item1&quot;, lv:1, num:99}&lt;/code&gt;. To save space, the developer changed the representation to an array: &lt;code&gt;[&quot;item1&quot;, 1, 99]&lt;/code&gt;. This removed redundant keys, with an API wrapped around the representation to access its fields.&lt;/p&gt;
&lt;p&gt;But was that optimization necessary? It might have halved the inventory system&apos;s memory use. Yet how much of the player&apos;s total data did inventory occupy? If it accounted for only 2% of memory, reducing it to 1% saved just one percentage point overall. In exchange, the code became harder to maintain and the project slowed down. That is a poor trade.&lt;/p&gt;
&lt;p&gt;Here are a few of my views on optimization:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;During game development, optimization has the lowest priority.&lt;/strong&gt; We should not proactively optimize everything. Development speed and maintainability come first, unless a particular feature has hit a bottleneck.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Understand the different bottlenecks on clients and servers.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In my experience, clients are often constrained by memory. They cache not only logical data but also images, models, fonts, and other assets, while having limited process memory available. Client-side optimization therefore often trades time for space: load data and assets dynamically when needed.&lt;/p&gt;
&lt;p&gt;Servers are often constrained by CPU. They serve thousands of clients at once. In frameworks such as Skynet, saturating a single CPU core can make some functionality noticeably stall. On the server, I therefore tend to trade space for time: prepare and cache data at startup. That can simplify the logic as well as reduce runtime computation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Define the workload before optimizing.&lt;/strong&gt; Optimization has no natural endpoint. Establish the data scale and call frequency first: the maximum players per server, scene size, maximum objects, and how often players act. Optimize around those constraints rather than creating work with little payoff. If a server holds only 1,000 players and a leaderboard needs only the top 100, insisting on a red-black tree may be overkill. I have made that mistake myself, even modifying the tree algorithm to support rankings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code structure deserves optimization too.&lt;/strong&gt; I prefer to refactor early, making interfaces clear and easy to use. That can delay the arrival of a tangled codebase—even if I suspect every sufficiently long-lived project eventually becomes one.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Know when to stop. Avoid an optimization when it is not needed. Most organizations are held together more loosely than we like to admit, and a one-percent performance gain is unlikely to earn you a special reward.&lt;/p&gt;
</content:encoded></item><item><title>Disabling Transparent Huge Pages on Ubuntu (Repost)</title><link>https://blog.coding1024.com/en/posts/4827ed55/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/4827ed55/</guid><description>Check Ubuntu’s THP state and disable it temporarily or persistently using GRUB, systemd, or rc.local.</description><pubDate>Tue, 23 Sep 2025 08:22:28 GMT</pubDate><content:encoded>&lt;p&gt;There are two main ways to disable Transparent Huge Pages (THP) on Ubuntu: temporarily, until the next reboot, or persistently. This repost walks through both methods and the checks to make afterward.&lt;/p&gt;
&lt;h2&gt;1. Check the current THP setting&lt;/h2&gt;
&lt;p&gt;Open a terminal and run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /sys/kernel/mm/transparent_hugepage/enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value in square brackets is selected. &lt;code&gt;[always]&lt;/code&gt; enables THP generally, while &lt;code&gt;[madvise]&lt;/code&gt; permits it for applications that request it. An output of &lt;code&gt;always madvise [never]&lt;/code&gt; indicates that THP is disabled.&lt;/p&gt;
&lt;h2&gt;2. Disable THP temporarily&lt;/h2&gt;
&lt;p&gt;To turn it off immediately for testing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/defrag  # 建议同时也关闭碎片整理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second command also disables THP defragmentation. These settings apply only to the current session; they do not persist across a reboot.&lt;/p&gt;
&lt;h2&gt;3. Disable THP persistently&lt;/h2&gt;
&lt;h3&gt;Option A: Edit the GRUB configuration&lt;/h3&gt;
&lt;p&gt;This guide uses GRUB as the main approach.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Edit the configuration file:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/default/grub
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Find &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; or &lt;code&gt;GRUB_CMDLINE_LINUX&lt;/code&gt;. Add &lt;code&gt;transparent_hugepage=never&lt;/code&gt; inside the quoted kernel arguments. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash transparent_hugepage=never&quot;
# 或者
GRUB_CMDLINE_LINUX=&quot;transparent_hugepage=never&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your particular database deployment also calls for disabling NUMA, its separate argument is &lt;code&gt;numa=off&lt;/code&gt;. Do not treat that as an inherent requirement of disabling THP.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Save the file and update GRUB:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sudo update-grub
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Reboot:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Option B: Use a systemd service or rc.local&lt;/h3&gt;
&lt;p&gt;The original guide presents this as an alternative for deployments that manage the setting through a startup service, mentioning MongoDB as an example.&lt;/p&gt;
&lt;p&gt;Create a unit such as &lt;code&gt;/etc/systemd/system/disable-thp.service&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=Disable Transparent Huge Pages (THP)
After=sysinit.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c &apos;echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled &amp;amp;&amp;amp; echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag&apos;

[Install]
WantedBy=basic.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, if your system supports &lt;code&gt;rc.local&lt;/code&gt;, edit or create &lt;code&gt;/etc/rc.local&lt;/code&gt; and insert the following before &lt;code&gt;exit 0&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
    echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
    echo never &amp;gt; /sys/kernel/mm/transparent_hugepage/defrag
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure &lt;code&gt;rc.local&lt;/code&gt; is executable.&lt;/p&gt;
&lt;p&gt;If you chose the systemd approach, reload the configuration, enable the service, and start it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl enable disable-thp.service
sudo systemctl start disable-thp.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reboot to confirm that the configuration persists.&lt;/p&gt;
&lt;h2&gt;4. Verify the setting&lt;/h2&gt;
&lt;p&gt;After rebooting, run the check again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /sys/kernel/mm/transparent_hugepage/enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expected result is &lt;code&gt;always madvise [never]&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Considerations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why disable THP?&lt;/strong&gt; The original repost discusses workloads involving Oracle Database, MongoDB, Redis, and Hadoop where THP can cause unwanted latency, overhead, or performance issues. Requirements depend on the application and version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance is a tradeoff.&lt;/strong&gt; THP can benefit other workloads. If you have no specific problem or application requirement, disabling it is not automatically an improvement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Defragmentation is separate.&lt;/strong&gt; The runtime examples set both &lt;code&gt;enabled&lt;/code&gt; and &lt;code&gt;defrag&lt;/code&gt; to &lt;code&gt;never&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NUMA is separate too.&lt;/strong&gt; Follow the requirements for your particular software rather than automatically combining &lt;code&gt;numa=off&lt;/code&gt; with the THP change.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whichever method you choose, reboot and verify the resulting state. If something does not behave as expected, investigate the requirements of the particular application before changing further memory settings.&lt;/p&gt;
</content:encoded></item><item><title>An Nginx Port-Forwarding Pitfall</title><link>https://blog.coding1024.com/en/posts/ef62fe3f/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/ef62fe3f/</guid><description>How unrestricted port capture exposed internal services through a public reverse proxy, and why destination ranges matter.</description><pubDate>Tue, 01 Apr 2025 08:33:20 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I recently made a serious mistake while configuring Nginx port forwarding. Here is what happened.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Our game server used WSS, and Nginx needed to forward many paths to backend WebSocket ports. For example, &lt;code&gt;wss://xxx.com/10000&lt;/code&gt; should reach &lt;code&gt;ws://xxx.com:10000&lt;/code&gt;. The requested range was around ports 10000–11000. I did not want to write a thousand separate rules, so I found this configuration online:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location ~* ^/(?&amp;lt;port&amp;gt;\d+)$ {
    proxy_pass http://127.0.0.1:$port;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection &quot;Upgrade&quot;;
    proxy_set_header Host $host;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first glance, it seemed to work: take the number after &lt;code&gt;/&lt;/code&gt; and use it as the backend port.&lt;/p&gt;
&lt;p&gt;Then a colleague noticed the problem. Although our security group exposed only the intended game-server ports, this rule allowed a user to reach &lt;strong&gt;any local port indirectly through Nginx&apos;s public port 80 or 443&lt;/strong&gt;. A small deployment might appear to work normally, but scanning could expose sensitive internal services as traffic grew.&lt;/p&gt;
&lt;h2&gt;Restrict the destination port&lt;/h2&gt;
&lt;p&gt;My first thought was to use &lt;code&gt;if&lt;/code&gt;. I had also encountered the Nginx community&apos;s “If Is Evil” discussion about unexpected behavior in some configurations, so I decided to restrict the numeric match instead.&lt;/p&gt;
&lt;p&gt;These are the two patterns recorded in the original post:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location ~* ^/(?&amp;lt;port&amp;gt;(20[0-9]\{3\}))$ {
    proxy_pass http://127.0.0.1:$port;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection &quot;Upgrade&quot;;
    proxy_set_header Host $host;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location ~* ^/(?&amp;lt;port&amp;gt;2[0-1]\d\d\d)$ {
    proxy_pass http://127.0.0.1:$port;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection &quot;Upgrade&quot;;
    proxy_set_header Host $host;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The intent was to match only an allowed range and reject other ports, rather than pass arbitrary user-supplied numbers to the upstream.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Translation note:&lt;/strong&gt; the original post describes a 10000–10999 match, but the two restricted patterns above do not implement that range as written. One also escapes the repetition braces. They are preserved here as historical examples; validate the actual pattern and allowed port range before using the configuration.&lt;/p&gt;
</content:encoded></item><item><title>Updating Google Play Billing to 6.2.1 in Unity</title><link>https://blog.coding1024.com/en/posts/76580d95/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/76580d95/</guid><description>A 2024 workaround using Unity IAP 4.11.0 with a manually replaced Google Play Billing Library AAR.</description><pubDate>Tue, 16 Jul 2024 07:48:02 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;In July 2024, I needed to update an app to Google Play Billing Library version 6 before the August 31 deadline described in the original post. Updating Unity IAP to 4.12.0 through Package Manager caused the Android build to fail. Other developers reported the same problem in the forum, and a fix was not yet available in that workflow. I rolled back to 4.11.0 and updated the billing library manually.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Roll back Unity IAP to 4.11.0&lt;/h2&gt;
&lt;p&gt;Select version &lt;strong&gt;4.11.0&lt;/strong&gt; in Package Manager.&lt;/p&gt;
&lt;h2&gt;Download the AAR&lt;/h2&gt;
&lt;p&gt;Download Billing Library 6.2.1 from &lt;a href=&quot;https://maven.google.com/web/index.html?q=billing#com.android.billingclient:billing:6.2.1&quot;&gt;Google&apos;s Maven repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Replace the AAR&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Copy &lt;code&gt;billing:6.2.1.aar&lt;/code&gt; into the Unity project&apos;s Assets directory. Unity generates a matching &lt;code&gt;.meta&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Search the project for the existing &lt;code&gt;billing:5.2.1.aar&lt;/code&gt;. Delete it and its adjacent &lt;code&gt;.meta&lt;/code&gt; file. Move &lt;code&gt;billing:6.2.1.aar&lt;/code&gt; and &lt;code&gt;billing:6.2.1.aar.meta&lt;/code&gt; into that directory.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Update build.gradle&lt;/h2&gt;
&lt;p&gt;Open &lt;code&gt;build.gradle&lt;/code&gt; and replace &lt;code&gt;billing:5.2.1&lt;/code&gt; with &lt;code&gt;billing:6.2.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That completed the workaround for this project and its 2024 dependency versions.&lt;/p&gt;
</content:encoded></item><item><title>Accessing an iOS App’s Documents Directory</title><link>https://blog.coding1024.com/en/posts/bb92b2a1/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/bb92b2a1/</guid><description>Expose an app’s sandboxed Documents directory in the iOS Files app using two property-list settings.</description><pubDate>Mon, 29 Jan 2024 01:50:51 GMT</pubDate><content:encoded>&lt;p&gt;On iOS 11 and later, setting &lt;code&gt;LSSupportsOpeningDocumentsInPlace&lt;/code&gt; and &lt;code&gt;UIFileSharingEnabled&lt;/code&gt; to &lt;code&gt;YES&lt;/code&gt; in the app&apos;s property list makes its Documents directory accessible through the system Files app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/bb92b2a1/creator-path.png&quot; alt=&quot;The app&apos;s Documents directory in Files&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Open &lt;strong&gt;Files → On My iPhone&lt;/strong&gt;. Apps with this feature enabled expose their folder here. This folder is linked to the app&apos;s sandbox; deleting the app also removes its stored documents.&lt;/p&gt;
</content:encoded></item><item><title>Integrating AdMob into Unity</title><link>https://blog.coding1024.com/en/posts/1621995/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/1621995/</guid><description>Dependency resolution steps and ProGuard rules used to fix a missing Google Mobile Ads initialization class in Unity.</description><pubDate>Fri, 19 Jan 2024 17:56:48 GMT</pubDate><content:encoded>&lt;h2&gt;Reference documentation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/admob/unity/quick-start?hl=zh-cn&quot;&gt;Official Unity quick-start guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/googleads/googleads-mobile-unity&quot;&gt;Google Mobile Ads Unity plugin and examples on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Resolve dependencies&lt;/h2&gt;
&lt;p&gt;In Unity, use the Google Mobile Ads dependency tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Android: &lt;strong&gt;Assets → Google Mobile Ads → Android → Resolve&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;iOS: &lt;strong&gt;Assets → Google Mobile Ads → iOS → CocoaPods&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fix a missing initialization-listener class&lt;/h2&gt;
&lt;p&gt;I encountered this error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AndroidJavaException: java.lang.ClassNotFoundException: com.google.android.gms.ads.initialization.OnInitializationCompleteListener
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go to &lt;strong&gt;Build Settings → Player Settings → Publishing Settings&lt;/strong&gt; and enable &lt;strong&gt;Custom Proguard File&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Add the following rules to &lt;code&gt;proguard-user.txt&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-keep class com.google.unity.** {
   *;
}
-keep public class com.google.android.gms.ads.**{
   public *;
}
-keep public class com.google.ads.**{
   public *;
}
-keepattributes *Annotation*
-dontobfuscate
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Configuring Docker Proxies</title><link>https://blog.coding1024.com/en/posts/753c22c6/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/753c22c6/</guid><description>Configure HTTP and HTTPS proxies for the Docker daemon, running containers, and image builds.</description><pubDate>Fri, 25 Aug 2023 06:20:46 GMT</pubDate><content:encoded>&lt;h2&gt;Set up Clash on Linux&lt;/h2&gt;
&lt;p&gt;The original setup used this reference: &lt;a href=&quot;https://blog.zzsqwq.cn/posts/how-to-use-clash-on-linux/&quot;&gt;Using Clash on Linux&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Configure a proxy for dockerd&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;docker pull&lt;/code&gt; is performed by the &lt;code&gt;dockerd&lt;/code&gt; daemon. On this system, systemd manages the daemon, so its HTTP and HTTPS proxy settings need to be supplied through systemd.&lt;/p&gt;
&lt;p&gt;Create a configuration directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mkdir -p /etc/systemd/system/docker.service.d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;/etc/systemd/system/docker.service.d/http-proxy.conf&lt;/code&gt; and add the environment variables:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Service]
Environment=&quot;HTTP_PROXY=http://proxy.example.com:8080/&quot;
Environment=&quot;HTTPS_PROXY=http://proxy.example.com:8080/&quot;
Environment=&quot;NO_PROXY=localhost,127.0.0.1,.example.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reload the configuration and restart Docker:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configure a proxy for containers&lt;/h2&gt;
&lt;p&gt;For HTTP and HTTPS traffic during container execution, either configure the Docker client or pass environment variables when starting a container.&lt;/p&gt;
&lt;p&gt;Create or edit &lt;code&gt;~/.docker/config.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
 &quot;proxies&quot;:
 {
   &quot;default&quot;:
   {
     &quot;httpProxy&quot;: &quot;http://proxy.example.com:8080/&quot;,
     &quot;httpsProxy&quot;: &quot;http://proxy.example.com:8080/&quot;,
     &quot;noProxy&quot;: &quot;localhost,127.0.0.1,.example.com&quot;
   }
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, specify environment variables with &lt;code&gt;docker run&lt;/code&gt;. The original command is reproduced below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run --env HTTP_PROXY=&quot;http://proxy.example.com:8080/ --env HTTPS_PROXY=&quot;http://proxy.example.com:8080/&quot; --env NO_PROXY=&quot;localhost,127.0.0.1,.example.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Translation note:&lt;/strong&gt; this original example has an unmatched quote after the &lt;code&gt;HTTP_PROXY&lt;/code&gt; value. Close that value before adding the next &lt;code&gt;--env&lt;/code&gt; option; also supply the image and other arguments needed by your own container.&lt;/p&gt;
&lt;h2&gt;Configure a proxy during docker build&lt;/h2&gt;
&lt;p&gt;During image builds, supply build arguments or use environment variables in the Dockerfile. Here is the original &lt;code&gt;--build-arg&lt;/code&gt; example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build \
    --build-arg &quot;HTTP_PROXY=http://proxy.example.com:8080/&quot; \
    --build-arg &quot;HTTPS_PROXY=http://proxy.example.com:8080/&quot; \
    --build-arg &quot;NO_PROXY=localhost,127.0.0.1,.example.com&quot; .
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://yeasy.gitbook.io/docker_practice/&quot;&gt;Docker: From Beginner to Practice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Exporting an xLights Project from Light Show Creator</title><link>https://blog.coding1024.com/en/posts/4ac7aace/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/4ac7aace/</guid><description>Export music, FSEQ, and XSQ files from Light Show Creator and open the sequence in xLights for finer editing.</description><pubDate>Wed, 02 Aug 2023 15:52:41 GMT</pubDate><content:encoded>&lt;p&gt;Here is a practical guide to exporting an xLights project from Light Show Creator so you can personalize your Tesla light show further. xLights can create impressive custom shows, but editing them can be laborious. I built Light Show Creator to make that process easier with automatic generation.&lt;/p&gt;
&lt;p&gt;Some users asked for an xLights-style timeline editor. After considering it, I decided that Light Show Creator should remain playful and simple. A timeline would add complexity, and a phone cannot offer the same precision as a desktop editor. Instead, I added XSQ export so that users who need finer control can continue in xLights.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ac7aace/manual-02.png&quot; alt=&quot;Light Show Creator&apos;s manual controls&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Export and open the project&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Import your music into Light Show Creator and create a show in automatic or manual mode. Export it to obtain three files: &lt;code&gt;lightshow.wav&lt;/code&gt;, &lt;code&gt;lightshow.fseq&lt;/code&gt;, and &lt;code&gt;lightshow.xsq&lt;/code&gt;. Copy all three into the same folder on your computer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ac7aace/export-01.png&quot; alt=&quot;Exporting the project files&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open xLights. For the workflow described in this 2023 guide, use the matching Tesla project files. The app&apos;s XSQ export was adapted to Tesla&apos;s April 27, 2023 revision, available here:&lt;/p&gt;
&lt;p&gt;https://github.com/teslamotors/light-show/blob/09601c577f838e84320faff8ea3a7266af783f56/xlights/tesla_xlights_show_folder.zip&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ac7aace/xLights-select-file.png&quot; alt=&quot;Selecting the sequence file&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In xLights, choose &lt;strong&gt;File → Open Sequence&lt;/strong&gt; and select the exported &lt;strong&gt;&lt;code&gt;lightshow.fseq&lt;/code&gt;&lt;/strong&gt;, not &lt;code&gt;lightshow.xsq&lt;/code&gt;. Choose &lt;strong&gt;OldView&lt;/strong&gt; from the View dropdown. The generated frames should now appear, ready for more detailed editing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ac7aace/xLights-select-oldview.png&quot; alt=&quot;The generated sequence in OldView&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Keep all three files—MP3 or WAV, FSEQ, and XSQ—in the same folder.&lt;/li&gt;
&lt;li&gt;Use the 2023 Tesla project files referenced by this guide from &lt;a href=&quot;https://github.com/teslamotors/light-show&quot;&gt;Tesla&apos;s GitHub project&lt;/a&gt;. The 2021 files may be incompatible with this export workflow.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;&lt;code&gt;lightshow.fseq&lt;/code&gt;&lt;/strong&gt;, rather than &lt;code&gt;lightshow.xsq&lt;/code&gt;, when opening the sequence. Opening the wrong file can produce warnings and lose data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope this helps you enjoy making your own Tesla light shows. If you run into problems or have ideas for the app, feel free to get in touch. I look forward to seeing what you create!&lt;/p&gt;
</content:encoded></item><item><title>Light Show Creator User Guide</title><link>https://blog.coding1024.com/en/posts/4ca667d5/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/4ca667d5/</guid><description>Create Tesla light shows, import music, use automatic and manual controls, and export files from your phone.</description><pubDate>Sat, 29 Jul 2023 16:32:22 GMT</pubDate><content:encoded>&lt;p&gt;Custom Light Show is one of Tesla&apos;s fun features. Light Show Creator is an app for making your own shows quickly and easily. If that sounds interesting, give it a try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/light-show-creator/id6446385602&quot;&gt;App Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.coding1024.tslshow&quot;&gt;Google Play&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.microsoft.com/store/productId/9PL28B7M856D&quot;&gt;Microsoft Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/preview.gif&quot; alt=&quot;Light Show Creator preview&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;USB-drive requirements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Include a folder named &lt;code&gt;LightShow&lt;/code&gt; at the drive&apos;s root. You can extract it from the project&apos;s &lt;code&gt;LightShow.zip&lt;/code&gt; download.&lt;/li&gt;
&lt;li&gt;Format the drive as exFAT, FAT32 on Windows, MS-DOS FAT on Mac, ext3, or ext4. NTFS was not supported in the setup described in this guide.&lt;/li&gt;
&lt;li&gt;Do not place a &lt;code&gt;TeslaCam&lt;/code&gt; folder at the root of this drive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tesla&apos;s official guide: https://github.com/teslamotors/light-show&lt;/p&gt;
&lt;h2&gt;Create a project&lt;/h2&gt;
&lt;p&gt;Open the &lt;strong&gt;Projects&lt;/strong&gt; page, tap &lt;strong&gt;New Project&lt;/strong&gt;, and enter a project name.&lt;/p&gt;
&lt;h2&gt;Import music&lt;/h2&gt;
&lt;p&gt;The app supports MP3 and WAV. I recommend WAV where possible, because some MP3 files can cause problems.&lt;/p&gt;
&lt;h3&gt;Android&lt;/h3&gt;
&lt;p&gt;Select an MP3 or WAV file no longer than five minutes directly from the filesystem.&lt;/p&gt;
&lt;h3&gt;iOS&lt;/h3&gt;
&lt;p&gt;There are two ways to import music:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Share a music file from another app to Light Show Creator.&lt;/li&gt;
&lt;li&gt;Copy the file into the LightShowCreator directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To import by copying, use Apple&apos;s &lt;strong&gt;Files&lt;/strong&gt; app. Install it from the App Store if it is not already on your device.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/files-app.png&quot; alt=&quot;Apple&apos;s Files app&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Open Files and tap &lt;strong&gt;On My iPhone&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/paths.png&quot; alt=&quot;On My iPhone&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Open the &lt;strong&gt;LightShowCreator&lt;/strong&gt; folder.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/creator-path.png&quot; alt=&quot;The LightShowCreator folder&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Inside it, the &lt;code&gt;music&lt;/code&gt; directory stores imported audio. Copy your music there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/main-dir.png&quot; alt=&quot;The app&apos;s music directory&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After sharing a file, iOS switches to Light Show Creator. Open the &lt;strong&gt;Music&lt;/strong&gt; page; the selected track should appear in the list within a few seconds.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/music-01.png&quot; alt=&quot;The music list&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Share music from another app&lt;/h2&gt;
&lt;p&gt;You can use a third-party app that supports file sharing, such as OneDrive, Google Drive, or Dropbox.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/share-01.png&quot; alt=&quot;Sharing a music file&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Choose &lt;strong&gt;Open in another app&lt;/strong&gt;, then select LightShowCreator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/share-02.png&quot; alt=&quot;Choosing LightShowCreator&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The track will appear in the list. Tap the track you want to use to complete the import.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/select-music.png&quot; alt=&quot;Selecting an imported track&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Use automatic mode&lt;/h2&gt;
&lt;p&gt;Turn on the &lt;strong&gt;Auto&lt;/strong&gt; button. The lights will respond automatically to the music.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/auto.png&quot; alt=&quot;Automatic mode&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can adjust several settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step time:&lt;/strong&gt; the duration of each frame. Longer frames use less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rhythm sensitivity:&lt;/strong&gt; how sensitively the lights respond to the music. Lower sensitivity should generally use less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Beat duration:&lt;/strong&gt; the maximum duration of each light activation. Longer durations use less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fog-light switch:&lt;/strong&gt; turn this off for the Standard Range Model 3 and Model Y configurations without front fog lights described in the original guide.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Use manual mode&lt;/h2&gt;
&lt;p&gt;Manual mode allows more personal editing, much like playing a piano. Each pair of symmetric lights forms a group. Black keys activate both sides; white keys activate one side.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/manual-01.png&quot; alt=&quot;Manual controls&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can also run automatic mode while recording manually, leaving you to control just a few key lights yourself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/manual-02.png&quot; alt=&quot;Combining manual and automatic modes&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Export a light show&lt;/h2&gt;
&lt;p&gt;Exporting uses sharing, just like importing music. Send the exported files to another app; OneDrive is used in this example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/export-01.png&quot; alt=&quot;Opening the export controls&quot; /&gt;
&lt;img src=&quot;/media/4ca667d5/export-02.png&quot; alt=&quot;Selecting a destination&quot; /&gt;
&lt;img src=&quot;/media/4ca667d5/export-03.png&quot; alt=&quot;Sharing exported files&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The app also exports the files to the filesystem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iOS: &lt;code&gt;LightShowCreator/export/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Android: &lt;code&gt;Downloads/LightShowExport/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to make shows entirely on your phone, without a computer, I strongly recommend a Lightning-to-USB or USB-C-to-USB adapter like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/4ca667d5/export-04.png&quot; alt=&quot;A USB adapter for a phone&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Refine a show in xLights&lt;/h2&gt;
&lt;p&gt;At the time of this guide, the app did not support fades or window and door controls. For those features, put &lt;code&gt;lightshow.wav&lt;/code&gt; or &lt;code&gt;lightshow.mp3&lt;/code&gt;, &lt;code&gt;lightshow.fseq&lt;/code&gt;, and &lt;code&gt;lightshow.xsq&lt;/code&gt; together in one folder on a computer, then open the project in xLights.&lt;/p&gt;
&lt;h2&gt;Questions and answers&lt;/h2&gt;
&lt;h3&gt;What if the music is too fast to follow in manual mode?&lt;/h3&gt;
&lt;p&gt;Change the playback speed on the settings page.&lt;/p&gt;
&lt;h3&gt;Why does the Windows version not support manual mode?&lt;/h3&gt;
&lt;p&gt;At the time of writing, no Windows update was planned. The Windows version was designed around a different interaction model from the touchscreen-based mobile version.&lt;/p&gt;
&lt;h3&gt;How can I make coordinated shows for multiple cars?&lt;/h3&gt;
&lt;p&gt;This was on the roadmap. In the meantime, one suggestion was to split the music into several tracks, create a project for each, and use automatic mode to prepare shows for multiple cars quickly.&lt;/p&gt;
</content:encoded></item><item><title>Integrating Unity IAP with Google Play</title><link>https://blog.coding1024.com/en/posts/784a9c64/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/784a9c64/</guid><description>Notes from a 2023 Unity in-app purchase integration: permissions, Player settings, license keys, and store testing.</description><pubDate>Tue, 11 Apr 2023 15:22:39 GMT</pubDate><content:encoded>&lt;p&gt;These are my notes from integrating Google Play in-app purchases with Unity in April 2023.&lt;/p&gt;
&lt;h2&gt;Upload a build with billing permission&lt;/h2&gt;
&lt;p&gt;Add this permission to &lt;code&gt;AndroidManifest.xml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;uses-permission android:name=&quot;com.android.vending.BILLING&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After uploading the APK and getting it approved, create the in-app products or subscriptions in Google Play Console.&lt;/p&gt;
&lt;h2&gt;Install Unity IAP&lt;/h2&gt;
&lt;p&gt;Open &lt;strong&gt;Window → Package Manager → Unity Registry&lt;/strong&gt;, select &lt;strong&gt;In App Purchasing&lt;/strong&gt;, and install it.&lt;/p&gt;
&lt;h2&gt;Check Unity Player settings&lt;/h2&gt;
&lt;p&gt;Go to &lt;strong&gt;Edit → Project Settings → Player&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Under &lt;strong&gt;Other Settings&lt;/strong&gt;, use &lt;strong&gt;IL2CPP&lt;/strong&gt; as the scripting backend for this setup.&lt;/li&gt;
&lt;li&gt;In the configuration section, set &lt;strong&gt;API Compatibility Level&lt;/strong&gt; to &lt;strong&gt;.NET Standard 2.0&lt;/strong&gt; or later.&lt;/li&gt;
&lt;li&gt;Make sure the package name matches the registered app.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Build App Bundle (Google Play)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Add the Google license key&lt;/h2&gt;
&lt;p&gt;Find the key on the monetization settings page in Google Play Console. Enter it in the project&apos;s &lt;strong&gt;In-app purchase (IAP) settings&lt;/strong&gt; on the Unity Dashboard.&lt;/p&gt;
&lt;p&gt;In my setup, the corresponding Unity editor panel could report an error. I configured the key through the Dashboard instead.&lt;/p&gt;
&lt;h2&gt;Add license-test accounts&lt;/h2&gt;
&lt;p&gt;In Google Play Console, open &lt;strong&gt;License testing → License testers&lt;/strong&gt; from the home page.&lt;/p&gt;
&lt;p&gt;License testers and internal-testing participants are different lists. Configure the relevant accounts in each. In the original test setup, China-region accounts could not complete payments; account region was one of the things I needed to check.&lt;/p&gt;
&lt;h2&gt;Test the store build&lt;/h2&gt;
&lt;p&gt;Publish an internal-testing build and download it from Google Play. Testing that installed store build was necessary for this workflow.&lt;/p&gt;
</content:encoded></item><item><title>Reflections on Game Programming</title><link>https://blog.coding1024.com/en/posts/52dda49a/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/52dda49a/</guid><description>Lessons on programming, technical leadership, open source, delivery, overtime, and pragmatic engineering.</description><pubDate>Tue, 21 Feb 2023 15:18:19 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;While taking some time off at home, I looked back on my work over the past few years. Here are a few lessons from that experience.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;What makes a strong game programmer?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The ability to argue a case constructively. Persuading someone to change their mind and cooperate is difficult. Pulling rank—“I am your manager” or “my manager said so”—does not count. A stronger approach is to understand the people involved, consider several perspectives, and propose a sound solution.&lt;/li&gt;
&lt;li&gt;Foresight. When designing a framework, consider future iterations and anticipate requests designers may eventually make, even if they deny needing them today. Make those requests quick to implement within the existing architecture.&lt;/li&gt;
&lt;li&gt;Ownership. Become the person who knows a module inside out. Deliver your own work well, but also help drive requirements forward and suggest solutions to colleagues in other roles.&lt;/li&gt;
&lt;li&gt;Efficiency. Use tools well, or write automation for coding and testing. The practical results should be faster delivery, fewer bugs, less rework, and less overtime.&lt;/li&gt;
&lt;li&gt;The ability to tackle hard problems, such as a critical algorithm or a fatal bug.&lt;/li&gt;
&lt;li&gt;Breadth of knowledge. Do not limit yourself to a single language or technology. Each has strengths; use it where it fits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What makes a strong lead programmer?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;First, be a strong programmer, and then go further.&lt;/li&gt;
&lt;li&gt;Judge people well. During a short interview, identify candidates who suit the team. Being a good fit is not the same as reciting interview answers: look for the qualities above, or the potential to develop them.&lt;/li&gt;
&lt;li&gt;Assign work thoughtfully rather than treating people as interchangeable tools. Match tasks to strengths or skills that need development, and give people substantial autonomy. Good work should also help them grow.&lt;/li&gt;
&lt;li&gt;Keep the schedule under control. Estimate requirements accurately, allow team members some buffer, and show designers a prototype as early as possible.&lt;/li&gt;
&lt;li&gt;Understand the game deeply. Know both what designers ultimately want and what matters most to them right now. That helps with iteration and scheduling.&lt;/li&gt;
&lt;li&gt;Retain people. Advocate for their interests and give them room to grow. Put plainly: pay them adequately, or at least do not let them feel mistreated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Thoughts on open source&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Code is a programmer&apos;s underwear: it is not something you show everyone casually. Publishing it means exposing what is underneath. If you show it, make sure it is worth showing.&lt;/li&gt;
&lt;li&gt;Do not open-source something just for the sake of doing so. Build something useful rather than another unnecessary wheel. A project or library should help other people, not merely show off how impressive an old project was. I will leave aside projects that use gimmicks to collect stars.&lt;/li&gt;
&lt;li&gt;Open source can improve your overall ability quickly. In a sense, it is a mutual exchange of free work. Communities contain all kinds of people, each with their own needs. Contributors and users can both benefit. Every interface and feature makes you ask: is this useful to most users? Does it add unnecessary bulk? Could it be more general? Is it extensible? We rarely ask those questions as consistently in our own closed-source projects. Over time, that habit leads to better code, with the high cohesion and low coupling we aim for.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Improving feature-development efficiency&lt;/h2&gt;
&lt;p&gt;This workflow came from a more experienced developer, and it has worked well for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Review the requirements with the designer.&lt;/strong&gt; Before the cross-functional meeting, read the document, record questions, and ask for clarification where possible. In the meeting, go through it line by line and resolve every uncertainty. This step matters.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agree on configuration-table fields and formats with the designer.&lt;/strong&gt; Ask for temporary data that covers testing, then implement import validation. This step matters even more: once the configuration is settled, the whole data model is usually clear in your mind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agree on the client-server protocol.&lt;/strong&gt; The backend should also define the persistent database structure. Communication and interaction between the two sides are now established.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write test cases.&lt;/strong&gt; Include this step whenever possible, before implementation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write the code.&lt;/strong&gt; By this point, you should understand the system&apos;s requirements thoroughly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hand it over for testing&lt;/strong&gt;, then enjoy a well-earned breather.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Thoughts on overtime&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Nobody likes overtime, but it can be difficult to avoid in game development. It is often about a shared deadline, such as finishing a particular build, when the whole team needs to be available.&lt;/li&gt;
&lt;li&gt;I see overtime as sometimes reflecting insufficient capability or time wasted during normal hours. Working with full concentration from 9 a.m. to 9 p.m. is exhausting.&lt;/li&gt;
&lt;li&gt;I can accept overtime when it is not imposed as a blanket company policy. Even when the extra hours are less intense, they can be used productively—for example, to improve something or prepare for a future version.&lt;/li&gt;
&lt;li&gt;Game teams need considerable face-to-face communication, so their schedules should overlap. If some people work very late and arrive late the next day, while others keep the opposite schedule, it becomes difficult to find someone for a quick requirements discussion. That can block progress unnecessarily.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Other lessons&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A technical expert is a bonus for a team, not an absolute prerequisite. Technical research should ultimately serve delivery.&lt;/li&gt;
&lt;li&gt;Code should be simple and easy to understand. Ideally, colleagues outside programming should be able to read it and even spot a bug.&lt;/li&gt;
&lt;li&gt;In most game-development work, unless you are pushing the frontier, someone has already solved the problem. Be cautious when a design or implementation departs from established approaches. If you thought of it, others probably did too; there may be a reason they did not choose it.&lt;/li&gt;
&lt;li&gt;When you discover a bizarre piece of old code, do not rush to delete it. Code does not lie; an unusual product or design requirement may explain it.&lt;/li&gt;
&lt;li&gt;Code itself is often the best documentation. Still, explain special handling and temporary code—at least leave a &lt;code&gt;// TODO&lt;/code&gt;, or expect criticism later.&lt;/li&gt;
&lt;li&gt;Programmers bridge human intent and computers. Ideally, every line we write reduces repetitive manual work in the future, even if getting there requires considerable thought. A good programmer should be eager to think and reluctant to repeat manual work.&lt;/li&gt;
&lt;li&gt;Avoid over-optimization, particularly on the server. Debating whether &lt;code&gt;++i&lt;/code&gt; is faster than &lt;code&gt;i++&lt;/code&gt; misses the bigger picture. Hardware is comparatively inexpensive; project progress matters far more than meaningless micro-optimizations. Optimize when something becomes a real bottleneck, rather than for its own sake.&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Troubleshooting C# IntelliSense in VS Code</title><link>https://blog.coding1024.com/en/posts/a421e405/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/a421e405/</guid><description>A historical Unity tooling setup that resolved an OmniSharp ILoggerFactory error by pinning compatible versions.</description><pubDate>Tue, 27 Dec 2022 14:46:37 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;C# IntelliSense in VS Code kept stopping unexpectedly. In December 2022, I ran into another failure:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;System.Composition.Hosting.CompositionFailedException: No export was found for the contract &apos;ILoggerFactory&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OmniSharp had updated automatically. In &lt;code&gt;settings.json&lt;/code&gt;, I changed &lt;code&gt;omnisharp.path&lt;/code&gt; from &lt;code&gt;latest&lt;/code&gt; to a pinned version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;omnisharp.path&quot;: &quot;1.39.2&quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Versions that worked together in this setup&lt;/h2&gt;
&lt;p&gt;Automatic extension updates were a recurring source of problems in this project. This is the historical combination I found stable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET Framework &lt;strong&gt;4.7.1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Unity&apos;s VS Code package &lt;strong&gt;1.2.0&lt;/strong&gt;: set &lt;code&gt;&quot;com.unity.ide.vscode&quot;: &quot;1.2.0&quot;&lt;/code&gt; in &lt;code&gt;manifest.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;VS Code&apos;s C# extension &lt;strong&gt;1.24.0&lt;/strong&gt;: use the arrow beside the uninstall button and choose &lt;strong&gt;Install Another Version&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;OmniSharp &lt;strong&gt;1.39.2&lt;/strong&gt;: pin it with &lt;code&gt;omnisharp.path&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Default .NET Framework reference-assembly path&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.1&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>Why My YouTube App Preview Still Had Ads</title><link>https://blog.coding1024.com/en/posts/15d916ce/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/15d916ce/</guid><description>A 2022 account of troubleshooting a Google Play video preview, music copyright claims, and ads on a non-monetized YouTube channel.</description><pubDate>Mon, 26 Dec 2022 14:55:41 GMT</pubDate><content:encoded>&lt;p&gt;I uploaded an app preview to YouTube for use on Google Play, but a few days later Google Play removed it. I suspected advertising: when I opened my own video, an ad would sometimes appear.&lt;/p&gt;
&lt;p&gt;The documentation said to turn off monetization. I searched through YouTube&apos;s settings but could not find the button. My channel did not even qualify for the YouTube Partner Program, so how could I disable monetization? Where were the ads coming from?&lt;/p&gt;
&lt;p&gt;After trying for a long time, I contacted Google Play support. This is an English translation of our exchange in December 2022.&lt;/p&gt;
&lt;h2&gt;My question to support&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;My app&apos;s video preview is no longer visible. I suspect my YouTube video still contains ads. However, my YouTube account is not in the Partner Program, and I cannot find an option to turn off ads on the monetization page or a monetization option for the selected video. Is there a way to disable YouTube ads, or another way to restore the app preview?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Google&apos;s reply&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;After investigating, we found that the system currently detects monetization on your promotional video. The system determines whether these features are present. If your video contains ads, they must be disabled before the video can appear on the Play Store. We want users browsing the Play Store to see your app in the video, rather than advertising that could confuse them.&lt;/p&gt;
&lt;p&gt;Please refer to the Help Center and the following video requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Turn off monetization for the video.&lt;/li&gt;
&lt;li&gt;Upload a video without a monetization claim, then update its URL in Google Play Console.&lt;/li&gt;
&lt;li&gt;Set the video to public or unlisted, rather than private.&lt;/li&gt;
&lt;li&gt;Make sure the video can be embedded in the Play Store Android app and website.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the video uses copyrighted material, turning off monetization may still not prevent ads. In that case, replace it with a video that contains no such copyrighted material or monetization claim.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On inspection, the background music in my video did indeed have a copyright claim.&lt;/p&gt;
&lt;p&gt;That explained why looking for my own monetization switch had not helped. YouTube&apos;s handling of music rights was stricter than I had expected from using short-video platforms in China. For a commercial preview, I needed music I was authorized to use, whether through a purchased license or an appropriate Creative Commons license. “Free” music still needs its usage terms checked.&lt;/p&gt;
&lt;h2&gt;Creative Commons music sources I collected&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Creative Commons collection on Aigei.&lt;/li&gt;
&lt;li&gt;The Audio Library in YouTube Studio.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;YouTube music channels and playlists I collected&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLHEabrqpFr0PlkzCTrgZ6ChhrtKSAgqyj&quot;&gt;Royalty-Free Music&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCyytiQuL-5S59OX1opqG-bQ&quot;&gt;RFM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/user/freemusicwave&quot;&gt;FreeMusicWave&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCEickjZj99-JJIU8_IJ7J-Q&quot;&gt;Vlog No Copyright Music&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Building Light Show Creator: Part 2</title><link>https://blog.coding1024.com/en/posts/9ccdb535/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/9ccdb535/</guid><description>Replacing a difficult timeline editor with piano-style manual controls designed for a phone’s touchscreen.</description><pubDate>Tue, 20 Dec 2022 03:43:29 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Light Show Creator had been available for a while when users told me that, although automatic mode was convenient, manual mode could suit a phone particularly well. I began planning a new manual mode.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/media/9ccdb535/preview.gif&quot; alt=&quot;Manual-mode preview&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The earliest prototype actually had manual editing. Like xLights, it used a timeline. The result was not satisfactory: fine timeline controls worked better with a mouse than a touchscreen. I removed manual mode from the first public release and kept only automatic generation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/media/9ccdb535/old.jpeg&quot; alt=&quot;The old timeline-based editor&quot; /&gt;
The old version was difficult to use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A piano app recently gave me another idea. What if controlling the lights worked like playing a keyboard? Press a key to turn a light on; release it to turn it off. A white key could control one side of the vehicle, while a black key could activate both sides together.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/9ccdb535/manual.png&quot; alt=&quot;The piano-style light controls&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Automatic mode can also run during a manual recording, so you only need to play the few lights you want to emphasize yourself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/9ccdb535/settings.png&quot; alt=&quot;Manual and automatic mode settings&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Changing the Nginx Upload Size Limit</title><link>https://blog.coding1024.com/en/posts/4a413d3a/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/4a413d3a/</guid><description>Resolve a 413 request-body error by adjusting Nginx’s client_max_body_size setting.</description><pubDate>Sun, 27 Nov 2022 08:42:25 GMT</pubDate><content:encoded>&lt;p&gt;With the default Nginx HTTP proxy configuration, request bodies are limited to 1 MB. A larger request can return &lt;strong&gt;413 Request Entity Too Large&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Adjust &lt;code&gt;client_max_body_size&lt;/code&gt; in the Nginx configuration. This example raises the limit to 8 MB:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;http {
    ...
    #上传文件的大小限制  默认1m
    client_max_body_size 8m;
    ...
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Removing ^M Line Endings from Multiple Files</title><link>https://blog.coding1024.com/en/posts/5dcaa2e/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/5dcaa2e/</guid><description>Use dos2unix to convert Windows line endings in individual files or a batch of Lua source files.</description><pubDate>Sat, 19 Nov 2022 03:17:16 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Files copied directly from Windows to Linux or macOS may show &lt;code&gt;^M&lt;/code&gt; at the ends of lines in &lt;code&gt;git diff&lt;/code&gt;. Windows line endings use two characters, &lt;code&gt;\r\n&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Install dos2unix&lt;/h2&gt;
&lt;p&gt;Ubuntu or Debian:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install dos2unix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CentOS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo yum install dos2unix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;macOS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install dos2unix
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Convert one file&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;dos2unix filename
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Convert multiple files&lt;/h2&gt;
&lt;p&gt;The original example finds Lua files and passes them to &lt;code&gt;dos2unix&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;find ./ -name *.lua | xargs dos2unix
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Changing Ubuntu’s Package Mirror</title><link>https://blog.coding1024.com/en/posts/fde212d5/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/fde212d5/</guid><description>A historical Ubuntu 18.04 Bionic fix for Tencent Cloud mirror resolution failures using an Aliyun source list.</description><pubDate>Wed, 16 Nov 2022 02:45:19 GMT</pubDate><content:encoded>&lt;p&gt;On a Tencent Cloud Ubuntu instance, installing packages with &lt;code&gt;apt&lt;/code&gt; failed because the configured mirror could not be resolved:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Err:1 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 m4 amd64 1.4.18-1
  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
Ign:2 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 autoconf all 2.69-11
Ign:3 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 autotools-dev all 20180224.1
Ign:4 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 automake all 1:1.15.1-3ubuntu2
Err:2 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 autoconf all 2.69-11
  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
Err:3 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 autotools-dev all 20180224.1
  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
Err:4 http://mirrors.tencentyun.com/ubuntu bionic/main amd64 automake all 1:1.15.1-3ubuntu2
  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
E: Failed to fetch http://mirrors.tencentyun.com/ubuntu/pool/main/m/m4/m4_1.4.18-1_amd64.deb  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
E: Failed to fetch http://mirrors.tencentyun.com/ubuntu/pool/main/a/autoconf/autoconf_2.69-11_all.deb  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
E: Failed to fetch http://mirrors.tencentyun.com/ubuntu/pool/main/a/autotools-dev/autotools-dev_20180224.1_all.deb  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
E: Failed to fetch http://mirrors.tencentyun.com/ubuntu/pool/main/a/automake-1.15/automake_1.15.1-3ubuntu2_all.deb  Something wicked happened resolving &apos;mirrors.tencentyun.com:http&apos; (-5 - No address associated with hostname)
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mirrors.tencentyun.com&lt;/code&gt; appeared to be unavailable; even a ping failed. Switching the package mirror resolved the problem in this setup.&lt;/p&gt;
&lt;h2&gt;Back up the source list&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo cp /etc/apt/sources.list /etc/apt/sources.list.bk
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Open sources.list&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo vi /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add the Aliyun mirror entries&lt;/h2&gt;
&lt;p&gt;I added these entries at the beginning of &lt;code&gt;/etc/apt/sources.list&lt;/code&gt;. They are for &lt;strong&gt;Ubuntu 18.04 Bionic&lt;/strong&gt;, the release used in this November 2022 post:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Refresh the package lists and upgrade&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get update
sudo apt-get upgrade
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Getting Started with Firebase Authentication in Unity</title><link>https://blog.coding1024.com/en/posts/cd4d0695/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/cd4d0695/</guid><description>My first Firebase Authentication integration: app registration, SHA fingerprints, provider setup, and email account creation.</description><pubDate>Mon, 14 Nov 2022 16:21:24 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I was looking for a third-party account SDK for an app aimed at international users. After comparing the options, I chose Firebase.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Integration was initially rough. I tried exporting an AAR from Android Studio into Unity, then exporting an Android Studio project from Unity. Neither attempt worked. I had not yet tried iOS.&lt;/p&gt;
&lt;p&gt;The real problem was that I had not read the official documentation carefully. Google supplied a Unity package: importing it and doing a little configuration in the Firebase console was much simpler.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://firebase.google.com/docs/auth/unity/start&quot;&gt;Official Firebase Authentication Unity guide&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Register the app in Firebase&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/media/cd4d0695/img1.png&quot; alt=&quot;Registering the app in the Firebase console&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Make sure the registered package name matches the app&apos;s final package name.&lt;/p&gt;
&lt;h2&gt;Add the SHA certificate fingerprint&lt;/h2&gt;
&lt;p&gt;Add the fingerprint in the app settings:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/cd4d0695/img2.png&quot; alt=&quot;Adding a SHA certificate fingerprint&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Download google-services.json&lt;/h2&gt;
&lt;p&gt;In the project described in this November 2022 note, I placed the file in &lt;code&gt;Asset/StreamingAssets&lt;/code&gt; in the Unity project.&lt;/p&gt;
&lt;h2&gt;Enable an authentication provider&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/media/cd4d0695/img3.png&quot; alt=&quot;Enabling an authentication provider&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Import FirebaseAuth.unitypackage&lt;/h2&gt;
&lt;p&gt;Import the authentication package into Unity.&lt;/p&gt;
&lt;h2&gt;Add test code&lt;/h2&gt;
&lt;p&gt;The following code tests account creation with an email address and password:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auth.CreateUserWithEmailAndPasswordAsync(email, password)
            .ContinueWith(task =&amp;gt;
            {
                if (task.IsCanceled)
                {
                    Debug.LogError(&quot;CreateUserWithEmailAndPasswordAsync was canceled.&quot;);
                    return;
                }
                if (task.IsFaulted)
                {
                    Debug.LogError(
                        &quot;CreateUserWithEmailAndPasswordAsync encountered an error: &quot;
                            + task.Exception
                    );
                    return;
                }

                // Firebase user has been created.
                FirebaseUser newUser = task.Result;
                Debug.LogFormat(
                    &quot;Firebase user created successfully: {0} ({1})&quot;,
                    newUser.DisplayName,
                    newUser.UserId
                );
            });
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Fixing the AndroidX Build Error After Adding Firebase to Unity</title><link>https://blog.coding1024.com/en/posts/3a0ce390/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/3a0ce390/</guid><description>Enable AndroidX and Jetifier through Unity’s custom Gradle properties template to resolve a Firebase build failure.</description><pubDate>Sun, 13 Nov 2022 17:46:35 GMT</pubDate><content:encoded>&lt;p&gt;After importing Firebase into Unity, I encountered the following build error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Could not determine the dependencies of task &apos;:launcher:lintVitalRelease&apos;.
&amp;gt; This project uses AndroidX dependencies, but the &apos;android.useAndroidX&apos; property is not enabled. Set this property to true in the gradle.properties file and retry.
  The following AndroidX dependencies are detected: androidx.fragment:fragment:1.0.0, androidx.slidingpanelayout:slidingpanelayout:1.0.0,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The project depended on AndroidX, but &lt;code&gt;android.useAndroidX&lt;/code&gt; had not been enabled.&lt;/p&gt;
&lt;h2&gt;Enable the Gradle properties template&lt;/h2&gt;
&lt;p&gt;Under &lt;strong&gt;Build Settings → Player → Publishing Settings&lt;/strong&gt;, enable &lt;strong&gt;Custom Gradle Properties Template&lt;/strong&gt;. Unity generates the template at &lt;code&gt;Assets/Plugins/Android/gradleTemplate.properties&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add these two lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;android.useAndroidX=true
android.enableJetifier=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My resulting properties file looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.enableR8=**MINIFY_WITH_R_EIGHT**
unityStreamingAssets=**STREAMING_ASSETS**
android.useAndroidX=true
android.enableJetifier=true
**ADDITIONAL_PROPERTIES**
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That resolved the problem in this project.&lt;/p&gt;
</content:encoded></item><item><title>Wireless Debugging on Android</title><link>https://blog.coding1024.com/en/posts/3c859465/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/3c859465/</guid><description>Pair an Android phone with ADB using a pairing code or Android Studio’s Wi-Fi QR code.</description><pubDate>Sun, 13 Nov 2022 13:43:44 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Android 11 introduced wireless debugging, making it possible to debug without a USB cable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A phone running Android 11 or later.&lt;/li&gt;
&lt;li&gt;Android SDK tools version 30.0.0 or later on the computer. Check the installed version with &lt;code&gt;adb --version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pair with a pairing code&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Enable developer mode on the phone, then enable USB debugging and the wireless debugging option.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Wireless debugging → Pair device with pairing code&lt;/strong&gt;. Note the pairing code, IP address, and port.&lt;/li&gt;
&lt;li&gt;In a terminal on the computer, run &lt;code&gt;adb pair ipaddr:port&lt;/code&gt;, replacing the address and port with the displayed values, and enter the pairing code when prompted.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;adb devices -l&lt;/code&gt; to see the connected device.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Pair with a QR code&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Enable developer mode, USB debugging, and wireless debugging on the phone.&lt;/li&gt;
&lt;li&gt;Select QR-code pairing. In Android Studio&apos;s device menu, choose &lt;strong&gt;Pair Devices Using WiFi&lt;/strong&gt; and scan the displayed code with the phone.&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Building Light Show Creator: Part 1</title><link>https://blog.coding1024.com/en/posts/33fc2e57/</link><guid isPermaLink="true">https://blog.coding1024.com/en/posts/33fc2e57/</guid><description>How I built a Tesla light-show generator, decoded FSEQ files, analyzed music, and validated exported sequences.</description><pubDate>Thu, 27 Oct 2022 15:10:39 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Tesla introduced Light Show across its vehicle lineup in the 2021 holiday update. Besides the built-in show, owners could create custom ones. I tried it immediately, but found editing too difficult. That gave me an idea.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/preview.gif&quot; alt=&quot;A light show created with the app&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Where the idea came from&lt;/h2&gt;
&lt;p&gt;Tesla recommended an open-source application called xLights, a professional tool for editing lighting performances. Import Tesla&apos;s template and some music, and you can start creating a show.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/xlights_overview.png&quot; alt=&quot;The xLights editor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Editing in xLights felt cumbersome: the show needed to be edited frame by frame, and the exported file then had to be checked with a script. Tesla imposes strict limits on lighting sequences, partly to protect the lights from damage. The process took time and effort. Could it be simpler—ideally, import a song and generate the show with one click? I decided to build an app.&lt;/p&gt;
&lt;h2&gt;Checking feasibility&lt;/h2&gt;
&lt;p&gt;The first and most important step was to determine whether I could generate a valid FSEQ sequence file, equivalent to one produced by xLights, that the vehicle would recognize. FSEQ is binary, so I had to examine what its bytes meant.&lt;/p&gt;
&lt;p&gt;Tesla&apos;s validation script helped me infer the basic format: a header followed by sequence frames describing each light&apos;s on/off state or brightness.&lt;/p&gt;
&lt;p&gt;To test the idea, I used Tesla&apos;s official example, which contained three files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lightshow.wav&lt;/code&gt;: the music file, which I could leave alone.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lightshow.xsq&lt;/code&gt;: the xLights project, with sequence information in XML form.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lightshow.fseq&lt;/code&gt;: the binary sequence exported by xLights for the vehicle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I imported sequence data from the XSQ project into my app, exported a new FSEQ file, and compared it byte by byte with the xLights output. I kept going until the two files matched exactly. That showed my app could export the same sequence format as xLights.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/compare.png&quot; alt=&quot;Comparing the exported files&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Building the core feature&lt;/h2&gt;
&lt;p&gt;After testing the export on a real vehicle, I moved on to the core feature: automatic generation.&lt;/p&gt;
&lt;p&gt;The principle is straightforward. Analyze the music, divide the frequency range into &lt;em&gt;n&lt;/em&gt; bands, and assign them to the vehicle&apos;s lights. Turn a light on when its band exceeds a threshold, and off otherwise. It resembles the animated spectrum display in a music player.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/music.png&quot; alt=&quot;Music analysis&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Supporting controls&lt;/h2&gt;
&lt;p&gt;Fast rhythms and rapidly changing frequencies can exceed the vehicle&apos;s limits, so I added parameters users could adjust:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Step time:&lt;/strong&gt; the duration of each frame. Longer steps use less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rhythm sensitivity:&lt;/strong&gt; sensitivity to changes in the music. In principle, lower sensitivity uses less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Beat duration:&lt;/strong&gt; the maximum duration of each light activation. Longer durations use less memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fog-light switch:&lt;/strong&gt; the Standard Range Model 3 and Model Y configurations described here did not have front fog lights, so switching this off made the result more suitable for those vehicles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/screenshot1.png&quot; alt=&quot;Generation settings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To prevent sequences from exceeding the memory limit, I ported Tesla&apos;s Python validation logic into the app. It checks usage while recording, displays it in real time, and refuses to export a sequence that exceeds the limit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/media/33fc2e57/validate.png&quot; alt=&quot;Live sequence validation&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;App-store release&lt;/h2&gt;
&lt;p&gt;The app was released on the Apple App Store and Google Play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://apps.apple.com/us/app/light-show-creator/id6446385602&quot;&gt;App Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.coding1024.tslshow&quot;&gt;Google Play&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Plans for future iterations&lt;/h2&gt;
&lt;p&gt;At the time of writing, the next items on my list were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Mac version.&lt;/li&gt;
&lt;li&gt;Manual editing.&lt;/li&gt;
&lt;li&gt;Audio recording.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also uploaded several shows recorded with the app, featuring some fun background music, to GitHub. Feel free to download and try them:&lt;/p&gt;
&lt;p&gt;https://github.com/xcoding1024/tesla-light-show&lt;/p&gt;
</content:encoded></item></channel></rss>