<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: GuardingPearSoftware</title>
    <description>The latest articles on DEV Community by GuardingPearSoftware (@guardingpearsoftware).</description>
    <link>https://dev.to/guardingpearsoftware</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3503084%2Fee0bf721-584f-49bc-9e41-6d2ddce4f0cf.jpg</url>
      <title>DEV Community: GuardingPearSoftware</title>
      <link>https://dev.to/guardingpearsoftware</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guardingpearsoftware"/>
    <language>en</language>
    <item>
      <title>GuardingPearSoftware Obfuscator vs Obfuz</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Sat, 22 Aug 2026 11:20:24 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/guardingpearsoftware-obfuscator-vs-obfuz-3m4g</link>
      <guid>https://dev.to/guardingpearsoftware/guardingpearsoftware-obfuscator-vs-obfuz-3m4g</guid>
      <description>&lt;p&gt;Compiled Unity code is not a secret by default. Open the player with a .NET or IL2CPP dump tool and you can still read class names, walk through game systems, and copy strings.&lt;/p&gt;

&lt;p&gt;When searching for Unity obfuscation tools, you might come across: &lt;strong&gt;Obfuz&lt;/strong&gt; (an open-source Unity obfuscator from the HybridCLR / Code Philosophy circle) and also &lt;a href="https://www.guardingpearsoftware.com/product/obfuscator" rel="noopener noreferrer"&gt;GuardingPearSoftware Obfuscator&lt;/a&gt; (a dedicated Unity asset with a Free tier and paid seats).&lt;/p&gt;

&lt;p&gt;Both tools are built for Unity. They are not the same product. Obfuz is made mostly for teams that already live in HybridCLR or xLua hot update. GuardingPearSoftware Obfuscator is made for a normal player build, enterprise type-level renaming, and hardening and a vendor behind the package.&lt;/p&gt;

&lt;p&gt;This comparison breaks down how both tools work, where their features differ, and which one fits your game development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GuardingPearSoftware Obfuscator Pro&lt;/strong&gt; costs $79.99 (one-time purchase). It includes symbol renaming, string obfuscation, fake code injection, method control flow, watermarks, and anti-tamper checks. It runs directly inside your Unity build pipeline and patches your game assets when it renames &lt;code&gt;MonoBehaviour&lt;/code&gt; classes and other serialized types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Obfuz&lt;/strong&gt; is a free MIT plugin. HybridCLR docs point to it when hot-update code needs protection. The public list is long: symbols, constants, strings, control flow, call and expression obfuscation, a random encryption VM, polymorphic DLLs and watermarks. It is made to work with little config, but it does not rename &lt;code&gt;MonoBehaviour&lt;/code&gt; type names. That is a Unity-safe default, and wanted.&lt;/p&gt;

&lt;p&gt;In simple words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;GuardingPearSoftware Obfuscator&lt;/strong&gt; if you want plug and play, Unity type renaming with asset updates, and a publisher behind the asset.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Obfuz&lt;/strong&gt; if you need HybridCLR or xLua hot update, you want the source for free, and you are fine configuring a code-first plugin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many teams can use one or the other. A few high-risk hot-update games may later study both layers. Start with one pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;GuardingPearSoftware Obfuscator&lt;/th&gt;
&lt;th&gt;Obfuz&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;GuardingPearSoftware&lt;/td&gt;
&lt;td&gt;Open-Source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Based in&lt;/td&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;China&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;Paid Asset Store seat (Free tier exists)&lt;/td&gt;
&lt;td&gt;MIT, free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;$79.99 Pro&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;Plug and play&lt;/td&gt;
&lt;td&gt;Plug and play&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MonoBehaviour class names&lt;/td&gt;
&lt;td&gt;Renames and patches assets&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hot update&lt;/td&gt;
&lt;td&gt;General Unity builds&lt;/td&gt;
&lt;td&gt;First-class HybridCLR and xLua&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOTS&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Addressables&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control flow&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption VM&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watermarks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support&lt;/td&gt;
&lt;td&gt;Phone, Email, Discord&lt;/td&gt;
&lt;td&gt;GitHub, Discord, QQ, Email&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;From Indie to Enterprise Studio&lt;/td&gt;
&lt;td&gt;Teams that already use HybridCLR or want OSS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is simple on purpose. Obfuz wins on hardening techniques and hot-update depth. GuardingPearSoftware Obfuscator wins on Unity integration because of the obfuscated asset patching (what most unity scripts are).&lt;/p&gt;

&lt;h2&gt;
  
  
  What GuardingPearSoftware Obfuscator does
&lt;/h2&gt;

&lt;p&gt;GuardingPearSoftware Obfuscator is a Unity cybersecurity asset. After you enable it, protection runs when you press Build. You do not export a DLL, open a second Windows GUI, then copy files back. The same hooks fire for a custom &lt;code&gt;BuildPipeline.BuildPlayer&lt;/code&gt; script and for cloud builders that run a normal Unity player build.&lt;/p&gt;

&lt;p&gt;The package can rename namespaces, classes, methods, fields, properties, and events. And also rename the Unity types that most tools skip: &lt;code&gt;MonoBehaviour&lt;/code&gt;, &lt;code&gt;ScriptableObject&lt;/code&gt;, and Playable classes. After the rename pass, it updates scenes, prefabs, and other assets that still store those names.&lt;/p&gt;

&lt;p&gt;Unity stores a lot of meaning as text. A button in the Inspector may keep the method name it should call. An animation event may keep a string. A serialized field on a component keeps its field name. Addressable bundles can keep script references too. Obfuscator has compatibility settings for those cases: Inspector values, UnityEvents, animation events, reflection and coroutines, UI Toolkit, and Addressables.&lt;/p&gt;

&lt;p&gt;It also hides strings, adds random fake code, and can suppress simple ILDasm inspection. Mono builds can get control flow and assembly signing. Standalone builds can get integrity checks. Watermarks are included to proof ownership. Mapping files stay available so crash logs are still readable after release. A Free tier exists if you want to test the pipeline first. MonoBehaviour and namespace renaming are Obfuscator Pro features.&lt;/p&gt;

&lt;p&gt;The tool stays local. You do not send the game to a cloud protector. Because it runs inside Unity and Tuanjie, it works on any platform where those editors run, including Windows, macOS, and Linux build machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Obfuz does
&lt;/h2&gt;

&lt;p&gt;Obfuz is a Unity package, not a generic .NET GUI. HybridCLR's own docs say that among current open-source tools, only Obfuz is deeply tied to Unity and fully supports HybridCLR.&lt;/p&gt;

&lt;p&gt;You install the package, mark assemblies, and generate secret key and VM files. That is simple for programmers. It is not the same as a one-click Asset Store product. HybridCLR workflows also need the &lt;code&gt;obfuz4hybridclr&lt;/code&gt; extension, because the default HybridCLR generate steps do not expect obfuscated names.&lt;/p&gt;

&lt;p&gt;Its public feature list is long:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Symbol obfuscation with rules and incremental builds&lt;/li&gt;
&lt;li&gt;Constant, string, and array obfuscation&lt;/li&gt;
&lt;li&gt;Evaluation-stack, expression, and call obfuscation&lt;/li&gt;
&lt;li&gt;Control-flow flattening&lt;/li&gt;
&lt;li&gt;A randomized encryption virtual machine&lt;/li&gt;
&lt;li&gt;Static and dynamic decryption&lt;/li&gt;
&lt;li&gt;Polymorphic / structurally random DLLs&lt;/li&gt;
&lt;li&gt;Garbage code&lt;/li&gt;
&lt;li&gt;Code watermarks&lt;/li&gt;
&lt;li&gt;Unity 2019+, Tuanjie, Mono, and IL2CPP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Roadmap items they have stated in public docs include anti-dump, anti-debug, and fuller code virtualization.&lt;/p&gt;

&lt;p&gt;The published feature list is closer to a commercial protector than to a rename-only tool. Free means you own the maintenance risk. There is no Asset Store seat and no publisher SLA.&lt;/p&gt;

&lt;p&gt;Obfuz keeps &lt;code&gt;MonoBehaviour&lt;/code&gt; type names because Unity looks those types up when it loads scenes and prefabs. It still obfuscates the code inside the class. That is a safe default. It also leaves the type name attackers search for first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The biggest difference
&lt;/h2&gt;

&lt;p&gt;Obfuz competes on hardening techniques and hot-update support. GuardingPearSoftware Obfuscator competes on Unity product workflow and type-level renaming.&lt;/p&gt;

&lt;p&gt;If your live game loads HybridCLR DLLs after install, those DLLs are as readable as a Mono build. That is why Obfuz exists, and why HybridCLR recommends it.&lt;/p&gt;

&lt;p&gt;If your game is a normal Unity player build (mobile, console, standalone) and you care about prefab-safe renaming plus a support channel, GuardingPearSoftware Obfuscator is the shorter path.&lt;/p&gt;

&lt;p&gt;A virtualized or encrypted method is hard to read. A class that still says &lt;code&gt;PlayerHealth&lt;/code&gt; on the prefab is still easy to find. GuardingPearSoftware Obfuscator attacks that second problem by renaming the type and updating the asset. Obfuz attacks the first problem and leaves the type name stable.&lt;/p&gt;

&lt;p&gt;You can invent a two-layer pipeline. You also get two ways to break the build. Start with one tool. Add a second layer only if you have a clear extra threat, such as hot-update DLLs plus a store build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unity-aware renaming matters
&lt;/h2&gt;

&lt;p&gt;Unity does not only compile C#. It also saves type names and member names inside assets. That is how the Inspector, scenes, and prefabs keep working after you close the Editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerHealth&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxHealth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TakeDamage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;maxHealth&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a generic protector renames &lt;code&gt;PlayerHealth&lt;/code&gt; or &lt;code&gt;maxHealth&lt;/code&gt;, the prefab can lose the script or reset the value. If it leaves those names alone so the prefab stays valid, attackers still search for &lt;code&gt;PlayerHealth&lt;/code&gt; and find the class.&lt;/p&gt;

&lt;p&gt;Obfuz chooses the second path for type names and still hides the method body. GuardingPearSoftware Obfuscator is built for the first path. It can rename the class and the serialized field, then update the related assets so the GameObject still points at the new names.&lt;/p&gt;

&lt;p&gt;Both answers are Unity-aware. They solve different parts of the same tradeoff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one should you pick?
&lt;/h2&gt;

&lt;p&gt;Pick &lt;strong&gt;GuardingPearSoftware Obfuscator&lt;/strong&gt; if you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Asset Store product with an enterprise vendor behind it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MonoBehaviour&lt;/code&gt; and &lt;code&gt;ScriptableObject&lt;/code&gt; renaming with asset updates&lt;/li&gt;
&lt;li&gt;Less time writing obfuscation rules&lt;/li&gt;
&lt;li&gt;Regular updates&lt;/li&gt;
&lt;li&gt;A normal player build, not a HybridCLR-first game&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pick &lt;strong&gt;Obfuz&lt;/strong&gt; if you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero license cost&lt;/li&gt;
&lt;li&gt;HybridCLR or xLua as a first-class target&lt;/li&gt;
&lt;li&gt;A wide OSS protection set, including an encryption VM&lt;/li&gt;
&lt;li&gt;Full source under MIT from day one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Obfuz is the open-source Unity obfuscator to take seriously in 2026, especially if HybridCLR is already in the project.&lt;/p&gt;

&lt;p&gt;GuardingPearSoftware Obfuscator is still the better everyday product for teams that want Unity type renaming, a simple build button and a enterpise cybersecurity vendor behind it. &lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>GuardingPearSoftware Obfuscator vs Beebyte</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:20:40 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/guardingpearsoftware-obfuscator-vs-beebyte-g3p</link>
      <guid>https://dev.to/guardingpearsoftware/guardingpearsoftware-obfuscator-vs-beebyte-g3p</guid>
      <description>&lt;p&gt;A shipped Unity player still contains readable C#. If you skip protection, a common decompiler can list your types, follow combat or shop logic, and pull string literals out of the build.&lt;/p&gt;

&lt;p&gt;For years, Unity developers typed "Beebyte" when they needed an obfuscator. It was the Asset Store default. Two Unity tools sit in that search path today: &lt;strong&gt;Beebyte Obfuscator&lt;/strong&gt; (the older Asset Store package) and also &lt;a href="https://www.guardingpearsoftware.com/product/obfuscator" rel="noopener noreferrer"&gt;GuardingPearSoftware Obfuscator&lt;/a&gt; (a dedicated Unity asset that still gets 2026 updates).&lt;/p&gt;

&lt;p&gt;Both tools hide compiled game code inside the Unity build. They are not in the same place now. Beebyte taught the store what a Unity obfuscator looks like. But GuardingPearSoftware Obfuscator is now the tool to go which is actively updated, and available for the current Unity versions.&lt;/p&gt;

&lt;p&gt;This comparison breaks down how both tools work, where their features differ, and which one fits a new project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Short answer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GuardingPearSoftware Obfuscator Pro&lt;/strong&gt; costs $79.99 (one-time purchase). It includes symbol renaming, string obfuscation, fake code injection, method control flow, and anti-tamper checks. It runs directly inside your Unity build pipeline and patches your game assets when it renames &lt;code&gt;MonoBehaviour&lt;/code&gt; classes and other serialized types. A Free tier exists if you want to test the pipeline first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Beebyte Obfuscator&lt;/strong&gt; costed about $80, and was the best known Unity obfuscator from about 2015 to 2024. It did renaming, string hiding, and fake methods, and it understood many Unity "do not touch this" cases. It did not offer real control flow. Public listings now mark it deprecated. Compatibility notes limit it to selected 2021.3 and 2022.3 builds, and newer Unity versions should be treated as incompatible.&lt;/p&gt;

&lt;p&gt;In simple words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;GuardingPearSoftware Obfuscator&lt;/strong&gt; if you ship on current Unity and want an asset that is still maintained.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Beebyte&lt;/strong&gt; only if you already own it and you are stuck on an old LTS that it still accepted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For new projects, Beebyte is no longer the safe default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;GuardingPearSoftware Obfuscator&lt;/th&gt;
&lt;th&gt;Beebyte Obfuscator&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vendor&lt;/td&gt;
&lt;td&gt;GuardingPearSoftware&lt;/td&gt;
&lt;td&gt;Beebyte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Based in&lt;/td&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;United Kingdom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Status in 2026&lt;/td&gt;
&lt;td&gt;Actively updated (2026.x)&lt;/td&gt;
&lt;td&gt;Deprecated / maintenance only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price&lt;/td&gt;
&lt;td&gt;$79.99 one-time (Free tier available)&lt;/td&gt;
&lt;td&gt;About $80 one-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unity workflow&lt;/td&gt;
&lt;td&gt;Native build pipeline&lt;/td&gt;
&lt;td&gt;Inspector settings, build-time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MonoBehaviour renaming&lt;/td&gt;
&lt;td&gt;Yes, with asset patching&lt;/td&gt;
&lt;td&gt;Limited after Unity 2018.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespaces&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (remove / flatten)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strings&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fake methods&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control flow&lt;/td&gt;
&lt;td&gt;Yes (Mono builds)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anti-tamper&lt;/td&gt;
&lt;td&gt;Yes on Mono, integrity on standalone&lt;/td&gt;
&lt;td&gt;No serious anti-tamper story&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IL2CPP&lt;/td&gt;
&lt;td&gt;Supported as a backend&lt;/td&gt;
&lt;td&gt;Compatible on supported old LTS versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Current Unity games&lt;/td&gt;
&lt;td&gt;Legacy projects that already bought it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is simple on purpose. Beebyte won on history and search. GuardingPearSoftware Obfuscator wins on current support, asset patching, and extra hardening.&lt;/p&gt;

&lt;h2&gt;
  
  
  What GuardingPearSoftware Obfuscator does
&lt;/h2&gt;

&lt;p&gt;GuardingPearSoftware Obfuscator is a Unity cybersecurity asset. After you enable it, protection runs when you press Build. You do not export a DLL, open a second Windows GUI, then copy files back. The same hooks fire for a custom &lt;code&gt;BuildPipeline.BuildPlayer&lt;/code&gt; script and for cloud builders that run a normal Unity player build.&lt;/p&gt;

&lt;p&gt;The package can rename namespaces, classes, methods, fields, properties, and events. And also rename the Unity types that most tools skip: &lt;code&gt;MonoBehaviour&lt;/code&gt;, &lt;code&gt;ScriptableObject&lt;/code&gt;, and Playable classes. After the rename pass, it updates scenes, prefabs, and other assets that still store those names.&lt;/p&gt;

&lt;p&gt;Unity stores a lot of meaning as text. A button in the Inspector may keep the method name it should call. An animation event may keep a string. A serialized field on a component keeps its field name. Addressable bundles can keep script references too. Obfuscator has compatibility settings for those cases: Inspector values, UnityEvents, animation events, reflection and coroutines, UI Toolkit, and Addressables (JSON and binary catalogs, custom local or remote paths, and Addressable Shield on Unity 6 and newer).&lt;/p&gt;

&lt;p&gt;It also hides strings, adds random fake code, and can suppress simple ILDasm inspection. Mono builds can get control flow and assembly signing. Standalone builds can get integrity checks. Mapping files stay available so crash logs are still readable after release. MonoBehaviour and namespace renaming are Obfuscator Pro features.&lt;/p&gt;

&lt;p&gt;The tool stays local. You do not send the game to a cloud protector. Because it runs inside Unity and Tuanjie, it works on any platform where those editors run, including Windows, macOS, and Linux build machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Beebyte does
&lt;/h2&gt;

&lt;p&gt;Beebyte obfuscates compiled assemblies, not your source files. That part is the same idea as most Unity obfuscators. You set options in the Inspector, then the package rewrites names when you build.&lt;/p&gt;

&lt;p&gt;Its known feature set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rename classes, methods, parameters, fields, properties, and events&lt;/li&gt;
&lt;li&gt;Hide string literals&lt;/li&gt;
&lt;li&gt;Add fake methods&lt;/li&gt;
&lt;li&gt;Respect many Unity types that must keep their names&lt;/li&gt;
&lt;li&gt;Work with assembly definition files&lt;/li&gt;
&lt;li&gt;Support IL2CPP on the Unity versions it still listed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was easy. That is why it won so many searches. The protection was also thin. Reverse-engineering writeups have said for years that Beebyte is mostly renaming plus junk methods. There is no control-flow layer and no packing or virtualization.&lt;/p&gt;

&lt;p&gt;Beebyte also struggled with &lt;code&gt;MonoBehaviour&lt;/code&gt; renaming on newer Unity. From 2018.2 onward, that feature was limited, especially outside some standalone cases. Public copies of the listing say only LTS Release 2022.3.29 and LTS Release 2021.3.38 were valid. Other versions, including newer LTS releases, should be considered incompatible.&lt;/p&gt;

&lt;p&gt;Search is not the same as "best tool to buy today." The name still shows up first in a lot of old threads. The listing is deprecated, and the publisher is no longer an active Unity-store default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The biggest difference
&lt;/h2&gt;

&lt;p&gt;Beebyte won on history. GuardingPearSoftware Obfuscator wins on current Unity use.&lt;/p&gt;

&lt;p&gt;If you start a Unity 6 or a current 2022 LTS project today, Beebyte's own compatibility notes are the problem. You also get only rename-and-junk protection. That was enough when few Unity teams used any obfuscator. It is a weak plan if you want more than shorter names.&lt;/p&gt;

&lt;p&gt;GuardingPearSoftware Obfuscator still ships 2026 updates. It can rename Unity types and patch the assets that point at them. Mono builds can get control flow and anti-tamper. Addressables work is part of the product, not a forum workaround.&lt;/p&gt;

&lt;p&gt;Price is close. Both sit around $80. The gap is maintenance and how far the rename pass can go without breaking scenes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unity-aware renaming matters
&lt;/h2&gt;

&lt;p&gt;Unity does not only compile C#. It also saves type names and member names inside assets. That is how the Inspector, scenes, and prefabs keep working after you close the Editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlayerHealth&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SerializeField&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxHealth&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TakeDamage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;maxHealth&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a protector renames &lt;code&gt;PlayerHealth&lt;/code&gt; or &lt;code&gt;maxHealth&lt;/code&gt; and never updates the prefab, the GameObject can lose the script or reset the value. If it leaves those names alone so the prefab stays valid, attackers still search for &lt;code&gt;PlayerHealth&lt;/code&gt; and find the logic.&lt;/p&gt;

&lt;p&gt;GuardingPearSoftware Obfuscator is built for that tradeoff. It can rename the class and the serialized field, then update the related assets so the GameObject still points at the new names. Beebyte understood many Unity skip cases, but &lt;code&gt;MonoBehaviour&lt;/code&gt; renaming was limited after 2018.2. On a current project, that often means the names attackers look for first stay readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one should you pick?
&lt;/h2&gt;

&lt;p&gt;Pick &lt;strong&gt;GuardingPearSoftware Obfuscator&lt;/strong&gt; if you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Unity obfuscator that is still updated&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MonoBehaviour&lt;/code&gt; and &lt;code&gt;ScriptableObject&lt;/code&gt; renaming with asset updates&lt;/li&gt;
&lt;li&gt;More than rename-and-junk protection&lt;/li&gt;
&lt;li&gt;A Free tier to test the workflow&lt;/li&gt;
&lt;li&gt;One seat price close to what Beebyte used to cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay on &lt;strong&gt;Beebyte&lt;/strong&gt; only if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already paid for it&lt;/li&gt;
&lt;li&gt;Your project is on a Unity version it still accepted&lt;/li&gt;
&lt;li&gt;You only need light renaming and you can live without new updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Beebyte taught the Asset Store what a Unity obfuscator looks like. For a long time it was the practical answer.&lt;/p&gt;

