Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/shaggy-sloths-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@godot-js/editor": minor
---

feat: Godot 4.7 (dev/pre-release) build.
13 changes: 6 additions & 7 deletions .github/workflows/runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ jobs:
- version: 4.6.1
version_mm: 4.6
version_ref: 4.6.1-stable
# - version: 4.7dev
# version_mm: 4.7
# version_ref: master
- version: 4.7dev
version_mm: 4.7
version_ref: master
uses: ./.github/workflows/build_engine_version.yml
with:
version: ${{ matrix.version }}
Expand All @@ -56,7 +56,7 @@ jobs:
matrix:
include:
- version: 4.6.1
# - version: 4.7dev
- version: 4.7dev
with:
version: ${{ matrix.version }}

Expand All @@ -79,8 +79,7 @@ jobs:
uses: ./.github/workflows/misc_release.yml
secrets: inherit
with:
versions: '4.6.1'
# versions: '4.6.1, 4.7'
versions: '4.6.1, 4.7'

upload-assets:
name: 📁 Upload Assets
Expand All @@ -95,6 +94,6 @@ jobs:
matrix:
include:
- version: 4.6.1
# - version: 4.7dev
- version: 4.7dev
with:
version: ${{ matrix.version }}
237 changes: 106 additions & 131 deletions bridge/jsb_editor_utility_funcs.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bridge/jsb_environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@

