From 2c2eae2991d8b03262dc8f5e0108b0dfde5eb745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Gschwind?= Date: Sat, 11 Jan 2025 21:27:47 +0100 Subject: [PATCH 01/11] Make SGodotJScriptLanguage static singleton within register_types.cpp --- register_types.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/register_types.cpp b/register_types.cpp index 17b55ad4..23d0a076 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -12,6 +12,7 @@ #include "weaver-editor/jsb_export_plugin.h" #endif +static GodotJSScriptLanguage* script_language_js; static Ref resource_loader_js; static Ref resource_saver_js; @@ -24,7 +25,7 @@ void jsb_initialize_module(ModuleInitializationLevel p_level) jsb::impl::GlobalInitialize::init(); // register javascript language - GodotJSScriptLanguage* script_language_js = memnew(GodotJSScriptLanguage()); + script_language_js = memnew(GodotJSScriptLanguage()); ScriptServer::register_language(script_language_js); resource_loader_js.instantiate(); @@ -59,7 +60,6 @@ void jsb_uninitialize_module(ModuleInitializationLevel p_level) ResourceSaver::remove_resource_format_saver(resource_saver_js); resource_saver_js.unref(); - GodotJSScriptLanguage *script_language_js = GodotJSScriptLanguage::get_singleton(); jsb_check(script_language_js); ScriptServer::unregister_language(script_language_js); memdelete(script_language_js); From 66e5a586ba981d72732b5066e16bf62ab909ba93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Gschwind?= Date: Sat, 11 Jan 2025 22:35:30 +0100 Subject: [PATCH 02/11] Rewrite ResourceLoader loader to support several languages --- register_types.cpp | 12 +++++---- weaver/jsb_resource_loader.cpp | 47 +++++++++++++++++++++++++++------- weaver/jsb_resource_loader.h | 12 +++++++++ 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/register_types.cpp b/register_types.cpp index 23d0a076..186b6887 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -13,7 +13,7 @@ #endif static GodotJSScriptLanguage* script_language_js; -static Ref resource_loader_js; +static Ref resource_loader; static Ref resource_saver_js; void jsb_initialize_module(ModuleInitializationLevel p_level) @@ -28,8 +28,10 @@ void jsb_initialize_module(ModuleInitializationLevel p_level) script_language_js = memnew(GodotJSScriptLanguage()); ScriptServer::register_language(script_language_js); - resource_loader_js.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_js); + resource_loader.instantiate(); + resource_loader->register_resource_extension(JSB_TYPESCRIPT_EXT, script_language_js); + resource_loader->register_resource_extension(JSB_JAVASCRIPT_EXT, script_language_js); + ResourceLoader::add_resource_format_loader(resource_loader); resource_saver_js.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_js); @@ -54,8 +56,8 @@ void jsb_uninitialize_module(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_CORE) { - ResourceLoader::remove_resource_format_loader(resource_loader_js); - resource_loader_js.unref(); + ResourceLoader::remove_resource_format_loader(resource_loader); + resource_loader.unref(); ResourceSaver::remove_resource_format_saver(resource_saver_js); resource_saver_js.unref(); diff --git a/weaver/jsb_resource_loader.cpp b/weaver/jsb_resource_loader.cpp index 56fd584d..48cc7a68 100644 --- a/weaver/jsb_resource_loader.cpp +++ b/weaver/jsb_resource_loader.cpp @@ -3,14 +3,33 @@ #include "jsb_script_language.h" #include "jsb_script.h" + +void ResourceFormatLoaderGodotJSScript::register_resource_extension(String ext, GodotJSScriptLanguage * lang) +{ + lang_map_.insert(ext, lang); +} + Ref ResourceFormatLoaderGodotJSScript::load(const String& p_path, const String& p_original_path, Error* r_error, bool p_use_sub_threads, float* r_progress, CacheMode p_cache_mode) { JSB_BENCHMARK_SCOPE(ResourceFormatLoaderGodotJSScript, load); + GodotJSScriptLanguage * lang = nullptr; + for (auto const & i: lang_map_) { + if (p_path.ends_with(i.key)) { + lang = i.value; + break; + } + } + + if (!lang) { + if (r_error) *r_error = ERR_FILE_UNRECOGNIZED; + return {}; + } + { //TODO a dirty but approaching solution for hot-reloading - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); - SelfList *elem = GodotJSScriptLanguage::singleton_->script_list_.first(); + MutexLock lock(lang->mutex_); + SelfList *elem = lang->script_list_.first(); while (elem) { if (elem->self()->get_path() == p_path) @@ -33,7 +52,6 @@ Ref ResourceFormatLoaderGodotJSScript::load(const String& p_path, cons return {}; } #endif - jsb_check(p_path.ends_with(JSB_TYPESCRIPT_EXT) || p_path.ends_with(JSB_JAVASCRIPT_EXT)); // in case `node_modules` is not ignored (which is not expected though), we do not want any GodotJSScript to be generated from it. if (p_path.begins_with("res://node_modules")) @@ -41,6 +59,7 @@ Ref ResourceFormatLoaderGodotJSScript::load(const String& p_path, cons if (r_error) *r_error = ERR_CANT_RESOLVE; return {}; } + // exclude this extension if (p_path.ends_with("." JSB_DTS_EXT)) { if (r_error) *r_error = ERR_FILE_UNRECOGNIZED; @@ -49,8 +68,7 @@ Ref ResourceFormatLoaderGodotJSScript::load(const String& p_path, cons JSB_LOG(VeryVerbose, "loading script resource %s on thread %s", p_path, uitos(Thread::get_caller_id())); // return a skeleton script which only contains path and source code without actually loaded in `realm` since `load` may called from background threads - Ref spt; - spt.instantiate(); + Ref spt = reinterpret_cast(lang->create_script()); spt->attach_source(p_path); if (r_error) *r_error = OK; return spt; @@ -58,19 +76,30 @@ Ref ResourceFormatLoaderGodotJSScript::load(const String& p_path, cons void ResourceFormatLoaderGodotJSScript::get_recognized_extensions(List* p_extensions) const { - p_extensions->push_back(JSB_TYPESCRIPT_EXT); - p_extensions->push_back(JSB_JAVASCRIPT_EXT); + for (auto const & i: lang_map_) { + p_extensions->push_back(i.key); + } } bool ResourceFormatLoaderGodotJSScript::handles_type(const String& p_type) const { - return (p_type == "Script" || p_type == jsb_typename(GodotJSScript)); + if (p_type == "Script") + return true; + for (auto const & i: lang_map_) { + if (p_type == i.value->get_type()) + return true; + } + return false; } String ResourceFormatLoaderGodotJSScript::get_resource_type(const String& p_path) const { const String el = p_path.get_extension().to_lower(); - return (el == JSB_TYPESCRIPT_EXT || el == JSB_JAVASCRIPT_EXT) ? jsb_typename(GodotJSScript) : ""; + for (auto const & i: lang_map_) { + if (el == i.key) + return i.value->get_type(); + } + return ""; } void ResourceFormatLoaderGodotJSScript::get_dependencies(const String& p_path, List* p_dependencies, bool p_add_types) diff --git a/weaver/jsb_resource_loader.h b/weaver/jsb_resource_loader.h index b695900d..2aa3fd61 100644 --- a/weaver/jsb_resource_loader.h +++ b/weaver/jsb_resource_loader.h @@ -3,9 +3,21 @@ #include "core/io/resource_loader.h" +#include "jsb_script_language.h" + class ResourceFormatLoaderGodotJSScript : public ResourceFormatLoader { + + ResourceFormatLoaderGodotJSScript(ResourceFormatLoaderGodotJSScript const &) = delete; + ResourceFormatLoaderGodotJSScript & operator=(ResourceFormatLoaderGodotJSScript const &) = delete; + + HashMap lang_map_; + public: + ResourceFormatLoaderGodotJSScript() { } + + void register_resource_extension(String ext, GodotJSScriptLanguage * lang); + virtual Ref load(const String& p_path, const String& p_original_path = "", Error* r_error = nullptr, bool p_use_sub_threads = false, float* r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; virtual void get_recognized_extensions(List* p_extensions) const override; virtual bool handles_type(const String& p_type) const override; From 48faa9ff57c0b0f99163c8bdfccd6a476a4db5ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Gschwind?= Date: Sat, 11 Jan 2025 21:10:53 +0100 Subject: [PATCH 03/11] Ensure script track their script language --- weaver/jsb_script.cpp | 31 ++++++++++++++----------------- weaver/jsb_script.h | 4 +++- weaver/jsb_script_instance.cpp | 4 ++-- weaver/jsb_script_language.cpp | 5 +++-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/weaver/jsb_script.cpp b/weaver/jsb_script.cpp index 87affdef..6dc3ad7f 100644 --- a/weaver/jsb_script.cpp +++ b/weaver/jsb_script.cpp @@ -10,12 +10,11 @@ #include "editor/editor_help.h" #endif -GodotJSScript::GodotJSScript(): script_list_(this) +GodotJSScript::GodotJSScript(GodotJSScriptLanguage * lang): script_list_(this), lang_(lang) { { JSB_BENCHMARK_SCOPE(GodotJSScript, Construct); - GodotJSScriptLanguage* lang = GodotJSScriptLanguage::get_singleton(); - MutexLock lock(lang->mutex_); + MutexLock lock(lang_->mutex_); lang->script_list_.add(&script_list_); } @@ -29,8 +28,7 @@ GodotJSScript::~GodotJSScript() { JSB_BENCHMARK_SCOPE(GodotJSScript, Destruct); - const GodotJSScriptLanguage* lang = GodotJSScriptLanguage::get_singleton(); - MutexLock lock(lang->mutex_); + MutexLock lock(lang_->mutex_); script_list_.remove_from_list(); } @@ -110,7 +108,7 @@ ScriptInstance* GodotJSScript::instance_create(const v8::Local& p_th /* STEP 2, INITIALIZE AND CONSTRUCT */ { - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); instances_.insert(owner); } instance->object_id_ = get_environment()->bind_godot_object(get_script_class()->native_class_id, owner, p_this); @@ -120,7 +118,7 @@ ScriptInstance* GodotJSScript::instance_create(const v8::Local& p_th instance->owner_->set_script_instance(nullptr); //NOTE `instance` becomes an invalid pointer since it's deleted in `set_script_instance` { - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); instances_.erase(owner); } memdelete(owner); @@ -147,7 +145,7 @@ ScriptInstance* GodotJSScript::instance_create(Object* p_this) /* STEP 2, INITIALIZE AND CONSTRUCT */ { - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); instances_.insert(instance->owner_); } instance->object_id_ = get_environment()->crossbind(p_this, script_class_id_); @@ -157,7 +155,7 @@ ScriptInstance* GodotJSScript::instance_create(Object* p_this) instance->owner_->set_script_instance(nullptr); //NOTE `instance` becomes an invalid pointer since it's deleted in `set_script_instance` { - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); instances_.erase(p_this); } JSB_LOG(Error, "Error constructing a GodotJSScriptInstance"); @@ -174,7 +172,7 @@ Error GodotJSScript::reload(bool p_keep_state) if (!p_keep_state) { - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); if (instances_.size()) { return ERR_ALREADY_IN_USE; @@ -209,7 +207,7 @@ Vector GodotJSScript::get_documentation() const const jsb::ScriptClassInfoPtr class_info = get_script_class(); String base_type; - const String class_name = GodotJSScriptLanguage::get_singleton()->get_global_class_name(get_path(), &base_type); + const String class_name = lang_->get_global_class_name(get_path(), &base_type); DocData::ClassDoc class_doc_data; class_doc_data.name = class_name; @@ -293,7 +291,7 @@ MethodInfo GodotJSScript::get_method_info(const StringName& p_method) const ScriptLanguage* GodotJSScript::get_language() const { - return GodotJSScriptLanguage::get_singleton(); + return lang_; } bool GodotJSScript::has_script_signal(const StringName& p_signal) const @@ -387,7 +385,7 @@ bool GodotJSScript::has_static_method(const StringName& p_method) const bool GodotJSScript::instance_has(const Object* p_this) const { jsb_check(loaded_); - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); + MutexLock lock(lang_->mutex_); return instances_.has(const_cast(p_this)); } @@ -431,8 +429,7 @@ void GodotJSScript::load_module_immediately() JSB_BENCHMARK_SCOPE(GodotJSScript, load_module); const String path = jsb::internal::PathUtil::convert_typescript_path(get_path()); - const GodotJSScriptLanguage* lang = GodotJSScriptLanguage::get_singleton(); - const std::shared_ptr env = lang->get_environment(); + const std::shared_ptr env = lang_->get_environment(); env_id_ = env->id(); loaded_ = true; @@ -464,7 +461,7 @@ void GodotJSScript::load_module_immediately() JSB_LOG(VeryVerbose, "GodotJSScript module loaded %s", path); { //TODO a dirty but approaching solution for hot-reloading - MutexLock lock(GodotJSScriptLanguage::singleton_->mutex_); // necessary? + MutexLock lock(lang_->mutex_); // necessary? for (RBSet::Element *E = instances_.front(); E;) { RBSet::Element *N = E->next(); @@ -583,7 +580,7 @@ PlaceHolderScriptInstance* GodotJSScript::placeholder_instance_create(Object* p_ { JSB_LOG(Warning, "creating placeholder instance on invalid script (%s)", get_path()); } - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GodotJSScriptLanguage::get_singleton(), Ref