&lt;p&gt;That answer aged. The listing is deprecated, newer Unity versions are a risk, and the protection stayed at renaming plus junk.&lt;/p&gt;

&lt;p&gt;If you want the same Unity workflow with a tool you can still buy and update, start with GuardingPearSoftware Obfuscator. It fits the build you already run, it can rename the Unity types attackers look for first, and it updates the assets those types live on.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SIM Swap Attacks: How They Work and How to Protect Yourself</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Fri, 21 Aug 2026 13:31:52 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/sim-swap-attacks-how-they-work-and-how-to-protect-yourself-245g</link>
      <guid>https://dev.to/guardingpearsoftware/sim-swap-attacks-how-they-work-and-how-to-protect-yourself-245g</guid>
      <description>&lt;p&gt;Your mobile phone number is more than a way for people to call or text you. For many people, it has become a key to their digital identity. Banks, email providers, social networks, cryptocurrency platforms, and other online services frequently use phone numbers for password recovery and multi-factor authentication (MFA).&lt;/p&gt;

&lt;p&gt;That makes a mobile number a target for cybercriminals.&lt;/p&gt;

&lt;p&gt;One of the most effective ways attackers exploit this is through SIM swapping, also known as SIM hijacking or SIM-swap fraud. This article examines how SIM swapping attacks work, the security risks they pose, and effective ways to prevent them. Understanding SIM swapping can help reduce the risk of identity theft, account takeover, and financial fraud.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a SIM Swap Attack?
&lt;/h2&gt;

&lt;p&gt;SIM swapping is a sophisticated cyberattack in which criminals hijack a victim’s mobile phone number to gain access to sensitive accounts and information.&lt;/p&gt;

&lt;p&gt;The attacker usually deceives or manipulates a mobile carrier into transferring the victim’s number to a SIM card they control. Once the transfer is complete, the attacker can receive SMS-based two-factor authentication codes, intercept calls and messages, and reset account passwords.&lt;/p&gt;

&lt;p&gt;The attacker does not necessarily need physical access to the victim's phone.&lt;/p&gt;

&lt;p&gt;Instead, they may obtain enough personal information to convince a carrier representative that they are the account holder. The FBI says criminals have used social engineering, phishing, and, in some cases, insider assistance to carry out SIM swaps.&lt;/p&gt;

&lt;p&gt;Once the number is transferred, the attacker can receive calls and SMS messages intended for the victim. That is very dangerous when SMS messages are used as a second authentication factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SIM Swapping Works
&lt;/h2&gt;

&lt;p&gt;A typical attack can unfold in several stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The attacker gathers information
&lt;/h3&gt;

&lt;p&gt;The first step is often reconnaissance.&lt;/p&gt;

&lt;p&gt;Attackers may collect information about a target from social media, data breaches, phishing campaigns, leaked databases, and other sources. They may look for the victim's name, phone number, email address, date of birth, address, carrier, and other information that could help them impersonate the victim.&lt;/p&gt;

&lt;p&gt;Publicly available information can sometimes make social engineering easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The attacker targets the mobile carrier
&lt;/h3&gt;

&lt;p&gt;The criminal then contacts the victim's mobile carrier, either through customer support, an online process, or a physical retail location.&lt;/p&gt;

&lt;p&gt;The attacker may claim that the victim lost their phone, damaged their SIM card, or purchased a new device.&lt;/p&gt;

&lt;p&gt;The objective is to persuade the carrier to move the victim's number to an attacker-controlled SIM or eSIM.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The phone suddenly loses service
&lt;/h3&gt;

&lt;p&gt;If the fraudulent transfer succeeds, the victim's SIM is usually disconnected from the cellular network.&lt;/p&gt;

&lt;p&gt;The victim may suddenly see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No cellular service&lt;/li&gt;
&lt;li&gt;No ability to make or receive calls&lt;/li&gt;
&lt;li&gt;No incoming SMS messages&lt;/li&gt;
&lt;li&gt;Unexpected carrier notifications&lt;/li&gt;
&lt;li&gt;An unexplained loss of mobile data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sudden and unexplained loss of cellular connectivity can therefore be an important warning sign.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The attacker receives SMS codes
&lt;/h3&gt;

&lt;p&gt;After taking control of the number, the attacker can receive SMS messages and voice calls that were intended for the victim. This is where the attack can escalate quickly.&lt;/p&gt;

&lt;p&gt;Suppose an attacker already knows your email address and password. If your email provider sends a login verification code to your phone number, the attacker may now receive that code.&lt;/p&gt;

&lt;p&gt;The attacker can use the same technique against banking, cryptocurrency, social media, and other accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Accounts are taken over
&lt;/h3&gt;

&lt;p&gt;The attacker may attempt password resets, account recovery procedures, or new-device logins.&lt;/p&gt;

&lt;p&gt;If the victim's phone number is the primary recovery mechanism, the attacker may be able to change passwords and other security settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Protect Yourself
&lt;/h2&gt;

&lt;p&gt;As the threat of SIM swapping continues to grow, businesses and individuals should adopt these security measures to reduce their exposure and protect themselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move away from SMS-Based MFA
&lt;/h3&gt;

&lt;p&gt;Multi-factor authentication is still one of the most important defenses against account takeover. However, not all MFA methods provide the same level of protection.&lt;/p&gt;

&lt;p&gt;The weakness of SMS-based MFA is that the authentication code is delivered through the phone network. If an attacker controls the victim's phone number, the attacker may receive the same code that was supposed to protect the account.&lt;/p&gt;

&lt;p&gt;That does not mean you should disable MFA if SMS is your only available option. SMS MFA is generally better than having no second factor at all. But where stronger options are available, they should be preferred.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use an Authenticator App
&lt;/h3&gt;

&lt;p&gt;One alternative is an authenticator application that generates one-time codes directly on your device.&lt;/p&gt;

&lt;p&gt;Instead of receiving the code through SMS, the application generates it locally using a previously established secret.&lt;/p&gt;

&lt;p&gt;This means an attacker who merely takes control of your mobile number does not automatically receive the authentication codes. Authenticator apps are therefore generally more resistant to SIM-swap attacks than SMS-based verification.&lt;/p&gt;

&lt;p&gt;However, users should still protect the device and account containing the authenticator carefully and maintain appropriate recovery options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Passkeys or Security Keys
&lt;/h3&gt;

&lt;p&gt;For your most important accounts, consider moving beyond SMS and one-time passwords.&lt;/p&gt;

&lt;p&gt;Security keys and passkeys can provide phishing-resistant authentication because they rely on cryptographic credentials rather than simply sending a code that a user can enter into a website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mobile Carrier Providers Should Do More
&lt;/h3&gt;

&lt;p&gt;Mobile carriers should strengthen identity verification procedures before activating replacement SIM cards or transferring customers’ phone numbers. They should also provide training for customer service staff to recognize suspicious requests and stop fraudulent SIM-swapping attempts before they succeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce the Amount of Personal Information You Publish
&lt;/h3&gt;

&lt;p&gt;Attackers do not necessarily need sophisticated malware to perform a SIM swap. Social engineering can be enough. Every publicly available piece of information can make impersonation easier.&lt;/p&gt;

&lt;p&gt;Avoid unnecessarily sharing sensitive personal information online, including your full date of birth, personal phone number, home address, detailed information about family members, financial information, or details about valuable assets. You do not need to disappear from social media altogether; instead, limit the amount of personal information available publicly so attackers have fewer identity-verification clues to exploit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect Your Email Account First
&lt;/h3&gt;

&lt;p&gt;Your primary email account deserves special attention because it can often be used to reset passwords for other services.&lt;/p&gt;

&lt;p&gt;If an attacker gains access to your email, they may be able to intercept password-reset messages, change account credentials, and lock you out.&lt;/p&gt;

&lt;p&gt;Where possible, protect your email account with a passkey, security key, or another phishing-resistant authentication method. You should also regularly review your recovery email addresses, recovery phone numbers, logged-in devices, active sessions, email forwarding rules, account-recovery settings, and recent login activity. If an attacker gains access to your email account, they may attempt to maintain persistent access by changing recovery information, adding their own devices, or creating forwarding rules that secretly redirect your messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Training
&lt;/h3&gt;

&lt;p&gt;Increasing awareness of SIM swapping and its associated risks is important for both individuals and organizations. Employees and users should be educated about how these attacks work, the warning signs to watch for, and the steps they can take to protect themselves. Regular cybersecurity training and ongoing reminders about security best practices can help reduce the likelihood of falling victim to SIM-swapping attacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SIM-swapping scams are part of social engineering and account takeover attacks. Attackers rarely rely on a single technique. Instead, they may combine phishing, doxing, and SIM swapping to create a chain of compromises that enables them to gain access to sensitive accounts and information.&lt;/p&gt;

&lt;p&gt;The growing adoption of eSIM technology adds another layer of complexity. Although eSIMs eliminate the need for a physical SIM card, they rely on digital processes for activating and transferring mobile numbers. If these processes are not adequately secured, attackers could potentially exploit them to carry out fraudulent transfers.&lt;/p&gt;

&lt;p&gt;For organizations, SIM-swap fraud shows the fact that the attack surface extends beyond networks, applications, and devices. Human error, weak identity-verification procedures, and continued reliance on vulnerable authentication methods can all provide attackers with opportunities to compromise accounts.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>First rule of cybersecurity: no tool alone will save you from bad habits</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Fri, 21 Aug 2026 07:42:56 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/first-rule-of-cybersecurity-no-tool-alone-will-save-you-from-bad-habits-2ko</link>
      <guid>https://dev.to/guardingpearsoftware/first-rule-of-cybersecurity-no-tool-alone-will-save-you-from-bad-habits-2ko</guid>
      <description>&lt;p&gt;Both companies and individuals often treat cybersecurity as something you just need to buy.&lt;/p&gt;

&lt;p&gt;They buy an antivirus program, a password manager, a SIEM, or a shiny new firewall with a really cool dashboard. They spend money and feel good about themselves, thinking about how they invest in their safety.&lt;/p&gt;

&lt;p&gt;My name is Erich Winkler. I have been working as a cybersecurity manager and head of IT security for years, and I want to show you why habits are what really make the difference, not tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why security as a product is a problem
&lt;/h2&gt;

&lt;p&gt;Let's face it, we all love the idea that security (or anything else) can be simply purchased.&lt;/p&gt;

&lt;p&gt;It feels good. You hand over money, get the thing, and the problem is now considered "handled," without any effort or the need to change your behavior.&lt;/p&gt;

&lt;p&gt;Just "buy a tool" sells better than "change how you work every single day."&lt;/p&gt;

&lt;p&gt;That is not how security works. If you buy a lawnmower and do not actually use it, the grass will still be tall. If you put a lock on an open door, it is still open. Simply having a seatbelt in your car will not help you either. You get the idea.&lt;/p&gt;

&lt;p&gt;Trust me, this problem is real, and I can imagine that maybe even you’ve experienced it yourself. And now that we know where this problem is coming from, let’s deep dive into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackers target people, not tools
&lt;/h2&gt;

&lt;p&gt;Hackers, attackers, or threat actors care about results. In some sense, they are like any other business. They want to get what they want (usually money) for the least effort possible.&lt;/p&gt;

&lt;p&gt;Like it or not, we humans and our behavior are the weakest link in many systems.&lt;/p&gt;

&lt;p&gt;Breaking an encryption algorithm is much harder (often impossible) than convincing someone to click a link that promises them one extra week of vacation a year.&lt;/p&gt;

&lt;p&gt;And I know, maybe you think you are too smart to fall for these scams. The statistics say you are not.&lt;/p&gt;

&lt;p&gt;Picture it yourself. A normal Tuesday evening. You are tired, half watching something, phone in hand. A message pops up: "Your package could not be delivered, confirm your address here." You tap it without thinking, because you actually are waiting for a package.&lt;/p&gt;

&lt;p&gt;That is the whole attack. No firewall was defeated. No password was cracked. You just did not pay attention for a second, and that was enough.&lt;/p&gt;

&lt;p&gt;If you want to know more about why smart people fall for dumb scams, read &lt;a href="https://www.decodedsecurity.com/p/the-psychology-of-hacking-why-smart" rel="noopener noreferrer"&gt;The psychology of hacking&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Remember:&lt;/strong&gt; You do not get hacked because you are important. You get hacked because you were easy that day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Top 5 security habits that anyone should do
&lt;/h2&gt;

&lt;p&gt;Okay, that was enough general lessons that maybe sound interesting, but do not help you at all.&lt;/p&gt;

&lt;p&gt;I want to tell you about five personal habits that have the biggest impact on the security of your identity, your accounts, and your digital life.&lt;/p&gt;

&lt;p&gt;And the good news is, it is easier than you think.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use unique passwords
&lt;/h3&gt;

&lt;p&gt;Never reuse your password. Each account deserves its own unique password.&lt;/p&gt;

&lt;p&gt;Why? Because breaches happen all the time, and you will never find out about all of them. When one site leaks, every other account that shares that password is suddenly open.&lt;/p&gt;

&lt;h3&gt;
  
  
  Turn on two-factor authentication
&lt;/h3&gt;

&lt;p&gt;Even a strong, unique password is not enough anymore. Credentials can be stolen, and the second layer of protection is exactly what separates you from an easy target.&lt;/p&gt;

&lt;p&gt;Attackers go for easy. Make your accounts a little less easy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pause before you tap
&lt;/h3&gt;

&lt;p&gt;This is probably the hardest one to implement. It takes time, but it can really save you the trouble.&lt;/p&gt;

&lt;p&gt;Before you click that link, check the sender. Think about it for two seconds. If something starts feeling off, verify it first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect your email first
&lt;/h3&gt;

&lt;p&gt;Your email account is your digital passport. If someone gets access to your email, they can get access to nearly all of your other accounts.&lt;/p&gt;

&lt;p&gt;So if there is one account you really should protect, it is this one. Unique password. Two-factor authentication. No exceptions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audit your app permissions
&lt;/h3&gt;

&lt;p&gt;Once in a while, check the app permissions on your phone. You will be surprised.&lt;/p&gt;

&lt;p&gt;A flashlight app with access to your gallery. Why? Remove everything that is not essential, and be extra careful about location, camera, and microphone access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools help. They do not replace the habit
&lt;/h2&gt;

&lt;p&gt;Let me be clear before we finish. I am not saying tools are useless. I use plenty of them every single day, and so should you.&lt;/p&gt;

&lt;p&gt;A good antivirus, a password manager, a solid backup. These things genuinely help. But they help the way a good pair of running shoes helps. They make it easier to run. They do not run for you.&lt;/p&gt;

&lt;p&gt;That is the whole point. Tools are here to support your goals, not to replace your effort. They remove the friction so the smart choice becomes the easy choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1: unique passwords and MFA
&lt;/h3&gt;

&lt;p&gt;Use unique passwords and MFA. Both become much more convenient when you use a good, secure password manager.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The goal&lt;/td&gt;
&lt;td&gt;Secure my accounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The habit&lt;/td&gt;
&lt;td&gt;Use unique passwords and MFA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The tool&lt;/td&gt;
&lt;td&gt;A password manager&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you skip the habit and jump directly to a tool, you will have a password vault full of weak reused passwords. Your accounts will still be vulnerable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 2: pause before you tap
&lt;/h3&gt;

&lt;p&gt;Pause before you tap, and support that habit with a SecureDNS service.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The goal&lt;/td&gt;
&lt;td&gt;Avoid clicking malicious links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The habit&lt;/td&gt;
&lt;td&gt;Pause before you click&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The tool&lt;/td&gt;
&lt;td&gt;SecureDNS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The tool can stop you if you click a malicious link, but it has limits. If you just turn on SecureDNS and click on everything you see, you will be scammed sooner or later.&lt;/p&gt;

&lt;p&gt;The moment you expect the tool to do the thinking for you, you are back to the lock on the open door.&lt;/p&gt;

&lt;p&gt;So buy the tools. Use the tools. But establish the goals and build the habits first, because the habits are the part that actually protects you.&lt;/p&gt;

&lt;p&gt;And here is the best part. Tools cost money. Habits are free, and the most important ones often do not require a significant effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I am &lt;a href="https://www.linkedin.com/in/winkleri" rel="noopener noreferrer"&gt;Erich Winkler&lt;/a&gt;, a cybersecurity manager and the creator of &lt;a href="https://www.decodedsecurity.com" rel="noopener noreferrer"&gt;Decoded Security&lt;/a&gt;, a newsletter and learning platform that helps people understand complex cybersecurity topics and build a career in cybersecurity.&lt;/p&gt;

&lt;p&gt;If you want to protect your digital identity, your privacy, or build a career in cybersecurity, feel free to reach out to me and our community.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Game monetization benchmarks 2026: skin, battle pass, and IAP prices</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Wed, 19 Aug 2026 12:05:38 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/game-monetization-benchmarks-2026-skin-battle-pass-and-iap-prices-59n1</link>
      <guid>https://dev.to/guardingpearsoftware/game-monetization-benchmarks-2026-skin-battle-pass-and-iap-prices-59n1</guid>
      <description>&lt;p&gt;You are planning a shop. Maybe the game is still in Early Access. Maybe it already has players and you are trying to guess what a skin, a coint pack, or a season pass should cost. And how many of your players will buy it, and what does that mean per person?&lt;/p&gt;

&lt;p&gt;Here is what you will learn in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to tell buy rate, ARPPU, and ARPU apart&lt;/li&gt;
&lt;li&gt;What skins, currency, loot, and battle passes actually cost in 2026&lt;/li&gt;
&lt;li&gt;How many of &lt;em&gt;your&lt;/em&gt; players will buy in your shop&lt;/li&gt;
&lt;li&gt;First-year planning tables by genre, plus three worked examples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The genre tables later in this piece are conservative first-year, per-title estimates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt; put the global games market at $201.6 billion in 2025, up 9.1%, and past $200 billion for the first time. That is consumer spend on games and services, not hardware. On PC, microtransactions were 47% of PC revenue and grew 9.1% year over year. Console in-game spending went the other way, down 4.6% to $13.3 billion. &lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower&lt;/a&gt; counted $81.75 billion in mobile game in-app purchases in 2025, up only 1.3%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.midiaresearch.com/reports/the-why-and-what-behind-in-game-spending" rel="noopener noreferrer"&gt;MIDiA Research&lt;/a&gt; found in its Q1 2024 consumer survey that cosmetic items now account for the majority of in-game spending, and that share is still rising. Players buy identity, not only power.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read every number in this article
&lt;/h2&gt;

&lt;p&gt;Three metrics get mixed together in industry posts. If you mix them, your forecast is wrong.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Formula&lt;/th&gt;
&lt;th&gt;What it answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Buy rate / conversion&lt;/td&gt;
&lt;td&gt;Paying players / reachable players&lt;/td&gt;
&lt;td&gt;How many people open their wallet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARPPU&lt;/td&gt;
&lt;td&gt;Revenue / paying players&lt;/td&gt;
&lt;td&gt;How much a &lt;em&gt;buyer&lt;/em&gt; spends&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ARPU&lt;/td&gt;
&lt;td&gt;Revenue / all players&lt;/td&gt;
&lt;td&gt;How much an &lt;em&gt;average player&lt;/em&gt; is worth&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The identity you must keep in your head:&lt;/p&gt;

&lt;p&gt;ARPU = buy rate x ARPPU&lt;/p&gt;

&lt;p&gt;Example: 4% of players buy skins, and those buyers spend $50 a year.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ARPPU = $50&lt;/li&gt;
&lt;li&gt;ARPU = 0.04 x $50 = $2.00 per player&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have 20,000 reachable players, first-year skin revenue is about $40,000, not 20,000 x $50.&lt;/p&gt;

&lt;p&gt;A second trap is worse.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kind of "buy rate"&lt;/th&gt;
&lt;th&gt;What it measures&lt;/th&gt;
&lt;th&gt;Can you use it as a per-game forecast?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lifetime ever-bought&lt;/td&gt;
&lt;td&gt;Share of &lt;em&gt;all players&lt;/em&gt; who have ever bought this &lt;em&gt;in any game&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;No. Upper bound only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-title conversion of actives&lt;/td&gt;
&lt;td&gt;Share of &lt;em&gt;your&lt;/em&gt; players who buy &lt;em&gt;your&lt;/em&gt; shop in a year&lt;/td&gt;
&lt;td&gt;Yes. This is the planning number.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;Entertainment Software Association's 2026 Essential Facts&lt;/a&gt; report says 27% of US players aged 8+ have ever bought skins. That is not "27% of your Steam page will buy your $12 jacket." That is "more than a quarter of US players have bought a cosmetic somewhere, at some point."&lt;/p&gt;

&lt;p&gt;For a new title, use the 1 to 5% one-off IAP and 8 to 20% battle pass bands from live-ops catalogs, then adjust by genre.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Do not plan as if 27% of your players will buy a skin. For a new game, expect about 1 to 5% to buy a one-off item, and about 8 to 20% to buy a battle pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The 2025 to 2026 market
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Platform revenue
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Segment&lt;/th&gt;
&lt;th&gt;2025 figure&lt;/th&gt;
&lt;th&gt;Year-over-year&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Global games market&lt;/td&gt;
&lt;td&gt;$201.6B&lt;/td&gt;
&lt;td&gt;+9.1%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;, Global Games Market Report, 2025 full year (2026 update)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;$113.3B&lt;/td&gt;
&lt;td&gt;+10.7%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console&lt;/td&gt;
&lt;td&gt;$44.7B&lt;/td&gt;
&lt;td&gt;+2.8%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PC&lt;/td&gt;
&lt;td&gt;$43.6B&lt;/td&gt;
&lt;td&gt;+12.0%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console in-game spending&lt;/td&gt;
&lt;td&gt;$13.3B&lt;/td&gt;
&lt;td&gt;-4.6%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console DLC&lt;/td&gt;
&lt;td&gt;$2.1B&lt;/td&gt;
&lt;td&gt;-23.4%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile game IAP (store-tracked)&lt;/td&gt;
&lt;td&gt;$81.75B&lt;/td&gt;
&lt;td&gt;+1.3%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower, State of Mobile 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile game downloads&lt;/td&gt;
&lt;td&gt;50.41B&lt;/td&gt;
&lt;td&gt;-7.2%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hours played in mobile games&lt;/td&gt;
&lt;td&gt;444.63B&lt;/td&gt;
&lt;td&gt;+0.9%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Share of mobile IAP from top 1% of publishers&lt;/td&gt;
&lt;td&gt;92.5%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;&lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Newzoo's $113.3B mobile number and Sensor Tower's $81.75B IAP number measure different things. Sensor Tower is App Store plus Google Play in-app purchases. Newzoo is a wider consumer-spend view. Do not average them.&lt;/p&gt;

