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
8 changes: 6 additions & 2 deletions bridge/jsb_class_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ namespace jsb
// signals (@signal_)
{
v8::Local<v8::Value> val_test;
if (prototype->Get(p_context, jsb_symbol(environment, ClassSignals)).ToLocal(&val_test) && val_test->IsArray())
const v8::Local<v8::Symbol> class_signals_symbol = jsb_symbol(environment, ClassSignals);
if (prototype->HasOwnProperty(p_context, class_signals_symbol).ToChecked()
&& prototype->Get(p_context, class_signals_symbol).ToLocal(&val_test) && val_test->IsArray())
{
v8::Local<v8::Array> collection = val_test.As<v8::Array>();
const uint32_t len = collection->Length();
Expand Down Expand Up @@ -238,7 +240,9 @@ namespace jsb
// detect all exported properties (which annotated with @export_)
{
v8::Local<v8::Value> val_test;
if (prototype->Get(p_context, jsb_symbol(environment, ClassProperties)).ToLocal(&val_test) && val_test->IsArray())
const v8::Local<v8::Symbol> class_properties_symbol = jsb_symbol(environment, ClassProperties);
if (prototype->HasOwnProperty(p_context, class_properties_symbol).ToChecked()
&& prototype->Get(p_context, class_properties_symbol).ToLocal(&val_test) && val_test->IsArray())
{
const v8::Local<v8::Array> collection = val_test.As<v8::Array>();
const uint32_t len = collection->Length();
Expand Down
4 changes: 2 additions & 2 deletions bridge/jsb_module_resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ namespace jsb
return true;
}
r_source_info = {};
JSB_LOG(Warning, "failed to check out module (absolute) %s", p_module_id);
JSB_LOG(Verbose, "module candidate not found (absolute probe): %s", p_module_id);
return false;
}

Expand Down Expand Up @@ -511,7 +511,7 @@ namespace jsb
return true;
}

JSB_LOG(Verbose, "failed to check out module (search_path: %s) %s", p_search_path, p_module_id);
JSB_LOG(Verbose, "module candidate not found (search_path: %s) %s", p_search_path, p_module_id);
return false;
}

Expand Down
45 changes: 42 additions & 3 deletions bridge/jsb_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ namespace jsb
v8::HandleScope handle_scope(isolate);
v8::Isolate::Scope isolate_scope(isolate);
const WorkerID worker_id = (WorkerID) info.Data().As<v8::Uint32>()->Value();
Worker::terminate(worker_id);
Worker::request_termination(worker_id);
}

// worker -> master (run in worker env)
Expand Down Expand Up @@ -1068,7 +1068,7 @@ namespace jsb
return (bool) o_worker_impl;
}

bool Worker::terminate(WorkerID p_id)
bool Worker::request_termination(WorkerID p_id)
{
bool res = false;
lock_.lock();
Expand All @@ -1082,6 +1082,41 @@ namespace jsb
return res;
}

bool Worker::terminate(WorkerID p_id)
{
WorkerImplPtr impl;
lock_.lock();
const bool found = worker_list_.try_get_value(p_id, impl);
if (found)
{
impl->finish();
}
lock_.unlock();

if (!found)
{
return false;
}

const Thread::ID thread_id = impl->get_thread_id();
jsb_check(thread_id != Thread::get_caller_id());
impl->join();

lock_.lock();
const WorkerID* mapped_id = workers_.getptr(thread_id);
if (mapped_id && *mapped_id == p_id)
{
workers_.erase(thread_id);
}
if (worker_list_.is_valid_index(p_id))
{
worker_list_.remove_at(p_id);
}
lock_.unlock();

return true;
}

void Worker::finish()
{
bool has_remaining_workers = true;
Expand Down Expand Up @@ -1309,11 +1344,15 @@ namespace jsb
jsb_throw(isolate, "bad this");
return;
}
const Worker* worker = (Worker*) self->GetAlignedPointerFromInternalField(IF_Pointer);
Worker* worker = (Worker*) self->GetAlignedPointerFromInternalField(IF_Pointer);
if (!Worker::terminate(worker->id_))
{
JSB_WORKER_LOG(Warning, "can not terminate a dead worker");
}
else
{
worker->id_ = {};
}
}

void Worker::register_(const v8::Local<v8::Context>& p_context, const v8::Local<v8::Object>& p_self)
Expand Down
5 changes: 4 additions & 1 deletion bridge/jsb_worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ namespace jsb

static bool try_get_worker(WorkerID p_id, WorkerImplPtr& o_worker_impl);

// terminate a worker
// request worker termination without joining/removing it
static bool request_termination(WorkerID p_id);

// terminate a worker from an external thread and remove it from the registry
static bool terminate(WorkerID p_id);

static bool parse_transfer_list(
Expand Down
11 changes: 0 additions & 11 deletions tests/project/tests/extend/child.ts

This file was deleted.

18 changes: 18 additions & 0 deletions tests/project/tests/extend/parent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Node, Variant } from "godot";
import { createClassBinder } from "godot.annotations";

const bind = createClassBinder();

@bind()
export default class Parent extends Node {
@bind.export(Variant.Type.TYPE_INT)
accessor parentOnlyExport: number = 11;

_ready() {
console.log("Parent ready");
}

parentFn() {
return true;
}
}
73 changes: 68 additions & 5 deletions tests/project/tests/extend/test-extend.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,72 @@
import Child from "./child";
import { PropertyUsageFlags, ResourceLoader, Script } from "godot";
import Parent from "./parent";
import { reportTestFailure } from "../test-status";