void Environment::init()
{
jsb::DefaultModuleResolver& resolver = this->add_module_resolver<jsb::DefaultModuleResolver>()

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🍎 macOS / Mac (editor, qjs-ng)

unused variable 'resolver'

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🤖 Android / Android (template_debug, qjs-ng)

unused variable 'resolver'

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🌐 Web / Web (template_debug, qjs-ng, threads=yes, dlink=no)

unused variable 'resolver'

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🏁 Windows / Windows (editor, qjs-ng)

'resolver': local variable is initialized but not referenced

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🍏 iOS / iOS (template_debug, qjs-ng)

unused variable 'resolver'

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🏁 Windows / Windows (editor, v8)

'resolver': local variable is initialized but not referenced

Check warning on line 444 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🌐 Web / Web (template_debug, browser, threads=yes, dlink=no)

unused variable 'resolver'
.add_search_path(jsb::internal::Settings::get_jsb_out_res_path()) // default path of js source (results of compiled ts, at '.godot/GodotJS' by default)
.add_search_path("res://") // use the root directory as custom lib path by default
.add_search_path("res://node_modules") // so far, it's the only supported path for node_modules in GodotJS
Expand Down Expand Up @@ -676,7 +676,7 @@

void _invoke(Environment* p_env, const v8::Local<v8::Context>& p_context, const v8::Local<v8::Function>& p_callback, const Message* p_message)
{
v8::Isolate *isolate = p_env->get_isolate();

Check warning on line 679 in bridge/jsb_environment.cpp

View workflow job for this annotation

GitHub Actions / ⚙️ Build Godot Version with GodotJS (4.6.1, 4.6, 4.6.1-stable) / 🌐 Web / Web (template_debug, browser, threads=yes, dlink=no)

unused variable 'isolate'

#if !JSB_WITH_WEB && !JSB_WITH_JAVASCRIPTCORE
v8::Local<v8::Value> value;
Expand Down Expand Up @@ -1525,7 +1525,7 @@
return nullptr;
}

String class_name = internal::NamingUtil::get_class_name(p_class_info->name);
String class_name = internal::NamingUtil::get_class_name(internal::ClassUtil::get_internal_class_name(*p_class_info));

if (const NativeClassID* it = godot_classes_index_.getptr(class_name))
{
Expand Down
42 changes: 21 additions & 21 deletions bridge/jsb_object_bindings.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "jsb_object_bindings.h"
#include "jsb_transpiler.h"
#include "jsb_type_convert.h"
#include "../internal/jsb_class_util.h"
// TODO: Refactor. Violates isolation of bridge.
#include "../weaver/jsb_script_instance.h"
#include "../weaver/jsb_script_language.h"
Expand All @@ -14,17 +15,18 @@ namespace jsb

jsb_check(p_class_info);

String class_name = internal::NamingUtil::get_class_name(p_class_info->name);
const StringName& internal_class_name = internal::ClassUtil::get_internal_class_name(*p_class_info);
String class_name = internal::NamingUtil::get_class_name(internal_class_name);
const NativeClassID class_id = p_env->add_native_class(NativeClassType::GodotObject, class_name);
JSB_LOG(VeryVerbose, "expose godot type %s(%d) as %s", p_class_info->name, class_id, class_name);
JSB_LOG(VeryVerbose, "expose godot type %s(%d) as %s", internal_class_name, class_id, class_name);

// construct type template
{

impl::ClassBuilder class_builder = ObjectTemplate::create(p_env, class_id);

//NOTE all singleton object will overwrite the class itself in 'godot' module, so we need make all things defined on PrototypeTemplate.
const bool is_singleton_class = Engine::get_singleton()->has_singleton(p_class_info->name);
const bool is_singleton_class = Engine::get_singleton()->has_singleton(internal_class_name);
auto static_builder = is_singleton_class ? class_builder.Instance() : class_builder.Static();

#if JSB_EXCLUDE_GETSET_METHODS
Expand Down Expand Up @@ -85,14 +87,14 @@ namespace jsb
}
}

if (p_class_info->name == jsb_string_name(Object))
if (internal_class_name == jsb_string_name(Object))
{
// class: special methods
class_builder.Instance().Method(jsb_literal(free), _godot_object_free);
}

// class: signals
for (const KeyValue<StringName, MethodInfo>& pair : p_class_info->signal_map)
for (auto& pair : internal::ClassUtil::get_class_signal_map(*p_class_info))
{
v8::HandleScope handle_scope_for_signal(isolate);
String signal_name = internal::NamingUtil::get_member_name(pair.key);
Expand All @@ -103,23 +105,21 @@ namespace jsb
HashSet<StringName> enum_consts;

// class: enum (nested in class)
for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo>& pair : p_class_info->enum_map)
{
internal::ClassUtil::for_class_enums(*p_class_info, [&](const StringName& enum_name, const internal::ClassEnumInfo& enum_info) {
v8::HandleScope handle_scope_for_enum(isolate);
impl::ClassBuilder::EnumDeclaration enumeration = static_builder.Enum(internal::NamingUtil::get_enum_name(pair.key));
for (const StringName& enum_value_name : pair.value.constants)
{
const String& js_enum_name = internal::NamingUtil::get_enum_value_name(enum_value_name);
impl::ClassBuilder::EnumDeclaration enumeration = static_builder.Enum(internal::NamingUtil::get_enum_name(enum_name));

const internal::ClassConstantMap& enum_map = internal::ClassUtil::get_class_enum_constants(*p_class_info, enum_name);
internal::ClassUtil::for_enum_internal_names(enum_info, [&](const StringName& internal_name) {
const String& js_enum_name = internal::NamingUtil::get_enum_value_name(internal_name);
jsb_not_implemented(js_enum_name.contains("."), "hierarchically nested definition is currently not supported");
const auto& const_it = p_class_info->constant_map.find(enum_value_name);
jsb_check(const_it);
enumeration.Value(js_enum_name, const_it->value);
enum_consts.insert(enum_value_name);
}
}
enumeration.Value(js_enum_name, enum_map[internal_name]);
enum_consts.insert(internal_name);
});
});

// class: constants
for (const KeyValue<StringName, int64_t>& pair : p_class_info->constant_map)
for (const KeyValue<StringName, int64_t>& pair : internal::ClassUtil::get_class_constant_map(*p_class_info))
{
if (enum_consts.has(pair.key)) continue;
const String& js_const_name = (String) internal::NamingUtil::get_constant_name(pair.key);
Expand All @@ -138,7 +138,7 @@ namespace jsb
// It's safe to expect that the base class is fully built,
// because single inheritance is used in Godot (which means a reflect_bind class will only be accessed until it's fully built).
class_builder.Inherit(super_class_info->clazz);
JSB_LOG(VeryVerbose, "%s (%d) extends %s (%d)", p_class_info->name, class_id, p_class_info->inherits_ptr->name, super_class_id);
JSB_LOG(VeryVerbose, "%s (%d) extends %s (%d)", internal_class_name, class_id, internal::ClassUtil::get_class_super_type_internal_name(*p_class_info), super_class_id);
}

// preparation for return
Expand All @@ -147,8 +147,8 @@ namespace jsb

class_info->clazz = class_builder.Build();
jsb_check(!class_info->clazz.IsEmpty());
jsb_check(class_info->name == internal::NamingUtil::get_class_name(p_class_info->name));
JSB_LOG(VeryVerbose, "build class info %s (%d) exposed as %s, addr: %s", p_class_info->name, class_id, class_info->name, class_info.ptr());
jsb_check(class_info->name == internal::NamingUtil::get_class_name(internal_class_name));
JSB_LOG(VeryVerbose, "build class info %s (%d) exposed as %s, addr: %s", internal_class_name, class_id, class_info->name, class_info.ptr());
if (r_class_id) *r_class_id = class_id;
return class_info;
}
Expand Down
136 changes: 136 additions & 0 deletions internal/jsb_class_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@