&lt;p&gt;Newzoo credited PC microtransaction growth in part to Counter-Strike 2 and Roblox. It blamed the console in-game drop on weaker engagement in Fortnite and Call of Duty. Full-game spending still grew 25% across PC and console.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; These billions are industry totals, not your forecast. Use them for context, then plan from the players who will actually find and try your game.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Who is buying
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fact&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;US players 8+ who have ever bought in-game content&lt;/td&gt;
&lt;td&gt;58%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026 Essential Facts&lt;/a&gt;, YouGov, n=13,545, 11 to 25 Feb 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gen Z / Millennial / Gen Alpha buyers, median monthly in-game spend&lt;/td&gt;
&lt;td&gt;$20&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parents who buy in-game content for their children&lt;/td&gt;
&lt;td&gt;54%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Of those parents, who require approval&lt;/td&gt;
&lt;td&gt;93%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PC microtransaction buyers who spend on cosmetics&lt;/td&gt;
&lt;td&gt;52%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (secondary recap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile players who have made at least one microtransaction&lt;/td&gt;
&lt;td&gt;68%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (secondary recap)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Older players have more cash. ESA and a &lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026 recap&lt;/a&gt; both note that the 44 to 59 group and the 50+ audience spend more per purchase and churn less. If your game is "for teens only," your ARPU will sit below these medians.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; A teen-only audience will sit below these medians. If parents must approve a purchase, expect fewer impulse buys and a lower ARPU.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What players actually buy
&lt;/h2&gt;

&lt;p&gt;ESA asked US players which types of in-game content they had ever purchased. Multiple answers were allowed, so rows overlap.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type of in-game content&lt;/th&gt;
&lt;th&gt;Share of US players aged 8+&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;In-game currency&lt;/td&gt;
&lt;td&gt;34%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026 Essential Facts&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skins or customization items&lt;/td&gt;
&lt;td&gt;27%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expansion packs&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Season pass / battle pass&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Additional maps or levels&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Randomized content packs&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Currency sits first because it is the payment method for everything else. In Fortnite and Call of Duty, buying V-Bucks or COD Points and buying the pass are often the same transaction. If you add both a currency pack and a battle pass to a forecast, do not add 34% + 26%.&lt;/p&gt;

&lt;p&gt;Loot sits last. That matches the regulatory and trust story: EU odds rules, UK and Australian scrutiny, and player fatigue. If you still want chests, price them honestly and show the odds.&lt;/p&gt;

&lt;p&gt;Game content (expansions, maps, story packs) is still a real line. It is not dead because battle passes exist. It is just a higher ticket and a lower purchase frequency. &lt;a href="https://www.gamedeveloper.com/business/total-consumer-spending-on-games-topped-60b-in-the-us-in-2025" rel="noopener noreferrer"&gt;Game Developer&lt;/a&gt; covered the same US spend picture through Circana and ESA.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Do not add currency buyers and pass buyers together. They are often the same purchase. Sell skins and a pass first. Treat loot as optional. Expansions still work if the price matches the game.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What things actually cost
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cosmetics, currency, and loot
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Typical price&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Global average cosmetic purchase&lt;/td&gt;
&lt;td&gt;$8.17 in 2025&lt;/td&gt;
&lt;td&gt;Up from $4.52 in 2020&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo, In-Game Apparel Market&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Basic cosmetic&lt;/td&gt;
&lt;td&gt;$0.99&lt;/td&gt;
&lt;td&gt;Entry SKU&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common psychological price points&lt;/td&gt;
&lt;td&gt;$4.99, $9.99, $19.99&lt;/td&gt;
&lt;td&gt;Convert better than round numbers&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium / legendary cosmetic&lt;/td&gt;
&lt;td&gt;$30 to $50+&lt;/td&gt;
&lt;td&gt;Brand collabs and ultra tiers&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium character skin (industry average)&lt;/td&gt;
&lt;td&gt;about $15&lt;/td&gt;
&lt;td&gt;Directional&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (secondary recap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limited-time cosmetic premium vs permanent&lt;/td&gt;
&lt;td&gt;+20 to 50%&lt;/td&gt;
&lt;td&gt;Scarcity pricing&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regional discount vs US list&lt;/td&gt;
&lt;td&gt;40 to 60% in developing markets&lt;/td&gt;
&lt;td&gt;Purchasing-power pricing&lt;/td&gt;
&lt;td&gt;&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Currency packs&lt;/td&gt;
&lt;td&gt;$4.99 / $9.99 / $19.99 / $49.99 / $99.99&lt;/td&gt;
&lt;td&gt;Larger packs have a better rate&lt;/td&gt;
&lt;td&gt;Publisher store listings, 2025 to 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loot / chest ticket&lt;/td&gt;
&lt;td&gt;$5 to $10 typical&lt;/td&gt;
&lt;td&gt;Lowest ESA ever-bought share&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt; plus common store SKUs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game content / expansion&lt;/td&gt;
&lt;td&gt;$10 to $20 indie; $20 to $40 AAA DLC&lt;/td&gt;
&lt;td&gt;Fewer purchases per year&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.gamedeveloper.com/business/total-consumer-spending-on-games-topped-60b-in-the-us-in-2025" rel="noopener noreferrer"&gt;Circana / ESA content mix&lt;/a&gt;, 2025 to 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Live-service cosmetic SKUs players already know
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Game&lt;/th&gt;
&lt;th&gt;SKU&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Valorant&lt;/td&gt;
&lt;td&gt;Select Edition weapon skin&lt;/td&gt;
&lt;td&gt;875 VP, about $10&lt;/td&gt;
&lt;td&gt;Riot support / community conversion, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valorant&lt;/td&gt;
&lt;td&gt;Deluxe Edition&lt;/td&gt;
&lt;td&gt;1,275 VP, about $16&lt;/td&gt;
&lt;td&gt;Riot, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valorant&lt;/td&gt;
&lt;td&gt;Premium Edition&lt;/td&gt;
&lt;td&gt;1,775 VP, about $23&lt;/td&gt;
&lt;td&gt;Riot, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valorant&lt;/td&gt;
&lt;td&gt;Exclusive / Ultra&lt;/td&gt;
&lt;td&gt;about $26 to $30+ per gun&lt;/td&gt;
&lt;td&gt;Dexerto bundle guide; Riot "varies"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;League of Legends&lt;/td&gt;
&lt;td&gt;Standard / Epic skin&lt;/td&gt;
&lt;td&gt;975 to 1,350 RP, about $11&lt;/td&gt;
&lt;td&gt;Riot Points chart, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;League of Legends&lt;/td&gt;
&lt;td&gt;Legendary&lt;/td&gt;
&lt;td&gt;1,820 RP, about $22&lt;/td&gt;
&lt;td&gt;Riot, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;League of Legends&lt;/td&gt;
&lt;td&gt;Ultimate&lt;/td&gt;
&lt;td&gt;3,250 RP, about $35&lt;/td&gt;
&lt;td&gt;Riot, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fortnite&lt;/td&gt;
&lt;td&gt;Individual skins&lt;/td&gt;
&lt;td&gt;typically $8 to $20&lt;/td&gt;
&lt;td&gt;Epic item shop, 2025 to 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are AAA reference prices, not indie targets. Your first shop should sit near the $5 to $12 band unless the item is a full bundle or a story expansion. MarketIntelo's $8.17 average is the cleanest single number for "what does a cosmetic checkout look like in 2025."&lt;/p&gt;

&lt;p&gt;Valorant Points in the US run about $0.0105 per VP on the smallest pack and $0.0091 on the largest. Players who buy the $99.99 pack get about 13% more points per dollar. If your economy only works when people buy the whale pack, the economy is wrong.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Price your first cosmetic between $5 and $12, and make it obvious in one screenshot. Valorant and League prices are AAA reference points, not indie targets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Battle pass prices in 2026
&lt;/h2&gt;

&lt;p&gt;The market converged on ten dollars. &lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM's May 2026 catalog&lt;/a&gt; of US battle and season-pass products makes that obvious.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apps running a battle / season pass&lt;/td&gt;
&lt;td&gt;754 (73% are games)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM, State of May 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game pass items in catalog&lt;/td&gt;
&lt;td&gt;977&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median game battle pass&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25th percentile (entry)&lt;/td&gt;
&lt;td&gt;$5.99&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium tail (top 10%)&lt;/td&gt;
&lt;td&gt;$29.99&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical standard pass&lt;/td&gt;
&lt;td&gt;$5 to $10 / season&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium / deluxe pass&lt;/td&gt;
&lt;td&gt;$15 to $25&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tier-skip bundle&lt;/td&gt;
&lt;td&gt;$5 to $15&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annual / subscription pass&lt;/td&gt;
&lt;td&gt;$30 to $60 / year&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;, emerging&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical season length&lt;/td&gt;
&lt;td&gt;4 to 12 weeks&lt;/td&gt;
&lt;td&gt;&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass adoption in top live-service titles&lt;/td&gt;
&lt;td&gt;about 85%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix&lt;/a&gt; / Kevuru 2026 recaps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass adoption in top online multiplayer (2025)&lt;/td&gt;
&lt;td&gt;about 73%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass share of those titles' revenue&lt;/td&gt;
&lt;td&gt;22 to 35%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enrolled consumer spend per season (pass + extras)&lt;/td&gt;
&lt;td&gt;about $31.50&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  2026 live-service list prices
&lt;/h3&gt;

&lt;p&gt;These are premium-currency prices, not always a clean dollar tag.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Game&lt;/th&gt;
&lt;th&gt;Premium pass&lt;/th&gt;
&lt;th&gt;Season checked&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fortnite&lt;/td&gt;
&lt;td&gt;800 V-Bucks ($8.99 cheapest pack after 19 Mar 2026)&lt;/td&gt;
&lt;td&gt;From 19 Mar 2026&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.fortnite.com/news/fortnite-v-bucks-price-increase" rel="noopener noreferrer"&gt;Epic Games&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apex Legends&lt;/td&gt;
&lt;td&gt;950 Apex Coins&lt;/td&gt;
&lt;td&gt;Season 30, from 4 Aug 2026&lt;/td&gt;
&lt;td&gt;EA / Respawn&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marvel Rivals&lt;/td&gt;
&lt;td&gt;990 Lattice&lt;/td&gt;
&lt;td&gt;Season 9, Jul 2026&lt;/td&gt;
&lt;td&gt;NetEase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valorant&lt;/td&gt;
&lt;td&gt;1,000 VP (about $9.99)&lt;/td&gt;
&lt;td&gt;2026 Act 2, from 18 Mar 2026&lt;/td&gt;
&lt;td&gt;Riot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overwatch&lt;/td&gt;
&lt;td&gt;1,000 Overwatch Coins (about $10)&lt;/td&gt;
&lt;td&gt;Season window Apr to Jun 2026&lt;/td&gt;
&lt;td&gt;Blizzard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Call of Duty: Black Ops 7&lt;/td&gt;
&lt;td&gt;1,100 COD Points&lt;/td&gt;
&lt;td&gt;Season 05, from 23 Jul 2026&lt;/td&gt;
&lt;td&gt;Activision&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.fortnite.com/news/fortnite-v-bucks-price-increase" rel="noopener noreferrer"&gt;Epic&lt;/a&gt; cut the Fortnite pass from 1,000 to 800 V-Bucks in March 2026, and cut the $8.99 pack from 1,000 to 800 V-Bucks on the same day. The dollar price did not fall. Completing the pass now returns 800 V-Bucks, enough for the next pass and no surplus. If you copy Fortnite's "the pass pays for itself" loop, budget that as retention, not extra revenue.&lt;/p&gt;

&lt;p&gt;Deluxe bundles sit above the pass. Activision's Battle Pass Bundle with 20 tier skips is 2,400 COD Points. Blizzard's premium plus 20 skips is 2,200 coins. Apex sells Ultimate tiers for real money.&lt;/p&gt;

&lt;p&gt;Casual and smaller games should start at $5.99, not $9.99. That is MWM's 25th percentile, and it is where puzzle, idle, and light seasonal games actually sit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Price a full live-service pass at $9.99. Start at $5.99 if the game is casual or small. If the pass pays for the next pass, count that as retention, not extra revenue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How many players pay
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Industry bands
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shop&lt;/th&gt;
&lt;th&gt;Per-title conversion of actives&lt;/th&gt;
&lt;th&gt;Lifetime ever-bought (US, any game)&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;One-off IAP (a single skin, pack, or currency bundle)&lt;/td&gt;
&lt;td&gt;1 to 5%&lt;/td&gt;
&lt;td&gt;Skins 27%, currency 34%, loot 15%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM 2026&lt;/a&gt;; &lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First purchase after install (mobile)&lt;/td&gt;
&lt;td&gt;2 to 5% typical; 8 to 12% top mid-core&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://appfollow.io/blog/mobile-game-kpis" rel="noopener noreferrer"&gt;AppFollow 2026&lt;/a&gt;, compiling AppsFlyer / Sensor Tower / Newzoo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Battle pass&lt;/td&gt;
&lt;td&gt;8 to 20% of actives&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM 2026&lt;/a&gt;; &lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Well-timed battle pass in a top title&lt;/td&gt;
&lt;td&gt;15 to 20%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix&lt;/a&gt; / Kevuru 2026 (secondary recaps)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile multi-pass&lt;/td&gt;
&lt;td&gt;8 to 12%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://recited.io/kb/game-monetization-strategies/in-game-purchase-systems/battle-passes-and-season-passes/" rel="noopener noreferrer"&gt;Recited&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console single-pass&lt;/td&gt;
&lt;td&gt;25 to 35%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://recited.io/kb/game-monetization-strategies/in-game-purchase-systems/battle-passes-and-season-passes/" rel="noopener noreferrer"&gt;Recited&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Mobile IAP conversion by genre (US / Canada, 2026)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre band&lt;/th&gt;
&lt;th&gt;IAP conversion&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hyper-casual&lt;/td&gt;
&lt;td&gt;0.5 to 2%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;2 to 4%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mid-core&lt;/td&gt;
&lt;td&gt;3 to 6%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPG&lt;/td&gt;
&lt;td&gt;4 to 8%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casino (first purchase in 30 days)&lt;/td&gt;
&lt;td&gt;4.95%&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer, App Monetization 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A battle pass converts better than a single skin because the pitch is "buy once, unlock the season by playing." MWM's catalog says pass holders also log in 30 to 60% more often. Cubix and Kevuru report pass owners are about 3x more likely to still be around after six months, and they make about 25% more secondary micro-purchases.&lt;/p&gt;

&lt;p&gt;That last point is a warning. &lt;a href="https://www.deconstructoroffun.com/blog/2022/6/4/battle-passes-analysis" rel="noopener noreferrer"&gt;Deconstructor of Fun (2022)&lt;/a&gt; showed that a generous pass steals a la carte shop spend. If the pass already contains the only skins people wanted, your shop ARPU falls. In planning, if you run a pass &lt;em&gt;and&lt;/em&gt; a shop, cut shop revenue by about 15%.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; More players will buy a pass than a single skin. If you sell both, cut your shop forecast by about 15%, because the pass often includes the skins people wanted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Revenue per person
&lt;/h2&gt;

&lt;p&gt;These numbers are not all measuring the same window. Read the period column.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Period&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Casual IAP ARPPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$7.26&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mid-core IAP ARPPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$9.80&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casino IAP ARPPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$11.40&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual IAP ARPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$1.34&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mid-core IAP ARPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$2.13&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casino IAP ARPU&lt;/td&gt;
&lt;td&gt;Day 90&lt;/td&gt;
&lt;td&gt;$2.43&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual monthly ARPPU&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;$10 to $30&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://appfollow.io/blog/mobile-game-kpis" rel="noopener noreferrer"&gt;AppFollow 2026&lt;/a&gt; compile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mid-core monthly ARPPU&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;$50 to $100&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://appfollow.io/blog/mobile-game-kpis" rel="noopener noreferrer"&gt;AppFollow 2026&lt;/a&gt; compile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gacha / hardcore monthly ARPPU&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;often $100+&lt;/td&gt;
&lt;td&gt;&lt;a href="https://appfollow.io/blog/mobile-game-kpis" rel="noopener noreferrer"&gt;AppFollow 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile ARPPU&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;about $12.30&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (directional, secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free-to-play ARPU&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;$7.20&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;US mobile player microtransaction spend&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;$15.60&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics 2026&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESA buyer median in-game spend&lt;/td&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;$20&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA 2026&lt;/a&gt;, younger generations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top RPG / strategy paying user&lt;/td&gt;
&lt;td&gt;Unspecified, tier-1 markets&lt;/td&gt;
&lt;td&gt;$45+&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile shooter annual ARPPU&lt;/td&gt;
&lt;td&gt;Year&lt;/td&gt;
&lt;td&gt;$45 to $120&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo&lt;/a&gt;, Mobile Shooter, 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Broader mobile annual ARPPU band&lt;/td&gt;
&lt;td&gt;Year&lt;/td&gt;
&lt;td&gt;$30 to $65&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console single-pass ARPPU&lt;/td&gt;
&lt;td&gt;Season&lt;/td&gt;
&lt;td&gt;$12 to $18&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://recited.io/kb/game-monetization-strategies/in-game-purchase-systems/battle-passes-and-season-passes/" rel="noopener noreferrer"&gt;Recited&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile multi-pass ARPPU&lt;/td&gt;
&lt;td&gt;Season&lt;/td&gt;
&lt;td&gt;about $47&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://recited.io/kb/game-monetization-strategies/in-game-purchase-systems/battle-passes-and-season-passes/" rel="noopener noreferrer"&gt;Recited&lt;/a&gt; (secondary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass + supplemental cosmetics&lt;/td&gt;
&lt;td&gt;Season&lt;/td&gt;
&lt;td&gt;about $31.50&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo 2025&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Day-90 ARPPU of $8 to $11 looks small next to "$50 to $100 a month." Both can be true. AppsFlyer is a short window across a huge install base. AppFollow's monthly band is what a healthy live mid-core title sees among payers in rich markets. For an indie PC forecast, annual ARPPU of $20 to $60 among shop buyers is the honest middle. $100+ a month is gacha and 4X, not a $12 Steam shooter skin.&lt;/p&gt;

&lt;p&gt;Dataintelo's $31.50 per season is spend by people who already bought the pass, including extra cosmetics and skips. If your model already has a separate skins line, do not add $31.50 on top. Use pass price times paid seasons for the pass, and a smaller shop ARPPU for extras.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Do not mix Day-90 numbers with monthly or yearly numbers. For an indie PC shop, plan about $20 to $60 per year from each buyer, not $50 to $100 a month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What each genre actually sells
&lt;/h2&gt;

&lt;p&gt;Industry recaps in 2026 agree on the shape, even when they disagree on the exact dollar.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Primary live-ops motion&lt;/th&gt;
&lt;th&gt;What to sell first&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shooter / Action&lt;/td&gt;
&lt;td&gt;Battle pass + cosmetics&lt;/td&gt;
&lt;td&gt;Season pass, then weapon / operator skins&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026&lt;/a&gt;; &lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM 2026&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MOBA&lt;/td&gt;
&lt;td&gt;Cosmetics and seasonal content&lt;/td&gt;
&lt;td&gt;Skins, then a pass&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RPG&lt;/td&gt;
&lt;td&gt;Collection + cosmetics&lt;/td&gt;
&lt;td&gt;Characters, skins, currency; pass is secondary&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix&lt;/a&gt; / Kevuru 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;Premium currency&lt;/td&gt;
&lt;td&gt;Time / resource packs, then a mid-core pass&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026&lt;/a&gt;; &lt;a href="https://sensortower.com/blog/state-of-gaming-2026" rel="noopener noreferrer"&gt;Sensor Tower 2026&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;Seasonal leagues + packs&lt;/td&gt;
&lt;td&gt;Currency, player packs, kits, a season pass&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics&lt;/a&gt; sports MTX; &lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;ESA&lt;/a&gt; content mix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual / puzzle&lt;/td&gt;
&lt;td&gt;Ads + cheap IAP&lt;/td&gt;
&lt;td&gt;$5 to $6 cosmetics, $5.99 pass, rewarded ads&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub&lt;/a&gt;; &lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure / story&lt;/td&gt;
&lt;td&gt;Premium + DLC&lt;/td&gt;
&lt;td&gt;Game content first, light cosmetics&lt;/td&gt;
&lt;td&gt;Newzoo PC / console 2026 (sandbox vs story split)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hyper-casual&lt;/td&gt;
&lt;td&gt;Ads&lt;/td&gt;
&lt;td&gt;Do not plan a $10 pass&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix 2026&lt;/a&gt; (about 90% ads)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://sensortower.com/blog/state-of-gaming-2026" rel="noopener noreferrer"&gt;Sensor Tower's 2026 State of Gaming&lt;/a&gt; note: strategy and puzzle led mobile growth in 2025. Strategy IAP was up 20%, puzzle up 14%. Strategy was the only mobile genre that grew revenue, downloads, and time together. On PC, action premium revenue on Steam was up 32%.&lt;/p&gt;

&lt;p&gt;That does not mean every strategy indie prints money. It means the category is where spend is moving.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Match the shop to the genre. Action games sell a pass and skins. Adventure games sell DLC. Hyper-casual games should not plan a $10 pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Planning tables by genre
&lt;/h2&gt;

&lt;p&gt;The tables below are first-year, per-title planning defaults for a reachable PC audience. They sit inside the research bands above. They are not Fortnite, Genshin, or Call of Duty Mobile.&lt;/p&gt;

&lt;p&gt;How to use a row:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take your reachable players (the people who will actually find and try the game).&lt;/li&gt;
&lt;li&gt;Multiply by buy rate. That is your buyers.&lt;/li&gt;
&lt;li&gt;Multiply buyers by price x purchases per year. That is first-year revenue for that shop.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;ARPU = buy rate x price x purchases per year&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Purchases per year is how often a &lt;em&gt;buyer&lt;/em&gt; comes back. A $10 pass bought 3.5 times is not $10 of revenue. It is $35 from that buyer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Battle pass
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Default price&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Paid seasons / year&lt;/th&gt;
&lt;th&gt;ARPPU&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;16%&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$5.59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;9%&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$25.0&lt;/td&gt;
&lt;td&gt;$2.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;$5.99&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;$21.0&lt;/td&gt;
&lt;td&gt;$2.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Racing&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$3.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role Playing&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$3.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;$7.99&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;td&gt;$22.4&lt;/td&gt;
&lt;td&gt;$2.24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;14%&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$4.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;11%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$3.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$3.60&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Paid seasons are lower than calendar seasons. A game can run five seasons and still only collect 3.5 purchases from the average pass buyer. People skip a season.&lt;/p&gt;

&lt;h3&gt;
  
  
  Skins
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Default SKU&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Purchases / year&lt;/th&gt;
&lt;th&gt;ARPPU&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;td&gt;3.2%&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$0.96&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure&lt;/td&gt;
&lt;td&gt;$8&lt;/td&gt;
&lt;td&gt;1.8%&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;$16.0&lt;/td&gt;
&lt;td&gt;$0.29&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;$6&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;$13.2&lt;/td&gt;
&lt;td&gt;$0.26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Racing&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;2.8%&lt;/td&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;$24.0&lt;/td&gt;
&lt;td&gt;$0.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role Playing&lt;/td&gt;
&lt;td&gt;$10&lt;/td&gt;
&lt;td&gt;4.2%&lt;/td&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;td&gt;$28.0&lt;/td&gt;
&lt;td&gt;$1.18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;$8&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;2.3&lt;/td&gt;
&lt;td&gt;$18.4&lt;/td&gt;
&lt;td&gt;$0.46&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;$12&lt;/td&gt;
&lt;td&gt;3.5%&lt;/td&gt;
&lt;td&gt;2.6&lt;/td&gt;
&lt;td&gt;$31.2&lt;/td&gt;
&lt;td&gt;$1.09&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;$8&lt;/td&gt;
&lt;td&gt;2.2%&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;$17.6&lt;/td&gt;
&lt;td&gt;$0.39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;$8&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;$19.2&lt;/td&gt;
&lt;td&gt;$0.48&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Currency
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Default pack&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Purchases / year&lt;/th&gt;
&lt;th&gt;ARPPU&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;3.5%&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$1.22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$25.0&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;$4.99&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$15.0&lt;/td&gt;
&lt;td&gt;$0.37&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Racing&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$0.75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role Playing&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;4.5%&lt;/td&gt;
&lt;td&gt;3.8&lt;/td&gt;
&lt;td&gt;$38.0&lt;/td&gt;
&lt;td&gt;$1.71&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;$7.99&lt;/td&gt;
&lt;td&gt;2.8%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$24.0&lt;/td&gt;
&lt;td&gt;$0.67&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;4.0%&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$1.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;4.0%&lt;/td&gt;
&lt;td&gt;4.0&lt;/td&gt;
&lt;td&gt;$40.0&lt;/td&gt;
&lt;td&gt;$1.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;3.0%&lt;/td&gt;
&lt;td&gt;3.2&lt;/td&gt;
&lt;td&gt;$32.0&lt;/td&gt;
&lt;td&gt;$0.96&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Currency converts a little more often than skins because it is the wallet, not the item. Strategy and RPG sit highest. That matches Cubix: strategy lives on premium currency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loot packs
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Default ticket&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Purchases / year&lt;/th&gt;
&lt;th&gt;ARPPU&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;$7.99&lt;/td&gt;
&lt;td&gt;1.5%&lt;/td&gt;
&lt;td&gt;2.5&lt;/td&gt;
&lt;td&gt;$20.0&lt;/td&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure&lt;/td&gt;
&lt;td&gt;$6.99&lt;/td&gt;
&lt;td&gt;1.0%&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;$14.0&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;$4.99&lt;/td&gt;
&lt;td&gt;1.0%&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;$11.0&lt;/td&gt;
&lt;td&gt;$0.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Racing&lt;/td&gt;
&lt;td&gt;$6.99&lt;/td&gt;
&lt;td&gt;1.2%&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;$15.4&lt;/td&gt;
&lt;td&gt;$0.18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role Playing&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$0.75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;$5.99&lt;/td&gt;
&lt;td&gt;1.2%&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;$12.0&lt;/td&gt;
&lt;td&gt;$0.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;$7.99&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;td&gt;$22.4&lt;/td&gt;
&lt;td&gt;$0.45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;$6.99&lt;/td&gt;
&lt;td&gt;1.5%&lt;/td&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td&gt;$16.8&lt;/td&gt;
&lt;td&gt;$0.25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;$6.99&lt;/td&gt;
&lt;td&gt;1.2%&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;$15.4&lt;/td&gt;
&lt;td&gt;$0.18&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RPG and sports are the only genres where loot still looks like a real line (gacha, card packs, Ultimate Team). Everywhere else, keep it small or skip it. ESA's 15% lifetime ever-bought rate is the ceiling, not the plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Game content (DLC, expansions, maps, story packs)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Genre&lt;/th&gt;
&lt;th&gt;Default price&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Purchases / year&lt;/th&gt;
&lt;th&gt;ARPPU&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Action&lt;/td&gt;
&lt;td&gt;$14.99&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;$18.0&lt;/td&gt;
&lt;td&gt;$0.36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adventure&lt;/td&gt;
&lt;td&gt;$19.99&lt;/td&gt;
&lt;td&gt;3.0%&lt;/td&gt;
&lt;td&gt;1.3&lt;/td&gt;
&lt;td&gt;$26.0&lt;/td&gt;
&lt;td&gt;$0.78&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Casual&lt;/td&gt;
&lt;td&gt;$9.99&lt;/td&gt;
&lt;td&gt;1.0%&lt;/td&gt;
&lt;td&gt;1.1&lt;/td&gt;
&lt;td&gt;$11.0&lt;/td&gt;
&lt;td&gt;$0.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Racing&lt;/td&gt;
&lt;td&gt;$12.99&lt;/td&gt;
&lt;td&gt;1.8%&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;$15.6&lt;/td&gt;
&lt;td&gt;$0.28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Role Playing&lt;/td&gt;
&lt;td&gt;$19.99&lt;/td&gt;
&lt;td&gt;3.5%&lt;/td&gt;
&lt;td&gt;1.4&lt;/td&gt;
&lt;td&gt;$28.0&lt;/td&gt;
&lt;td&gt;$0.98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation&lt;/td&gt;
&lt;td&gt;$14.99&lt;/td&gt;
&lt;td&gt;2.2%&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;$18.0&lt;/td&gt;
&lt;td&gt;$0.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports&lt;/td&gt;
&lt;td&gt;$14.99&lt;/td&gt;
&lt;td&gt;2.5%&lt;/td&gt;
&lt;td&gt;1.3&lt;/td&gt;
&lt;td&gt;$19.5&lt;/td&gt;
&lt;td&gt;$0.49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strategy&lt;/td&gt;
&lt;td&gt;$14.99&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;$18.0&lt;/td&gt;
&lt;td&gt;$0.36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other&lt;/td&gt;
&lt;td&gt;$14.99&lt;/td&gt;
&lt;td&gt;2.0%&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;$18.0&lt;/td&gt;
&lt;td&gt;$0.36&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Adventure and RPG pay for expansions. Casual barely does. Do not put a $20 story pack behind a $5.99 hyper-casual loop.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Find your genre row. First-year revenue is reachable players times buy rate times (price times purchases per year). That is your shop, not Fortnite.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three worked examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example A. Free-to-play multiplayer action game
&lt;/h3&gt;

&lt;p&gt;Assume 50,000 reachable players in year one. You ship a $9.99 pass, $12 skins, and $9.99 currency. No loot.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shop&lt;/th&gt;
&lt;th&gt;Buyers&lt;/th&gt;
&lt;th&gt;Spend per buyer&lt;/th&gt;
&lt;th&gt;Revenue&lt;/th&gt;
&lt;th&gt;ARPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Battle pass&lt;/td&gt;
&lt;td&gt;8,000 (16%)&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$279,720&lt;/td&gt;
&lt;td&gt;$5.59&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skins&lt;/td&gt;
&lt;td&gt;1,600 (3.2%)&lt;/td&gt;
&lt;td&gt;$30.0&lt;/td&gt;
&lt;td&gt;$48,000&lt;/td&gt;
&lt;td&gt;$0.96&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Currency&lt;/td&gt;
&lt;td&gt;1,750 (3.5%)&lt;/td&gt;
&lt;td&gt;$35.0&lt;/td&gt;
&lt;td&gt;$61,163&lt;/td&gt;
&lt;td&gt;$1.22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shop after 15% pass overlap&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;$92,788&lt;/td&gt;
&lt;td&gt;$1.86&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total live-ops&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;$372,508&lt;/td&gt;
&lt;td&gt;$7.45&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Store fees are not in this table. Steam still takes its cut. So does the platform owner on console.&lt;/p&gt;

&lt;p&gt;If the same game is single-player only, cut live-ops by about 30%. Identity cosmetics convert worse when nobody else can see them. Multiplayer can justify about a 15% lift.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example B. Premium $25 adventure game plus DLC
&lt;/h3&gt;

&lt;p&gt;The box price does the heavy lifting. Add a $19.99 expansion and a light $8 skin line.&lt;/p&gt;

&lt;p&gt;On 20,000 reachable players:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line&lt;/th&gt;
&lt;th&gt;Buy rate&lt;/th&gt;
&lt;th&gt;Revenue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Game ($25, using your store conversion, not these live-ops rates)&lt;/td&gt;
&lt;td&gt;your catalog model&lt;/td&gt;
&lt;td&gt;catalog revenue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Game content&lt;/td&gt;
&lt;td&gt;3.0% x $19.99 x 1.3&lt;/td&gt;
&lt;td&gt;about $15,600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skins&lt;/td&gt;
&lt;td&gt;1.8% x $8 x 2.0&lt;/td&gt;
&lt;td&gt;about $5,760&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Live-ops here is a bonus, not the business.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example C. Casual game, $5.99 pass only
&lt;/h3&gt;

&lt;p&gt;On 100,000 reachable players:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buyers: 10,000&lt;/li&gt;
&lt;li&gt;Spend: $5.99 x 3.5 = $20.97&lt;/li&gt;
&lt;li&gt;Revenue: about $209,700&lt;/li&gt;
&lt;li&gt;ARPU: $2.10&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why casual studios still run passes. The ticket is small. The conversion is not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; In a free-to-play action game, the pass is most of the live-ops money. In a $25 adventure game, live-ops is a bonus. The box price is still the business.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Design notes that change the math
&lt;/h2&gt;

&lt;p&gt;Price the pass at a visible discount. &lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo&lt;/a&gt; says a $9.99 to $19.99 pass often looks like 30 to 40% off the a la carte value of the items inside. If the pass is not obviously cheaper than buying two skins, people will not convert at 8 to 20%.&lt;/p&gt;

&lt;p&gt;Keep a free track. The free track fills lobbies and teaches the loop. The paid track is the product.&lt;/p&gt;

&lt;p&gt;Keep seasons between 4 and 12 weeks. Shorter than four weeks feels like a chore. Longer than twelve loses the deadline. Most action games land near five seasons a year. Casual can run more, cheaper.&lt;/p&gt;

&lt;p&gt;Do not put progression power in the shop if you sell a competitive game. Cosmetics are the majority of in-game spend because they do not break the match. Pay-to-win still prints money in 4X and some RPGs. It also prints reviews you cannot undo.&lt;/p&gt;

&lt;p&gt;Loot is optional and politically expensive. ESA puts randomized packs last. If you ship them, disclose odds, cap child spend, and do not make the only good skin a chest exclusive.&lt;/p&gt;

&lt;p&gt;A pass can eat your shop. Watch ARPPU after the first season. If high spenders drop, the pass is too generous. &lt;a href="https://www.deconstructoroffun.com/blog/2022/6/4/battle-passes-analysis" rel="noopener noreferrer"&gt;Deconstructor of Fun&lt;/a&gt; called this out in 2022. It is still true.&lt;/p&gt;

&lt;p&gt;Currency is not content. A coin pack with nothing worth buying is a dead SKU. Currency ARPU only shows up if skins, passes, or content exist to sink it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Takeaway:&lt;/strong&gt; Make the pass look cheaper than two skins, keep a free track, and keep seasons between 4 and 12 weeks. Do not put power in a competitive shop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Your takeaway
&lt;/h2&gt;

&lt;p&gt;If you are shipping a live game in 2026, start with three prices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A $6 to $12 cosmetic people can understand in one screenshot.&lt;/li&gt;
&lt;li&gt;A $5.99 or $9.99 pass with a free track and a season short enough to finish.&lt;/li&gt;
&lt;li&gt;A currency pack only if something on that list is worth buying.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then forecast with buy rate times spend per buyer. Do not use ESA's 27% as your conversion. That number is "have they ever bought a skin in any game." Your number is "will they buy &lt;em&gt;your&lt;/em&gt; shop this year."&lt;/p&gt;

&lt;p&gt;Here is the short version to keep:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Split the metrics. Buy rate is how many players pay. ARPPU is how much a buyer spends. ARPU is those two multiplied. Never apply ARPPU to every player.&lt;/li&gt;
&lt;li&gt;Use 1 to 5% for a single item and 8 to 20% for a pass. Adjust down if the game is new or single-player.&lt;/li&gt;
&lt;li&gt;Price a cosmetic at $5 to $12. Price a pass at $5.99 (casual or small) or $9.99 (live action). Add coins only if there is something worth buying.&lt;/li&gt;
&lt;li&gt;If you run a pass and a shop, cut shop revenue by about 15%. The pass often includes the skins people wanted.&lt;/li&gt;
&lt;li&gt;Sell what the genre already buys. Action: pass and skins. Adventure: DLC. Casual: a cheap pass. Hyper-casual: ads, not a $10 pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want a first look at the potential for &lt;em&gt;your&lt;/em&gt; game, put the genre, platform, and game type into the &lt;a href="https://www.guardingpearsoftware.com/calculator/market" rel="noopener noreferrer"&gt;Market Insights calculator&lt;/a&gt;. It estimates where the game sits in the market and what audience that implies. Then come back to the tables above and run buy rate times spend per buyer on that audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.theesa.com/resources/essential-facts-about-the-us-video-game-industry/2026-data/" rel="noopener noreferrer"&gt;Entertainment Software Association, 2026 Essential Facts About the U.S. Video Game Industry&lt;/a&gt;. YouGov survey of 13,545 US respondents, 11 to 25 February 2026.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.theesa.com/two-thirds-of-americans-play-video-games-every-week-according-tonew-report-from-the-entertainment-software-association/" rel="noopener noreferrer"&gt;ESA press release, 3 June 2026&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gamedeveloper.com/business/total-consumer-spending-on-games-topped-60b-in-the-us-in-2025" rel="noopener noreferrer"&gt;Game Developer / Circana coverage of ESA 2026 spend&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://newzoo.com/articles/year-in-review-2025/" rel="noopener noreferrer"&gt;Newzoo, Year in review: 2025&lt;/a&gt;. Global Games Market Report quarterly update, June 2026, covering full-year 2025.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sensortower.com/blog/state-of-mobile-2026/" rel="noopener noreferrer"&gt;Sensor Tower, State of Mobile 2026&lt;/a&gt; and &lt;a href="https://sensortower.com/blog/state-of-gaming-2026" rel="noopener noreferrer"&gt;State of Gaming 2026&lt;/a&gt;. Mobile game IAP $81.75B; strategy / puzzle growth.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mwm.ai/glossary/battle-pass" rel="noopener noreferrer"&gt;MWM, Battle Pass: How It Works, 2026 Pricing Benchmarks and Design&lt;/a&gt;. State of May 2026 catalog.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://marketintelo.com/report/in-game-apparel-market" rel="noopener noreferrer"&gt;MarketIntelo, In-Game Apparel Market Research Report 2034&lt;/a&gt;. 2025 pricing section: $8.17 average cosmetic.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.midiaresearch.com/reports/the-why-and-what-behind-in-game-spending" rel="noopener noreferrer"&gt;MIDiA Research, The "why" and "what" behind in-game spending&lt;/a&gt;. August 2024. Q1 2024 survey in US, UK, Australia, Canada, Germany, France, Poland, Turkey, South Africa.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.appsflyer.com/resources/reports/app-marketing-monetization-report/" rel="noopener noreferrer"&gt;AppsFlyer, The State of App Monetization, 2026 Edition&lt;/a&gt;. D90 IAP ARPU / ARPPU and conversion.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://appfollow.io/blog/mobile-game-kpis" rel="noopener noreferrer"&gt;AppFollow, Mobile Game KPIs: The 2026 Guide to Gaming Metrics&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://business.rewardinghub.com/blog/monetization-benchmarks-by-genre/" rel="noopener noreferrer"&gt;RewardingHub, Mobile Game Monetization Benchmarks by Genre 2026&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dataintelo.com/report/global-online-microtransaction-market" rel="noopener noreferrer"&gt;Dataintelo, Online Microtransaction Market&lt;/a&gt;. Pass adoption, $31.50 per season, shooter ARPPU $45 to $120.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://recited.io/kb/game-monetization-strategies/in-game-purchase-systems/battle-passes-and-season-passes/" rel="noopener noreferrer"&gt;Recited, Battle Passes and Season Passes&lt;/a&gt;. Mobile vs console conversion and ARPPU. Secondary playbook.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.deconstructoroffun.com/blog/2022/6/4/battle-passes-analysis" rel="noopener noreferrer"&gt;Deconstructor of Fun, Battle Passes: Everything You Ought to Know and Then Some&lt;/a&gt;. 4 June 2022.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://worldmetrics.org/microtransactions-in-video-games-statistics/" rel="noopener noreferrer"&gt;WorldMetrics, Microtransactions In Video Games Statistics, 2026 Edition&lt;/a&gt;. 12 Feb 2026, verified 11 Jul 2026. Secondary recap.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.fortnite.com/news/fortnite-v-bucks-price-increase" rel="noopener noreferrer"&gt;Epic Games, Fortnite V-Bucks Price Increase&lt;/a&gt;. 10 March 2026, effective 19 March 2026.&lt;/li&gt;
&lt;li&gt;Riot Games. Valorant skin tiers and Riot Points / VP pack prices, 2026. Publisher listings, no single stable public support URL.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cubix.co/blog/game-monetization-statistics-iap-ads-and-premium-models/" rel="noopener noreferrer"&gt;Cubix, Game Monetization Statistics 2026&lt;/a&gt;. 8 July 2026. Secondary recap, not a primary survey.&lt;/li&gt;
&lt;li&gt;Kevuru Games, Game Monetization Statistics: Data and Insights. Secondary recap of the 15 to 20% pass band.&lt;/li&gt;
&lt;li&gt;Xiao, Zhang, Mao. What Makes Loyalty Programme Work: The Effectiveness of the Battle Pass System in Chinese MOBA Game. Advances in Economics, Management and Political Sciences 172 (published 8 May 2025). Academic pass and loyalty framing, not Western ARPU.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Growing Threat of Vishing and AI Voice Cloning</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Fri, 14 Aug 2026 14:18:09 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/the-growing-threat-of-vishing-and-ai-voice-cloning-4fcf</link>
      <guid>https://dev.to/guardingpearsoftware/the-growing-threat-of-vishing-and-ai-voice-cloning-4fcf</guid>
      <description>&lt;p&gt;Voice has long been one of the most trusted forms of communication, allowing people to recognize colleagues, family members, customers, and business partners simply by hearing them. But advances in generative artificial intelligence are challenging that assumption. With AI voice-cloning technology capable of producing remarkably realistic speech, cybercriminals can now impersonate trusted individuals and organizations. &lt;/p&gt;

&lt;p&gt;According to Google Mandiant, while exploits remained the most common initial infection vector in 2026, highly interactive voice phishing has surged, accounting for 11% of observed incidents and becoming the second-most common initial access vector.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is voice phishing?
&lt;/h2&gt;

&lt;p&gt;Voice phishing, or vishing, is a form of social engineering in which cybercriminals use phone calls, voice messages, or other voice-based communications to impersonate trusted individuals or organizations and manipulate victims into revealing sensitive information or taking actions that compromise their security. &lt;/p&gt;

&lt;h2&gt;
  
  
  AI voice cloning
&lt;/h2&gt;

&lt;p&gt;AI voice cloning is a technology that uses artificial intelligence to create a synthetic version of a person’s voice based on recordings of their speech. AI models can generate highly realistic speech that sounds like the original speaker by analyzing characteristics such as tone, pitch, pronunciation, rhythm, and speaking patterns. While the technology has applications in areas such as accessibility, entertainment, and content creation, it can also be abused by cybercriminals to impersonate trusted individuals. &lt;/p&gt;

&lt;p&gt;The problem is particularly serious when the attacker knows something about the victim.&lt;/p&gt;

&lt;p&gt;A cloned voice alone may not be enough to convince someone. But a convincing voice combined with knowledge of a person's name, job title, colleagues, current projects, or organizational structure can make the interaction much more credible.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Vishing Scams Work
&lt;/h2&gt;

&lt;p&gt;Attackers typically move through several stages, gradually building trust before attempting to achieve their objective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reconnaissance
&lt;/h3&gt;

&lt;p&gt;The attack usually begins with reconnaissance, during which the attacker collects as much information as possible about the intended victim. This information can come from social media profiles, company websites, professional networking platforms, public records, data breaches, leaked credentials, or previously compromised accounts. Attackers may look for an employee's job title, manager, colleagues, responsibilities, phone number, email address, and even information about ongoing projects. The more details an attacker has, the easier it becomes to construct a believable story and make the subsequent phone conversation appear legitimate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identity Preparation
&lt;/h3&gt;

&lt;p&gt;After gathering information, the attacker develops a convincing identity and determines whom they will impersonate. In corporate attacks, this could be an IT administrator, help-desk employee, manager, executive, business partner, or security representative. Attackers may also impersonate a trusted service provider, bank, telecommunications company, or government agency. The objective is to select an identity that the victim would have a legitimate reason to trust, and that can plausibly make the request the attacker intends to deliver.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Contact
&lt;/h3&gt;

&lt;p&gt;The attacker then establishes contact with the victim, typically through a phone call, although modern campaigns can combine voice calls with email, text messages, messaging applications, or collaboration platforms. The initial communication is often designed to appear routine rather than immediately suspicious. For example, the caller may claim to be following up on an account problem, security alert, password issue, payment, or technical-support request. Attackers may also use caller-ID spoofing or other techniques to make the incoming call appear to originate from a legitimate organization or familiar number.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voice Impersonation
&lt;/h3&gt;

&lt;p&gt;AI voice cloning can make this stage more convincing by allowing attackers to generate speech that resembles a real person. A criminal may use publicly available recordings or other audio samples to create a synthetic voice that imitates an executive, colleague, family member, customer-service representative, or other trusted individual. During a live conversation, the attacker can use the cloned voice to reinforce the impersonation and make it more difficult for the victim to recognize that they are communicating with a criminal. &lt;/p&gt;

&lt;h3&gt;
  
  
  Social Engineering
&lt;/h3&gt;

&lt;p&gt;Once communication has been established, the attacker uses social-engineering techniques to manipulate the victim into taking the desired action. A common tactic is to create a sense of urgency by claiming that an account has been compromised, a payment needs immediate approval, an employee must complete a security verification, or access will be suspended unless action is taken. Attackers may deliberately limit the victim's opportunity to think or independently verify the request. They combine urgency with authority, familiarity, and information gathered during reconnaissance, to make the fraudulent request appear both legitimate and time-sensitive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credential and Information Theft
&lt;/h3&gt;

&lt;p&gt;After gaining the victim's trust, the attacker attempts to obtain something valuable. This could include usernames, passwords, one-time authentication codes, recovery codes, financial information, or other sensitive data. In some cases, the caller may direct the victim to a fraudulent website that resembles a legitimate login portal. The victim may be instructed to enter their credentials or authentication information while remaining on the phone with the attacker. This allows the criminal to capture the information in real time and use it before the victim realizes that the interaction was fraudulent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lateral Movement
&lt;/h3&gt;

&lt;p&gt;A compromised account may be only the beginning of the attack. After gaining an initial foothold, criminals can search for additional accounts, applications, documents, credentials, and systems that can provide greater access. They may use the compromised identity to impersonate the victim and target colleagues, access sensitive business information, or obtain higher privileges. &lt;/p&gt;

&lt;h2&gt;
  
  
  Types of Vishing Scams
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Family Emergency Scams
&lt;/h3&gt;

&lt;p&gt;Family emergency scams use AI-generated voices to impersonate a relative who supposedly needs immediate assistance. The attacker may claim that the relative has been involved in an accident, arrested, hospitalized, or stranded and urgently needs money. The caller may then instruct the victim to transfer funds or provide financial information. These attacks are particularly effective because they exploit emotional responses rather than relying solely on technical deception. When someone believes that a loved one is in immediate danger, fear and urgency can override normal skepticism. &lt;/p&gt;

&lt;h3&gt;
  
  
  Bank and Financial Institution Impersonation
&lt;/h3&gt;

&lt;p&gt;In bank impersonation scams, criminals use AI-generated voices to pose as representatives of banks or other financial institutions. The caller may claim that suspicious activity has been detected on the victim's account, that a transaction needs to be reversed, or that the customer's identity must be verified. The victim may then be asked to provide account information, passwords, one-time passcodes, or other authentication details. Attackers often combine the voice call with spoofed text messages or emails to reinforce the legitimacy of the story. They may also possess partial information about the victim obtained from previous data breaches, leaked databases, or compromised accounts, making the conversation appear more credible and convincing.&lt;/p&gt;

&lt;h3&gt;
  
  
  IT Help-Desk Scams
&lt;/h3&gt;

&lt;p&gt;InnIT help-desk scams, attackers can use a cloned voice to pose as an internal IT employee or support technician. The supposed technician may claim that the employee's account has experienced a security problem and that immediate action is required. The victim could then be asked to reset a password, approve an MFA request, disclose an authentication code, or install remote-access software. Once the attacker gains access, the compromised account can be used to reach corporate applications, internal systems, and sensitive information. &lt;/p&gt;

&lt;h3&gt;
  
  
  Customer-Service and Technical-Support Impersonation
&lt;/h3&gt;

&lt;p&gt;Attackers can also clone the voices of customer-service representatives or technical-support personnel and contact individuals claiming to help resolve an account or device problem. The caller may create a sense of urgency by claiming that the victim's account is compromised or that immediate verification is required to prevent unauthorized activity. The victim may subsequently be directed to a fraudulent website, asked to reveal authentication information, or persuaded to grant remote access to a device. &lt;/p&gt;

&lt;h3&gt;
  
  
  Government and Law-Enforcement Impersonation
&lt;/h3&gt;

&lt;p&gt;Another use of AI voice cloning involves impersonating government officials, law-enforcement personnel, tax authorities, or other public institutions. The attacker may claim that the victim is under investigation, has an outstanding payment, or must provide information to resolve an alleged legal or administrative issue. Threats of penalties, arrest, or other consequences are used to create fear and discourage the victim from questioning the request. &lt;/p&gt;

&lt;h3&gt;
  
  
  CEO Fraud
&lt;/h3&gt;

&lt;p&gt;CEO fraud is one of the most financially damaging forms of AI-powered voice impersonation targeting organizations. In these attacks, criminals use a cloned voice to impersonate a CEO, senior executive, or other authority figure and contact employees, often those in finance or accounting, with an urgent request to transfer funds or approve a payment. &lt;/p&gt;

&lt;p&gt;Attackers may deliberately make the request outside normal working hours or claim that the transaction is confidential, reducing the chances that the employee will independently verify it with the executive. &lt;/p&gt;

&lt;h2&gt;
  
  
  How organizations can defend against AI-powered vishing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Establish independent verification
&lt;/h3&gt;

&lt;p&gt;Employees should verify unexpected requests through a separate, trusted channel. If an executive calls asking for a sensitive action, the employee should not verify the request by calling the same number back. Instead, they should use a previously established corporate contact method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create strict help-desk procedures
&lt;/h3&gt;

&lt;p&gt;Account recovery and authentication resets should require strong verification. Help-desk personnel should not be able to override established identity controls merely because a caller sounds convincing or knows internal information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Train employees for AI impersonation
&lt;/h3&gt;

&lt;p&gt;Organizations should implement structured, role-based cybersecurity awareness training that specifically covers the risks posed by AI-powered voice-cloning scams. Training should teach employees how to recognize common social-engineering tactics, follow established identity-verification procedures, and respond appropriately to urgent or suspicious requests without allowing pressure or perceived authority to influence their decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Report Suspected AI Voice-Cloning Scams
&lt;/h3&gt;

&lt;p&gt;Individuals who encounter suspected AI voice-cloning scams should report them to the appropriate authorities and organizations. Organizations should additionally notify their internal security teams so that other employees can be warned about similar attempts. Early reporting can help authorities identify recurring campaigns, connect related incidents, and alert other potential victims before attackers can reuse the same impersonation techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  The future
&lt;/h2&gt;

&lt;p&gt;The next generation of AI voice attacks is likely to be even more sophisticated. Attackers may use AI voice cloning to respond to verification questions. Combining deepfake video with cloned voices could also make live video calls with fake identities difficult to distinguish from genuine interactions.&lt;/p&gt;

&lt;p&gt;At the same time, defensive technologies are advancing. Researchers are developing watermarking techniques that embed identifiers into synthetic speech, although widespread adoption remains limited.&lt;/p&gt;

&lt;p&gt;Legal and regulatory frameworks are evolving as well. Courts and compliance teams will need to determine how voice recordings should be treated as evidence as voice cloning becomes more prevalent and the authenticity of audio becomes harder to establish.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hoop Dynasty - The Continue button is the hardest part of a living sports simulation</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Thu, 13 Aug 2026 05:59:55 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/hoop-dynasty-the-continue-button-is-the-hardest-part-of-a-living-sports-simulation-3c3i</link>
      <guid>https://dev.to/guardingpearsoftware/hoop-dynasty-the-continue-button-is-the-hardest-part-of-a-living-sports-simulation-3c3i</guid>
      <description>&lt;p&gt;When I started building &lt;strong&gt;Hoop Dynasty: Rise of a Legend&lt;/strong&gt;, the interface was rough and the project was still searching for its final identity. The real work was happening underneath.&lt;/p&gt;

&lt;p&gt;I am Giulio Caruso, the solo developer behind the game. Hoop Dynasty is a single-player basketball career simulator. You do not watch a legend from a distance. You build your own.&lt;/p&gt;

&lt;p&gt;Create a young prospect, choose your role, shape your skills and mentality, then live an entire basketball career in an original world that evolves season after season. You can begin in College, enter International basketball, or face the pressure of the Pro world from day one. Every path carries different opportunities, risks, and expectations.&lt;/p&gt;

&lt;p&gt;Performances, consistency, form, injuries, and decisions determine your minutes, development, and reputation. A prospect can become a star, or follow a path no one expected.&lt;/p&gt;

&lt;p&gt;That living world is the part that took years to make honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The work happened in long simulations
&lt;/h2&gt;

&lt;p&gt;I spent years simulating careers through repeated, sometimes almost endless cycles. I wanted to understand what happened to rosters after several seasons, how injuries affected development, how contracts changed the balance between teams, and how a player's career could remain believable over time.&lt;/p&gt;

&lt;p&gt;Many of the most important corrections came from these long simulations.&lt;/p&gt;

&lt;p&gt;A roster could become unbalanced. An injury could have too much or too little impact. A player could develop in a way that looked mathematically valid but felt completely wrong from a basketball perspective.&lt;/p&gt;

&lt;p&gt;That forced me to create a QA system capable of generating alerts around the mathematical model behind the game. It had to identify unusual roster situations, unexpected progression, injury patterns, broken career paths, and inconsistencies that were almost impossible to see during a short manual test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pressing Continue starts a chain of events
&lt;/h2&gt;

&lt;p&gt;The most difficult part, however, was creating the living world.&lt;/p&gt;

&lt;p&gt;In Hoop Dynasty, pressing Continue does not simply move the calendar forward. It activates a large chain of events and validations. Matches are processed, player conditions change, rosters evolve, injuries are evaluated, contracts and decisions move forward, national team selections can appear, rivalries develop, and the world records the consequences.&lt;/p&gt;

&lt;p&gt;Every new feature has to find a place inside that chain without breaking something that already works.&lt;/p&gt;

&lt;p&gt;The Services layer that powers this system has grown to roughly 100,000 lines of engine code. I do not see that number as a badge of honour. I see it as a reminder of how much interconnected logic a sports simulation can contain.&lt;/p&gt;

&lt;p&gt;Whenever I had a new idea, I could not simply add it in isolation. I had to understand where it belonged, what it affected, and how it would behave after several seasons. The goal was not just to make the feature work once. It had to remain coherent inside a world that keeps moving.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bugs that only appear after many seasons
&lt;/h2&gt;

&lt;p&gt;There were also plenty of absurd moments. I remember situations where a player was called up to the national team and then never returned to the club. Other bugs were less obvious but even more dangerous, because the simulation continued while quietly becoming inconsistent.&lt;/p&gt;

&lt;p&gt;That is why the QA system became such an important part of development. It allowed me to observe the world over long periods, catch problems earlier, and measure whether the mathematical model still produced believable outcomes.&lt;/p&gt;

&lt;p&gt;Hoop Dynasty is still not perfectly coherent. That is one of the main areas I am working on before the demo. The ambition is not to pretend that a complex simulation is flawless. The ambition is to make the remaining inconsistencies visible, understandable, and progressively easier to correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ten years, nights, and Visual Studio
&lt;/h2&gt;

&lt;p&gt;I have been working on this project for more than ten years. I develop it after my regular job and family time, often late at night, with little more than Visual Studio, a cigarette, and another season to investigate.&lt;/p&gt;

&lt;p&gt;The project has changed enormously since the first prototypes. The UX became more deliberate, the systems became deeper, and the world became much more ambitious.&lt;/p&gt;

&lt;p&gt;But the central question remained the same:&lt;/p&gt;

&lt;p&gt;Can this world continue to live when the player is not looking?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where AI fits, and where it does not
&lt;/h2&gt;

&lt;p&gt;That question is also where I use AI today. I write the code and design the systems myself, then use AI to challenge the implementation, search for weaknesses, and expose blind spots. I do not delegate the game's logic or its design identity to AI. Some promotional assets were also created with AI, but the final creative direction and selection remain mine.&lt;/p&gt;

&lt;p&gt;I still do not know exactly where Hoop Dynasty will take me. I do know that it now has an identity of its own. After so many years, that is what gives me the confidence to keep pushing it forward.&lt;/p&gt;

&lt;p&gt;Every season is another test.&lt;br&gt;
Every Continue button is another chance to find out whether the world is still alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build an arena the world will remember
&lt;/h2&gt;

&lt;p&gt;Hoop Dynasty needs places with an identity. Until &lt;strong&gt;16 August 2026 at 23:59 CEST&lt;/strong&gt;, the first HD Foundry community challenge is open: imagine the next arena in this universe and turn it into a proposal ready for editorial selection.&lt;/p&gt;

&lt;p&gt;Give it an original name, a fictional city or region, an architectural identity, an atmosphere the crowd would recognize with their eyes closed, and one ritual or detail that could become part of its legend. No real teams, leagues, brands, venues, or copied identities. Build something that could only belong to the Hoop Dynasty universe.&lt;/p&gt;

&lt;p&gt;Every entry goes through editorial and originality review. Selected ideas may be adapted for the game world and credited in the Community Credits. Submission does not guarantee inclusion. The strongest ideas are the ones that feel ready to live inside the game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://foundry.hoopdynasty.info/?challenge=arena-01" rel="noopener noreferrer"&gt;Enter the arena challenge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://store.steampowered.com/app/4968700/Hoop_Dynasty_Rise_of_a_Legend/" rel="noopener noreferrer"&gt;Hoop Dynasty: Rise of a Legend on Steam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://foundry.hoopdynasty.info/?challenge=arena-01" rel="noopener noreferrer"&gt;Foundry Challenge #1: Create an Arena&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What MonoMod is and how Unity developers can detect it</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Wed, 12 Aug 2026 19:38:57 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/what-monomod-is-and-how-unity-developers-can-detect-it-6k1</link>
      <guid>https://dev.to/guardingpearsoftware/what-monomod-is-and-how-unity-developers-can-detect-it-6k1</guid>
      <description>&lt;p&gt;If you have read about BepInEx, MelonLoader, or HarmonyX, you have probably also seen MonoMod mentioned underneath them. MonoMod is not a player facing mod manager. It is a lower level .NET modding toolkit. Loaders and libraries use MonoMod pieces to hook and rewrite methods at runtime.&lt;/p&gt;

&lt;p&gt;You will learn what MonoMod is, how frameworks use it, what it does inside a Unity process, and how to spot its traces.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MonoMod is
&lt;/h2&gt;

&lt;p&gt;MonoMod is a general purpose .NET modding "basework." That word is intentional. It is a set of base tools and libraries, not one single app.&lt;/p&gt;

&lt;p&gt;Depending on which package is involved, it can help with runtime method detours, IL rewriting, hook helper generation, and patching support across Mono and related runtimes.&lt;/p&gt;

&lt;p&gt;In Unity modding and cheating talks, people usually mean the runtime pieces, especially MonoMod.RuntimeDetour. Those let foreign code redirect your methods while the game is running.&lt;/p&gt;

&lt;p&gt;A useful way to place it in the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BepInEx or MelonLoader get into the process and load mods.&lt;/li&gt;
&lt;li&gt;The mod or plugin is the actual cheat or feature code.&lt;/li&gt;
&lt;li&gt;HarmonyX is often the friendly patch API the mod calls.&lt;/li&gt;
&lt;li&gt;MonoMod is one of the deeper engines that carries out detours and IL work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Players rarely install "MonoMod" as the main product. They install a loader, and MonoMod arrives with that toolchain.&lt;/p&gt;

&lt;h2&gt;
  
  
  How mod loaders and frameworks use MonoMod
&lt;/h2&gt;

&lt;p&gt;Mod frameworks need a way to change compiled methods without shipping a cracked game build. MonoMod helps with that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.guardingpearsoftware.com/blog/what-harmonyx-is-and-how-unity-developers-can-detect-it-79053" rel="noopener noreferrer"&gt;HarmonyX&lt;/a&gt; is the API many plugin authors write against. Underneath, HarmonyX is built on MonoMod.RuntimeDetour. BepInEx docs list both as runtime patching options, and patches from both can coexist.&lt;/p&gt;

&lt;p&gt;Some ecosystems also use MonoMod directly. RuntimeDetour attaches hooks and builds detour chains. HookGen can generate helper assemblies so hooks feel like C# events, for example &lt;code&gt;On.SomeType.SomeMethod += MyHook;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When a Unity PC game runs with BepInEx or MelonLoader, you will often find MonoMod assemblies loaded with the loader core. The usual flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The loader boots into the Unity process.&lt;/li&gt;
&lt;li&gt;It loads plugin DLLs plus support libraries such as MonoMod.RuntimeDetour.&lt;/li&gt;
&lt;li&gt;A plugin creates a &lt;code&gt;Hook&lt;/code&gt;, an &lt;code&gt;ILHook&lt;/code&gt;, or goes through HarmonyX.&lt;/li&gt;
&lt;li&gt;The hook redirects the target method into a detour chain.&lt;/li&gt;
&lt;li&gt;From that moment, selected game methods run through the hooked path.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For legitimate mods, that might mean better UI or content hooks. For cheats, that might mean free purchases, skipped cooldowns, or rewritten damage and inventory logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How MonoMod works technically
&lt;/h2&gt;

&lt;p&gt;MonoMod's runtime model is easiest to understand as layered detours.&lt;/p&gt;

&lt;p&gt;At the bottom, a detour redirects execution from one method entry point to another. Higher level hooks accept delegates and pass a trampoline so your code can call the next handler or the original method. That detour can change arguments, skip the original behavior, call through, or change the return value.&lt;/p&gt;

&lt;p&gt;MonoMod can also work at the IL level through &lt;code&gt;ILHook&lt;/code&gt;. An IL hook receives the method body as instructions and rewrites them. This is similar in spirit to a Harmony transpiler.&lt;/p&gt;

&lt;p&gt;HookGen does not turn your game assembly into a cracked copy for distribution. It generates a helper DLL, often named like &lt;code&gt;MMHOOK_Assembly-CSharp.dll&lt;/code&gt;, with events that use RuntimeDetour behind the scenes. The game EXE may still match Steam. The change happens live in memory.&lt;/p&gt;

&lt;p&gt;Unity gameplay code is full of normal methods: take damage, spend currency, unlock item, check entitlement, start cooldown. If those methods exist on the client and the client decides the result, MonoMod gives a mod a clean way to intercept them. On Mono games this is especially direct. On IL2CPP games, loaders add interop so many mods can still reach equivalent targets.&lt;/p&gt;

&lt;p&gt;A cheat does not need MonoMod's full toolkit. It only needs one reliable hook on a valuable method.&lt;/p&gt;

&lt;h2&gt;
  
  
  MonoMod vs HarmonyX
&lt;/h2&gt;

&lt;p&gt;These two are related, but they are different tools.&lt;/p&gt;

&lt;p&gt;HarmonyX is the higher level patch API. Authors write prefixes, postfixes, and transpilers. MonoMod is the lower level detour and IL toolkit. It can be used directly, and HarmonyX can use it underneath. BepInEx and MelonLoader often ship both.&lt;/p&gt;

&lt;p&gt;Think of it this way: the loader is the workshop, the mod is the worker, HarmonyX is the standard wrench, and MonoMod is part of the machine shop that makes those wrenches work.&lt;/p&gt;

&lt;p&gt;Many Unity cheat plugins stay on Harmony attributes and never mention MonoMod by name, even when MonoMod assemblies are present.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MonoMod.RuntimeDetour&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Reflection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Skip SpendCoins completely&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;spendCoins&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spendCoins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PlayerWallet&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do not call orig. The wallet never spends.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a real cheat, that kind of hook can stop coin spending or force free unlocks. Many cheats never write this MonoMod code by hand. They write a HarmonyX prefix instead, and MonoMod still ends up in the process underneath.&lt;/p&gt;

&lt;p&gt;The important part for developers is the model: once MonoMod style hooking is active, your methods are no longer guaranteed to run as compiled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unity developers should care
&lt;/h2&gt;

&lt;p&gt;If you develop a single player game, you will mostly not care about mods or cheats. Maybe you even appreciate the extra content. A user bought the game and can modify it. No one gets hurt.&lt;/p&gt;

&lt;p&gt;But what if someone does get hurt? That usually means financial loss for you, or a broken experience for other players. No one wants a wallhacking opponent in multiplayer. And no one wants a player on top of a competitive leaderboard without earning it.&lt;/p&gt;

&lt;p&gt;Financially, that can mean skipping licence checks, skipping ads, or unlocking items they should not have. The attacker only needs the right method name and a host that can apply the hook.&lt;/p&gt;

&lt;p&gt;So how can you protect your game? Let's look at the clues MonoMod leaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traces MonoMod leaves
&lt;/h2&gt;

&lt;p&gt;MonoMod is quieter than a full mod loader tree. Its fingerprints are the toolkit itself. Useful MonoMod specific clues include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assemblies such as &lt;code&gt;MonoMod.RuntimeDetour&lt;/code&gt;, &lt;code&gt;MonoMod.Utils&lt;/code&gt;, and often &lt;code&gt;MonoMod.Core&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;HookGen helpers named &lt;code&gt;MMHOOK_...&lt;/code&gt;, commonly &lt;code&gt;MMHOOK_Assembly-CSharp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;RuntimeDetour types such as &lt;code&gt;Hook&lt;/code&gt;, &lt;code&gt;ILHook&lt;/code&gt;, and &lt;code&gt;DetourConfig&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;HookGen namespaces such as &lt;code&gt;On.&lt;/code&gt; and &lt;code&gt;IL.&lt;/code&gt; generated against your game types&lt;/li&gt;
&lt;li&gt;MonoMod or &lt;code&gt;MMHOOK_*.dll&lt;/code&gt; files on disk that are not part of your shipped build&lt;/li&gt;
&lt;li&gt;Method entry points rewritten by RuntimeDetour after JIT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those signals point at MonoMod style hooking even when the cheat author only writes Harmony attributes on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting MonoMod traces
&lt;/h2&gt;

&lt;p&gt;You can check for these signals in your game and then warn, restrict online features, or block startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  MonoMod assemblies loaded into the process
&lt;/h3&gt;

&lt;p&gt;A normal Unity player does not ship MonoMod. When RuntimeDetour is active, you usually see several MonoMod assemblies in the current AppDomain. Newer stacks often include &lt;code&gt;MonoMod.Core&lt;/code&gt; under RuntimeDetour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;monoModLoaded&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAssemblies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"MonoMod.RuntimeDetour"&lt;/span&gt;
                &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"MonoMod.Utils"&lt;/span&gt;
                &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"MonoMod.Core"&lt;/span&gt;
                &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"MonoMod.RuntimeDetour.HookGen"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monoModLoaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MonoMod assembly detected. Blocking game from starting."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  HookGen helpers and RuntimeDetour types
&lt;/h3&gt;

&lt;p&gt;HookGen generates a helper DLL whose name starts with &lt;code&gt;MMHOOK_&lt;/code&gt;. That helper does not contain your original game code. It exposes event style hooks under namespaces like &lt;code&gt;On.YourNamespace&lt;/code&gt; and &lt;code&gt;IL.YourNamespace&lt;/code&gt;. An &lt;code&gt;MMHOOK_&lt;/code&gt; assembly in your process is a strong MonoMod signal.&lt;/p&gt;

&lt;p&gt;Inside &lt;code&gt;MonoMod.RuntimeDetour&lt;/code&gt;, mods construct &lt;code&gt;Hook&lt;/code&gt; for delegate based detours and &lt;code&gt;ILHook&lt;/code&gt; for IL rewrites. Finding those types means the MonoMod hooking API is available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;assemblies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAssemblies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;mmhookLoaded&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assemblies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MMHOOK_"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;markers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.RuntimeDetour.Hook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.RuntimeDetour.ILHook"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.RuntimeDetour.DetourConfig"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;typeNames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assemblies&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmptyTypes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;runtimeDetourApi&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;marker&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;typeNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mmhookLoaded&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;runtimeDetourApi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MonoMod HookGen or RuntimeDetour API detected."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MonoMod files on disk
&lt;/h3&gt;

&lt;p&gt;MonoMod often leaves files under the install tree. Typical names include &lt;code&gt;MonoMod.RuntimeDetour.dll&lt;/code&gt;, &lt;code&gt;MonoMod.Utils.dll&lt;/code&gt;, &lt;code&gt;MonoMod.Core.dll&lt;/code&gt;, and &lt;code&gt;MMHOOK_*.dll&lt;/code&gt; helpers. Scan next to your executable for those names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;monoModFiles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.RuntimeDetour.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.Utils.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MonoMod.Core.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"MMHOOK_Assembly-CSharp.dll"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnumerateFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*.dll"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SearchOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllDirectories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetFileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;monoModFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MMHOOK_"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MonoMod files found on disk."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Method entry points rewritten by RuntimeDetour
&lt;/h3&gt;

&lt;p&gt;MonoMod does not need to permanently rewrite your shipped DLLs on disk. A file hash can still match. What RuntimeDetour changes is the compiled method itself. After Unity has JIT compiled a method, MonoMod's native detour layer can overwrite the entry point so every call jumps into the detour chain.&lt;/p&gt;

&lt;p&gt;A simple approach is to force a method to compile, read the first bytes of its entry point, and keep that as a baseline early at startup. Later, read those bytes again. If they changed, a detour library rewrote the method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Runtime.CompilerServices&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;MethodInfo&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;RuntimeHelpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PrepareMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodHandle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// force JIT compile&lt;/span&gt;
    &lt;span class="n"&gt;IntPtr&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodHandle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFunctionPointer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Read the first bytes at 'entry' and compare them&lt;/span&gt;
    &lt;span class="c1"&gt;// with a clean baseline taken at startup.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works well on Mono desktop builds. A changed entry point proves a detour, not the name "MonoMod" by itself. Pair it with the assembly and type checks above when you want the signal to stay MonoMod specific.&lt;/p&gt;

&lt;p&gt;You do not want to create all those checks by yourself? There are tools that can help you. Check out my &lt;a href="https://www.guardingpearsoftware.com/product/anticheat" rel="noopener noreferrer"&gt;Anti-Cheat&lt;/a&gt; solution that can help you detect MonoMod based hooking stacks and other cheating or modding tools. Plus a tone of more features to help you with your anti-cheat needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  There is still one problem
&lt;/h2&gt;

&lt;p&gt;Do you remember the example from earlier?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;spendCoins&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spendCoins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PlayerWallet&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do not call orig. The wallet never spends.&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Especially the &lt;code&gt;nameof(PlayerWallet.SpendCoins)&lt;/code&gt; part?&lt;/p&gt;

&lt;p&gt;All those checks you implemented to detect MonoMod are useless if an attacker can bypass them. An attacker could look for something like &lt;code&gt;My.Amazing.MonoMod.Detector.Detect&lt;/code&gt; and hook the body of the &lt;code&gt;Detect&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;There are two main ways to address this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outsource critical code to an external source&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can move part of your important code to an external source, such as your server, and load it at runtime. This makes it much harder for attackers to analyze your code in advance. Your detection logic can live in this external code and run before attackers have a chance to patch it.&lt;/p&gt;

&lt;p&gt;However, this approach can be quite complicated to implement and maintain.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use an obfuscation solution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obfuscation can make your source code much harder to understand. That makes it harder for attackers to find and patch your detection logic. For example, a name like &lt;code&gt;My.Amazing.MonoMod.Detector.Detect&lt;/code&gt; would become something like &lt;code&gt;IUQWEWQ.XACBSCA&lt;/code&gt;. That is still possible to reverse, but it takes more effort.&lt;/p&gt;

&lt;p&gt;You might consider using my &lt;a href="https://www.guardingpearsoftware.com/product/obfuscator" rel="noopener noreferrer"&gt;Obfuscator&lt;/a&gt; to obfuscate your source code. It is a powerful build-time tool that can make your code much harder to understand and analyze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your takeaway
&lt;/h2&gt;

&lt;p&gt;MonoMod is a low level .NET modding toolkit, not a loader. BepInEx and MelonLoader bring it in so mods can detour methods and rewrite IL at runtime. HarmonyX is often the friendlier API above it. Once a hook is applied, your method no longer runs as compiled. That is fine in many single player games, but it becomes a real problem when cheats hurt your revenue or other players.&lt;/p&gt;

&lt;p&gt;The good news is that MonoMod leaves its own traces: RuntimeDetour and Core assemblies, HookGen &lt;code&gt;MMHOOK_&lt;/code&gt; helpers, known &lt;code&gt;Hook&lt;/code&gt; / &lt;code&gt;ILHook&lt;/code&gt; types, toolkit DLLs on disk, and method entry points that suddenly jump into a detour chain. You can check for those signals yourself, or use existing tools to help you.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Replacing a Live MMORPG Client Without Replacing the World</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Mon, 10 Aug 2026 12:00:26 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/replacing-a-live-mmorpg-client-without-replacing-the-world-12ng</link>
      <guid>https://dev.to/guardingpearsoftware/replacing-a-live-mmorpg-client-without-replacing-the-world-12ng</guid>
      <description>&lt;p&gt;Fantasy Online 2 is a massively multiplayer online role-playing game you can play in a web browser or on Windows through Steam. It is a huge little pixel-art world of quests, crafting, rare loot, character builds, and adventures with other players Built around social progression and discovery. Players invest in one character across equipment, skills, factions, achievements, and cosmetics, then carry that adventure between supported platforms.&lt;/p&gt;

&lt;p&gt;That persistent world is also what made replacing the client hard.&lt;/p&gt;

&lt;p&gt;Replacing a game client sounds straightforward when the game is still a prototype. You can change the renderer, rebuild the interface, rewrite the input layer, and reset whatever data no longer fits. Fantasy Online 2 was already live when I began. Players had accounts, characters, inventories, quests, skills, guilds, market listings, achievements, and years of expectations about how the game behaved. The server and database had to stay online. The world could not be reset just because I wanted a better foundation for the client.&lt;/p&gt;

&lt;p&gt;That changed the job from an engine rewrite into a live-system migration.&lt;/p&gt;

&lt;p&gt;The first important decision was defining what would not change. The server remained authoritative. Existing accounts, character data, game content, and network messages were treated as contracts. PxEngine, the new TypeScript and WebGL2 client, had to understand the same world rather than invent a replacement for it.&lt;/p&gt;

&lt;p&gt;That boundary reduced the risk considerably. I was not rewriting the game server, moving the database, and replacing the client at the same time. I was rebuilding the presentation, input, rendering, audio, and interface layers around a backend that players already depended on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parity came before improvement
&lt;/h2&gt;

&lt;p&gt;The most tempting mistake during a migration is redesigning every system while porting it. A new interface makes old choices look dated, and a new renderer makes it easy to imagine larger structural changes. Doing both at once makes failures much harder to diagnose.&lt;/p&gt;

&lt;p&gt;I made feature parity the first target. Login, character selection, zone loading, movement, combat, inventory, equipment, skills, quests, dialogue, shops, crafting, parties, guilds, banking, trading, settings, reconnect behavior, and error states all needed to survive the move.&lt;/p&gt;

&lt;p&gt;A system was not complete just because its main screen rendered. Inventory also had to handle pending operations, full bags, drag cancellation, server rejection, and updates arriving while another window was open. Skills had to cover casting from the book, hotbar assignment, cooldowns, targeting, and failure conditions. Mobile input had to block touches where desktop mouse input was already blocked. Those edge cases are where a port that looks finished begins to feel unreliable.&lt;/p&gt;

&lt;p&gt;The production game became the specification. Old behavior, server responses, player reports, and real content were more useful than a clean theoretical design document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building for the actual workload
&lt;/h2&gt;

&lt;p&gt;PxEngine is a custom TypeScript and WebGL2 client built around Fantasy Online 2's real requirements. It renders tile maps, animated sprites, effects, particles, interface windows, and GPU text while handling mouse, keyboard, controller, and touch input.&lt;/p&gt;

&lt;p&gt;The engine uses retained buffers, pooling, and preallocated working storage wherever the game would otherwise create garbage every frame. Browser garbage collection is not automatically a problem, but repeated per-frame allocation can turn into visible pauses during movement or combat. Avoiding those allocations also makes performance more predictable across a wide range of devices.&lt;/p&gt;

&lt;p&gt;That does not mean every subsystem was generalized into a giant reusable framework. The useful approach was to build the smallest solid primitive that solved a production need, then expand it when another real feature required more. The tile renderer, sprite batching, text system, GUI batching, pathfinding, particles, and input stack all grew from scenes the game actually had to run.&lt;/p&gt;

&lt;p&gt;Keeping the server authoritative helped here too. The client could focus on responsive presentation and clear feedback while the server remained the source of truth for movement, combat, inventory, quests, and progression. That gave the migration a stable center even while the visual and interaction layers were changing quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ship the migration in slices
&lt;/h2&gt;

&lt;p&gt;A live migration needs checkpoints that players can actually exercise. Waiting until every old feature has been recreated produces one enormous, difficult-to-debug launch.&lt;/p&gt;

&lt;p&gt;I brought the new client to the official website and CrazyGames first. That exposed the browser build to real accounts, real network conditions, and the full production data set. Android followed after the touch controls, storage behavior, layout constraints, and platform wrapper were ready for broader use. Steam has its own migration and testing path; it is not treated as a simple copy of the browser release.&lt;/p&gt;

&lt;p&gt;The core client stays shared, while platform-specific code remains around the edges. Authentication, local storage, storefront behavior, and wrappers differ, but movement, rendering, combat, interface systems, and game content do not need separate implementations for every platform.&lt;/p&gt;

&lt;p&gt;This staged rollout also made bug reports more useful. A setting that appeared correct in the browser could still fail when a platform supplied a different storage service. A window that blocked mouse input could still allow a mobile touch to pass through. A reconnect path could work during local testing and fail after a real network interruption. Shipping smaller slices made those boundaries visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mistakes were usually at the seams
&lt;/h2&gt;

&lt;p&gt;The hardest bugs were rarely in a single isolated renderer function. They appeared where systems met.&lt;/p&gt;

&lt;p&gt;A feature might display correctly but lose its state after a new session. A touch event might reach the world through an open interface window. A remote actor could receive the right server update while showing the wrong transient effect. A UI port finished too quickly could preserve the happy path but miss drag cancellation, selection state, or server rejection.&lt;/p&gt;

&lt;p&gt;The lesson was to test each feature as a state machine rather than as a screenshot. What happens before the action, while it is pending, after success, after rejection, after reconnecting, and after changing platforms? That checklist catches far more than asking whether a button works.&lt;/p&gt;

&lt;p&gt;It also helped to keep the distribution wrappers thin. The more game logic that moves into platform-specific code, the harder it becomes to know whether a bug belongs to the game, the engine, the wrapper, authentication, or storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What made the migration possible
&lt;/h2&gt;

&lt;p&gt;The migration worked because it had a stable boundary. The server protocol, persistent data, and game rules remained the center of the system. PxEngine could replace the client one subsystem at a time without asking players to abandon their characters or asking the backend to become a different game simultaneously.&lt;/p&gt;

&lt;p&gt;For another small team considering the same kind of move, my main recommendations are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Decide which contracts must remain stable before writing the replacement.&lt;/li&gt;
&lt;li&gt;Build a complete parity checklist that includes failure and persistence states.&lt;/li&gt;
&lt;li&gt;Separate platform wrappers from shared game logic.&lt;/li&gt;
&lt;li&gt;Test against real production content as early as possible.&lt;/li&gt;
&lt;li&gt;Ship in controlled slices with a rollback path.&lt;/li&gt;
&lt;li&gt;Treat player reports as evidence about system boundaries, not just isolated bugs.&lt;/li&gt;
&lt;li&gt;Delay unrelated redesigns until the replacement is trustworthy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The successful moment is not when the new renderer draws its first map. It is when a returning player logs in, sees the same character and world, and continues playing without needing to understand how much changed underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Play Fantasy Online 2
&lt;/h2&gt;

&lt;p&gt;Fantasy Online 2 can be played here: &lt;a href="https://fantasyonline2.com/" rel="noopener noreferrer"&gt;fantasyonline2.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;Jeromy Stroh is the solo developer of Fantasy Online 2 and the founder of Pixel Games LLC. He works primarily in TypeScript, WebGL2, Java, and MySQL while building and operating the game's custom client, persistent world, server, and player tools.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What HarmonyX is and how Unity developers can detect it</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Sun, 09 Aug 2026 17:46:31 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/what-harmonyx-is-and-how-unity-developers-can-detect-it-290e</link>
      <guid>https://dev.to/guardingpearsoftware/what-harmonyx-is-and-how-unity-developers-can-detect-it-290e</guid>
      <description>&lt;p&gt;If you have read about BepInEx or MelonLoader, you have probably also seen HarmonyX mentioned right next to them. HarmonyX is not another mod loader. It is the patching library that many mods use &lt;em&gt;after&lt;/em&gt; a loader has already put their code into your game.&lt;/p&gt;

&lt;p&gt;You will learn what HarmonyX is, how mod loaders and frameworks use it, and what it technically does inside a Unity process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What HarmonyX is
&lt;/h2&gt;

&lt;p&gt;HarmonyX is a runtime method patching library for .NET code. In the Unity world, that usually means it can change how your C# methods behave while the game is already running.&lt;/p&gt;

&lt;p&gt;It is a BepInEx maintained fork of the original Harmony project (often called Lib.Harmony). Most Unity modding docs simply say "Harmony," but BepInEx and MelonLoader commonly ship HarmonyX specifically.&lt;/p&gt;

&lt;p&gt;A useful way to place it in the stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BepInEx or MelonLoader are the frameworks and loaders. They get into the process and load mods.&lt;/li&gt;
&lt;li&gt;The mod or plugin is the actual cheat or feature code.&lt;/li&gt;
&lt;li&gt;HarmonyX is the library that mod uses to rewrite game methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So HarmonyX is a tool used by frameworks and by the mods those frameworks load. It is not the &lt;em&gt;host&lt;/em&gt; that starts the modding session.&lt;/p&gt;

&lt;h2&gt;
  
  
  How mod loaders and frameworks use HarmonyX
&lt;/h2&gt;

&lt;p&gt;Tools like BepInEx and MelonLoader include HarmonyX, so plugin authors do not have to ship their own patcher. &lt;/p&gt;

&lt;p&gt;The usual flow for a mod using HarmonyX looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The loader boots into the Unity process.&lt;/li&gt;
&lt;li&gt;The loader finds and loads plugin or mod DLLs.&lt;/li&gt;
&lt;li&gt;A plugin creates a &lt;code&gt;Harmony&lt;/code&gt; instance, often with a unique ID.&lt;/li&gt;
&lt;li&gt;The plugin calls something like &lt;code&gt;PatchAll()&lt;/code&gt; to apply its patch classes.&lt;/li&gt;
&lt;li&gt;From that moment, selected game methods run through the patched path.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is why people sometimes think HarmonyX "is BepInEx." BepInEx makes HarmonyX easy to use, but HarmonyX can also work outside BepInEx if some other host loads the assembly first.&lt;/p&gt;

&lt;p&gt;In practice, a mod uses HarmonyX when it wants to do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run code before a method starts&lt;/li&gt;
&lt;li&gt;Run code after a method finishes&lt;/li&gt;
&lt;li&gt;Change parameters or return values&lt;/li&gt;
&lt;li&gt;Skip the original method completely&lt;/li&gt;
&lt;li&gt;Rewrite parts of the method's IL for more advanced changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For legitimate mods, that might mean better UI, accessibility options, or content hooks. For cheats, that might mean forcing &lt;code&gt;return true&lt;/code&gt; on a purchase check, skipping cooldowns, or rewriting damage and inventory logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  How HarmonyX works technically
&lt;/h2&gt;

&lt;p&gt;HarmonyX does not edit your source code and it does not need to permanently rewrite your shipped DLLs on disk. It patches methods at runtime.&lt;/p&gt;

&lt;p&gt;At a high level, HarmonyX:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finds the target method through reflection.&lt;/li&gt;
&lt;li&gt;Collects your prefix, postfix, transpiler, or finalizer patches.&lt;/li&gt;
&lt;li&gt;Builds a new combined method that includes those patches.&lt;/li&gt;
&lt;li&gt;Redirects the original method to that new implementation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After that redirect, every call to the original method goes through the patched version instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prefixes
&lt;/h3&gt;

&lt;p&gt;A prefix runs before the original method. It can inspect or change inputs. It can also return &lt;code&gt;false&lt;/code&gt; to skip the original method body. That is one of the simplest cheat patterns: patch a validation method with a prefix that returns early and pretends everything is valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Postfixes
&lt;/h3&gt;

&lt;p&gt;A postfix runs after the original method. It can read or replace the result. A common pattern is "let the game calculate the value, then overwrite the return with something better for the cheater."&lt;/p&gt;

&lt;h3&gt;
  
  
  Transpilers
&lt;/h3&gt;

&lt;p&gt;A transpiler edits the Intermediate Language (IL) of the method before the patched version is created. This is more advanced. Instead of only wrapping the method, the mod can change individual instructions inside it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this is powerful in Unity
&lt;/h3&gt;

&lt;p&gt;Unity gameplay code is full of normal methods: take damage, spend currency, unlock item, check entitlement, start cooldown, submit score. If those methods exist on the client and the client is allowed to decide the result, HarmonyX gives a mod a clean way to intercept them.&lt;/p&gt;

&lt;p&gt;On Mono games, this is especially direct because the managed methods are easier to target. On IL2CPP games, the loader and interop layer still let many mods reach equivalent method targets, so HarmonyX style patching remains relevant there too.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HarmonyPatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpendCoinsPatch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Runs before SpendCoins&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Skip the original method completely&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a real cheat, that kind of patch can stop coin spending, force free unlocks, or combine with a postfix that changes balances. The important part for developers is not this exact sample. The important part is the model: once HarmonyX is active, your methods are no longer guaranteed to run as compiled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unity developers should care
&lt;/h2&gt;

&lt;p&gt;If you develop a single player game, you will mostly not care about mods or cheats. Maybe you even appreciate the extra content and longer lifecycle other players create. A user bought the game or app and can modify it to their advantage. No one gets hurt.&lt;/p&gt;

&lt;p&gt;But what if someone does get hurt? That usually means financial loss for you as the developer, or a broken experience for your players. No one wants a speeding or wallhacking opponent in a multiplayer game. And no one wants a player sitting on top of a competitive leaderboard without actually being the best.&lt;/p&gt;

&lt;p&gt;Financially, that can mean skipping licence checks, skipping ads, or unlocking items and features they should not have.&lt;/p&gt;

&lt;p&gt;The attacker does not need to reverse every system. They only need the right method name and a loader that can host the patch.&lt;/p&gt;

&lt;p&gt;So how can you protect your game? Let's start by looking at the clues HarmonyX leaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traces HarmonyX leaves
&lt;/h2&gt;

&lt;p&gt;HarmonyX is quieter than a full mod loader tree, but it still leaves clues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managed assemblies such as &lt;code&gt;HarmonyX&lt;/code&gt; or &lt;code&gt;0Harmony&lt;/code&gt; loaded into the process&lt;/li&gt;
&lt;li&gt;Known Harmony types and patch registries present at runtime&lt;/li&gt;
&lt;li&gt;Methods that suddenly have detours or wrappers they did not have at build time&lt;/li&gt;
&lt;li&gt;Loader folders nearby, because HarmonyX patches usually arrive through BepInEx or MelonLoader&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Unity games, HarmonyX plus an unofficial loader is a very common modding and cheating pattern. It is a pattern that can be detected and blocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting HarmonyX traces
&lt;/h2&gt;

&lt;p&gt;The traces from the prior chapter are a good starting point. You can check for them in your game and decide what to do next: warn, restrict online features, or block startup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loader folders nearby, because HarmonyX patches usually arrive through BepInEx or MelonLoader.
&lt;/h3&gt;

&lt;p&gt;HarmonyX rarely shows up alone. It usually arrives with a loader, and that loader leaves folders and files next to your game install.&lt;/p&gt;

&lt;p&gt;BepInEx often looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BepInEx/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BepInEx/core/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BepInEx/plugins/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BepInEx/config/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BepInEx/patchers/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;doorstop_config.ini&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MelonLoader is a bit more mixed, and can include things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MelonLoader/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mods/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Plugins/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserData/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserLibs/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;version.dll&lt;/code&gt;, &lt;code&gt;winhttp.dll&lt;/code&gt;, or &lt;code&gt;dobby.dll&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple first check is to look for those loader folders when your game starts. If they are present, you can treat that as a strong signal and block the session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"BepInEx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MelonLoader"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mod loader detected. Blocking game from starting."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managed assemblies such as &lt;code&gt;HarmonyX&lt;/code&gt; or &lt;code&gt;0Harmony&lt;/code&gt; loaded into the process
&lt;/h3&gt;

&lt;p&gt;HarmonyX is loaded into the process as a managed assembly. The common assembly names are &lt;code&gt;0Harmony&lt;/code&gt; and sometimes &lt;code&gt;HarmonyX&lt;/code&gt;. That is the DLL name, not a C# type name. You can detect it by scanning the assemblies already loaded into the current AppDomain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;harmonyLoaded&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAssemblies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetName&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"0Harmony"&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"HarmonyX"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;harmonyLoaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HarmonyX detected. Blocking game from starting."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Known Harmony types and patch registries present at runtime
&lt;/h3&gt;

&lt;p&gt;Inside that assembly, Harmony exposes types in the &lt;code&gt;HarmonyLib&lt;/code&gt; namespace. Useful signals include &lt;code&gt;HarmonyLib.Harmony&lt;/code&gt;, &lt;code&gt;HarmonyLib.PatchProcessor&lt;/code&gt;, and related patch metadata types. Once patches are applied, Harmony also keeps a runtime registry of patched methods. You can look for the known types first, then ask that registry if anything was patched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;harmonyType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAssemblies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmptyTypes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"HarmonyLib.Harmony"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;harmonyType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Harmony type detected."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;MethodInfo&lt;/span&gt; &lt;span class="n"&gt;getAllPatchedMethods&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;harmonyType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"GetAllPatchedMethods"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Public&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;BindingFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Static&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getAllPatchedMethods&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;patchedMethods&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getAllPatchedMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patchedMethods&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;patchedMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cast&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Harmony patch registry has active patches."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Methods that suddenly have detours or wrappers they did not have at build time
&lt;/h3&gt;

&lt;p&gt;This topic is a bit more complex, and detection is not as simple as with the other traces. HarmonyX does not change your DLL on disk, nor does it rewrite the managed IL sitting in memory. If you hash the loaded assembly and compare it with the file next to your game, both will look the same.&lt;/p&gt;

&lt;p&gt;What does change is the compiled method itself. After Unity has JIT compiled a method, Harmony can overwrite the entry point so every call jumps into a patched version. That jump is the signal you can check for.&lt;/p&gt;

&lt;p&gt;A simple approach is to force a method to compile, read the first bytes of its entry point, and keep that as a baseline early at startup. Later, read those bytes again. If they changed, something hooked the method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Runtime.CompilerServices&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;MethodInfo&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GetMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;RuntimeHelpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PrepareMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodHandle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// force JIT compile&lt;/span&gt;
    &lt;span class="n"&gt;IntPtr&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodHandle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFunctionPointer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Read the first bytes at 'entry' and compare them&lt;/span&gt;
    &lt;span class="c1"&gt;// with a clean baseline taken at startup.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to keep in mind: this works well on Mono desktop builds, and a changed entry point proves a hook, not HarmonyX by name. For cheat detection that is usually fine, because any detour library that rewrites your methods leaves the same kind of fingerprint.&lt;/p&gt;

&lt;p&gt;You do not want to create all those checks by yourself? There are tools that can help you. Check out my &lt;a href="https://www.guardingpearsoftware.com/product/anticheat" rel="noopener noreferrer"&gt;Anti-Cheat&lt;/a&gt; solution that can help you detect HarmonyX and other cheating or modding tools. Plus a tone of more features to help you with your anti-cheat needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  There is still one problem
&lt;/h2&gt;

&lt;p&gt;Do you remember the example from the beginning of this article?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HarmonyPatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlayerWallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpendCoins&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpendCoinsPatch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Runs before SpendCoins&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Skip the original method completely&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Especially the &lt;code&gt;nameof(PlayerWallet.SpendCoins)&lt;/code&gt; part?&lt;/p&gt;

&lt;p&gt;All those fancy checks you implemented to detect HarmonyX are useless if an attacker can simply bypass them. An attacker could look for something like &lt;code&gt;My.Amazing.HarmonyX.Detector.Detect&lt;/code&gt; and patch the body of the &lt;code&gt;Detect&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;There are two main ways to address this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Outsource critical code to an external source&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can move part of your important code to an external source, such as your server, and load it at runtime. This makes it much harder for attackers to analyze your code in advance. Your detection logic can reside in this external code and execute before attackers have a chance to patch it. As a result, they won't see exactly what happens or know what to patch.&lt;/p&gt;

&lt;p&gt;However, this approach can be quite complicated to implement and maintain.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use an obfuscation solution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obfuscation can make your source code very difficult to understand and analyze. This makes it much harder for attackers to find and patch your detection logic. For example, a name like &lt;code&gt;My.Amazing.HarmonyX.Detector.Detect&lt;/code&gt; would become something like &lt;code&gt;IUQWEWQ.XACBSCA&lt;/code&gt;, making it significantly more difficult to locate and modify. While not impossible, it greatly increases the level of effort required.&lt;/p&gt;

&lt;p&gt;You might consider using my &lt;a href="https://www.guardingpearsoftware.com/product/obfuscator" rel="noopener noreferrer"&gt;Obfuscator&lt;/a&gt; to obfuscate your source code. It is a powerful build-time tool that can make your code much harder to understand and analyze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your takeaway
&lt;/h2&gt;

&lt;p&gt;HarmonyX is a runtime patching library, not a loader. BepInEx and MelonLoader bring it in so mods can rewrite Unity methods. Once a patch is applied, your method no longer runs as compiled. That is fine in many single player games, but it becomes a real problem when cheats or hacks hurt your revenue or other players.&lt;/p&gt;

&lt;p&gt;The good news is that HarmonyX leaves traces: loader folders, assemblies, known types and method entry points that suddenly jump somewhere else. You can check for those signals yourself, or use existing tools to help you.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Snake: Gridbreaker - What changed when player occupied twenty cells!</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Sat, 08 Aug 2026 18:21:13 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/snake-gridbreaker-what-changed-when-player-occupied-twenty-cells-17h0</link>
      <guid>https://dev.to/guardingpearsoftware/snake-gridbreaker-what-changed-when-player-occupied-twenty-cells-17h0</guid>
      <description>&lt;p&gt;A position is one of the first concepts we learn when programming a game.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The player is at (10, 12).&lt;/li&gt;
&lt;li&gt;An enemy is at (4, 8).&lt;/li&gt;
&lt;li&gt;A portal moves the player from one position to another.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Classic Snake already breaks this simple model. The head has a position, but so does every segment behind it. Together, those positions form the player.&lt;/p&gt;

&lt;p&gt;I understood that before starting Snake: Gridbreaker. What I missed was how many systems would eventually depend on the exact meaning of the word “player.”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes the player meant the head. Collision checks often cared about the next head position.&lt;/li&gt;
&lt;li&gt;Sometimes it meant the complete body. Rendering, self-collision, area transitions and several build mechanics needed every segment.&lt;/li&gt;
&lt;li&gt;In a few cases, the player was closer to a process than to an object. The head started an action, while the tail completed it several movement ticks later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction became important after the prototype grew into an action roguelite with enemies, hazards, classes, shops, mutations, secret rooms and bosses.&lt;/p&gt;

&lt;p&gt;The initial version proved that the idea could work. The following 1,600 commits taught me what the original prototype had left unanswered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The array was fine at first
&lt;/h2&gt;

&lt;p&gt;My first representation of the snake body was an array ordered from head to tail.&lt;/p&gt;

&lt;p&gt;Movement looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;move_snake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;snake_body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;snake_body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is easy to read:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove the final element.&lt;/li&gt;
&lt;li&gt;Insert a new head at index zero.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a short prototype, I would probably make the same choice again.&lt;/p&gt;

&lt;p&gt;The problem appeared gradually. &lt;code&gt;insert(0, value)&lt;/code&gt; has to move the existing elements in the array. Other systems also used checks such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;snake_body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The cell is occupied.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those operations became part of normal movement. They also became more common as the body gained more responsibilities.&lt;/p&gt;

&lt;p&gt;The snake was no longer only a visual trail. Its length affected builds. Hazards could interact with specific segments. Systems asked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether a position belonged to the body&lt;/li&gt;
&lt;li&gt;where the tail was&lt;/li&gt;
&lt;li&gt;how the body should be restored after loading&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I eventually replaced the direct array with circular deque storage.&lt;/p&gt;

&lt;p&gt;The current structure keeps a backing array, an index pointing to the head and the current length:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_snake_segments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_snake_head_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_snake_length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_snake_occupancy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normal movement step changes the head index instead of shifting the whole body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;move_snake_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;old_tail&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_tail_position&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;_decrement_snake_occupancy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_tail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_snake_length&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;_ensure_snake_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_snake_length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_snake_head_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_wrap_snake_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_snake_head_index&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_snake_segments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_snake_head_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;
    &lt;span class="n"&gt;_snake_length&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;_increment_snake_occupancy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_mark_snake_body_snapshot_dirty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The occupancy dictionary answers membership questions without scanning the body.&lt;/p&gt;

&lt;p&gt;I still needed compatibility with systems that expected an ordered array. Rewriting all of them at once would have made the change much riskier, so &lt;code&gt;get_snake_body()&lt;/code&gt; creates an ordered snapshot only when something requests it after the body has changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;get_snake_body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_snake_body_snapshot_dirty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_snake_body_snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_snake_length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_wrap_snake_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_snake_head_index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;_snake_body_snapshot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_snake_segments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="n"&gt;_snake_body_snapshot_dirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_snake_body_snapshot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gave the storage a faster movement path while preserving the old interface during migration.&lt;/p&gt;

&lt;p&gt;I would not start every Snake prototype with this structure.&lt;/p&gt;

&lt;p&gt;For a snake containing five segments and a game that is still proving its basic idea, the simple array is easier to inspect and modify. The deque became worthwhile after movement became frequent, the body grew longer and many systems depended on it.&lt;/p&gt;

&lt;p&gt;The useful question was not whether a circular buffer was theoretically better. I needed to know whether the current representation was creating work in the hottest part of the game.&lt;/p&gt;

&lt;p&gt;By then, it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering faster did not solve the first problem
&lt;/h2&gt;

&lt;p&gt;Performance problems appeared as the board gained more content.&lt;/p&gt;

&lt;p&gt;My first instinct was to improve the renderer. I looked at how cells and body lines were drawn, how many visual nodes existed and how often geometry was rebuilt.&lt;/p&gt;

&lt;p&gt;Some of those areas did need work. Per-cell nodes were later replaced with MultiMesh renderers, trails were pooled and several visual systems became incremental.&lt;/p&gt;

&lt;p&gt;The earlier mistake was broader.&lt;/p&gt;

&lt;p&gt;The game was asking the renderer to update objects that had not changed.&lt;/p&gt;

&lt;p&gt;The first architecture used one main notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;board_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After movement, the game emitted it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;move_snake_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;emit_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"board_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The view received a new board state and performed a broad synchronization.&lt;/p&gt;

&lt;p&gt;That is a sensible design for a prototype. One signal means fewer update paths and fewer chances for the visual state to fall behind the logical state.&lt;/p&gt;

&lt;p&gt;It becomes expensive when the most common event is a snake moving by one cell.&lt;/p&gt;

&lt;p&gt;During a clean movement step, the walls remain where they were. Food usually stays in place. Hazards, items and the exit do not need to be reconstructed. The body loses a tail cell and gains a head cell.&lt;/p&gt;

&lt;p&gt;I introduced a separate signal for that path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;board_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;signal&lt;/span&gt; &lt;span class="n"&gt;snake_changed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The movement code could then decide what had actually happened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;board_visual_changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;emit_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"board_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;snake_moved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;emit_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"snake_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_snake_body&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was the start rather than the final design. As the project continued, the broad notification split into more specific signals for terrain, pickups, hazards, enemies and interactions.&lt;/p&gt;

&lt;p&gt;I do not have a reliable before-and-after FPS chart for the original change.&lt;/p&gt;

&lt;p&gt;The game was evolving quickly, and several rendering changes happened around the same period. Presenting one clean percentage would imply a controlled benchmark that I did not perform.&lt;/p&gt;

&lt;p&gt;What I do have is a set of testable invariants:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clean movement should not emit &lt;code&gt;board_changed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It should emit &lt;code&gt;snake_changed&lt;/code&gt; once.&lt;/li&gt;
&lt;li&gt;A non-growing step should logically touch at most the old tail cell and the new head cell.&lt;/li&gt;
&lt;li&gt;A growing step only needs to add the new head.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those guarantees are less exciting than an impressive FPS number, but they protect the architecture from slowly returning to full-board work.&lt;/p&gt;

&lt;p&gt;Here is the order in which the optimization actually developed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Broad board refresh&lt;/li&gt;
&lt;li&gt;Separate clean snake movement&lt;/li&gt;
&lt;li&gt;Update individual board layers&lt;/li&gt;
&lt;li&gt;Replace expensive per-cell presentation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I originally started near the bottom of this sequence.&lt;/p&gt;

&lt;p&gt;Reducing the amount of work at the top produced a more useful change.&lt;/p&gt;

&lt;h2&gt;
  
  
  A portal became a multi-step operation
&lt;/h2&gt;

&lt;p&gt;Secret rooms introduced a problem that I had not encountered with normal player characters.&lt;/p&gt;

&lt;p&gt;Consider a snake moving into a breach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source board                 Destination board

[T][B][B][H] -&amp;gt; | BREACH |   [ entry cells ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;H is the head, B is a body segment and T is the tail.&lt;/p&gt;

&lt;p&gt;The head reaches the breach first. Several movement ticks may pass before the tail arrives.&lt;/p&gt;

&lt;p&gt;My first mental model was an ordinary teleport. Commit the destination board, place the player on it and hide the swap behind an animation.&lt;/p&gt;

&lt;p&gt;That model produced an obvious visual problem.&lt;/p&gt;

&lt;p&gt;The breach could close while most of the body was still meant to be passing through it.&lt;/p&gt;

&lt;p&gt;Moving the complete body instantly also looked wrong. The head had entered naturally, but the tail vanished from the previous board.&lt;/p&gt;

&lt;p&gt;The transition eventually became a release process.&lt;/p&gt;

&lt;p&gt;After the board handoff, only part of the snake was shown as fully emerged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source board                 Destination board

[T][B] -&amp;gt; | BREACH | -&amp;gt; [H][B]
           still open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each movement revealed another segment. The game tracked whether a portal release was active, how many solid segments had emerged and the emergence direction.&lt;/p&gt;

&lt;p&gt;A simplified version of the state looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="n"&gt;portal_release_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;portal_release_solid_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;portal_release_direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exit_direction&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then movement advances the release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;advance_portal_release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;portal_release_solid_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;portal_release_solid_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;get_snake_length&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;portal_release_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;
        &lt;span class="n"&gt;seal_breach_visual&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final state is ordinary gameplay again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source board                 Destination board

             | SEALED |      [H][B][B][T]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual implementation also had to survive saving, loading and transitions back to the main board. Collision state could be authoritative before the visual aperture closed, so logical safety and visual continuity were handled separately.&lt;/p&gt;

&lt;p&gt;The terminology helped here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Hide the board swap” described a presentation trick.&lt;/li&gt;
&lt;li&gt;“Portal handoff” described a state change.&lt;/li&gt;
&lt;li&gt;“Portal release” described the body emerging over time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once those operations had separate names, it became easier to decide which system owned each part.&lt;/p&gt;

&lt;p&gt;This design is still more complicated than an instant teleport. Instant teleportation would be a valid solution if I wanted a fast flash and were willing to accept the complete body moving at once.&lt;/p&gt;

&lt;p&gt;I kept the gradual emergence because preserving the physical continuity of the snake mattered to the feel of this particular transition.&lt;/p&gt;

&lt;p&gt;The state machine follows from that design decision. It is not a requirement for every segmented character.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four directions still needed an input resolver
&lt;/h2&gt;

&lt;p&gt;The first controller implementation checked movement actions one after another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_action_just_pressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"move_up"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;queue_direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_action_just_pressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"move_down"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;queue_direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_action_just_pressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"move_left"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;queue_direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LEFT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_action_just_pressed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"move_right"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;queue_direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RIGHT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked with a keyboard.&lt;/p&gt;

&lt;p&gt;It became less predictable when several controller sources were active. A player could hold Up on the D-pad and move the analog stick sideways. Diagonal stick input could also make more than one action cross its threshold.&lt;/p&gt;

&lt;p&gt;Sequential checks allowed several directions to compete during the same input update.&lt;/p&gt;

&lt;p&gt;Snake is unforgiving here. A direction selected for a fraction of a second may place the head into the body or into a wall.&lt;/p&gt;

&lt;p&gt;The input system now resolves all controller data into one vector before adding anything to the movement queue.&lt;/p&gt;

&lt;p&gt;The current implementation gives the D-pad priority while any D-pad button is held. Analog input uses different thresholds for activation and release:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;STICK_ACTIVATION_THRESHOLD&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.50&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;STICK_RELEASE_THRESHOLD&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.35&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;STICK_AXIS_DOMINANCE_RATIO&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.25&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;STICK_AXIS_NEAR_EQUAL_GAP&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The gap between 0.50 and 0.35 creates hysteresis.&lt;/p&gt;

&lt;p&gt;Hysteresis means that the boundaries for entering a state and leaving it are different.&lt;/p&gt;

&lt;p&gt;A stick must move far enough to select a direction. Once selected, a small drop in strength does not immediately release it. Without that gap, noisy input near one threshold can repeatedly switch between active and inactive.&lt;/p&gt;

&lt;p&gt;The resolver is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;resolve_direction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;any_dpad_button_is_held&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resolve_dpad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stick&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_stick_vector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stick_is_below_release_threshold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stick&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Vector2i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ZERO&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stick_is_near_diagonal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stick&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;previous_resolved_direction&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dominant_axis_direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact threshold values came from this game and its movement feel. They are not universal controller constants.&lt;/p&gt;

&lt;p&gt;The important change was resolving one intended direction before touching the queue.&lt;/p&gt;

&lt;p&gt;Input buffering solved another issue. At high speed, a player may press Up and then Left between two movement ticks. A short queue preserves both turns, while validation rejects reversals and duplicate inputs.&lt;/p&gt;

&lt;p&gt;Controller work later spread into menus, focus restoration, overlays, disconnected devices and versioned binding migrations. Those are separate problems, although they share one rule: the game needs an explicit owner for the current input state.&lt;/p&gt;

&lt;p&gt;A keyboard-only prototype does not need all of this. Even a digital-only controller setup can stay much simpler.&lt;/p&gt;

&lt;p&gt;The resolver became necessary when D-pad input, analog input and a strict four-direction movement model had to coexist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-frame effects need an escape route
&lt;/h2&gt;

&lt;p&gt;Portals are one example of an operation that lasts across several frames. Animations, pauses and temporary effects create the same type of risk.&lt;/p&gt;

&lt;p&gt;A code review found a subtle problem in a death effect.&lt;/p&gt;

&lt;p&gt;The effect was shrinking a sprite by interpolating from its current scale every frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;lerp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;end_scale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current scale already contained the result of the previous frame. Reusing it as the starting point caused the values to compound. The final size depended on how often the update ran.&lt;/p&gt;

&lt;p&gt;The correction stored the initial scale once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initial_scale&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;lerpf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END_SCALE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same sequence temporarily changed the global time scale. Under normal completion, it restored the previous value.&lt;/p&gt;

&lt;p&gt;There was still an interruption path.&lt;/p&gt;

&lt;p&gt;If the scene was removed while the sequence was waiting for an animation, the cleanup code on the normal completion path might never execute. The next scene could inherit a time scale of 0 or 0.25.&lt;/p&gt;

&lt;p&gt;The fix stored the previous value on the sequence and restored it from &lt;code&gt;_exit_tree()&lt;/code&gt; as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_exit_tree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time_scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;previous_time_scale&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This changed the way I review multi-frame code.&lt;/p&gt;

&lt;p&gt;I look at the normal timeline first, then I interrupt it mentally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if the player quits?&lt;/li&gt;
&lt;li&gt;What if the scene changes?&lt;/li&gt;
&lt;li&gt;What if an awaited object is deleted?&lt;/li&gt;
&lt;li&gt;What if a save is loaded in the middle?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A system that has a start and an expected finish also needs a path for cases where it never reaches that finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving AI instructions created another source of stale state
&lt;/h2&gt;

&lt;p&gt;AI coding tools have helped with implementation, tests, reviews and refactors throughout the project.&lt;/p&gt;

&lt;p&gt;They work better when the repository explains itself.&lt;/p&gt;

&lt;p&gt;I added files describing architecture, conventions, verification commands and project-specific constraints. &lt;code&gt;AGENTS.md&lt;/code&gt;, for example, now contains rules about commits, type annotations, deployment and the need to expose architectural compromises instead of hiding them.&lt;/p&gt;

&lt;p&gt;While reviewing the repository for this article, I found a useful failure in that approach.&lt;/p&gt;

&lt;p&gt;An older guidance file still said that the project had no test framework. It also described &lt;code&gt;game.gd&lt;/code&gt; as the owner of the authoritative grid and documented the snake as a normal array.&lt;/p&gt;

&lt;p&gt;Those statements were accurate for an earlier version.&lt;/p&gt;

&lt;p&gt;They had become instructions pointing toward an architecture that the project had already replaced.&lt;/p&gt;

&lt;p&gt;An agent following them carefully could make a worse change than an agent receiving no architecture description at all. The wrong guidance would make the mistake look intentional.&lt;/p&gt;

&lt;p&gt;I have spent plenty of time explaining that documentation helps AI understand a codebase. The missing half of that advice is maintenance.&lt;/p&gt;

&lt;p&gt;Agent instructions behave like code-adjacent state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They can become stale.&lt;/li&gt;
&lt;li&gt;They can disagree with the implementation.&lt;/li&gt;
&lt;li&gt;They deserve review after a large refactor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is now part of the same checklist I use for runtime systems. When ownership changes, I search for every place where the old ownership model may still exist. That includes tests, comments, plans and AI guidance files.&lt;/p&gt;

&lt;p&gt;The repository should describe the current project rather than preserve a confident explanation of its past.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching without stopping the game
&lt;/h2&gt;

&lt;p&gt;The technical problems were only half of the difficulty. Snake: Gridbreaker also moves quickly, and that changes how much information the player can reasonably process.&lt;/p&gt;

&lt;p&gt;One of the hardest design questions was how to present objectives without asking the player to stop and read. A level still needs to communicate what matters, but a long explanation competes directly with movement, combat and the risk of colliding with the snake’s own body.&lt;/p&gt;

&lt;p&gt;Removing a traditional tutorial did not remove the need to teach. It moved teaching into progression, animation, level structure and feedback.&lt;/p&gt;

&lt;p&gt;The first version of a system often feels clear to its developer because the developer already knows why it exists. A new player sees several unknowns at once: what the objective means, which objects are dangerous, what an enemy is preparing to do and which part of the snake is responsible for an effect.&lt;/p&gt;

&lt;p&gt;This became more difficult as the number of possible builds increased.&lt;/p&gt;

&lt;p&gt;Each class has its own mastery progression. Runs can also introduce abilities, mutations, items and systems that change how movement, the head, the tail, shields, power-ups or the economy behave. Showing all of that immediately would make the early game broader, but not necessarily deeper. The player would be learning terminology instead of learning through decisions.&lt;/p&gt;

&lt;p&gt;The Anomaly System became one answer to that problem.&lt;/p&gt;

&lt;p&gt;It acts as metaprogression, but it also controls the order in which complexity enters the game. New abilities and mechanics appear gradually, after the player has already formed a basic model of movement and survival.&lt;/p&gt;

&lt;p&gt;That changed how I think about unlock systems. They are not only rewards. They can also be a form of information budgeting.&lt;/p&gt;

&lt;p&gt;A new mechanic has a cost beyond implementation and balance. It consumes part of the player’s attention. Introducing several mechanics together may make each one less visible, even if every individual mechanic is explained correctly.&lt;/p&gt;

&lt;p&gt;The same principle applies inside a level.&lt;/p&gt;

&lt;p&gt;Enemy attacks need to be understandable while the player is moving. Telegraphing cannot rely only on a tooltip or an icon. The shape, timing, animation and sound of an attack have to communicate enough information before the attack resolves.&lt;/p&gt;

&lt;p&gt;At low speed, a slightly unclear effect may only cause hesitation. At high speed, it can cause an immediate collision.&lt;/p&gt;

&lt;p&gt;This means readability is not separate from difficulty. It is part of difficulty.&lt;/p&gt;

&lt;p&gt;I want the game to be challenging, but I do not want every death to feel arbitrary. The useful question after a failed run is not only whether the player lost. It is whether the player can form a better plan for the next attempt.&lt;/p&gt;

&lt;p&gt;A readable failure can still be severe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The snake may move too quickly.&lt;/li&gt;
&lt;li&gt;A wall may remove the last safe route.&lt;/li&gt;
&lt;li&gt;An enemy may force the head toward the body.&lt;/li&gt;
&lt;li&gt;A build may become powerful but difficult to control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game does not need to protect the player from those outcomes, but it should make the chain of cause and effect visible enough to learn from.&lt;/p&gt;

&lt;p&gt;That balancing act is still ongoing.&lt;/p&gt;

&lt;p&gt;If every threat waits too long, the game loses pressure. If every signal is subtle, the player may understand the rules only after dying several times for reasons that feel unrelated to their decisions.&lt;/p&gt;

&lt;p&gt;I am aiming for a state in which the player can say, “I see why that happened,” even when the correct response would have been difficult.&lt;/p&gt;

&lt;p&gt;Variation created another design problem.&lt;/p&gt;

&lt;p&gt;A run should not feel different merely because rooms and rewards appear in another order. I wanted some discoveries to change the player’s priorities. Secret rooms and risk rooms help with that because entering them is not only a content change. It is a decision about whether the current build can afford another danger.&lt;/p&gt;

&lt;p&gt;That kind of variation is more useful to me than randomness by itself.&lt;/p&gt;

&lt;p&gt;A secret room can offer an opportunity that changes the direction of a run. A risk room can turn a strong build into a dangerous gamble. The important part is that the player chooses to engage with the possibility.&lt;/p&gt;

&lt;p&gt;The broader lesson is that fast games still need space for thought, but that space does not always have to be a pause screen. It can appear in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the order of unlocks&lt;/li&gt;
&lt;li&gt;the shape of an arena&lt;/li&gt;
&lt;li&gt;a short warning animation&lt;/li&gt;
&lt;li&gt;the decision to enter an optional room&lt;/li&gt;
&lt;li&gt;the moment after death, when the result is clear enough to suggest a different choice next time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to remove complexity. The goal is to schedule it, signal it and connect it to decisions the player can understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I would keep the simpler version
&lt;/h2&gt;

&lt;p&gt;Several solutions in this article would have been unnecessary during the first weeks of development. I would still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;begin a small Snake prototype with an array&lt;/li&gt;
&lt;li&gt;consider one broad board update signal before creating six specialized paths&lt;/li&gt;
&lt;li&gt;use direct digital input checks if the game only supported a keyboard&lt;/li&gt;
&lt;li&gt;teleport the full body immediately if preserving movement through the portal did not matter visually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The later systems cost more to understand and maintain. They earn that cost by solving specific problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Movement repeatedly shifts or scans a growing body.&lt;/li&gt;
&lt;li&gt;Broad notifications rebuild unchanged layers.&lt;/li&gt;
&lt;li&gt;The body must visibly cross a boundary over time.&lt;/li&gt;
&lt;li&gt;Several controller sources can produce conflicting directions.&lt;/li&gt;
&lt;li&gt;Long-running effects can be interrupted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because a postmortem can make every final decision look inevitable.&lt;/p&gt;

&lt;p&gt;It was not.&lt;/p&gt;

&lt;p&gt;The original implementations were useful because they allowed the game to exist quickly. I replaced them after the cost became visible in the profiler, in tests or through bugs I could reproduce.&lt;/p&gt;

&lt;p&gt;Starting with the final architecture would have delayed the prototype and required me to predict problems before I understood the game.&lt;/p&gt;

&lt;h2&gt;
  
  
  The questions left by those bugs
&lt;/h2&gt;

&lt;p&gt;My current checklist is fairly small.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What does this system mean by “the player”?&lt;/li&gt;
&lt;li&gt;Who owns the state it wants to change?&lt;/li&gt;
&lt;li&gt;Which parts of the game actually need an update?&lt;/li&gt;
&lt;li&gt;Can the operation be interrupted before its expected end?&lt;/li&gt;
&lt;li&gt;Is an old save, test or documentation file still describing the previous model?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each question came from a real problem in the repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The circular deque came from treating the body as a constantly rebuilt array.&lt;/li&gt;
&lt;li&gt;Granular signals came from treating every movement as a new board.&lt;/li&gt;
&lt;li&gt;The portal release came from treating the snake as one teleportable position.&lt;/li&gt;
&lt;li&gt;The input resolver came from treating four actions as four independent intentions.&lt;/li&gt;
&lt;li&gt;The cleanup paths came from assuming that every sequence reaches its final line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Snake movement is still easy to explain: the head moves and the body follows.&lt;/p&gt;

&lt;p&gt;The difficult part was deciding what “follows” meant inside every other system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes the body followed within the same function.&lt;/li&gt;
&lt;li&gt;Sometimes it followed on the next movement tick.&lt;/li&gt;
&lt;li&gt;At the portal, the tail completed an operation that the head had started several ticks earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the most useful change in how I think about the project now. The player is represented by positions, but its behaviour often unfolds as a process.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;Arkadiusz Włodarczyk is a programming instructor and solo game developer from Poland. He develops Snake: Gridbreaker under GEM Games and has taught programming to more than 350,000 students.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://store.steampowered.com/app/4828340/Snake_Gridbreaker/" rel="noopener noreferrer"&gt;Snake: Gridbreaker on Steam&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://snake-gridbreaker.com" rel="noopener noreferrer"&gt;Official website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Protecting Corporate Data on Personal Devices: Best Practices for Securing BYOD Workplace</title>
      <dc:creator>GuardingPearSoftware</dc:creator>
      <pubDate>Fri, 07 Aug 2026 14:11:46 +0000</pubDate>
      <link>https://dev.to/guardingpearsoftware/protecting-corporate-data-on-personal-devices-best-practices-for-securing-byod-workplace-1o5a</link>
      <guid>https://dev.to/guardingpearsoftware/protecting-corporate-data-on-personal-devices-best-practices-for-securing-byod-workplace-1o5a</guid>
      <description>&lt;p&gt;The boundary between personal and professional life has become increasingly blurred. Employees no longer rely solely on company-issued laptops and smartphones to perform their jobs. Instead, many use their personal devices to access corporate email, collaborate with colleagues, edit sensitive documents, and connect to cloud applications from virtually anywhere. This trend, commonly known as Bring Your Own Device (BYOD), has become a standard practice across organizations of all sizes.&lt;/p&gt;

&lt;p&gt;This article explores the risks associated with BYOD and outlines practical strategies organizations can implement to protect corporate data without compromising employee productivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of BYOD
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Lower Hardware Costs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;BYOD can significantly reduce an organization's technology expenses by shifting some of the cost of purchasing devices to employees. Instead of buying laptops or smartphones for every staff member, organizations may only need to provide software licenses, security tools, or partial reimbursements. This reduction in capital expenditure allows businesses, particularly small and medium-sized enterprises, to allocate more resources toward strategic initiatives such as cybersecurity, innovation, employee training, or business expansion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Greater Workplace Flexibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allowing employees to use their personal devices supports flexible working arrangements, including remote work and hybrid work models. Employees can securely access company resources from virtually any location without relying on organization-issued equipment. This flexibility enables businesses to maintain operations during travel, emergencies, or unexpected disruptions while supporting a modern workforce that values mobility and work-life balance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improved Employee Satisfaction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many employees prefer using devices they have personally selected and customized rather than standardized corporate hardware. Familiar devices often provide a more comfortable user experience, enabling employees to work more confidently and efficiently. BYOD can increase job satisfaction by giving staff greater autonomy over how they work, which may contribute to higher employee engagement, improved morale, and better retention rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster Technology Adoption&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Employees typically replace their personal devices more frequently than organizations refresh corporate hardware. As a result, businesses implementing BYOD often benefit from access to newer smartphones, tablets, and laptops with improved processing power, improved security features, and better battery life. Organizations can take advantage of modern technology without bearing the full cost of frequent hardware upgrades, helping employees work more efficiently with up-to-date devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;BYOD enables employees to stay connected through communication and collaboration platforms regardless of their location. Access to messaging applications, video conferencing tools, shared documents, and cloud-based productivity suites allows teams to communicate in real time and collaborate more effectively. This continuous connectivity improves coordination across departments, speeds up decision-making, and supports collaboration among geographically dispersed teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Security Risks of Personal Devices
&lt;/h2&gt;

&lt;p&gt;Unlike company-issued devices, personal devices are primarily managed by their owners rather than the IT department. These behaviors create opportunities for attackers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Malware Infections&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Personal devices frequently download applications from app stores, websites, and third-party sources. Some apps may contain malware capable of stealing credentials, recording keystrokes, or accessing stored files. If an infected device connects to corporate resources, attackers may gain unauthorized access to business data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lost or Stolen Devices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Smartphones and laptops are easily misplaced or stolen. If a device stores corporate emails, documents, authentication tokens, or credentials without encryption, unauthorized individuals may gain access to sensitive company information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many users continue to rely on simple passwords or reuse credentials across multiple accounts. If attackers obtain credentials through phishing or data breaches, they may successfully log into corporate systems from compromised personal devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unsecured Networks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Employees frequently use their personal devices to access corporate resources from coffee shops, airports, hotels, and other public locations where Wi-Fi networks may be open or poorly secured. These environments increase the risk of cyberattacks, including man-in-the-middle attacks, rogue Wi-Fi hotspots, session hijacking, and traffic interception, all of which can allow attackers to intercept sensitive communications or steal credentials. Without strong security measures such as encrypted connections, VPNs, and secure authentication, confidential corporate information transmitted over these networks may be exposed to unauthorized parties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shadow IT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Employees sometimes install unauthorized applications to improve productivity. These unofficial tools may store corporate data outside approved environments, making it difficult for IT teams to monitor or protect sensitive information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixing Personal and Business Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Personal devices often contain family photos, social media applications, entertainment software, banking apps, and work documents all on the same system. Without proper separation, corporate files may be accidentally shared, backed up to personal cloud storage, or exposed through consumer applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliance Risks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Organizations implementing BYOD programs often face greater challenges in meeting regulatory and data privacy requirements. As employees access and store business information on personal devices, organizations have less direct control over how sensitive data is protected, managed, and removed. Failure to adequately secure customer or corporate information, or to ensure that business data is completely erased from personal devices when employees leave the organization, can result in regulatory violations, financial penalties, legal consequences, and reputational damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices for Protecting Corporate Data
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Implement a Clear BYOD Policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Organizations should establish a comprehensive BYOD policy that clearly defines the rules governing the use of personal devices for work. The policy should specify which devices are approved, minimum operating system requirements, mandatory security controls, acceptable use guidelines, employee responsibilities, privacy expectations, and procedures for reporting lost devices or security incidents.&lt;/p&gt;

&lt;p&gt;It should also explain what business data the organization can access on personal devices and what personal information remains private. A well-defined policy helps ensure that employees understand their responsibilities while providing a consistent framework for securing corporate data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Mobile Device Management (MDM)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MDM solutions enable organizations to enforce security requirements on employee-owned devices without taking complete control of personal content. These platforms allow IT administrators to require device encryption, enforce screen locks, verify operating system versions, deploy security updates, restrict the installation of high-risk applications, and remotely remove corporate data if a device is lost, stolen, or when an employee leaves the organization. Modern Mobile Application Management (MAM) solutions provide an additional layer of protection by securing only business applications and data while leaving personal files, photos, and applications untouched, helping balance security with employee privacy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Require Multi-Factor Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Organizations should require multi-factor authentication (MFA) for all systems that contain sensitive corporate information. Passwords alone are vulnerable to phishing, credential theft, and brute-force attacks, making additional verification essential. By requiring users to provide a second form of authentication, such as an authentication app, hardware security key, or biometric verification, organizations significantly reduce the likelihood of unauthorized access. MFA is especially important for email systems, VPNs, cloud storage platforms, financial applications, human resource systems, and customer databases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encrypt Sensitive Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Encryption is one of the most effective ways to protect corporate information stored on or transmitted by personal devices. Even if a device is lost or stolen, encrypted data remains unreadable without the appropriate decryption keys. Organizations should ensure that full-disk encryption is enabled on employee devices, sensitive files remain encrypted both at rest and during transmission, secure messaging platforms are used for business communications, and corporate backups are encrypted to prevent unauthorized access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adopt Zero Trust Principles&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Zero Trust security model assumes that no user, device, or connection should be trusted automatically, regardless of whether it originates inside or outside the corporate network. Every access request should be continuously evaluated by verifying user identity, device security posture, login location, risk level, and access permissions. Access should follow the principle of least privilege, ensuring employees can only access the systems, applications, and data required to perform their specific job responsibilities, thereby reducing the impact of compromised accounts or devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep Devices Updated&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regular software updates play a critical role in protecting BYOD environments from cyber threats. Operating system and application updates frequently contain security patches that address newly discovered vulnerabilities exploited by attackers. Organizations should require employees to use supported operating system versions and enable automatic updates whenever possible. Maintaining up-to-date devices reduces exposure to known security flaws and strengthens the overall security posture of the organization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Educate Employees&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Employee awareness is a critical component of any successful BYOD security strategy because technology alone cannot prevent every cyber threat. Organizations should provide regular security awareness training that teaches employees how to recognize phishing attacks, create strong passwords, practice safe browsing habits, secure mobile devices, connect safely to wireless networks, and promptly report suspicious activities. Well-informed employees are more likely to identify potential threats early and follow security best practices, significantly reducing organizational risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A successful BYOD program depends on balancing organizational security with respect for employee privacy. Organizations should be transparent about how personal devices are managed, what business data is monitored, and what personal information remains private. Data collection should be limited to what is necessary for legitimate business and security purposes, and employees should be informed about the organization's monitoring practices and privacy protections. By fostering openness, accountability, and mutual trust, organizations can encourage greater employee cooperation and strengthen compliance with BYOD security policies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Role-based access control (RBAC)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not everyone needs the keys to the entire organization. RBAC limits system access to what each role requires, effectively reducing the blast radius of a security incident involving a compromised personal device.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor for Threats&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Continuous monitoring enables organizations to detect suspicious activity before it develops into a major security incident. Security teams should monitor unusual login behavior, impossible travel events, suspicious application activity, malware detections, device compliance status, and potential attempts to exfiltrate sensitive data. Modern Endpoint Detection and Response (EDR) and Extended Detection and Response (XDR) solutions provide comprehensive visibility across both personal and corporate endpoints, allowing organizations to rapidly identify, investigate, and respond to emerging cyber threats in BYOD environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of BYOD Security
&lt;/h2&gt;

&lt;p&gt;As organizations continue embracing hybrid work, BYOD will remain a permanent part of enterprise IT. At the same time, attackers are using artificial intelligence, credential-stealing malware, and increasingly sophisticated phishing campaigns to target personal devices.&lt;/p&gt;

&lt;p&gt;Future BYOD security strategies will increasingly rely on AI-driven threat detection, passwordless authentication, continuous risk assessment, behavioral analytics, and Zero Trust architectures. These technologies can help identify compromised devices, unusual user behavior, and emerging threats before they result in data breaches.&lt;/p&gt;

&lt;p&gt;Organizations that treat personal devices as integral components of their security ecosystem, not as exceptions, will be better positioned to protect sensitive information while enabling a flexible workforce.&lt;/p&gt;

&lt;p&gt;Read more on my blog: &lt;a href="https://www.guardingpearsoftware.com" rel="noopener noreferrer"&gt;www.guardingpearsoftware.com&lt;/a&gt;!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
