Skip to content

Commit

Permalink
chore: Documentation update
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzzybinary committed Sep 8, 2024
1 parent b80cc8e commit 1ddf3ef
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 115 deletions.
42 changes: 29 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ The rest of this document helps me / you understand how to build the extension.

### Updating the Dart SDK

Currently, the Dart SDK Windows dll included in the repo is Dart 2.19.4. You can
Currently, the Dart SDK dynamic libraries are included in the repo, currently using Dart 3.5. You can
update this by building the
[dart_shared_library](https:/fuzzybinary/dart_shared_library) repo
and copying the dlls to the example directory (`/simple`).
and copying files to `src/dart_skk/bin` directory. Alternately, you can get the artifacts compiled
from the Github action on each release.

### Updating FFI Bindings

The files in `godot-headers/godot` are from the 4.0.2 release of Godot. If you
working on a different version of Godot post Godot 4.0.2, you will need to
generate those files as explained in the [Godot
documentation](https:/godotengine/godot-cpp/tree/master/gdextension).
This repo uses (godot-cpp)[https:/godotengine/godot-cpp/] to make working with GDExtension
easier. This is included as a submodule at `./godot-cpp` and includes both the GDExtension
header as well as the GDExtension API json file.

Once you have the files, you can generate the FFI bindings using Dart's ffigen
tool. From the `/src/dart` directory run:
To update to more recent versions of `godot-cpp` or GDExtension, checkout a more recent version of `godot-cpp`
and generate the FFI bindings using Dart's ffigen tool.

From the `/src/dart` directory run:

```bash
dart run ffigen
Expand All @@ -33,18 +35,32 @@ This will regenerate `/dart/lib/src/core/gdextension_ffi_bindings.dart`

### Regenerating Class Files

The `binding_generator` tool held in the `tools` directory generates the rest of
the library's generated source files from
`godot-headers/godot/extension_api.json`. It can be run from the
`tools/binding_generator` directory with:
The `binding_generator` tool held `tools/binding_generator` directory generates the rest of
the library's generated source files from `godot-coo/gdextension/extension_api.json`.
It can be run from the `tools/binding_generator` directory with:

```bash
dart ./bin/binding_generator.dart
```

For now this generator takes no options, but it potentially will take options in
For now, this generator takes no options, but it potentially will take options in
the future.

### Building

Building the C++ source uses CMake. The following is the easiest way to build the required dynamic
libraries needed to work with Godot Dart.

From `./src/cpp`:

```bash
cmake -DCMAKE_BUILD_TYPE=Release . -B "build"
cmake --build build --config release
```

This will put the dynamic library into `./src/cpp/build/` (under `Release` on Windows). It will also copy
the required files to `./example/2d_tutorial` for your convenience.

## Other Stuff

For code formating, please use `dartfmt` and the provided `.clangformat` files.
201 changes: 99 additions & 102 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ And I want to use it in Godot.

# Current State

> [!WARNING]
> The current `master` branch of this extension is unstable after a massive rewrite of `Variant` that is ongoing.
> [!NOTE]
> This extension is compatible with Godot 4.2+
Expand All @@ -23,61 +20,101 @@ working, 🟨 - Partially working, ❌ - Not working)
| Dart as a Godot Extension Language | 🟨 | |
| Dart Debugging Extension || Attach to `http://127.0.0.1:5858` |
| Dart Available as a Scripting Language | 🟨 | Very early implementation |
| Hot Reload | | |
| Hot Reload | | Reloading from Godot will reload the Dart module. |
| Simplified Binding using build_runner | 🟨 | Early implementation |
| Dart native Variants || Needed for performance reasons |
| Memory efficiency / Leak prevention || |
| Memory efficiency / Leak prevention || All RefCounted objects appear to be working correclty. |
| Godot Editor inspector integration || |
| Godot Editor -> Dart LSP Integration || |
| Dart Macro Support || |

# Setup

Some notes about the current state:
* The binding is likely leaking both Dart objects and native allocations. I
intend on making a pass through to make sure all of that is cleaned up at some
point and correctly utilizes native finalizers.
You can now download a usable extension zip from out [Github Actions](https:/fuzzybinary/dart_shared_library/actions).

# Using
Unzip this into a Godot project, then run `dart pub get` in the `./src` directory before relaunching Godot.

> [!NOTE]
> This extension is compatible with Godot 4.2+ x64 and has been tested for Linux and Windows

## Things you will need

* A clone of this repo.
* Dart 3.0 stable
* Godot 4.2.x - Note above the pending pull request.
* A build of the [Dart Shared
Library](https:/fuzzybinary/dart_shared_libray). Windows x64 .dlls
for Dart 3 are provided in `src/dart_dll/bin/win64`.
* CMake 3.21+

## Current Setup

To use the extension, you need to:

* Copy both your `dart_dll` dynamic library and the `godot_dart` dynamic library
to your project directory.
* Copy `example/2d_tutorial/example.gdextension` to your project directory (note
this is only configured for `windows.64` builds and will need to be modified
for any other OS).
* Create a `src` directory in your project directory to hold your Dart code.
This should be a proper Dart package, complete with a `pubspec.yaml` file. Add
a `main.dart` to this directory.
* Run the Binding Generator
```bash
# From tools/binding_generator
dart ./bin/binding_generator.dart
```
* Add a reference to the `godot_dart` package that is defined in `src/dart`. You
will need to use a path dependency for this for now.
* Add a `main` function to your `main.dart`. This is where you will register
your Godot classes
You should now be able to create Dart scripts from Godot.