namespace jsb::internal
{

#if GODOT_4_6_OR_NEWER
using ClassConstantMap = AHashMap<StringName, int64_t>;
#else
using ClassConstantMap = HashMap<StringName, int64_t>;
#endif

#if GODOT_4_7_OR_NEWER
using ClassEnumInfo = GDType::EnumInfo;
#else
using ClassEnumInfo = ClassDB::ClassInfo::EnumInfo;
#endif

#if GODOT_4_7_OR_NEWER
using ClassSignalMap = AHashMap<StringName, const MethodInfo*>;
#elif GODOT_4_6_OR_NEWER
using ClassSignalMap = AHashMap<StringName, MethodInfo>;
#else
using ClassSignalMap = HashMap<StringName, MethodInfo>;
#endif

struct ClassUtil
{
// jsb_force_inline static bool check_class(const StringName& p_class_name, const StringName& p_expected_class_name)
Expand All @@ -18,6 +39,121 @@ namespace jsb::internal
// return get_method_info_recursively(*p_class_info.inherits_ptr, method_name);
// }

template <typename T>
static constexpr decltype(auto) get_value(T&& arg)
{
if constexpr (std::is_pointer_v<std::remove_reference_t<T>>)
{
return *arg;
}
else
{
return std::forward<T>(arg);
}
}

#if GODOT_4_7_OR_NEWER

static const StringName& get_internal_class_name(const ClassDB::ClassInfo& class_info)
{
return class_info.gdtype->get_name();
}

template <typename Lambda>
static void for_enum_internal_names(const ClassEnumInfo &enum_info, Lambda callback)
{
for (auto it = enum_info.values.begin(); it != enum_info.values.end(); ++it)
{
callback(it->key);
}
}

template <typename Lambda>
static void for_class_enums(const ClassDB::ClassInfo& class_info, Lambda callback)
{
for (auto it : class_info.gdtype->get_enum_map(true))
{
callback(it.key, *it.value);
}
}

static const ClassConstantMap& get_class_constant_map(const ClassDB::ClassInfo& class_info)
{
return class_info.gdtype->get_integer_constant_map(true);
}

static const AHashMap<StringName, const ClassEnumInfo*>& get_class_enum_map(const ClassDB::ClassInfo& class_info)
{
return class_info.gdtype->get_enum_map(true);
}

static const ClassSignalMap& get_class_signal_map(const ClassDB::ClassInfo& class_info)
{
return class_info.gdtype->get_signal_map(true);
}

static const ClassConstantMap& get_class_enum_constants(const ClassDB::ClassInfo& class_info, const StringName& enum_name)
{
return class_info.gdtype->get_enum_map(true)[enum_name]->values;
}

static String get_class_super_type_internal_name(const ClassDB::ClassInfo& class_info)
{
return class_info.gdtype->get_super_type_name();
}

#else

static constexpr const StringName& get_internal_class_name(const ClassDB::ClassInfo& class_info)
{
return class_info.name;
}

template <typename Lambda>
static void for_enum_internal_names(const ClassEnumInfo &enum_info, Lambda callback)
{
for (List<StringName>::ConstIterator it = enum_info.constants.begin(); it != enum_info.constants.end(); ++it)
{
callback(*it);
}
}

template <typename Lambda>
static void for_class_enums(const ClassDB::ClassInfo& class_info, Lambda callback)
{
for (auto it : class_info.enum_map)
{
callback(it.key, it.value);
}
}

static const ClassConstantMap& get_class_constant_map(const ClassDB::ClassInfo& class_info)
{
return class_info.constant_map;
}

static const HashMap<StringName, ClassEnumInfo>& get_class_enum_map(const ClassDB::ClassInfo& class_info)
{
return class_info.enum_map;
}

static const ClassSignalMap& get_class_signal_map(const ClassDB::ClassInfo& class_info)
{
return class_info.signal_map;
}

static const ClassConstantMap& get_class_enum_constants(const ClassDB::ClassInfo& class_info, const StringName& _enum_name)
{
return class_info.constant_map;
}

static String get_class_super_type_internal_name(const ClassDB::ClassInfo& class_info)
{
return class_info.inherits;
}

#endif

};
}
#endif
3 changes: 1 addition & 2 deletions tests/test_jsb_any_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ console.assert(!gd.is_instance_valid(inst));

