<?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: Gustavo Lopes</title>
    <description>The latest articles on DEV Community by Gustavo Lopes (@gustavolr548).</description>
    <link>https://dev.to/gustavolr548</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3671153%2Fa6844df3-31e8-43e9-9733-fff92da066f2.jpeg</url>
      <title>DEV Community: Gustavo Lopes</title>
      <link>https://dev.to/gustavolr548</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gustavolr548"/>
    <language>en</language>
    <item>
      <title>Programming with GDExtension: High-Performance C++ in Godot 4 (Part #1)</title>
      <dc:creator>Gustavo Lopes</dc:creator>
      <pubDate>Mon, 16 Feb 2026 13:34:00 +0000</pubDate>
      <link>https://dev.to/gustavolr548/programming-with-gdextension-high-performance-c-in-godot-4-part-1-3c19</link>
      <guid>https://dev.to/gustavolr548/programming-with-gdextension-high-performance-c-in-godot-4-part-1-3c19</guid>
      <description>&lt;p&gt;When it comes to game development in Godot, GDScript is the primary language in 90% of cases. It is simple, direct, easy to learn, and—most importantly—it is the language specifically designed for the engine. However, it isn't the only option. For instance, we have C#, which offers better performance in certain contexts, more language features, and vast libraries, making it a popular choice for those migrating from Unity. But what about C++?&lt;/p&gt;

&lt;p&gt;Using C++ in Godot is the definitive choice for those seeking maximum performance, as it is the very language the engine was built in. Historically, this required recompiling the entire engine every time a modification was made—a complex process that made development extremely slow and tedious. Today, however, we have a much more practical and flexible solution: GDExtension. In this guide, we will focus on exactly that: how to create C++ code for your Godot projects and the essential concepts you need to master.&lt;/p&gt;

&lt;h1&gt;
  
  
  What exactly is GDExtension?
&lt;/h1&gt;

&lt;p&gt;In simple terms, GDExtension is the official interface for Godot 4 that allows us to register classes written in C++ (or other languages) as if they were native Godot classes. In practice, it functions as a dynamic library. You compile your C++ logic separately using the API as a base, and Godot loads your binary at runtime. You can visualize GDExtension as a USB flash drive for Godot, where the engine is the computer; it allows you to "plug in" and utilize your custom C++ code.&lt;/p&gt;

&lt;p&gt;The primary advantage is, of course, performance. If you have a heavy algorithm—such as complex physics processing, AI, or manipulation of large volumes of data—moving it to C++ can result in a massive speed gain compared to GDScript. Furthermore, it opens the door to the vast ecosystem of existing C and C++ libraries, such as OpenCV or SQLite.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Trade-offs: Complexity and Workflow
&lt;/h1&gt;

&lt;p&gt;There are, however, disadvantages to consider. The first is complexity. Beyond C++ itself being more difficult than GDScript, setting up the environment is undoubtedly more involved than simply opening the editor and coding. You will have to deal with compilers, build scripts, and a slower development cycle. You’ll need to configure significantly more within your C++ classes before they can be tested or read by GDScript.&lt;/p&gt;

&lt;p&gt;Finally, you must compile your code for every operating system you intend to target. Unlike GDScript, where the same code is accepted across multiple platforms, C++ is platform-specific. The dynamic library you generate is only compatible with the target platform you choose, meaning you must recompile for different systems and, in specific cases, adapt the code to ensure it functions correctly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Organizing the Workspace
&lt;/h1&gt;

&lt;p&gt;Setting up GDExtension for the first time is the most labor-intensive part, but once completed, the process is repeatable. In this overview, we focus on the official path using godot-cpp to understand the foundation of how everything works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeso7z8c2moabliw08hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeso7z8c2moabliw08hc.png" alt=" " width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you prefer a more direct path, there are frameworks like &lt;a href="https://github.com/Jenova-Framework/J.E.N.O.V.A" rel="noopener noreferrer"&gt;Projekt J.E.N.O.V.A&lt;/a&gt;. that attempt to make C++ in Godot as simple as using GDScript. These tools offer "one-click" environment setups and hot-reloading. However, such frameworks act as an abstraction layer; you become dependent on their specific systems, which may not track Godot’s updates as quickly and can be harder to debug if something breaks.&lt;/p&gt;

&lt;p&gt;One final consideration, this guide assumes a basic understanding of C++ and compilation tools. It is not a C++ tutorial, but rather a map of the Godot integration process.&lt;/p&gt;

&lt;h1&gt;
  
  
  Phase 1: Configuring godot-cpp
&lt;/h1&gt;

&lt;p&gt;The configuration process is divided into two phases: the one-time setup of godot-cpp, and the ongoing development cycle of your own code.&lt;/p&gt;

&lt;p&gt;For the setup, we need two essential tools: a C++ compiler and the SCons build tool (the same one Godot uses). On Linux, the compiler is usually included, while SCons is easily installed via package managers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ubuntu&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;scons
&lt;span class="c"&gt;# Arch Linux&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; scons
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, tools like MSYS2, Cygwin or the Visual Studio Build Tools to provide the necessary environment.&lt;/p&gt;

&lt;p&gt;Once the tools are ready, we need access to the godot-cpp repository, which contains the official bindings. The best method is to add this as a Git submodule in your project directory using git submodule add, ensuring you select the branch that matches your Godot version (e.g., branch 4.6 for Godot 4.6).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add the submodule (replace '4.6' with your version)&lt;/span&gt;
git submodule add &lt;span class="nt"&gt;-b&lt;/span&gt; 4.6 https://github.com/godotengine/godot-cpp.git
&lt;span class="c"&gt;# Also, if you are cloning the repository, remember to use this command:&lt;/span&gt;
git submodule update &lt;span class="nt"&gt;--init&lt;/span&gt; &lt;span class="nt"&gt;--remote&lt;/span&gt; &lt;span class="nt"&gt;--recursive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After downloading, you must compile the bindings using your engine’s specific API information. By running the Godot executable with the command --dump-extension-api, you generate an extension_api.json file. This file contains the "blueprint" of how Godot works internally. Copy this JSON into the godot-cpp folder and run scons. This processes the JSON to generate the C++ code that "mirrors" Godot, resulting in a static library that serves as your project's foundation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Export the engine API&lt;/span&gt;
./godot.exe &lt;span class="nt"&gt;--dump-extension-api&lt;/span&gt;

&lt;span class="c"&gt;# 2. Move it to the bindings folder&lt;/span&gt;
&lt;span class="nb"&gt;mv &lt;/span&gt;extension_api.json godot-cpp/

&lt;span class="c"&gt;# 3. Compile the bindings&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;godot-cpp
scons &lt;span class="nv"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;insert-platform] &lt;span class="nv"&gt;custom_api_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;extension_api.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Phase 2: The Development Cycle
&lt;/h1&gt;