You should now be able to write Dart code for Godot!
Note, I recommend editing your code in another IDE (I use VSCode) and have `build_runner` watching your code to regenerate the
required files on save. When you return to Godot, clicking `Reload` for the modified files will also trigger a Dart hot-reload,
and all of your properties will be available in the Godot editor.

# Setup From source

See [CONTRIBUTING.md](CONTRIBUTING.md)

# Using

Note there are two ways to use Dart with Godot: as an extension language and as
a Script language. Both are only partially implemented

### Dart classes as Extensions
## Dart classes as Scripts

Scripts require a little bit more setup, but can then be attached to exiting
nodes, just like any other GDScript. You should be able to create a Dart script
by using the "Attach Script" command in the editor. This will create the
necessary boilerplate for a Dart Script.

While not required, the easiest way to create a scripts is to use `build_runner`
and the `godot_dart_builder` package. After creating your script, run `build_runner`
and the necessary boilerplate will be generated.


```dart
// Include the <file>.g.dart with the generated code
part 'simple_script.g.dart';
// Generate the boilerplate for this object to be an accessible Godot script
@GodotScript()
class SimpleScript extends Sprite2D {
// Return the type info that was generated...
static TypeInfo get sTypeInfo => _$SimpleScriptTypeInfo();
// And provide an instance method to get the type info
@override
TypeInfo get typeInfo => SimpleScript.sTypeInfo;
// Required constructor
SimpleScript() : super();
// Second required contructor. Classes that are Scripts must have a named constructor
// called `withNonNullOwner`.
SimpleScript.withNonNullOwner(Pointer<Void> owner)
: super.withNonNullOwner(owner);
// You can export fields as properties
@GodotProperty()
int speed = 400
// Any method that needs to be seen by a signal needs to be exported
@GodotExport()
void onSignal() {
}
// Overridden virtuals are added automatically via build_runner
@override
void vReady() {}
@override
void vProcess(double delta) {}
}
```

`build_runner` will also generate a registration file that must be imported into your
`main.dart`, and its script resolver will need to be attached:

```dart
import 'godot_dart_scripts.g.dart';
void main() {
// ... other bindings
attachScriptResolver();
}
```

## Dart classes as Extensions

There are requirements for almost any Godot accessible Dart class. Here's a Simple
example class
Expand Down Expand Up @@ -138,70 +175,30 @@ void main() {
}
```

### Dart classes as Scripts
## Deviations from Godot code

Scripts require a little bit more setup, but can then be attached to exiting
nodes, just like any other GDScript. You should be able to create a Dart script
by using the "Attach Script" command in the editor. This will create the
necessary boilerplate for a Dart Script.
### Casting

While not required, the easiest way to create a scripts is to use `build_runner`
and the `godot_dart_builder` package. After creating your script, run `build_runner`
and the necessary boilerplate will be generated.
When you are working with a Godot object, do not use `is` or `as` to perform downcasting. This will
always fail because of how Godot extension works. Instead, use `.cast<T>`, which will return `null`
if the cast fails.

### Virtual functions

```dart
// Include the <file>.g.dart with the generated code
part 'simple_script.g.dart';
Godot prefixes virtual functions with `_`, which obviously Dart doesn't like. I wanted to have
these just remove the `_`, but this creates some conflicts with methods that have the same names.

// Generate the boilerplate for this object to be an accessible Godot script
@GodotScript()
class SimpleScript extends Sprite2D {
// Return the type info that was generated...
static TypeInfo get sTypeInfo => _$SimpleScriptTypeInfo();
// And provide an instance method to get the type info
@override
TypeInfo get typeInfo => SimpleScript.sTypeInfo;
// Required constructor
SimpleScript() : super();
So instead, Godot Dart prefixes all virtual methods with `v`.

// Second required contructor. Classes that are Scripts must have a named constructor
// called `withNonNullOwner`.
SimpleScript.withNonNullOwner(Pointer<Void> owner)
: super.withNonNullOwner(owner);
// You can export fields as properties
@GodotProperty()
int speed = 400
// Any method that needs to be seen by a signal needs to be exported
@GodotExport()
void onSignal() {
### Indirectly Calling Godot Functions

}
The Dart API uses `lowerPascalCase` instead of `snake_case` in GDScript/C++. Where possible, fields and getters/setters have been converted to properties. In general, the Dart Godot API strives to be as idiomatic as is reasonably possible.

// Overridden virtuals are added automatically via build_runner
@override
void vReady() {}
However, Godot still thinks of these methods as being named in `snake_case`, so if you are calling them by their name (for example)
when using `call`, `callDeferred`, `connect`, or `callGroup`, you need to use `snake_case` for the method name.

@override
void vProcess(double delta) {}
}
```

`build_runner` will also generate a registration file that must be imported into your
`main.dart`, and its script resolver will need to be attached:

```dart
import 'godot_dart_scripts.g.dart';
void main() {
// ... other bindings
attachScriptResolver();
}
```
Basically, if you defined the method, use `lowerPascalCase`. If Godot defined the method, use `snake_case`. And if Godot defined
the method and its virtual, use `_snake_case` instead of `vPascalCase` currently used in Dart.

# More Info

Expand Down

0 comments on commit 1ddf3ef

Please sign in to comment.