TEST_CASE("[jsb] RefCounted objects")
{
WeakRef* weak_ref = memnew(WeakRef);
Ref<WeakRef> weak_ref = memnew(WeakRef);
{
GodotJSScriptLanguageIniter initer;

Expand Down Expand Up @@ -535,7 +535,6 @@ file = undefined;
}
// There is no strong reference anymore, therefore the FileAccess object should have been deleted by JS GC.
CHECK(weak_ref->get_ref().is_null());
memdelete(weak_ref);
}
}

Expand Down
12 changes: 11 additions & 1 deletion weaver-editor/jsb_editor_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,12 @@ Dictionary GodotJSEditorHelper::_build_node_type_descriptor(jsb::JSEnvironment&

if (animation_mixer)
{
#if GODOT_4_7_OR_NEWER
LocalVector<StringName> library_names;
#else
List<StringName> library_names;
#endif

animation_mixer->get_animation_library_list(&library_names);

Dictionary animation_libraries_object_literal;
Expand All @@ -173,7 +178,12 @@ Dictionary GodotJSEditorHelper::_build_node_type_descriptor(jsb::JSEnvironment&

Array animation_names_union_array;

#if GODOT_4_7_OR_NEWER
LocalVector<StringName> animation_names;
#else
List<StringName> animation_names;
#endif

library->get_animation_list(&animation_names);

for (const StringName& animation_name : animation_names)
Expand Down Expand Up @@ -316,7 +326,7 @@ Dictionary GodotJSEditorHelper::get_resource_type_descriptor(const String& p_pat
return descriptor;
}

PackedScene* scene = Object::cast_to<PackedScene>(resource.ptr());
PackedScene* scene = Object::cast_to<PackedScene>(resource.ptr());

if (scene)
{
Expand Down
2 changes: 1 addition & 1 deletion weaver-editor/jsb_export_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class GodotJSExportPlugin: public EditorExportPlugin
virtual String get_name() const override;
virtual bool supports_platform(const Ref<EditorExportPlatform>& p_export_platform) const override;

static const HashSet<String> get_ignored_paths() { return ignored_paths_; }
static const HashSet<String>& get_ignored_paths() { return ignored_paths_; }

protected:
virtual void _export_begin(const HashSet<String>& p_features, bool p_debug, const String& p_path, int p_flags) override;
Expand Down
Loading