&lt;p&gt;With the configuration complete, we move to the project itself. A clean folder structure is recommended: a folder for the Godot project, the godot-cpp folder, and a src folder for your C++ source code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_gdextension_project/
├── godot-cpp/          # The engine bindings (Git submodule)
├── src/                # Your C++ source code (.cpp and .h files)
├── SConstruct          # The build script that ties it all together
└── project/            # Your actual Godot Project folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, is important to note that, when creating C++ code with GDExentesion, there is three important steps:&lt;/p&gt;

&lt;p&gt;1 - Creating classes&lt;br&gt;
2 - Registering class data with "bind_methods"&lt;br&gt;
3 - Registering the classes in Godot with ClassDB&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Creating Classes
&lt;/h2&gt;

&lt;p&gt;In the src folder, every class you wish to expose to Godot requires a header (.h) for definitions and a source file (.cpp) for logic. When defining a class, such as GDExample, it must inherit from a Godot class (like Sprite2D).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#pragma once
&lt;/span&gt;
&lt;span class="c1"&gt;// We include the base class we want to inherit from&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/classes/sprite2d.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/core/class_db.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;godot&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;GDExample&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Sprite2D&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This macro is mandatory for all GDExtension classes. &lt;/span&gt;
    &lt;span class="c1"&gt;// It allows Godot to handle type-checking and inheritance internally.&lt;/span&gt;
    &lt;span class="n"&gt;GDCLASS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Sprite2D&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nl"&gt;private:&lt;/span&gt;
    &lt;span class="c1"&gt;// Internal variables for our logic&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;time_passed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amplitude&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;time_emit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nl"&gt;protected:&lt;/span&gt;
    &lt;span class="c1"&gt;// This is where we register our properties, methods, and signals to Godot&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_bind_methods&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nl"&gt;public:&lt;/span&gt;
    &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Standard Godot virtual function for frame-by-frame logic&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Setters and Getters for the 'amplitude' property&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;set_amplitude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;p_amplitude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;get_amplitude&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Example methods for logic and scene interaction&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sum_two_numbers&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;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;test_function&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="c1"&gt;// namespace godot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crucially, you must use the GDCLASS(GDExample, Sprite2D) macro to allow Godot to manage the class. &lt;/p&gt;

&lt;h2&gt;
  
  
  Binding data
&lt;/h2&gt;

&lt;p&gt;You also declare standard node functions like _process or _ready, along with a mandatory static function called _bind_methods. This is where the magic happens: it is in _bind_methods that you tell Godot which functions, properties, and signals are recognized by the editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"gdexample.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/classes/engine.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/variant/utility_functions.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/classes/scene_tree.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// _bind_methods is where we register our C++ code with Godot's internal ClassDB.&lt;/span&gt;
&lt;span class="c1"&gt;// If you don't bind a method here, Godot (and GDScript) won't know it exists.&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;_bind_methods&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// 1. REGISTERING METHODS&lt;/span&gt;
    &lt;span class="c1"&gt;// D_METHOD provides the name Godot will use and the names of the parameters.&lt;/span&gt;
    &lt;span class="n"&gt;ClassDB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bind_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"get_amplitude"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_amplitude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ClassDB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bind_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"set_amplitude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"p_amplitude"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;set_amplitude&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. CREATING PROPERTIES (The @export equivalent)&lt;/span&gt;
    &lt;span class="c1"&gt;// This allows you to edit "amplitude" directly in the Godot Inspector.&lt;/span&gt;
    &lt;span class="c1"&gt;// We define the type (FLOAT), the name, and the Hint (a slider from 0 to 100).&lt;/span&gt;
    &lt;span class="n"&gt;ADD_PROPERTY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Variant&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FLOAT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"amplitude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PROPERTY_HINT_RANGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"0,100,0.1"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
                 &lt;span class="s"&gt;"set_amplitude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"get_amplitude"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Registering our custom math and utility functions&lt;/span&gt;
    &lt;span class="n"&gt;ClassDB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bind_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test_function"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;test_function&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ClassDB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bind_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;D_METHOD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sum_two_numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"number1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"number2"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sum_two_numbers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. REGISTERING SIGNALS&lt;/span&gt;
    &lt;span class="c1"&gt;// This allows our C++ node to broadcast events that GDScript can listen to.&lt;/span&gt;
    &lt;span class="c1"&gt;// Here we define a signal "position_changed" that sends the Node itself and its new Vector2.&lt;/span&gt;
    &lt;span class="n"&gt;ADD_SIGNAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MethodInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"position_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
               &lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Variant&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
               &lt;span class="n"&gt;PropertyInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Variant&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VECTOR2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"new_pos"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Initialize our variables with default values.&lt;/span&gt;
    &lt;span class="n"&gt;time_passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;time_emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::~&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Clean up if necessary.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;_process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// IMPORTANT: Check if we are inside the editor.&lt;/span&gt;
    &lt;span class="c1"&gt;// If we don't do this, the script will run and move the node while you are designing!&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;godot&lt;/span&gt;&lt;span class="o"&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;get_singleton&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;is_editor_hint&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;time_passed&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// A simple trigonometric movement pattern (Swaying motion)&lt;/span&gt;
    &lt;span class="n"&gt;Vector2&lt;/span&gt; &lt;span class="n"&gt;new_position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vector2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time_passed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time_passed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// We call the native Godot 'set_position' method&lt;/span&gt;
    &lt;span class="n"&gt;set_position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. EMITTING SIGNALS&lt;/span&gt;
    &lt;span class="c1"&gt;// We use a timer logic to emit our custom signal once every second.&lt;/span&gt;
    &lt;span class="n"&gt;time_emit&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;delta&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;time_emit&lt;/span&gt; &lt;span class="o"&gt;&amp;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="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="s"&gt;"position_changed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;time_emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&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="c1"&gt;// GETTERS AND SETTERS&lt;/span&gt;
