diff options
31 files changed, 340 insertions, 305 deletions
diff --git a/SConstruct b/SConstruct index 98438d2c60..857daf7b0e 100644 --- a/SConstruct +++ b/SConstruct @@ -593,8 +593,6 @@ if selected_platform in platform_list: env.Append(CPPDEFINES=["PTRCALL_ENABLED"]) if env["tools"]: env.Append(CPPDEFINES=["TOOLS_ENABLED"]) - if env["tests"]: - env.Append(CPPDEFINES=["TESTS_ENABLED"]) if env["disable_3d"]: if env["tools"]: print( @@ -650,10 +648,6 @@ if selected_platform in platform_list: } ) - # Enable test framework globally and inform it of configuration method. - if env["tests"]: - env.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) - scons_cache_path = os.environ.get("SCONS_CACHE") if scons_cache_path != None: CacheDir(scons_cache_path) diff --git a/core/object.cpp b/core/object.cpp index ba002024e6..ff6d4a666f 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -680,84 +680,6 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call return Variant(); } -#ifdef DEBUG_ENABLED -static void _test_call_error(const StringName &p_func, const Callable::CallError &error) { - switch (error.error) { - case Callable::CallError::CALL_OK: - case Callable::CallError::CALL_ERROR_INVALID_METHOD: - break; - case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(Variant::Type(error.expected)) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); - break; - } - case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL: - break; - } -} -#else - -#define _test_call_error(m_str, m_err) - -#endif - -void Object::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (p_method == CoreStringNames::get_singleton()->_free) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference."); - - ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed."); -#endif - - //must be here, must be before everything, - memdelete(this); - return; - } - - //Variant ret; - OBJ_DEBUG_LOCK - - Callable::CallError error; - - if (script_instance) { - script_instance->call_multilevel(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } - - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } -} - -void Object::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - MethodBind *method = ClassDB::get_method(get_class_name(), p_method); - - Callable::CallError error; - OBJ_DEBUG_LOCK - - if (method) { - method->call(this, p_args, p_argcount, error); - _test_call_error(p_method, error); - } - - //Variant ret; - - if (script_instance) { - script_instance->call_multilevel_reversed(p_method, p_args, p_argcount); - //_test_call_error(p_method,error); - } -} - bool Object::has_method(const StringName &p_method) const { if (p_method == CoreStringNames::get_singleton()->_free) { return true; @@ -820,21 +742,6 @@ Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { return ret; } -void Object::call_multilevel(const StringName &p_name, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - //Callable::CallError error; - call_multilevel(p_name, argptr, argc); -} - Variant Object::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; diff --git a/core/object.h b/core/object.h index 954be5304c..d9847d10aa 100644 --- a/core/object.h +++ b/core/object.h @@ -655,10 +655,7 @@ public: void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper - void call_multilevel(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper void notification(int p_notification, bool p_reversed = false); String to_string(); diff --git a/core/script_language.cpp b/core/script_language.cpp index 420a560782..b63aeb952c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -308,16 +308,6 @@ Variant ScriptInstance::call(const StringName &p_method, VARIANT_ARG_DECLARE) { return call(p_method, argptr, argc, error); } -void ScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - -void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - Callable::CallError ce; - call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls -} - void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { if (r_valid) { *r_valid = false; @@ -331,19 +321,6 @@ Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) return Variant(); } -void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - call_multilevel(p_method, argptr, argc); -} - ScriptInstance::~ScriptInstance() { } diff --git a/core/script_language.h b/core/script_language.h index 6ba38399a1..aa7014ed3e 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -199,9 +199,6 @@ public: virtual bool has_method(const StringName &p_method) const = 0; virtual Variant call(const StringName &p_method, VARIANT_ARG_LIST); virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) = 0; - virtual void call_multilevel(const StringName &p_method, VARIANT_ARG_LIST); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void notification(int p_notification) = 0; virtual String to_string(bool *r_valid) { if (r_valid) { @@ -428,8 +425,6 @@ public: r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); } - //virtual void call_multilevel(const StringName& p_method,VARIANT_ARG_LIST) { return Variant(); } - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount,Callable::CallError &r_error) { return Variant(); } virtual void notification(int p_notification) {} virtual Ref<Script> get_script() const { return script; } diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 9a78e45d46..4991a1e58b 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -478,7 +478,17 @@ <argument index="0" name="id" type="int"> </argument> <description> - Returns an array of the tile's shapes. + Returns an array of dictionaries describing the tile's shapes. + [b]Dictionary structure in the array returned by this method:[/b] + [codeblock] + { + "autotile_coord": Vector2, + "one_way": bool, + "one_way_margin": int, + "shape": CollisionShape2D, + "shape_transform": Transform2D, + } + [/codeblock] </description> </method> <method name="tile_get_texture" qualifiers="const"> diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 60ba3802fb..dc2abe15ee 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -136,28 +136,39 @@ void ShaderTextEditor::_load_theme_settings() { syntax_highlighter->set_function_color(EDITOR_GET("text_editor/highlighting/function_color")); syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/highlighting/member_variable_color")); + syntax_highlighter->clear_keyword_colors(); + List<String> keywords; ShaderLanguage::get_keyword_list(&keywords); + const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), keyword_color); + } + // Colorize built-ins like `COLOR` differently to make them easier + // to distinguish from keywords at a quick glance. + + List<String> built_ins; if (shader.is_valid()) { for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) { - keywords.push_back(F->key()); + built_ins.push_back(F->key()); } } for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) { - keywords.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); + built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); } } - const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - syntax_highlighter->clear_keyword_colors(); - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { - syntax_highlighter->add_keyword_color(E->get(), keyword_color); + const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + + for (List<String>::Element *E = built_ins.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), member_variable_color); } - //colorize comments + // Colorize comments. const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); syntax_highlighter->clear_color_regions(); syntax_highlighter->add_color_region("/*", "*/", comment_color, false); diff --git a/main/SCsub b/main/SCsub index 152d0c4d03..97f77840f1 100644 --- a/main/SCsub +++ b/main/SCsub @@ -7,18 +7,23 @@ import main_builders env.main_sources = [] -env.add_source_files(env.main_sources, "*.cpp") +env_main = env.Clone() -env.Depends("#main/splash.gen.h", "#main/splash.png") -env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) +env_main.add_source_files(env.main_sources, "*.cpp") -env.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") -env.CommandNoCache( +if env["tests"]: + env_main.Append(CPPDEFINES=["TESTS_ENABLED"]) + +env_main.Depends("#main/splash.gen.h", "#main/splash.png") +env_main.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) + +env_main.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") +env_main.CommandNoCache( "#main/splash_editor.gen.h", "#main/splash_editor.png", run_in_subprocess(main_builders.make_splash_editor) ) -env.Depends("#main/app_icon.gen.h", "#main/app_icon.png") -env.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon)) +env_main.Depends("#main/app_icon.gen.h", "#main/app_icon.png") +env_main.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon)) -lib = env.add_library("main", env.main_sources) +lib = env_main.add_library("main", env.main_sources) env.Prepend(LIBS=[lib]) diff --git a/modules/SCsub b/modules/SCsub index 9155a53eaf..2d774306e4 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -1,10 +1,10 @@ #!/usr/bin/env python -Import("env") - import modules_builders import os +Import("env") + env_modules = env.Clone() Export("env_modules") @@ -12,6 +12,15 @@ Export("env_modules") # Header with MODULE_*_ENABLED defines. env.CommandNoCache("modules_enabled.gen.h", Value(env.module_list), modules_builders.generate_modules_enabled) +# Header to be included in `tests/test_main.cpp` to run module-specific tests. +if env["tests"]: + env.CommandNoCache( + "modules_tests.gen.h", + Value(env.module_list), + Action(modules_builders.generate_modules_tests, "Generating modules tests header."), + ) + env.AlwaysBuild("modules_tests.gen.h") + vs_sources = [] # libmodule_<name>.a for each active module. for name, path in env.module_list.items(): diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index f4550c2024..274493ed17 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -504,6 +504,9 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) { int l_width = d["width"]; int l_depth = d["depth"]; + ERR_FAIL_COND_MSG(l_width < 2, "Map width must be at least 2."); + ERR_FAIL_COND_MSG(l_depth < 2, "Map depth must be at least 2."); + // TODO This code will need adjustments if real_t is set to `double`, // because that precision is unnecessary for a heightmap and Bullet doesn't support it... diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 94aa2125c2..632f4e5fee 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -991,7 +991,8 @@ void NativeScriptInstance::notification(int p_notification) { Variant value = p_notification; const Variant *args[1] = { &value }; - call_multilevel("_notification", args, 1); + Callable::CallError error; + call("_notification", args, 1, error); } String NativeScriptInstance::to_string(bool *r_valid) { @@ -1087,31 +1088,6 @@ ScriptLanguage *NativeScriptInstance::get_language() { return NativeScriptLanguage::get_singleton(); } -void NativeScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - godot_variant res = E->get().method.method((godot_object *)owner, - E->get().method.method_data, - userdata, - p_argcount, - (godot_variant **)p_args); - godot_variant_destroy(&res); - } - script_data = script_data->base_data; - } -} - -void NativeScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - NativeScriptDesc *script_data = GET_SCRIPT_DESC(); - - if (script_data) { - _ml_call_reversed(script_data, p_method, p_args, p_argcount); - } -} - NativeScriptInstance::~NativeScriptInstance() { NativeScriptDesc *script_data = GET_SCRIPT_DESC(); diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index e709ce2337..145bf7dcb6 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -231,9 +231,6 @@ public: virtual ScriptLanguage *get_language(); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index 6309b6fde3..690d1a0432 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -62,12 +62,6 @@ public: virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - // Rely on default implementations provided by ScriptInstance for the moment. - // Note that multilevel call could be removed in 3.0 release, so stay tuned - // (see https://godotengine.org/qa/9244/can-override-the-_ready-and-_process-functions-child-classes) - //virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); - //virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount); - virtual void notification(int p_notification); virtual Ref<Script> get_script() const; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 40ef0aeec6..9170255c02 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1309,39 +1309,6 @@ Variant GDScriptInstance::call(const StringName &p_method, const Variant **p_arg return Variant(); } -void GDScriptInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - GDScript *sptr = script.ptr(); - Callable::CallError ce; - - while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - return; - } - sptr = sptr->_base; - } -} - -void GDScriptInstance::_ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount) { - if (sptr->_base) { - _ml_call_reversed(sptr->_base, p_method, p_args, p_argcount); - } - - Callable::CallError ce; - - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get()->call(this, p_args, p_argcount, ce); - } -} - -void GDScriptInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - if (script.ptr()) { - _ml_call_reversed(script.ptr(), p_method, p_args, p_argcount); - } -} - void GDScriptInstance::notification(int p_notification) { //notification is not virtual, it gets called at ALL levels just like in C. Variant value = p_notification; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 8236464f15..9906b4014d 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -146,7 +146,6 @@ protected: void _get_property_list(List<PropertyInfo> *p_properties) const; Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; - //void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount); static void _bind_methods(); @@ -258,8 +257,6 @@ class GDScriptInstance : public ScriptInstance { SelfList<GDScriptFunctionState>::List pending_func_states; - void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount); - public: virtual Object *get_owner() { return owner; } @@ -271,8 +268,6 @@ public: virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); - virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; } diff --git a/modules/modules_builders.py b/modules/modules_builders.py index e7be6380d1..2243162555 100644 --- a/modules/modules_builders.py +++ b/modules/modules_builders.py @@ -12,5 +12,16 @@ def generate_modules_enabled(target, source, env): f.write("#define %s\n" % ("MODULE_" + module.upper() + "_ENABLED")) +def generate_modules_tests(target, source, env): + import os + import glob + + with open(target[0].path, "w") as f: + for name, path in env.module_list.items(): + headers = glob.glob(os.path.join(path, "tests", "*.h")) + for h in headers: + f.write('#include "%s"\n' % (os.path.normpath(h))) + + if __name__ == "__main__": subprocess_main(globals()) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 7d3ae31588..3d6ff1466d 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -897,7 +897,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Call OnBeforeSerialize if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) { - obj->get_script_instance()->call_multilevel(string_names.on_before_serialize); + obj->get_script_instance()->call(string_names.on_before_serialize); } // Save instance info @@ -1133,7 +1133,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Call OnAfterDeserialization if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) { - obj->get_script_instance()->call_multilevel(string_names.on_after_deserialize); + obj->get_script_instance()->call(string_names.on_after_deserialize); } } } @@ -1866,41 +1866,6 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, return Variant(); } -void CSharpInstance::call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) { - GD_MONO_SCOPE_THREAD_ATTACH; - - if (script.is_valid()) { - MonoObject *mono_object = get_mono_object(); - - ERR_FAIL_NULL(mono_object); - - _call_multilevel(mono_object, p_method, p_args, p_argcount); - } -} - -void CSharpInstance::_call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount) { - GD_MONO_ASSERT_THREAD_ATTACHED; - - GDMonoClass *top = script->script_class; - - while (top && top != script->native) { - GDMonoMethod *method = top->get_method(p_method, p_argcount); - - if (method) { - method->invoke(p_mono_object, p_args); - return; - } - - top = top->get_parent_class(); - } -} - -void CSharpInstance::call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) { - // Sorry, the method is the one that controls the call order - - call_multilevel(p_method, p_args, p_argcount); -} - bool CSharpInstance::_reference_owner_unsafe() { #ifdef DEBUG_ENABLED CRASH_COND(!base_ref); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index c2370364f9..f0b43a40f9 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -265,8 +265,6 @@ class CSharpInstance : public ScriptInstance { friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *); static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle); - void _call_multilevel(MonoObject *p_mono_object, const StringName &p_method, const Variant **p_args, int p_argcount); - void get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state); void get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state); @@ -285,8 +283,6 @@ public: /* TODO */ void get_method_list(List<MethodInfo> *p_list) const override {} bool has_method(const StringName &p_method) const override; Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; - void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount) override; - void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount) override; void mono_object_disposed(MonoObject *p_obj); diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index db64a14635..49c77468ed 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -18,6 +18,7 @@ iphone_lib = [ "godot_view.mm", "display_layer.mm", "godot_view_renderer.mm", + "godot_view_gesture_recognizer.m", ] env_ios = env.Clone() diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm index cd17ff5430..c0a31549c4 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/iphone/godot_view.mm @@ -33,6 +33,7 @@ #include "core/ustring.h" #import "display_layer.h" #include "display_server_iphone.h" +#import "godot_view_gesture_recognizer.h" #import "godot_view_renderer.h" #import <CoreMotion/CoreMotion.h> @@ -57,6 +58,8 @@ static const int max_touches = 8; @property(strong, nonatomic) CMMotionManager *motionManager; +@property(strong, nonatomic) GodotViewGestureRecognizer *delayGestureRecognizer; + @end @implementation GodotView @@ -139,6 +142,10 @@ static const int max_touches = 8; self.animationTimer = nil; } + if (self.delayGestureRecognizer) { + self.delayGestureRecognizer = nil; + } + [super dealloc]; } @@ -157,6 +164,12 @@ static const int max_touches = 8; self.motionManager = nil; } } + + // Initialize delay gesture recognizer + GodotViewGestureRecognizer *gestureRecognizer = [[GodotViewGestureRecognizer alloc] init]; + self.delayGestureRecognizer = gestureRecognizer; + [self addGestureRecognizer:self.delayGestureRecognizer]; + [gestureRecognizer release]; } - (void)stopRendering { @@ -359,9 +372,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touchesSet containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseBegan) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; @@ -375,9 +385,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseMoved) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; @@ -392,9 +399,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseEnded) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); [self removeTouch:touch]; @@ -409,9 +413,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseCancelled) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); DisplayServerIPhone::get_singleton()->touches_cancelled(tid); diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/iphone/godot_view_gesture_recognizer.h new file mode 100644 index 0000000000..ca3bd808d1 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.h @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// GLViewGestureRecognizer allows iOS gestures to work currectly by +// emulating UIScrollView's UIScrollViewDelayedTouchesBeganGestureRecognizer. +// It catches all gestures incoming to UIView and delays them for 150ms +// (the same value used by UIScrollViewDelayedTouchesBeganGestureRecognizer) +// If touch cancelation or end message is fired it fires delayed +// begin touch immediately as well as last touch signal + +#import <UIKit/UIKit.h> + +@interface GodotViewGestureRecognizer : UIGestureRecognizer + +- (instancetype)init; + +@end diff --git a/platform/iphone/godot_view_gesture_recognizer.m b/platform/iphone/godot_view_gesture_recognizer.m new file mode 100644 index 0000000000..377ccd52a5 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.m @@ -0,0 +1,171 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "godot_view_gesture_recognizer.h" + +// Using same delay interval that is used for `UIScrollView` +const NSTimeInterval kGLGestureDelayInterval = 0.150; + +// Minimum distance for touches to move to fire +// a delay timer before scheduled time. +// Should be the low enough to not cause issues with dragging +// but big enough to allow click to work. +const CGFloat kGLGestureMovementDistance = 0.5; + +@interface GodotViewGestureRecognizer () + +// Timer used to delay begin touch message. +// Should work as simple emulation of UIDelayedAction +@property(strong, nonatomic) NSTimer *delayTimer; + +// Delayed touch parameters +@property(strong, nonatomic) NSSet *delayedTouches; +@property(strong, nonatomic) UIEvent *delayedEvent; + +@end + +@implementation GodotViewGestureRecognizer + +- (instancetype)init { + self = [super init]; + + self.cancelsTouchesInView = YES; + self.delaysTouchesBegan = YES; + self.delaysTouchesEnded = YES; + + return self; +} + +- (void)dealloc { + if (self.delayTimer) { + [self.delayTimer invalidate]; + self.delayTimer = nil; + } + + if (self.delayedTouches) { + self.delayedTouches = nil; + } + + if (self.delayedEvent) { + self.delayedEvent = nil; + } + + [super dealloc]; +} + +- (void)delayTouches:(NSSet *)touches andEvent:(UIEvent *)event { + [self.delayTimer fire]; + + self.delayedTouches = touches; + self.delayedEvent = event; + + self.delayTimer = [NSTimer + scheduledTimerWithTimeInterval:kGLGestureDelayInterval + target:self + selector:@selector(fireDelayedTouches:) + userInfo:nil + repeats:NO]; +} + +- (void)fireDelayedTouches:(id)timer { + [self.delayTimer invalidate]; + self.delayTimer = nil; + + if (self.delayedTouches) { + [self.view touchesBegan:self.delayedTouches withEvent:self.delayedEvent]; + } + + self.delayedTouches = nil; + self.delayedEvent = nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseBegan]; + [self delayTouches:cleared andEvent:event]; + [cleared release]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseMoved]; + + if (self.delayTimer) { + // We should check if movement was significant enough to fire an event + // for dragging to work correctly. + for (UITouch *touch in cleared) { + CGPoint from = [touch locationInView:self.view]; + CGPoint to = [touch previousLocationInView:self.view]; + CGFloat xDistance = from.x - to.x; + CGFloat yDistance = from.y - to.y; + + CGFloat distance = sqrt(xDistance * xDistance + yDistance * yDistance); + + // Early exit, since one of touches has moved enough to fire a drag event. + if (distance > kGLGestureMovementDistance) { + [self.delayTimer fire]; + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; + return; + } + } + + [cleared release]; + return; + } + + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseEnded]; + [self.view touchesEnded:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + [self.view touchesCancelled:touches withEvent:event]; +}; + +- (NSSet *)copyClearedTouches:(NSSet *)touches phase:(UITouchPhase)phaseToSave { + NSMutableSet *cleared = [touches mutableCopy]; + + for (UITouch *touch in touches) { + if (touch.phase != phaseToSave) { + [cleared removeObject:touch]; + } + } + + return cleared; +} + +@end diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 5e209a6e6b..ffe60ad582 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2793,7 +2793,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window - [wd.window_object orderOut:nil]; + if ([wd.window_object isVisible]) { + [wd.window_object orderOut:nil]; + } wd.borderless = p_enabled; if (p_enabled) { [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; @@ -2807,7 +2809,13 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [wd.window_object setFrame:frameRect display:NO]; } _update_window(wd); - [wd.window_object makeKeyAndOrderFront:nil]; + if ([wd.window_object isVisible]) { + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } + } } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { wd.on_top = p_enabled; @@ -2875,7 +2883,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { const WindowData &wd = windows[p_window]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [wd.window_object makeKeyAndOrderFront:nil]; + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } } bool DisplayServerOSX::window_can_draw(WindowID p_window) const { diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 73f17060df..bd9e4f5bde 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -174,7 +174,7 @@ void Node3D::_notification(int p_what) { ERR_FAIL_COND(!data.viewport); if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_enter_world); } #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { @@ -202,7 +202,7 @@ void Node3D::_notification(int p_what) { #endif if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_exit_world); } data.viewport = nullptr; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index d1bf038b8d..d6d1134cc9 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -434,7 +434,7 @@ void CanvasItem::_update_callback() { notification(NOTIFICATION_DRAW); emit_signal(SceneStringNames::get_singleton()->draw); if (get_script_instance()) { - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_draw); } current_item_drawn = nullptr; drawing = false; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 88f9730f78..cdc06c7c5d 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -55,15 +55,13 @@ void Node::_notification(int p_notification) { case NOTIFICATION_PROCESS: { if (get_script_instance()) { Variant time = get_process_delta_time(); - const Variant *ptr[1] = { &time }; - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_process, ptr, 1); + get_script_instance()->call(SceneStringNames::get_singleton()->_process, time); } } break; case NOTIFICATION_PHYSICS_PROCESS: { if (get_script_instance()) { Variant time = get_physics_process_delta_time(); - const Variant *ptr[1] = { &time }; - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_physics_process, ptr, 1); + get_script_instance()->call(SceneStringNames::get_singleton()->_physics_process, time); } } break; @@ -146,7 +144,7 @@ void Node::_notification(int p_notification) { set_physics_process(true); } - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_ready); } } break; @@ -216,7 +214,7 @@ void Node::_propagate_enter_tree() { notification(NOTIFICATION_ENTER_TREE); if (get_script_instance()) { - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_enter_tree); } emit_signal(SceneStringNames::get_singleton()->tree_entered); @@ -264,7 +262,7 @@ void Node::_propagate_exit_tree() { data.blocked--; if (get_script_instance()) { - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, nullptr, 0); + get_script_instance()->call(SceneStringNames::get_singleton()->_exit_tree); } emit_signal(SceneStringNames::get_singleton()->tree_exiting); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index d6159e089b..75b3d7a73d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -250,11 +250,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) { - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - } else { - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } + nodes[i]->call(p_function, VARIANT_ARG_PASS); } else { MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); } @@ -267,11 +263,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) { - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - } else { - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } + nodes[i]->call(p_function, VARIANT_ARG_PASS); } else { MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); } @@ -883,7 +875,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p continue; } - n->call_multilevel(p_method, (const Variant **)v, 1); + n->call(p_method, (const Variant **)v, 1); //ERR_FAIL_COND(node_count != g.nodes.size()); } diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 41dc49bc64..0f74f2e973 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -223,7 +223,6 @@ public: GROUP_CALL_REVERSE = 1, GROUP_CALL_REALTIME = 2, GROUP_CALL_UNIQUE = 4, - GROUP_CALL_MULTILEVEL = 8, }; _FORCE_INLINE_ Window *get_root() const { return root; } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1c259b7d32..16d0325881 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1607,7 +1607,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu } if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) { - control->call_multilevel(SceneStringNames::get_singleton()->_gui_input, ev); + control->call(SceneStringNames::get_singleton()->_gui_input, ev); } if (!control->is_inside_tree() || control->is_set_as_toplevel()) { @@ -2306,7 +2306,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.key_focus) { gui.key_event_accepted = false; if (gui.key_focus->can_process()) { - gui.key_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, p_event); + gui.key_focus->call(SceneStringNames::get_singleton()->_gui_input, p_event); if (gui.key_focus) { //maybe lost it gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); } @@ -2516,7 +2516,7 @@ void Viewport::_drop_mouse_focus() { mb->set_global_position(c->get_local_mouse_position()); mb->set_button_index(i + 1); mb->set_pressed(false); - c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + c->call(SceneStringNames::get_singleton()->_gui_input, mb); } } } @@ -2581,7 +2581,7 @@ void Viewport::_post_gui_grab_click_focus() { mb->set_position(click); mb->set_button_index(i + 1); mb->set_pressed(false); - gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb); } } diff --git a/tests/SCsub b/tests/SCsub index cb1d35b12f..9c32eb8ec3 100644 --- a/tests/SCsub +++ b/tests/SCsub @@ -3,7 +3,13 @@ Import("env") env.tests_sources = [] -env.add_source_files(env.tests_sources, "*.cpp") -lib = env.add_library("tests", env.tests_sources) +env_tests = env.Clone() + +# Enable test framework and inform it of configuration method. +env_tests.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) + +env_tests.add_source_files(env.tests_sources, "*.cpp") + +lib = env_tests.add_library("tests", env.tests_sources) env.Prepend(LIBS=[lib]) diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 91eff28f86..0fb9f2fcda 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -49,6 +49,8 @@ #include "test_string.h" #include "test_validate_testing.h" +#include "modules/modules_tests.gen.h" + #include "thirdparty/doctest/doctest.h" const char **tests_get_names() { |