Forgive me Odin for I have sinned. Along with the creation of this repo I have summoned the deep inheritance system of a C++ application. Some will be shallow, some will be 7 layers deep. Most will create a system of triple procedure jumps. For that is the nature of interop with a game engine built up using a node system. Although I may have faltered I will not fall. Code which is used for Odin within Odin will remain pure. Standing strong on their own as they proceed through their lifetime within the applications they will reside within. Until the day of Ragnarok where all memory will be wiped.
This repo is to provide a wrapper and userspace in order to work with Godot's API. The goal is to avoid the need to preprocess the code and simply write what you need. The userspace starts at the Toxin package.
It may be better to work with Godot in a different manner. If you'd like to forge your own path you can start from the GD+Classes Package and the GDWrapper layer.
This latest version is not thoroughly tested. This is available in main so that I can work on it while building an actual Godot project separately.
Current features include :
- entry point is included in Toxin package
- MainLoop callbacks initilized and be overridden
- Create custom class
- Create Signals
- Connect to Signals
- Convert to-from Godot's variants
- Define Godot's custom types
- Export class variables as Godot base types
- Parsers to create Builtins and Class files.
- Method Binds to all classes with their call signatures
stress-tests to verify performance
Feel free to make suggestions
Deprecated examples will not run unless the GDWrapper they were written with is included in their folder.
- Godot.
- Ideally compiled for debug mode to allow you to step through the code. (Godot only takes 5-10 minutes to compile.)
- Building Godot will require Python and scons...
- Set the path for Godot in your environment pointing to the compiled executable. In my build script I point to the exe itself because I have 2 versions of Godot... ** Performance is significantly impacted by a debug compilation of Godot.
- Odin-lang
- either run the classes_parser or download the classes package text
Import the GDWrapper folder into your code as you would any other package. Import the Toxin folder into your code. Import the GD_Classes folder into your code.
Make sure that the version you use is up to date with the version you want to method bind to. I have setup the method binds based on version 4.6.0 There is currently no version check in this package. //TODO: Check Version.
GDExtensions are a shared library with a single exported entry procedure. Godot will call that procedure and you should provide the pointers to references to the init procedures as well as save the ClassLibrary pointer which Godot shares with you. This is handled by Toxin.
- Some methods DO change on version changes. If you see a message from Godot stating that there is no fallback method it means that the method's hashid does not match what Godot expects it to be. Open an issue on Godot_Odin_Binds and I will update it.
- You will need to setup your own init procedure. You will need to provide Godot with the name of a proc that it will use as an entry point and set that proc as @(export).
- Entry proc is specified in the .gdextension file provided to Godot.
- Compile your Odin code as a dynamic library. Place it somewhere in the Godot project's folder alongside the .gdextension file.
- For exported builds you can either have the dll in the root folder or in the folder specified in the .gdextension file.
- Make sure the name of your dll matches what you specify in the .gdextension file. build.sh and build.cmd script changes the name and then copies it to a godot project folder based on what I'm working on. Update as needed.
In addition to the shared lib which you will compile, you will also need to provide Godot with the information about your shared lib in the form of a *.gdextension file. This can (apparently) be placed anywhere in the project file and must include:
- the file name of your GDExtension lib
- the procedure name of the exported procedure
- the types of builds that this extension should be loaded for and the different libs each version should use.
For more details on the *.gdextension file please check the official docs.
https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/gdextension_file.html
I recommend checking Godot's own documentation if you are trying to understand what methods and classes are needed in Godot in order to achieve a certain result. The c# examples are often fairly close to what you will want to do. It's not a perfect match but it's better than C++ code examples which have a lot of magic behind the steps they take. C++'s extension seems to do a lot of work processing files to add the necessary extra bindings that Godot needs. C# is a bit more direct.
Sometimes it's difficult to find the exact correct page of Godot Docs you want/need so I've done my best to include links to those pages when I remember to. (for example render server doesn't find the page I want but renderingserver does.)
There is a templates folder which contains the barebones configs to get an extension up and running with a custom class. (excluding the GDWrapper package)
DEFINITELY get this setup if you're having bugs and don't know why. Stepping through what Godot does is a lot easier to figure out than trying to piece together the five different c++ files required to init one class or variable. Also helps when matching pointer mem locations.
VSCode Setup instructions. Requires building from source : https://godotforums.org/d/32073-debug-c-gdextension/16 (Sia2005's comment adds more context) https://www.reddit.com/r/godot/comments/11d56t1/gdextension_how_to_get_debugger_working_when/
The project includes a .vscode folder which has the current debug launch configs I'm using. There is also build.cmd which has the compilation steps in addition to the steps to rename and move the built shared lib to a corresponding project folder which would be the Godot game project folder.
Debugging will work with Raddebugger if you are on Windows
To keep myself somewhat sane. There's 1k classes in Godot. Separating those into individual files will mean nesting them all over and extra packages simply to manage the init procedures. That's not where the big work of getting Godot to play nice is.
- gdextension is the core bindings. They don't offer much because Godot does not expose much.
- gdAPI is an organization of those method signatures in order to fetch them. This is still barely anything because most are simply pointers to methods which fetch the correct methods.
- GDWrapper is where things start to take off. It sets up the builtin types and a few core helper functions to allow for simpler fetching of values. StringName compares, StringName creators, a procedure to fetch method binds.
- GD_Classes is just a list of all the classes, their constants, enums and an init procedure to generate all the methods they may or may not have. Check there for methods and virtuals supported by a class.
- Toxin will be the main userspace. Code there allows an easier way create a custom class, export types, signals etc.
Variant. A c++ class which represents a type. Examples are Float, Array, String.
PropertyHint. A combo of enum and string which tells Godot's editor how to handle a property. This does not affect behaviour in the Script.
Node. A 'thing' which can be included in a tree-like structure of inheritance.
Class. An encapsulation of data and procedures. A class exported to Godot to be 'exposed' will be available as a Node in Godot's editor and scripts.
Object. The most rudimentary Class in Godot.
Method. A method will refer to a function which is associated with one of Godot's C++ classes.
Bind. The act of importing or exporting something between the GDExtension library and Godot's.
MethodBind. A class that Godot has created which stores information about a method. This includes parameter info, class, and a pointer to the method. Part of this class handles calling the method.
Extend. Include an additional class into the one you are working with. This will provide access to all the public variables and methods.
Virtual. A Class method which uses data specific to a class instance. Often times these will be called automatically by Godot. For example the _process virtual method.
Signal. An event driven notification system to communicate an event between Nodes.
Connect. The act which sets a Node to listen for an event from a specific Signal.
Reference Count (RefCount). A Class which wraps around another Class in order to count the amount of times the Class has been passed to another Class as a pointer. Once RefCount hits 0 the Class and RefCounter are destroyed. Initializes at 1.
Singleton. A globally available class. Examples are RenderServer, Input, Engine.
Resource. A Class which contains and knows how to manage specific data. This could be a resource from disk or an engine resource such as the body of a physics object.
Resource ID. A runtime identifier to a Resource. This is not a pointer.
Callable. A method or procedure packaged in a struct which can be shared with other Classes at runtime. These callables are most often associated with Signals. There should be enough data on a Callable for Godot to call it.
Server. A system which controls a type of activity such as rendering, sound, etc.
MainLoop. The core loop which will call the servers and trigger the SceneTree.
SceneTree. The main structure which Scenes and Nodes are typically attached to.
GDScript. Godot's own scripting language. These are not compiled unless you turn them into tools.
StringName. A specially hashed string which is refCounted and stored in a its own bucket of memory. Often used as an identifier for unique entities such as classes or constants. Often abreviated to SN in this package.\
~
odin run odin_check
This will go through all the stress-test and unit_test files and do a compilation check. If this is successful, all the packages necessary to compile those projects are present in the expected path.
This does not run the actual tests.
~
run a project:
C:\Godot\Godot_v4.6-release.exe --path .\stress-test\spritebench_Odin
a project.godot file should be present in the specified folder.
open a project into the editor:
C:\Godot\Godot_v4.6-release.exe --path .\stress-test\spritebench_Odin --editor
a project.godot file should be present in the specified folder.
run a specific script: C:\Godot\Godot_v4.6-release.exe --path .\stress-test\spritebench_Odin -s .\node.gd will require that the script load the extension by referencing the .gdextension file relative path starts relative to the folder from --path
export example command: C:\Godot\Godot_v4.6-release.exe --path .\TopDown --export-release "Windows Desktop" C:\Godot\testExport\sprite_bench.exe --headless Godot will move the shared lib into the root of the export folder. If Godot is able to access your shared lib based on the filepath of the project you're building, it will move it to the export root along with the exe. Otherwise there will be an error stating that it could not find the file. It does not seem to create any sort of folders for you, but if you create the folder structure specified in the .gdextention file and move the shared file into the new folder this will still work.
- If you move the file to an unexpected location Godot will not be able to find it.
- if you move the shared lib to a /bin folder Godot will find it even if this wasn't where you specified
- if you move the shared lib to a folder that matches the relative path described in gdextension Godot will find it.
- If you did a res:/../ you just went up a folder and now need to put your dll in the folder above your exe. If your path was res://../bin you need to create a bin folder in the folder above the folder containing your exe.. Just don't do this. >.>
- with the .dll in the same folder as your .exe Godot finds and loads it.
Best practice is to put your GDE binaries in a bin folder in your project's root folder. Target that folder with -out: during your build.