&lt;span class="c1"&gt;// Required for the Property system to work.&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;set_amplitude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;p_amplitude&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;amplitude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p_amplitude&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get_amplitude&lt;/span&gt;&lt;span class="p"&gt;()&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;amplitude&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// EXAMPLE: Basic data processing&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sum_two_numbers&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;a&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;b&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// EXAMPLE: Interacting with the Scene Tree&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;test_function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Printing to the Godot Output console&lt;/span&gt;
    &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UtilityFunctions&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from C++!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Accessing another node relative to this one (just like get_node in GDScript)&lt;/span&gt;
    &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sprite2D&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;child_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sprite2D&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sprite2D"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UtilityFunctions&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Found child node: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Accessing Groups (extremely useful for game logic)&lt;/span&gt;
    &lt;span class="n"&gt;Array&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_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;get_nodes_in_group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyGroup"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UtilityFunctions&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Nodes in group 'MyGroup': "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&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;h2&gt;
  
  
  3. Registration and Compilation
&lt;/h2&gt;

&lt;p&gt;Next, you need an entry point for your library, typically called register_types. This file contains an initialization function where you use ClassDB to register each class you've created. This step is what makes your C++ class actually appear in the "Add Node" list inside Godot.&lt;/p&gt;

&lt;h3&gt;
  
  
  register_types.h
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @file register_types.h
 * @brief Module initialization and registration for the GDExtension plugin.
 */&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/core/class_db.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @brief Initializes the GDExtension module at the specified initialization level.
 * 
 * This function is called by Godot Engine during plugin initialization. It registers
 * all custom classes, methods, and properties defined in this GDExtension with the
 * Godot ClassDB, making them available in the editor and at runtime.
 * 
 * @param p_level The initialization level at which classes should be registered
 *                (e.g., MODULE_INITIALIZATION_LEVEL_SCENE for scene-related classes).
 */&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize_example_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModuleInitializationLevel&lt;/span&gt; &lt;span class="n"&gt;p_level&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @brief Uninitializes the GDExtension module at the specified initialization level.
 * 
 * This function is called by Godot Engine during plugin cleanup. It should perform
 * any necessary cleanup operations for the module.
 * 
 * @param p_level The initialization level at which cleanup should occur.
 */&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;uninitialize_example_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModuleInitializationLevel&lt;/span&gt; &lt;span class="n"&gt;p_level&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  register_types.cpp
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;gdexample.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;godot_cpp/core/class_db.hpp&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// This function is called by Godot when the extension is loaded&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize_example_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModuleInitializationLevel&lt;/span&gt; &lt;span class="n"&gt;p_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// We only want to register our classes at a specific 'level' &lt;/span&gt;
    &lt;span class="c1"&gt;// (the Scene level is where Nodes live).&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;p_level&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;MODULE_INITIALIZATION_LEVEL_SCENE&lt;/span&gt;&lt;span class="p"&gt;)&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="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// This makes 'GDExample' appear in the "Create New Node" menu&lt;/span&gt;
    &lt;span class="n"&gt;ClassDB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;register_class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GDExample&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This function is called when the extension is unloaded&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;uninitialize_example_module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModuleInitializationLevel&lt;/span&gt; &lt;span class="n"&gt;p_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Cleanup code goes here if necessary&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Initialization.&lt;/span&gt;
  &lt;span class="n"&gt;GDExtensionBool&lt;/span&gt; &lt;span class="n"&gt;GDE_EXPORT&lt;/span&gt;                                                       &lt;span class="n"&gt;example_library_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GDExtensionInterfaceGetProcAddress&lt;/span&gt; &lt;span class="n"&gt;p_get_proc_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;GDExtensionClassLibraryPtr&lt;/span&gt; &lt;span class="n"&gt;p_library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GDExtensionInitialization&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;r_initialization&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;godot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GDExtensionBinding&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;InitObject&lt;/span&gt; &lt;span class="n"&gt;init_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p_get_proc_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p_library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r_initialization&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;init_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_initializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialize_example_module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;init_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_terminator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uninitialize_example_module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;init_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_minimum_library_initialization_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MODULE_INITIALIZATION_LEVEL_SCENE&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;init_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&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;To compile, you create an SConstruct file at the project root. This file acts as a build script that configures the compilation and links your code with the godot-cpp library. Once you run scons at the root, it generates the final binary—a .dll for Windows or a .so for Linux.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="c1"&gt;# We import error printing from SCons methods to keep output clean
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;print_error&lt;/span&gt;

&lt;span class="c1"&gt;# --- CONFIGURATION AREA ---
# Change these names to match your specific project
&lt;/span&gt;&lt;span class="n"&gt;folder_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;godot-cpp-example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;library_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GodotCppExample&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;project_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;game_project&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# This is the folder where your Godot 'project.godot' lives
&lt;/span&gt;
&lt;span class="c1"&gt;# Initialize the SCons environment
&lt;/span&gt;&lt;span class="n"&gt;localEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;PLATFORM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Load custom build options (like compiler flags) if a 'custom.py' exists
&lt;/span&gt;&lt;span class="n"&gt;customs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;custom.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;customs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;os&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="nf"&gt;abspath&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Variables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ARGUMENTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localEnv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generate a 'help' text for when you run 'scons --help'
&lt;/span&gt;&lt;span class="nc"&gt;Help&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerateHelpText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localEnv&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localEnv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Clone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# --- SAFETY CHECK ---
# Before we try to compile, we make sure the user didn't forget the submodules.
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&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="nf"&gt;isdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;godot-cpp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;godot-cpp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="nf"&gt;print_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;The &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;godot-cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; bindings are missing!
You likely forgot to initialize Git submodules. Run this command:

    git submodule update --init --recursive&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- THE BUILD PROCESS ---