export default class TestExtend extends Child {
const ChildCategoryName = "test-extend.ts";
const ParentOnlyExportName = "parentOnlyExport";

function countScriptPropertiesInCategory(script: Script, categoryName: string, propertyName: string): number {
let count = 0;
let currentCategory = "";

for (const property of script.get_script_property_list()) {
const usage = property.get("usage");
const name = property.get("name");
if (typeof usage === "number" && (usage & PropertyUsageFlags.PROPERTY_USAGE_CATEGORY) !== 0) {
currentCategory = typeof name === "string" ? name : "";
continue;
}

if (currentCategory === categoryName && name === propertyName) {
count += 1;
}
}

return count;
}

function countScriptProperties(script: Script, propertyName: string): number {
let count = 0;

for (const property of script.get_script_property_list()) {
const usage = property.get("usage");
const name = property.get("name");
if (typeof usage === "number" && (usage & PropertyUsageFlags.PROPERTY_USAGE_CATEGORY) !== 0) {
continue;
}

if (name === propertyName) {
count += 1;
}
}

return count;
}

export default class TestExtend extends Parent {
_ready() {
super._ready();
console.log("TestExtend ready");
console.assert(this.childFn());
try {
super._ready();
console.log("TestExtend ready");
console.assert(this.parentFn());

const childScript = ResourceLoader.load("res://tests/extend/test-extend.ts");

if (!(childScript instanceof Script)) {
throw new Error("failed to load child TestExtend script");
}

const totalExportCount = countScriptProperties(childScript, ParentOnlyExportName);
const childExportCount = countScriptPropertiesInCategory(childScript, ChildCategoryName, ParentOnlyExportName);

if (totalExportCount !== 1) {
throw new Error(`${ParentOnlyExportName} total property count mismatch: ${totalExportCount}`);
}
if (childExportCount !== 0) {
throw new Error(`${ChildCategoryName} category leaked inherited property ${ParentOnlyExportName}: ${childExportCount}`);
}
} catch (error) {
reportTestFailure("extend", error);
}
}
}
38 changes: 37 additions & 1 deletion weaver-editor/jsb_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "jsb_docked_panel.h"
#include "jsb_export_plugin.h"

#include "core/string/char_utils.h"
#include "core/templates/hash_map.h"

#if GODOT_4_7_OR_NEWER
#include "core/object/callable_mp.h"
#endif
Expand Down Expand Up @@ -183,6 +186,15 @@ String GodotJSEditorPlugin::mutate_types(const String& p_content)
// Internal utility types are double underscore prefixed
return p_identifier.begins_with("__");
};
auto should_ignore_function_identifier = [&](const String& p_identifier) -> bool
{
if (should_ignore_identifier(p_identifier))
{
return true;
}

return !p_identifier.is_empty() && is_ascii_upper_case(p_identifier[0]);
};

// Regex obviously isn't the best tool for the job and this regex will, for example, match some generic parameter
// names. However, for now, it does the job.
Expand Down Expand Up @@ -247,6 +259,7 @@ String GodotJSEditorPlugin::mutate_types(const String& p_content)
RegEx function_regex("(?m)\\b(?!(?:if|for|while|switch|catch|return|new|super|this)\\b)([a-zA-Z_]\\w*)\\s*(?:<[^>]+>)?\\s*\\(");
RegEx parameter_regex("(?m)\\b([a-zA-Z_]\\w*)\\s*(?:\\?|)\\s*:");
TypedArray<RegExMatch> func_matches = function_regex.search_all(result);
HashMap<String, String> function_replacements;
for (int match_index = func_matches.size() - 1; match_index >= 0; match_index--)
{
Ref<RegExMatch> func_match = func_matches[match_index];
Expand Down Expand Up @@ -297,16 +310,39 @@ String GodotJSEditorPlugin::mutate_types(const String& p_content)
}
}

if (!should_ignore_identifier(func_identifier))
if (!should_ignore_function_identifier(func_identifier))
{
String func_replacement = jsb::internal::NamingUtil::get_member_name(func_identifier);
if (func_replacement != func_identifier)
{
function_replacements.insert(func_identifier, func_replacement);
result = result.substr(0, func_name_start) + func_replacement + result.substr(func_name_end);
}
}
}

RegEx typeof_value_regex("(?m)\\btypeof\\s+([a-zA-Z_]\\w*)");
TypedArray<RegExMatch> typeof_value_matches = typeof_value_regex.search_all(result);
for (int match_index = typeof_value_matches.size() - 1; match_index >= 0; match_index--)
{
Ref<RegExMatch> match = typeof_value_matches[match_index];

const int start = match->get_start(1);
const int end = match->get_end(1);
const String identifier = result.substr(start, end - start);

if (should_ignore_function_identifier(identifier) || !function_replacements.has(identifier))
{
continue;
}

const String replacement = function_replacements[identifier];
if (replacement != identifier)
{
result = result.substr(0, start) + replacement + result.substr(end);
}
}

// Remove references
RegEx reference_regex("(?m)^///\\s*<reference\\spath=.+$");
TypedArray<RegExMatch> reference_matches = reference_regex.search_all(result);
Expand Down
4 changes: 3 additions & 1 deletion weaver-editor/jsb_export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ void GodotJSExportPlugin::get_script_resources(const String &p_dir, Vector<Strin
{
get_script_resources(path, r_list, p_is_node_module);
}
else if (ResourceLoader::get_resource_type(path) == jsb_typename(GodotJSScript) && !get_ignored_paths().has(path))
else if (!get_ignored_paths().has(path)
&& (ResourceLoader::get_resource_type(path) == jsb_typename(GodotJSScript)
|| (p_is_node_module && filename == "package.json")))
{
r_list.push_back(path);
}
Expand Down
Loading