Skip to content

Commit

Permalink
feat: Support global classes in 4.3
Browse files Browse the repository at this point in the history
This also updates the full godot_cpp to 4.3, and fixes a minor issue with HotReload.
  • Loading branch information
fuzzybinary committed Sep 10, 2024
1 parent 1ddf3ef commit a3d2dd4
Show file tree
Hide file tree
Showing 24 changed files with 655 additions and 750 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ And I want to use it in Godot.
# Current State

> [!NOTE]
> This extension is compatible with Godot 4.2+
> This extension is compatible with Godot 4.2+. Global Classes require Godot 4.3

Here's a list of planned features and work still to be done ( ✅ - Seems to be
Expand Down
10 changes: 5 additions & 5 deletions example/2d_tutorial/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ config_version=5

config/name="simple"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.2", "Forward Plus")
config/features=PackedStringArray("4.3", "Forward Plus")
config/icon="res://icon.svg"

[display]
Expand All @@ -25,21 +25,21 @@ window/stretch/mode="canvas_items"

move_right={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_left={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_down={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
2 changes: 1 addition & 1 deletion godot-cpp
Submodule godot-cpp updated 138 files
4 changes: 2 additions & 2 deletions src/assets/src/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ environment:

dependencies:
ffi: ^2.0.1
godot_dart: ^0.2.0
godot_dart: ^0.3.0
collection: ^1.17.2

dev_dependencies:
lints: ^2.0.0
build_runner: ^2.3.3
godot_dart_build: ^0.1.0
godot_dart_build: ^0.2.0
33 changes: 33 additions & 0 deletions src/cpp/dart_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include <gdextension_interface.h>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/string_name.hpp>
#include <godot_cpp/classes/editor_file_system.hpp>
#include <godot_cpp/classes/editor_interface.hpp>


#include "dart_helpers.h"
#include "dart_instance_binding.h"
Expand Down Expand Up @@ -172,7 +175,27 @@ bool GodotDartBindings::initialize(const char *script_path, const char *package_
return true;
}

void GodotDartBindings::add_pending_reload(const godot::String &path) {
_pending_reloads.insert(path);
reload_code();
}

void GodotDartBindings::perform_pending_reloads() {
for (const auto &str : _pending_reloads) {
auto editor_interface = godot::EditorInterface::get_singleton();
if (editor_interface) {
editor_interface->get_resource_filesystem()->update_file(str);
}
}
_pending_reloads.clear();
}

void GodotDartBindings::reload_code() {
if (_is_reloading) {
return;
}

_is_reloading = true;
execute_on_dart_thread([&] {
DartBlockScope scope;

Expand Down Expand Up @@ -257,6 +280,16 @@ void GodotDartBindings::perform_frame_maintanance() {
// which we couldn't do while the finalizer was running.
perform_pending_ref_changes();

// If we're reloading, check to see if we're done.
if (_is_reloading) {
Dart_Handle root_library = Dart_HandleFromPersistent(_godot_dart_library);
DART_CHECK(dart_is_reloading, Dart_GetField(root_library, Dart_NewStringFromCString("_isReloading")), "Failed to get _isReloading");
Dart_BooleanValue(dart_is_reloading, &_is_reloading);
if (!_is_reloading) {
5 perform_pending_reloads();
}
}

uint64_t currentTime = Dart_TimelineGetMicros();
Dart_NotifyIdle(currentTime + 1000); // Idle for 1 ms... maybe more

Expand Down
10 changes: 8 additions & 2 deletions src/cpp/dart_bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <dart_api.h>
#include <gdextension_interface.h>
#include <godot_cpp/variant/string.hpp>

#include "dart_instance_binding.h"
#include "gde_dart_converters.h"
Expand All @@ -28,7 +29,7 @@ class GodotDartBindings {
}

explicit GodotDartBindings()
: _is_stopping(false), _fully_initialized(false), _pending_messages(0), _isolate(nullptr) {
: _is_stopping(false), _fully_initialized(false), _is_reloading(false), _pending_messages(0), _isolate(nullptr) {
}
~GodotDartBindings();

Expand All @@ -38,6 +39,7 @@ class GodotDartBindings {
}
void shutdown();

void add_pending_reload(const godot::String& path);
void reload_code();

void bind_method(const TypeInfo &bind_type, const char *method_name, const TypeInfo &ret_type_info,
Expand All @@ -61,6 +63,8 @@ class GodotDartBindings {
const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);

private:
void perform_pending_reloads();

static void bind_call(void *method_userdata, GDExtensionClassInstancePtr instance,
const GDExtensionConstVariantPtr *args, GDExtensionInt argument_count,
GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
Expand All @@ -70,12 +74,14 @@ class GodotDartBindings {
static GodotDartBindings *_instance;

public:
bool _fully_initialized;
bool _fully_initialized;
bool _is_stopping;
bool _is_reloading;
int32_t _pending_messages;
std::mutex _work_lock;
Dart_Isolate _isolate;
std::thread::id _isolate_current_thread;
std::set<godot::String> _pending_reloads;
std::set<DartGodotInstanceBinding *> _pending_ref_changes;

Dart_PersistentHandle _godot_dart_library;
Expand Down
9 changes: 8 additions & 1 deletion src/cpp/dart_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@
#define DART_CHECK_RET(var, expr, ret, message) \
Dart_Handle var = (expr); \
if (Dart_IsError(var)) { \
GD_PRINT_ERROR("GodotDart: " message ": "); \
GD_PRINT_ERROR("GodotDart: " message ": "); \
GD_PRINT_ERROR(Dart_GetError(var)); \
return ret; \
}

#define DART_CHECK(var, expr, message) DART_CHECK_RET(var, expr, , message)

#define DART_HANDLE_ERROR(var, message) \
if (Dart_IsError(var)) { \
GD_PRINT_ERROR("GodotDart: " message ": "); \
GD_PRINT_ERROR(Dart_GetError(var)); \
return; \
}

class DartBlockScope {

public:
Expand Down
4 changes: 2 additions & 2 deletions src/cpp/script/dart_resource_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ bool DartResourceFormatLoader::_recognize_path(const godot::String &path, const
godot::String DartResourceFormatLoader::_get_resource_type(const godot::String &path) const {
String extension = path.get_extension();

return extension == String(".dart") ? String("DartScript") : String();
return extension == String("dart") ? String("DartScript") : String();
}

godot::String DartResourceFormatLoader::_get_resource_script_class(const godot::String &path) const {
return String("DartScript");
return path.get_extension().to_lower() == "dart" ? godot::String("DartScript") : "";
}

bool DartResourceFormatLoader::_exists(const godot::String &path) const {
Expand Down
46 changes: 36 additions & 10 deletions src/cpp/script/dart_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/editor_file_system.hpp>
#include <godot_cpp/classes/editor_interface.hpp>

#include "../dart_bindings.h"

Expand All @@ -11,7 +13,7 @@

using namespace godot;

DartScript::DartScript() : _source_code(), _dart_type(nullptr), _script_info(nullptr) {
DartScript::DartScript() : _source_code(), _needs_refresh(false), _dart_type(nullptr), _script_info(nullptr) {
}

DartScript::~DartScript() {
Expand Down Expand Up @@ -239,7 +241,8 @@ godot::Error DartScript::_reload(bool keep_state) {
GodotDartBindings *bindings = GodotDartBindings::instance();

if (bindings != nullptr) {
bindings->reload_code();
bindings->add_pending_reload(_path);
_needs_refresh = true;
}

return godot::Error::OK;
Expand All @@ -261,11 +264,12 @@ godot::StringName DartScript::_get_instance_base_type() const {

Dart_Handle dart_type = Dart_HandleFromPersistent(_dart_type);
DART_CHECK(type_info, Dart_GetField(dart_type, Dart_NewStringFromCString("sTypeInfo")), "Failed getting type info");
DART_CHECK(dart_native_type_name, Dart_GetField(type_info, Dart_NewStringFromCString("nativeTypeName")), "Failed to get nativeTypeName");

DART_CHECK(dart_native_type_name, Dart_GetField(type_info, Dart_NewStringFromCString("nativeTypeName")),
"Failed to get nativeTypeName");

native_base_type = *(godot::StringName *)get_object_address(dart_native_type_name);
});

return native_base_type;
}

Expand All @@ -283,15 +287,36 @@ godot::Variant DartScript::_get_property_default_value(const godot::StringName &
}

godot::StringName DartScript::_get_global_name() const {
return godot::StringName();
WITH_SCRIPT_INFO(godot::StringName());

godot::StringName ret;

bindings->execute_on_dart_thread([&] {
DartBlockScope scope;

Dart_Handle dart_type = Dart_HandleFromPersistent(_dart_type);
DART_CHECK(type_info, Dart_GetField(dart_type, Dart_NewStringFromCString("sTypeInfo")), "Failed getting type info");
DART_CHECK(value, Dart_GetField(type_info, Dart_NewStringFromCString("isGlobalClass")),
"Failed to get isGlobalClass");
bool is_global = false;
Dart_BooleanValue(value, &is_global);
if (is_global) {
DART_CHECK(class_name, Dart_GetField(type_info, Dart_NewStringFromCString("className")),
"Failed getting class name from type info");
ret = *(godot::StringName *)get_object_address(class_name);
}
});

return ret;
}

void DartScript::load_from_disk(const godot::String &path) {
Ref<FileAccess> file = FileAccess::open(path, FileAccess::READ);
if (!file.is_null()) {
String text = file->get_as_text();
set_source_code(text);
file->close();
file->close();
_path = path;
}
}

Expand Down Expand Up @@ -340,7 +365,7 @@ void DartScript::refresh_type() const {
return;
}

if (_dart_type != nullptr) {
if (_dart_type != nullptr && !_needs_refresh) {
// Don't bother unless we've been asked to reload
return;
}
Expand All @@ -362,13 +387,14 @@ void DartScript::refresh_type() const {
DartScriptLanguage *language = DartScriptLanguage::instance();

String path = get_path();

Dart_Handle dart_type = language->get_type_for_script(path);
if (!Dart_IsNull(dart_type)) {
_dart_type = Dart_NewPersistentHandle(dart_type);
DART_CHECK(type_info, Dart_GetField(dart_type, Dart_NewStringFromCString("sTypeInfo")),
"Failed getting type info");
DART_CHECK(script_info, Dart_GetField(type_info, Dart_NewStringFromCString("scriptInfo")), "Failed to get scriptInfo");
DART_CHECK(script_info, Dart_GetField(type_info, Dart_NewStringFromCString("scriptInfo")),
"Failed to get scriptInfo");
if (script_info != nullptr) {
_script_info = Dart_NewPersistentHandle(script_info);

Expand Down
2 changes: 2 additions & 0 deletions src/cpp/script/dart_script.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class DartScript : public godot::ScriptExtension {
void refresh_type() const;

godot::String _source_code;
godot::String _path;
mutable bool _needs_refresh;
mutable godot::Ref<DartScript> _base_script;
mutable Dart_PersistentHandle _dart_type;
mutable Dart_PersistentHandle _script_info;
Expand Down
71 changes: 70 additions & 1 deletion src/cpp/script/dart_script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,76 @@ bool DartScriptLanguage::_handles_global_class_type(const godot::String &type) c
}

godot::Dictionary DartScriptLanguage::_get_global_class_name(const godot::String &path) const {
return godot::Dictionary();
godot::Dictionary ret{};

GodotDartBindings *bindings = GodotDartBindings::instance();
if (bindings == nullptr) {
return ret;
}

bindings->execute_on_dart_thread([&] {
DartBlockScope scope;

Dart_Handle dart_type = get_type_for_script(path);
if (Dart_IsNull(dart_type)) {
return;
}

// Some strings we're going to need a bunch during this call
Dart_Handle s_type_info_str = Dart_NewStringFromCString("sTypeInfo");
Dart_Handle is_global_class_str = Dart_NewStringFromCString("isGlobalClass");
Dart_Handle class_name_str = Dart_NewStringFromCString("className");

Dart_Handle args[] = {dart_type};
DART_CHECK(type_info, Dart_GetField(dart_type, s_type_info_str), "Failed getting type info");
DART_CHECK(value, Dart_GetField(type_info, is_global_class_str), "Failed to get global class value");
bool is_global = false;
Dart_BooleanValue(value, &is_global);
if (is_global) {

DART_CHECK(class_name, Dart_GetField(type_info, class_name_str), "Failed getting class name from type info");
godot::StringName gd_class_name = *(godot::StringName *)get_object_address(class_name);
ret["name"] = godot::String(gd_class_name);

DART_CHECK(native_type_name, Dart_GetField(type_info, Dart_NewStringFromCString("nativeTypeName")),
"Failed getting class name from type info");
godot::StringName gd_native_type_name = *(godot::StringName *)get_object_address(native_type_name);

// More overly used strings
Dart_Handle parent_type_str = Dart_NewStringFromCString("parentType");

Dart_Handle current_type_info = type_info;

bool found_base_type = false;

while (!found_base_type) {
DART_CHECK(parent_type, Dart_GetField(current_type_info, parent_type_str), "Failed getting parent type");
if (Dart_IsNull(parent_type)) {
break;
}
DART_CHECK(parent_type_info, Dart_GetField(parent_type, s_type_info_str), "Failed to get parent type info!");
DART_CHECK(value, Dart_GetField(parent_type_info, is_global_class_str), "Failed to get isGlobalClass from typeInfo!");
bool is_global = false;
Dart_BooleanValue(value, &is_global);

DART_CHECK(class_name, Dart_GetField(parent_type_info, class_name_str),
"Failed getting class name from type info");
godot::StringName gd_class_name = *(godot::StringName *)get_object_address(class_name);
if (gd_class_name == gd_native_type_name || is_global) {
found_base_type = true;
ret["base_type"] = godot::String(gd_class_name);
break;
}
current_type_info = parent_type_info;
}

if (!found_base_type) {
ret["base_type"] = godot::String(gd_native_type_name);
}
}
});

return ret;
}

void DartScriptLanguage::attach_type_resolver(Dart_Handle resolver) {
Expand Down
Loading

0 comments on commit a3d2dd4

Please sign in to comment.