&lt;/span&gt;
&lt;span class="c1"&gt;# 1. We call the SConstruct file inside godot-cpp to prepare the base bindings
&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SConscript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;godot-cpp/SConstruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;customs&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Tell SCons where our source code is
&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CPPPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/*.cpp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# This automatically finds all .cpp files in the src folder
&lt;/span&gt;
&lt;span class="c1"&gt;# 3. Handle Documentation (Godot 4.3+)
# If you are making an editor plugin, this compiles your XML documentation into the binary
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;editor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;template_debug&lt;/span&gt;&lt;span class="sh"&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="n"&gt;doc_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GodotCPPDocData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src/gen/doc_data.gen.cpp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc_classes/*.xml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skipping class reference: targeting a pre-4.3 Godot baseline.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Handle Naming Conventions
# Different OS's have different naming rules (e.g., .dll vs .so). 
# This logic ensures the filename is formatted correctly for Godot.
&lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;suffix&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.universal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lib_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}{}{}{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$SHLIBPREFIX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;library_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$SHLIBSUFFIX&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# 5. The Compilation Step
# This actually triggers the compiler to create the Shared Library (binary)
&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SharedLibrary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bin/{}/{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;platform&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;lib_filename&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- THE INSTALLATION STEP ---
# Instead of manually copying files, we tell SCons to automatically 'Install' 
# the new binary directly into our Godot project's addons folder.
# This makes the development loop much faster!
&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}/addons/{}/bin/{}/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;folder_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Set the library and the copy operation as the default action when 'scons' is run
&lt;/span&gt;&lt;span class="n"&gt;default_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;default_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. The .gdextension File
&lt;/h2&gt;

&lt;p&gt;The final step is telling Godot how to load your newly compiled binary. You do this by creating a simple text file with the .gdextension extension (e.g., my_project.gdextension).&lt;/p&gt;

&lt;p&gt;Before we look at the file content, it is important to understand where this file sits. Typically, you want a clean separation between your C++ workspace and your Godot project files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_gdextension_project/
├── godot-cpp/          # The engine bindings (Git submodule)
├── src/                # Your C++ source code (.cpp and .h files)
├── SConstruct          # The build script that ties it all together
└── project/            # Your actual Godot Project folder
    ├── project.godot
    ├── main.tscn
    └── bin/            # Where your compiled binaries and .gdextension live
        ├── my_project.gdextension
        ├── libgdexample.windows.debug.x86_64.dll
        └── libgdexample.windows.release.x86_64.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Observation: The deliberate omission of the "addons" folder (unlike in the Scons file) in this example, serves a purpose: to emphasize that Godot does not mandate placing the .gdextension file within the "addons" directory, which is the expectation for GDScript plugins.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This file acts as a manifest. It contains a [configuration] section pointing to your C++ entry point and a [libraries] section that maps specific platforms and build targets to the correct file paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Build Targets
&lt;/h3&gt;

&lt;p&gt;It is important to understand that you will typically deal with two types of builds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug Builds: These are used during development and inside the Godot Editor. They include extra symbols that make debugging easier and allow the engine to give you descriptive error messages if the C++ code crashes.&lt;/li&gt;
&lt;li&gt;Release Builds: These are optimized for performance. They are smaller and faster because they strip away the debugging "clutter," and they are what you will actually distribute to your players.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how you would set up your .gdextension file to handle both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[configuration]
# This must match the entry function name defined in your registration file (register_types.cpp)
entry_symbol = "example_library_init"
compatibility_minimum = "4.6"
reloadable=true # add this to integrate hot-reload inside the editor!

[libraries]
# We map specific operating systems to the resulting compiled files.
# 'res://' points to the root of your Godot project folder.
# but you can also use relative paths.
windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
macos.debug.x86_64 = "res://bin/libgdexample.macos.template_debug.x86_64.dylib"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why separate them?
&lt;/h2&gt;

&lt;p&gt;By defining both debug and release paths, Godot is smart enough to swap the libraries automatically. When you are working in the editor, it uses the debug version. When you click Export Project and uncheck "Export with Debug," Godot will automatically bundle the release version of your C++ code, ensuring your players get the best possible performance.&lt;/p&gt;

&lt;p&gt;But most importantly, when Godot sees the .gdextension file, it loads the correct binary for your platform, and your C++ classes are dynamically linked. They will appear in the editor ready to be used like any native node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7cmd8k9vfol83hzf6xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7cmd8k9vfol83hzf6xx.png" alt=" " width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Observation: If your classes don't appear immediatly in the editor, reload the current project, and make sure during development to activate "hot reload" for a better developer experience.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;You now understand the fundamental flow of GDExtension. This is only the beginning of the journey. While the initial setup is the steepest hurdle, the performance rewards and architectural flexibility are significant.&lt;/p&gt;

&lt;p&gt;In a future deep-dive, we will explore the more complex challenges of GDExtension, including available macros, documenting classes for the editor, and—most importantly—a performance comparison to see exactly how much speed is gained when migrating a GDScript plugin over to C++.&lt;/p&gt;

&lt;p&gt;Link to the repository:&lt;br&gt;
&lt;a href="https://github.com/GuaraProductions/Godot-GDExtension-minimalist-example" rel="noopener noreferrer"&gt;https://github.com/GuaraProductions/Godot-GDExtension-minimalist-example&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>godot</category>
    </item>
    <item>
      <title>Resurrecting a 25-Year-Old Horror Game: How I Ported 'Fiend' to Modern Systems</title>
      <dc:creator>Gustavo Lopes</dc:creator>
      <pubDate>Tue, 13 Jan 2026 13:20:36 +0000</pubDate>
      <link>https://dev.to/gustavolr548/resurrecting-a-25-year-old-horror-game-how-i-ported-fiend-to-modern-systems-3m4o</link>
      <guid>https://dev.to/gustavolr548/resurrecting-a-25-year-old-horror-game-how-i-ported-fiend-to-modern-systems-3m4o</guid>
      <description>&lt;h2&gt;
  
  
  1 - Introduction
&lt;/h2&gt;

&lt;p&gt;Game restoration is more than just a technical challenge; it is an essential act of preservation. Video games are a unique blend of art and complex engineering, but unlike movies or books, they can become stuck to the configurations they were born on. Just like software, a video game project risks becoming "abandonware" if its fundamental components—such as supporting libraries—become obsolete and are not adequately maintained.&lt;/p&gt;

&lt;p&gt;As a passionate computer scientist and an avid gamer, I always dreamed of the chance to dive into and help preserve the source code of older games. That opportunity finally arrived when I came across the source code for the survival horror title, Fiend, originally released in 2001. This game holds a special place for me. Although not a classic or the best of its time, it was one of the first horror games I ever played.&lt;/p&gt;

&lt;p&gt;My goal was ambitious: to take source code written for Windows 98/XP and make it run natively on modern 64-bit Linux and Windows 10/11.&lt;/p&gt;

&lt;p&gt;This wasn't just a simple "recompile." It required modernizing a lot of components of the codebase. I replaced the outdated audio library, fixed memory corruption bugs that had been sleeping for 20 years, and built a CI/CD pipeline using GitHub Workflows, and more. This ensures that every time I change the code, the game is automatically built and tested, guaranteeing it won't break again in the future.&lt;/p&gt;

&lt;p&gt;This post documents the game's revitalization, the technical challenges, and aims to highlight this influential, lost relic that is, in a way, very influential to a major video game company's history.&lt;/p&gt;

&lt;p&gt;But first, let's start with some context.&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - What is "Fiend"?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5zg6s3yijvwholf0gpz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa5zg6s3yijvwholf0gpz.png" alt="GripDesign Logo that appears when you boot the game" width="240" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To understand the restoration, you first have to understand the subject. Fiend is a top-down survival horror game released in 2001 by GripDesign—the alias of Thomas Grip, who would go on to co-found Frictional Games.&lt;/p&gt;

&lt;p&gt;If you have played Amnesia: The Dark Descent or SOMA, you can see the DNA of those games right here in Fiend. It features a heavy Lovecraftian atmosphere, limited resources, and a combination of psychological horror and combat.&lt;/p&gt;

&lt;p&gt;The story is as follows: you play as Nick Cane, a researcher sent to the small mining town of Lauder. What starts as a routine mineral survey quickly spirals into a nightmare as you uncover an ancient evil buried beneath the town.&lt;/p&gt;

&lt;p&gt;If you like to see a full playthrough of the game &lt;a href="https://youtu.be/OS99HNMkyQ4?si=vrhy9hQx0fgNXs9U" rel="noopener noreferrer"&gt;here is a link for it.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, for more information on some of Frictional Games' lesser-known projects, such as Fiend, visit &lt;a href="https://frictionalgames.com/games/other-projects/" rel="noopener noreferrer"&gt;this page, on the official website&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 - The Tech Stack (2001 Era):
&lt;/h3&gt;

&lt;p&gt;The game was a technical marvel for a one-man team in 2001, featuring real-time lighting and particle effects. It was built using:&lt;/p&gt;

&lt;p&gt;Language: C (The grandfather of modern systems programming).&lt;/p&gt;

&lt;p&gt;Graphics: Allegro 3.9.3 (A famous game programming library from the 90s/2000s).&lt;/p&gt;

&lt;p&gt;Audio: FMOD (A powerful sound engine still used today, though the 2001 version is ancient history).&lt;/p&gt;

&lt;p&gt;But most impressive of all, alongside the game there is also a Map Editor. The restoration project also includes the restoration of the Map Editor as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sxym0sj5cxdqm0ya5hr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sxym0sj5cxdqm0ya5hr.png" alt="The map editor open on one of the game's many houses" width="796" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn't just a tool for drawing walls; it is a complete development environment for the game. It allows you to design map layouts, define collision data, place items, and add complex logic like triggers and events. By fixing the editor, I ensured that users can not only play Fiend but also study how it was put together—or even create their own mods and stories (if they so desire).&lt;/p&gt;

&lt;p&gt;With the project’s current state being explained, it becomes clear as day as to why the game is “unplayable” in its current state. This boils down to three main factors: the dependence on the closed-source FMOD library, the choice of programming language, and the use of an obsolete game programming framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Getting it to boot
&lt;/h2&gt;

&lt;p&gt;And so, let’s get started into the process of revitalizing this game, with the first step being, getting it to run. Surprisingly, the project featured a functional CMake setup. It was designed to automatically detect essential libraries on the user's system, particularly Allegro and FMOD binaries, allowing anyone to clone and build the repository with a single command. Nevertheless, crucial architectural decisions for the project still needed to be made.&lt;/p&gt;

&lt;p&gt;The game was originally built on Allegro 3.9.3, a library from the late 90s. While the modern standard is Allegro 5, upgrading to it was impossible without rewriting the entire game. Allegro 5 fundamentally changes how input works, moving from a "polling" system (checking if a key is down right now) to an "event queue" system (waiting for the OS to report a key press). To bridge this gap, I chose Allegro 4.4.3. This version is modern enough to compile on 2025 Linux and Windows, but retains the legacy architecture the code expects, requiring only minor updates to deprecated math functions and updating the CMake to link to the "math.h" header.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitottibf94lev11domvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fitottibf94lev11domvu.png" alt="These math functions where responsible to calculate the direction of the game's fog and also helped NPCs face the correct direction that they are facing the player when interacted" width="629" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the graphics sorted, I hit a wall with the audio. The game relied on an ancient version of FMOD that is incompatible with modern Linux. Rather than getting stuck in "dependency hell," I used a standard development tactic called &lt;strong&gt;feature flagging&lt;/strong&gt;. By wrapping all audio code in pre-processor directives (#ifdef USE_FMOD), I made the sound system optional during the first stages of development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example of how I silenced the audio engine&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PlaySound&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;id&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;vol&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;pan&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;freq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#ifdef USE_FMOD
&lt;/span&gt;        &lt;span class="c1"&gt;// Original code: only compiles if FMOD is found&lt;/span&gt;
        &lt;span class="n"&gt;FSOUND_PlaySound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sound_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="cp"&gt;#else
&lt;/span&gt;        &lt;span class="c1"&gt;// If FMOD is missing, do nothing (game runs silently)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allowed the compiler to ignore the missing library and build a silent—but functional—version of the game so I could focus on stability.&lt;/p&gt;

&lt;p&gt;After this point, the game was actually initializing, but there were still a lot of issues that made it crash on startup. One of them is that I had to hard-code the system locale to "C" (standard English). The game crashed on systems using languages like Portuguese or German because the fscanf function tries to use commas for decimals instead of dots.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Storing the user's original locale&lt;/span&gt;
&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;old_locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;setlocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LC_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Forcing the game to use "." for decimals (English Standard)&lt;/span&gt;
&lt;span class="n"&gt;setlocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LC_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ... Parsing code runs here ...&lt;/span&gt;

&lt;span class="c1"&gt;// Restoring the user's locale&lt;/span&gt;
&lt;span class="n"&gt;setlocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LC_NUMERIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_locale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fix was important, because a lot of data was being read from .txt files with important information, like for example, the data for the weapons of the game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12j4oenci9ielw555rvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12j4oenci9ielw555rvj.png" alt="This .txt is the file for the revolver" width="568" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After fixing that (and some logic issues inside the game), I faced the most complex challenge yet: &lt;strong&gt;Binary Compatibility&lt;/strong&gt;. The game saved maps by dumping raw memory structures to disk. In 2001, on 32-bit systems, memory pointers were 4 bytes. On my 64-bit Linux machine, they are 8 bytes.&lt;/p&gt;

&lt;p&gt;This size mismatch meant the game was reading garbage data. To fix this, I wrote a custom loader that reads the files field-by-field, manually discarding the old 32-bit pointers to realign the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The Fix: Manual Field Reading &amp;amp; Skipping 32-bit Pointers&lt;/span&gt;
&lt;span class="n"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;temp_map&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num_of_lights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// On 32-bit Windows, the next 4 bytes were a pointer.&lt;/span&gt;
&lt;span class="c1"&gt;// On 64-bit Linux, we don't need that old address, so we skip it.&lt;/span&gt;
&lt;span class="n"&gt;fseek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SEEK_CUR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Skip 32-bit pointer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these fixes, the game was finally playable—albeit silent.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 - Fixing memory issues
&lt;/h2&gt;

&lt;p&gt;After the initial port, I felt confident to work on the audio. The game compiled, the graphics rendered, and I could walk around the first map. But when I switched the compiler from "Debug" mode to "Release" (turning on optimizations like -O2), the game immediately crashed.&lt;/p&gt;

&lt;p&gt;This is a classic problem in C programming. Debug builds often add "padding" around variables that can accidentally hide memory errors. Release builds remove that padding, causing those sleeping bugs—often called &lt;em&gt;"Heisenbugs"&lt;/em&gt;—to wake up and crash the application.&lt;/p&gt;

&lt;p&gt;To hunt them down, I needed a memory debugger.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 - The Tool Selection: Valgrind vs. AddressSanitizer
&lt;/h3&gt;

&lt;p&gt;My initial strategy for memory checking involved Valgrind, a tool I was already familiar with. It works by executing the program within a virtual environment, thoroughly inspecting every single instruction. While remarkably comprehensive, this approach comes with a severe performance hit, slowing execution by a factor of 20 to 50.&lt;/p&gt;

&lt;p&gt;The issue with Valgrind in this context was immediate: its drastic slowdown made it unusable for a real-time game. The resulting frame rate was so poor that I couldn't even navigate the menus to access the very bugs I was trying to find.&lt;/p&gt;

&lt;p&gt;Consequently, I switched to AddressSanitizer (ASAN). Rather than virtualizing the CPU, ASAN integrates error-checking code directly into the program during the compilation process. This makes it significantly more efficient, reducing the slowdown to only about 2x. This much faster performance finally allowed me to play the game at a manageable frame rate while ASAN monitored for errors in the background.&lt;/p&gt;

&lt;p&gt;The moment I launched the game with ASAN active, the console instantly filled with red text. The 2001 original code was quickly exposed as being full of "ticking time bombs."&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 - "Off-by-One" Error and Unitialized Memory
&lt;/h3&gt;

&lt;p&gt;The most severe bug—the one causing the crashes—was hidden in the Line-of-Sight (LOS) system. The game uses an array to track light sources, defined with a size of 18. However, the loop iterating through this array was written to go from 0 to 18.&lt;/p&gt;

&lt;p&gt;In C, an array of size 18 has indices 0 through 17. Accessing index 18 means you are reading/writing memory that doesn't belong to that array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The Bug: Iterating too far&lt;/span&gt;
&lt;span class="c1"&gt;// 'l' goes up to 18, but array size is 18 (indices 0-17)&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;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="n"&gt;light_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&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="c1"&gt;// Writes to invalid memory at index 18!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The Fix: Stop at 17&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;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;light_source&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ASAN flagged this as a "Global Buffer Overflow". This single byte of corruption was overwriting adjacent memory, destabilizing the entire engine during map transitions.&lt;/p&gt;

&lt;p&gt;A similar bug caused loops to iterate using MAX_OBJECT_NUM instead of the actual number of objects (map-&amp;gt;num_of_objects), leading to uninitialized memory access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE (heap buffer overflow):&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MAX_OBJECT_NUM&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Accesses beyond allocated memory!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER (correct bounds):&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;num_of_objects&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Uses dynamic bounds to stay within the allocated heap space&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3 The Dangers of sprintf
&lt;/h3&gt;

&lt;p&gt;The original code heavily relied on sprintf to generate save filenames. This function is dangerous because it doesn't check if the text fits into the destination buffer. ASAN detected multiple stack-buffer overflows where the game tried to write long map names into small variables.&lt;/p&gt;

&lt;p&gt;I replaced these unsafe calls with strncpy, which forces a limit on how many characters can be copied, ensuring we never write past the end of the buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE (unsafe)&lt;/span&gt;
&lt;span class="n"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER (safe)&lt;/span&gt;
&lt;span class="n"&gt;strncpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;-&amp;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;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_name&lt;/span&gt;&lt;span class="p"&gt;)&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;temp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_name&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Memory Leaks and Double-Free
&lt;/h3&gt;

&lt;p&gt;Due to the significant memory consumption of storing many in-game images as bitmaps, which would make simultaneous rendering challenging, the game employs an efficient strategy: Allegro's Run-Length Encoding (RLE) Sprites. This method is particularly effective for simpler images that feature large, uniform areas of color. By replacing repeated pixel data, RLE reduces both the size of the image files and the time required to draw them, making the rendering process much faster.&lt;/p&gt;

&lt;p&gt;The core issue is twofold: while the game correctly converts the bitmap to RLE and cleans it up, the RLE Sprites are never cleaned up, not even during transitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;release_objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_of_objects&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&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;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;num_of_frames&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;angles&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;door&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Single bitmap - free it&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;object_info&lt;/span&gt;&lt;span class="p"&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;pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&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;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;destroy_bitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&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;data&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="k"&gt;else&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;object_info&lt;/span&gt;&lt;span class="p"&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;additive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Additive objects - free angle bitmaps&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&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;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_angles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&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;object_info&lt;/span&gt;&lt;span class="p"&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;pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;destroy_bitmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;data&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Normal objects - free RLE sprites (MEMORY LEAK FIX)&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&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;k&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num_angles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&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;object_info&lt;/span&gt;&lt;span class="p"&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;rle_pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;destroy_rle_sprite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;rle_pic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;k&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="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;Second, in specific scenarios, flawed boolean logic leads to the same memory data being freed multiple times, which results in a Double-Free Error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// BEFORE (double-free):&lt;/span&gt;
&lt;span class="c1"&gt;// Loading logic:&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;additive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Bitmaps NOT freed&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Normal objects (includes trans without additive)&lt;/span&gt;
        &lt;span class="c1"&gt;// Bitmaps FREED here&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Cleanup logic (MISMATCH):&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;additive&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;trans&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Tries to free bitmaps AGAIN!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AFTER (correct):&lt;/span&gt;
&lt;span class="c1"&gt;// Cleanup now matches loading:&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;object_info&lt;/span&gt;&lt;span class="p"&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;additive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Only additive objects, matches loading&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5 Results
&lt;/h3&gt;

&lt;p&gt;There were some other errors, but it would take a lot more context to explain them, but in short, by the end of this phase, I had fixed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 Buffer Overflows &lt;/li&gt;
&lt;li&gt;1 Heap Corruption (The LOS bug) &lt;/li&gt;
&lt;li&gt;2 Memory Leaks &lt;/li&gt;
&lt;li&gt;1 Double-Free Error &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these fixes, the game was now stable in Release mode, and running without a single report from AddressSanitizer.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 - Replacing FMOD
&lt;/h2&gt;

&lt;p&gt;By this point, the game was playable and stable, but it was completely silent. The final challenge was to restore the atmosphere that makes a horror game scary: the sound.&lt;/p&gt;

&lt;p&gt;The game originally used FMOD, but trying to link a 2001 audio library to a 2025 operating system was a dead end. I needed a replacement that was modern, open-source, and easy to integrate. I chose miniaudio.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 - The Choice: Why Miniaudio?
&lt;/h3&gt;

&lt;p&gt;Unlike FMOD, miniaudio simplifies the development process as it only requires a single file (miniaudio.h) to be dropped into the project, eliminating the need for complex installation. Since the game's audio requirements were minimal—solely focused on playback, looping, and volume control—miniaudio was the perfect fit. The library also offers native support for essential features like mixing, volume management, and resource handling across Linux, Windows, and other platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 - The Wrapper: Faking the Old System
&lt;/h3&gt;

&lt;p&gt;With the API issue resolved, the central challenge shifted to integrating the new library without rewriting the existing sound-playing code. To achieve this, I introduced a Wrapper API (audio.c). This wrapper acts as an intermediary, translating calls from the existing game code, which uses generic functions like PlaySound(), into the necessary miniaudio instructions. This strategic approach allowed for a fundamental change in the underlying audio engine while successfully preserving the original game logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 - The Crisis: The ".it" vs ".wav" Corruption
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz4dlxjc7nvzx4nsmvqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxz4dlxjc7nvzx4nsmvqx.png" alt="Screenshot of the impulse tracker software" width="640" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original music assets were stored in the legacy Impulse Tracker (.it) format, dating back to the 1990s. Jeffrey Lim ('Pulse') created Impulse Tracker in 1995 as the spiritual successor to Scream Tracker 3. It quickly gained popularity within the demoscene and independent game development community due to its advanced features, including full 32-channel support, new note effects, and superior sample handling. Since miniaudio lacks support for .it files, all these assets were converted to the standard .wav format.&lt;/p&gt;

&lt;p&gt;The change in file format, however, led to a significant issue. The map files, which contain the binary data defining the game levels, had specific references to files ending in the ".it" extension. Initially, I attempted a simple find-and-replace operation within the map files, changing text like "music.it" to "music.wav."&lt;/p&gt;

&lt;p&gt;This action caused widespread corruption. Because the ".wav" extension (4 characters) is one character longer than ".it" (3 characters), the replacement shifted every subsequent byte in the binary file by one position. In a densely packed binary file structure, even a single-byte shift turns valid data—such as door triggers—into unusable garbage.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 - The Solution: The Map Editor Tool
&lt;/h3&gt;

&lt;p&gt;I realized I couldn't edit the raw files safely. I had to do it logically. Since I had already restored the Map Editor in Phase 1, I used it to build a migration tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy57715d9t54lqt8lp7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy57715d9t54lqt8lp7y.png" alt="Batch replace tool for music file extensions" width="793" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I wrote a script inside the editor to Load a map (reading the data into correct memory structures).&lt;/li&gt;
&lt;li&gt;The script then finds every string ending in .it and safely replaces it with .wav in memory.&lt;/li&gt;
&lt;li&gt;Finally, it Saves the map back to disk.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the editor knows how to write the file structure correctly, it handled the size difference automatically, preventing the "bit shift" corruption. With this final fix, the game was complete: stable, modernized, and fully audible.&lt;/p&gt;

&lt;h2&gt;
  
  
  6 - CI/CD - Making the game Cross-Platform
&lt;/h2&gt;

&lt;p&gt;With the game stable and audible, I wanted to ensure it stayed that way. I set up a CI/CD pipeline using GitHub Actions. The goal was simple: every time I push code, a cloud server should automatically compile the game for both Linux and Windows, bundle the assets, and publish a release. Also I wanted to bundle with the game all the required libraries, so that everything the game needed to run was packaged with the final product.&lt;/p&gt;

&lt;p&gt;The Linux build was straightforward—just a standard &lt;code&gt;ubuntu-latest&lt;/code&gt; container installing necessary packages via &lt;code&gt;apt&lt;/code&gt; and compiling the allegro library with only necessary components. The Windows build, however, turned into a nightmare.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 - The Windows Problem
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzq87fzia2s3v9fkjgswr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzq87fzia2s3v9fkjgswr.png" alt="Mingw Installer window" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I initially tried to compile the Windows version using modern tools (latest GCC/MinGW). It failed miserably. The game would crash every single time on the title screen.&lt;/p&gt;

&lt;p&gt;I realized that Allegro 4 and the 2001 code were tightly coupled to the specific behavior of older compilers and APIs. Achieving the desired outcome required essential changes to the entire build process.&lt;/p&gt;

&lt;p&gt;First, I manually installed an older version, MinGW 6.3.0, which I sourced from SourceForge, instead of installing the compiler through the use of the MSYS2’s package manager.&lt;/p&gt;

&lt;p&gt;The second major hurdle was the incompatibility of modern Windows SDKs with the specific DirectDraw interfaces used by Fiend. This necessitated tracking down the original DirectX 8 SDK, which was eventually located in the archives of the official Allegro website.&lt;/p&gt;

&lt;p&gt;Finally, a custom step was incorporated into the pipeline script. This step forcibly extracts the archaic SDK and injects its necessary header and library files directly into the path recognized by the MinGW compiler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A snippet of the "Digital Archaeology" in build.yml&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Injecting DX8 into MinGW...&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;Copy-Item -Path "C:\DX8\include\*" -Destination "C:\mingw32\include" -Recurse -Force&lt;/span&gt;
    &lt;span class="s"&gt;Copy-Item -Path "C:\DX8\lib\*" -Destination "C:\mingw32\lib" -Recurse -Force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 - The "Text Test" Debugging
&lt;/h3&gt;

&lt;p&gt;I only figured out the problem's root cause after I put together a small, focused test program just for checking out how text rendering worked in Allegro. When compiled with modern GCC, it failed. When compiled with the legacy stack, it worked. This confirmed that the issue wasn't my code—it was the toolchain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;allegro.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting Allegro font test&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Starting Allegro font test&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;allegro_init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"After init&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;install_keyboard&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;set_color_depth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Attempting to set graphics mode...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&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;set_gfx_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GFX_AUTODETECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;640&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;480&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[ERROR] Failed to set graphics mode!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allegro_error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Graphics mode set successfully.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Using Allegro's built-in font.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;clear_to_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;makecol&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="mi"&gt;0&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;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Screen cleared. Attempting to render text...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;textout_centre_ex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Text test in Windows Allegro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;320&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;makecol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&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;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Text rendering attempted.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Waiting for key press...&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;readkey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;allegro_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[LOG] Exiting.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;allegro_exit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;END_OF_MAIN&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the repository works like a factory.&lt;/p&gt;

&lt;p&gt;The repository functions as a build factory. For Linux, it performs a native build using bundled dependencies. Conversely, for Windows, it initiates a legacy environment to build the executable and bundle essential DLLs (such as libgcc and libstdc++).&lt;/p&gt;

&lt;p&gt;The pipeline handles the automatic zipping and uploading of these builds as a release. This makes a fully playable, modern-compatible version of Fiend readily available for download, allowing anyone to use it without the need for compilation.&lt;/p&gt;

&lt;h2&gt;
  
  
  7 - Conclusion
&lt;/h2&gt;

&lt;p&gt;So this conclude the process of how I restored the source code of the game “Fiend”. This was a highly enjoyable project that successfully refreshed my memory on various low-level concepts crucial for many programmers. Although I am sure that I may have missed some other interesting facts, I believe I grasped the most interesting points of the hole process.&lt;/p&gt;

&lt;p&gt;To end this post I would like to answer a few questions that you may have about the project&lt;/p&gt;

&lt;h3&gt;
  
  
  How long did it took you to finish this project?
&lt;/h3&gt;

&lt;p&gt;The project's completion time was approximately 50 days, or about a month and a half. However, as I took some breaks throughout the process, the precise number of working days is unknown.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where did you get the original source code?
&lt;/h3&gt;

&lt;p&gt;The original, unpatched code, was published by someone on Github, and can be found &lt;a href="https://github.com/arvidfm/fiend" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Please note this is the broken version and does not contain my necessary fixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where I can download the game?
&lt;/h3&gt;

&lt;p&gt;The modified source code and game binaries cannot be released at this time because the original 2001 license only allows for the game's distribution "in its original form."&lt;/p&gt;

&lt;p&gt;I did find a repository claiming to allow "redistribution and use in source and binary forms, with or without modifications." However, the validity of this claim is uncertain, as it is not an official Frictional Games repository, nor does the individual who posted it appear to be affiliated with Frictional Games.&lt;/p&gt;

&lt;p&gt;I have reached out to Thomas Grip (Frictional Games) to request permission to share this modernized port with the world. Until then, this post serves as a record of my journey into making this port.&lt;/p&gt;

&lt;p&gt;Fingers crossed that we can bring &lt;em&gt;Fiend&lt;/em&gt; back to the public soon! I will share any new project updates in a subsequent post here.&lt;/p&gt;

&lt;p&gt;But that's about it, thank you for reading, and have a nice day!&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>c</category>
      <category>programming</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
