diff options
489 files changed, 16780 insertions, 12545 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index cf8b0f4132..a9808fee95 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -23,7 +23,7 @@ jobs: - name: Install Python dependencies and general setup run: | - pip3 install black==23.3.0 pytest==7.1.2 mypy==0.971 + pip3 install pytest==7.1.2 mypy==0.971 git config diff.wsErrorHighlight all - name: Get changed files @@ -46,6 +46,9 @@ jobs: run: | bash ./misc/scripts/gitignore_check.sh + - name: Style checks via pre-commit + uses: pre-commit/action@v3.0.1 + - name: File formatting checks (file_format.sh) run: | bash ./misc/scripts/file_format.sh changed.txt @@ -54,14 +57,6 @@ jobs: run: | bash ./misc/scripts/header_guards.sh changed.txt - - name: Python style checks via black (black_format.sh) - run: | - if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then - bash ./misc/scripts/black_format.sh - else - echo "Skipping Python formatting as no Python files were changed." - fi - - name: Python scripts static analysis (mypy_check.sh) run: | if grep -qE '\.py$|SConstruct|SCsub' changed.txt || [ -z "$(cat changed.txt)" ]; then @@ -92,12 +87,6 @@ jobs: - name: Documentation checks run: | doc/tools/doc_status.py doc/classes modules/*/doc_classes platform/*/doc_classes - doc/tools/make_rst.py --dry-run --color doc/classes modules platform - - - name: Style checks via clang-format (clang_format.sh) - run: | - clang-format --version - bash ./misc/scripts/clang_format.sh changed.txt - name: Style checks via dotnet format (dotnet_format.sh) run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..3493219ea7 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,49 @@ +repos: + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v16.0.6 + hooks: + - id: clang-format + files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java|glsl)$ + types_or: [text] + exclude: | + (?x)^( + tests/python_build.*| + .*thirdparty.*| + .*platform/android/java/lib/src/com.*| + .*-so_wrap.* + ) + + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 23.3.0 + hooks: + - id: black + files: (\.py$|SConstruct|SCsub) + types_or: [text] + exclude: .*thirdparty.* + args: + - --line-length=120 + + - repo: local + hooks: + - id: make-rst + name: make-rst + entry: python3 doc/tools/make_rst.py doc/classes modules platform --dry-run --color + pass_filenames: false + language: python + files: ^(doc|modules|platform).*xml$ + + - id: copyright-headers + name: copyright-headers + language: python + files: \.(c|h|cpp|hpp|cc|cxx|m|mm|inc|java)$ + entry: python3 misc/scripts/copyright_headers.py + exclude: | + (?x)^( + tests/python_build.*| + .*thirdparty.*| + .*platform/android/java/lib/src/com.*| + .*-so_wrap.*| + platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.*| + platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper.*| + platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.* + ) diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 2bb8837849..d714ec42c2 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -114,6 +114,8 @@ Dictionary Engine::get_version_info() const { String hash = String(VERSION_HASH); dict["hash"] = hash.is_empty() ? String("unknown") : hash; + dict["timestamp"] = VERSION_TIMESTAMP; + String stringver = String(dict["major"]) + "." + String(dict["minor"]); if ((int)dict["patch"] != 0) { stringver += "." + String(dict["patch"]); diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index d9a5a5094a..d1c90ed7e6 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1514,6 +1514,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray()); + GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false); ProjectSettings::get_singleton()->add_hidden_prefix("input/"); } diff --git a/core/io/resource.cpp b/core/io/resource.cpp index daa57be76f..7e8d0b43cd 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -41,7 +41,12 @@ #include <stdio.h> void Resource::emit_changed() { - emit_signal(CoreStringNames::get_singleton()->changed); + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the connection happen on the main thread, later, since signals are not thread-safe. + call_deferred("emit_signal", CoreStringNames::get_singleton()->changed); + } else { + emit_signal(CoreStringNames::get_singleton()->changed); + } } void Resource::_resource_path_changed() { @@ -152,12 +157,22 @@ bool Resource::editor_can_reload_from_file() { } void Resource::connect_changed(const Callable &p_callable, uint32_t p_flags) { + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the check and connection happen on the main thread, later, since signals are not thread-safe. + callable_mp(this, &Resource::connect_changed).call_deferred(p_callable, p_flags); + return; + } if (!is_connected(CoreStringNames::get_singleton()->changed, p_callable) || p_flags & CONNECT_REFERENCE_COUNTED) { connect(CoreStringNames::get_singleton()->changed, p_callable, p_flags); } } void Resource::disconnect_changed(const Callable &p_callable) { + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the check and disconnection happen on the main thread, later, since signals are not thread-safe. + callable_mp(this, &Resource::disconnect_changed).call_deferred(p_callable); + return; + } if (is_connected(CoreStringNames::get_singleton()->changed, p_callable)) { disconnect(CoreStringNames::get_singleton()->changed, p_callable); } diff --git a/core/object/method_bind.h b/core/object/method_bind.h index a1723adb9a..88b867a1ca 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -226,7 +226,7 @@ class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, v public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)(p_args, p_arg_count, r_error); return {}; @@ -265,7 +265,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error); } @@ -336,7 +336,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); @@ -348,7 +348,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args(static_cast<T *>(p_object), method, p_args); @@ -359,7 +359,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args); @@ -420,7 +420,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); @@ -432,7 +432,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_argsc(static_cast<T *>(p_object), method, p_args); @@ -443,7 +443,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args); @@ -515,7 +515,7 @@ public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { Variant ret; #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); @@ -527,7 +527,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args_ret(static_cast<T *>(p_object), method, p_args, r_ret); @@ -538,7 +538,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); @@ -611,7 +611,7 @@ public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { Variant ret; #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); @@ -623,7 +623,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args_retc(static_cast<T *>(p_object), method, p_args, r_ret); @@ -634,7 +634,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); diff --git a/core/object/object.cpp b/core/object/object.cpp index 5db1d2534f..d9a5713c20 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1483,10 +1483,15 @@ String Object::tr(const StringName &p_message, const StringName &p_context) cons } if (Engine::get_singleton()->is_editor_hint()) { + String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context); + if (!tr_msg.is_empty()) { + return tr_msg; + } + return TranslationServer::get_singleton()->tool_translate(p_message, p_context); - } else { - return TranslationServer::get_singleton()->translate(p_message, p_context); } + + return TranslationServer::get_singleton()->translate(p_message, p_context); } String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { @@ -1499,10 +1504,15 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu } if (Engine::get_singleton()->is_editor_hint()) { + String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context); + if (!tr_msg.is_empty()) { + return tr_msg; + } + return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context); - } else { - return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); } + + return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); } void Object::_clear_internal_resource_paths(const Variant &p_var) { diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp index 32e4564c5e..8ae2efb787 100644 --- a/core/string/node_path.cpp +++ b/core/string/node_path.cpp @@ -92,6 +92,14 @@ StringName NodePath::get_subname(int p_idx) const { return data->subpath[p_idx]; } +int NodePath::get_total_name_count() const { + if (!data) { + return 0; + } + + return data->path.size() + data->subpath.size(); +} + void NodePath::unref() { if (data && data->refcount.unref()) { memdelete(data); @@ -229,6 +237,27 @@ StringName NodePath::get_concatenated_subnames() const { return data->concatenated_subpath; } +NodePath NodePath::slice(int p_begin, int p_end) const { + const int name_count = get_name_count(); + const int total_count = get_total_name_count(); + + int begin = CLAMP(p_begin, -total_count, total_count); + if (begin < 0) { + begin += total_count; + } + int end = CLAMP(p_end, -total_count, total_count); + if (end < 0) { + end += total_count; + } + const int sub_begin = MAX(begin - name_count - 1, 0); + const int sub_end = MAX(end - name_count, 0); + + const Vector<StringName> names = get_names().slice(begin, end); + const Vector<StringName> sub_names = get_subnames().slice(sub_begin, sub_end); + const bool absolute = is_absolute() && (begin == 0); + return NodePath(names, sub_names, absolute); +} + NodePath NodePath::rel_path_to(const NodePath &p_np) const { ERR_FAIL_COND_V(!is_absolute(), NodePath()); ERR_FAIL_COND_V(!p_np.is_absolute(), NodePath()); @@ -331,7 +360,7 @@ NodePath NodePath::simplified() const { } NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { - if (p_path.size() == 0) { + if (p_path.size() == 0 && !p_absolute) { return; } @@ -343,7 +372,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { } NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) { - if (p_path.size() == 0 && p_subpath.size() == 0) { + if (p_path.size() == 0 && p_subpath.size() == 0 && !p_absolute) { return; } diff --git a/core/string/node_path.h b/core/string/node_path.h index 876d69924e..56799839d7 100644 --- a/core/string/node_path.h +++ b/core/string/node_path.h @@ -57,10 +57,12 @@ public: StringName get_name(int p_idx) const; int get_subname_count() const; StringName get_subname(int p_idx) const; + int get_total_name_count() const; Vector<StringName> get_names() const; Vector<StringName> get_subnames() const; StringName get_concatenated_names() const; StringName get_concatenated_subnames() const; + NodePath slice(int p_begin, int p_end = INT_MAX) const; NodePath rel_path_to(const NodePath &p_np) const; NodePath get_as_property_path() const; diff --git a/core/string/translation.cpp b/core/string/translation.cpp index db0c3f6006..2f25f56eac 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -772,6 +772,20 @@ StringName TranslationServer::tool_translate_plural(const StringName &p_message, return p_message_plural; } +void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) { + property_translation = p_translation; +} + +StringName TranslationServer::property_translate(const StringName &p_message) const { + if (property_translation.is_valid()) { + StringName r = property_translation->get_message(p_message); + if (r) { + return r; + } + } + return p_message; +} + void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) { doc_translation = p_translation; } @@ -800,13 +814,13 @@ StringName TranslationServer::doc_translate_plural(const StringName &p_message, return p_message_plural; } -void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) { - property_translation = p_translation; +void TranslationServer::set_extractable_translation(const Ref<Translation> &p_translation) { + extractable_translation = p_translation; } -StringName TranslationServer::property_translate(const StringName &p_message) const { - if (property_translation.is_valid()) { - StringName r = property_translation->get_message(p_message); +StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const { + if (extractable_translation.is_valid()) { + StringName r = extractable_translation->get_message(p_message, p_context); if (r) { return r; } @@ -814,6 +828,20 @@ StringName TranslationServer::property_translate(const StringName &p_message) co return p_message; } +StringName TranslationServer::extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (extractable_translation.is_valid()) { + StringName r = extractable_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); + if (r) { + return r; + } + } + + if (p_n == 1) { + return p_message; + } + return p_message_plural; +} + bool TranslationServer::is_pseudolocalization_enabled() const { return pseudolocalization_enabled; } diff --git a/core/string/translation.h b/core/string/translation.h index 4eca37f6be..bd7082dc9d 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -82,8 +82,9 @@ class TranslationServer : public Object { HashSet<Ref<Translation>> translations; Ref<Translation> tool_translation; - Ref<Translation> doc_translation; Ref<Translation> property_translation; + Ref<Translation> doc_translation; + Ref<Translation> extractable_translation; bool enabled = true; @@ -181,11 +182,14 @@ public: Ref<Translation> get_tool_translation() const; StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; + void set_property_translation(const Ref<Translation> &p_translation); + StringName property_translate(const StringName &p_message) const; void set_doc_translation(const Ref<Translation> &p_translation); StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_property_translation(const Ref<Translation> &p_translation); - StringName property_translate(const StringName &p_message) const; + void set_extractable_translation(const Ref<Translation> &p_translation); + StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const; + StringName extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void setup(); diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index a8a96e6e3f..f4b00255a1 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -5391,9 +5391,7 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St /** * "Run-time TRanslate". Performs string replacement for internationalization - * within a running project. The translation string must be supplied by the - * project, as Godot does not provide built-in translations for `RTR()` strings - * to keep binary size low. A translation context can optionally be specified to + * without the editor. A translation context can optionally be specified to * disambiguate between identical source strings in translations. When * placeholders are desired, use `vformat(RTR("Example: %s"), some_string)`. * If a string mentions a quantity (and may therefore need a dynamic plural form), @@ -5407,9 +5405,8 @@ String RTR(const String &p_text, const String &p_context) { String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context); if (rtr.is_empty() || rtr == p_text) { return TranslationServer::get_singleton()->translate(p_text, p_context); - } else { - return rtr; } + return rtr; } return p_text; @@ -5417,13 +5414,10 @@ String RTR(const String &p_text, const String &p_context) { /** * "Run-time TRanslate for N items". Performs string replacement for - * internationalization within a running project. The translation string must be - * supplied by the project, as Godot does not provide built-in translations for - * `RTRN()` strings to keep binary size low. A translation context can - * optionally be specified to disambiguate between identical source strings in - * translations. Use `RTR()` if the string doesn't need dynamic plural form. - * When placeholders are desired, use - * `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`. + * internationalization without the editor. A translation context can optionally + * be specified to disambiguate between identical source strings in translations. + * Use `RTR()` if the string doesn't need dynamic plural form. When placeholders + * are desired, use `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`. * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`. * * NOTE: Do not use `RTRN()` in editor-only code (typically within the `editor/` @@ -5434,9 +5428,8 @@ String RTRN(const String &p_text, const String &p_text_plural, int p_n, const St String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); if (rtr.is_empty() || rtr == p_text || rtr == p_text_plural) { return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context); - } else { - return rtr; } + return rtr; } // Return message based on English plural rule if translation is not possible. diff --git a/core/string/ustring.h b/core/string/ustring.h index b1348ceb48..468a015302 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -556,6 +556,43 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St String RTR(const String &p_text, const String &p_context = ""); String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = ""); +/** + * "Extractable TRanslate". Used for strings that can appear inside an exported + * project (such as the ones in nodes like `FileDialog`), which are made possible + * to add in the POT generator. A translation context can optionally be specified + * to disambiguate between identical source strings in translations. + * When placeholders are desired, use vformat(ETR("Example: %s"), some_string)`. + * If a string mentions a quantity (and may therefore need a dynamic plural form), + * use `ETRN()` instead of `ETR()`. + * + * NOTE: This function is for string extraction only, and will just return the + * string it was given. The translation itself should be done internally by nodes + * with `atr()` instead. + */ +_FORCE_INLINE_ String ETR(const String &p_text, const String &p_context = "") { + return p_text; +} + +/** + * "Extractable TRanslate for N items". Used for strings that can appear inside an + * exported project (such as the ones in nodes like `FileDialog`), which are made + * possible to add in the POT generator. A translation context can optionally be + * specified to disambiguate between identical source strings in translations. + * Use `ETR()` if the string doesn't need dynamic plural form. When placeholders + * are desired, use `vformat(ETRN("%d item", "%d items", some_integer), some_integer)`. + * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`. + * + * NOTE: This function is for string extraction only, and will just return the + * string it was given. The translation itself should be done internally by nodes + * with `atr()` instead. + */ +_FORCE_INLINE_ String ETRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "") { + if (p_n == 1) { + return p_text; + } + return p_text_plural; +} + bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); _FORCE_INLINE_ void sarray_add_str(Vector<String> &arr) { diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index b551a7059e..503254d1d3 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2033,6 +2033,7 @@ static void _register_variant_builtin_methods() { bind_method(NodePath, get_subname, sarray("idx"), varray()); bind_method(NodePath, get_concatenated_names, sarray(), varray()); bind_method(NodePath, get_concatenated_subnames, sarray(), varray()); + bind_method(NodePath, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(NodePath, get_as_property_path, sarray(), varray()); bind_method(NodePath, is_empty, sarray(), varray()); diff --git a/core/version.h b/core/version.h index abb81312ac..18a97cadf0 100644 --- a/core/version.h +++ b/core/version.h @@ -33,6 +33,8 @@ #include "core/version_generated.gen.h" +#include <stdint.h> + // Copied from typedefs.h to stay lean. #ifndef _STR #define _STR(m_x) #m_x @@ -77,4 +79,8 @@ // Git commit hash, generated at build time in `core/version_hash.gen.cpp`. extern const char *const VERSION_HASH; +// Git commit date UNIX timestamp (in seconds), generated at build time in `core/version_hash.gen.cpp`. +// Set to 0 if unknown. +extern const uint64_t VERSION_TIMESTAMP; + #endif // VERSION_H diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index 7ba328c8b8..e5b47ffb89 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -94,7 +94,7 @@ <theme_item name="font_hover_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [Button] is being hovered and pressed. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the [Button]. </theme_item> <theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 0e4dcacc56..dd0522e091 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -429,6 +429,9 @@ <member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter=""> If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor. </member> + <member name="editors/polygon_editor/auto_bake_delay" type="float" setter="" getter=""> + The delay in seconds until more complex and performance costly polygon editors commit their outlines, e.g. the 2D navigation polygon editor rebakes the navigation mesh polygons. A negative value stops the auto bake. + </member> <member name="editors/polygon_editor/point_grab_radius" type="int" setter="" getter=""> The radius in which points can be selected in the [Polygon2D] and [CollisionPolygon2D] editors (in pixels). Higher values make it easier to select points quickly, but can make it more difficult to select the expected point when several points are located close to each other. </member> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 580756c12d..4c8859baf2 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -4,7 +4,7 @@ Provides access to engine properties. </brief_description> <description> - The [Engine] singleton allows you to query and modify the project's run-time parameters, such as frames per second, time scale, and others. + The [Engine] singleton allows you to query and modify the project's run-time parameters, such as frames per second, time scale, and others. It also stores information about the current build of Godot, such as the current version. </description> <tutorials> </tutorials> @@ -12,8 +12,8 @@ <method name="get_architecture_name" qualifiers="const"> <return type="String" /> <description> - Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code]. - To detect whether the current CPU architecture is 64-bit, you can use the fact that all 64-bit architecture names have [code]64[/code] in their name: + Returns the name of the CPU architecture the Godot binary was built for. Possible return values include [code]"x86_64"[/code], [code]"x86_32"[/code], [code]"arm64"[/code], [code]"arm32"[/code], [code]"rv64"[/code], [code]"riscv"[/code], [code]"ppc64"[/code], [code]"ppc"[/code], [code]"wasm64"[/code], and [code]"wasm32"[/code]. + To detect whether the current build is 64-bit, you can use the fact that all 64-bit architecture names contain [code]64[/code] in their name: [codeblocks] [gdscript] if "64" in Engine.get_architecture_name(): @@ -28,74 +28,74 @@ GD.Print("Running a 32-bit build of Godot."); [/csharp] [/codeblocks] - [b]Note:[/b] [method get_architecture_name] does [i]not[/i] return the name of the host CPU architecture. For example, if running an x86_32 Godot binary on a x86_64 system, the returned value will be [code]x86_32[/code]. + [b]Note:[/b] This method does [i]not[/i] return the name of the system's CPU architecture (like [method OS.get_processor_name]). For example, when running a [code]x86_32[/code] Godot binary on a [code]x86_64[/code] system, the returned value will still be [code]"x86_32"[/code]. </description> </method> <method name="get_author_info" qualifiers="const"> <return type="Dictionary" /> <description> - Returns engine author information in a Dictionary. - [code]lead_developers[/code] - Array of Strings, lead developer names - [code]founders[/code] - Array of Strings, founder names - [code]project_managers[/code] - Array of Strings, project manager names - [code]developers[/code] - Array of Strings, developer names + Returns the engine author information as a [Dictionary], where each entry is an [Array] of strings with the names of notable contributors to the Godot Engine: [code]lead_developers[/code], [code]founders[/code], [code]project_managers[/code], and [code]developers[/code]. </description> </method> <method name="get_copyright_info" qualifiers="const"> <return type="Dictionary[]" /> <description> - Returns an Array of copyright information Dictionaries. - [code]name[/code] - String, component name - [code]parts[/code] - Array of Dictionaries {[code]files[/code], [code]copyright[/code], [code]license[/code]} describing subsections of the component + Returns an [Array] of dictionaries with copyright information for every component of Godot's source code. + Every [Dictionary] contains a [code]name[/code] identifier, and a [code]parts[/code] array of dictionaries. It describes the component in detail with the following entries: + - [code]files[/code] - [Array] of file paths from the source code affected by this component; + - [code]copyright[/code] - [Array] of owners of this component; + - [code]license[/code] - The license applied to this component (such as "[url=https://en.wikipedia.org/wiki/MIT_License#Ambiguity_and_variants]Expat[/url]" or "[url=https://creativecommons.org/licenses/by/4.0/]CC-BY-4.0[/url]"). </description> </method> <method name="get_donor_info" qualifiers="const"> <return type="Dictionary" /> <description> - Returns a Dictionary of Arrays of donor names. + Returns a [Dictionary] of categorized donor names. Each entry is an [Array] of strings: {[code]platinum_sponsors[/code], [code]gold_sponsors[/code], [code]silver_sponsors[/code], [code]bronze_sponsors[/code], [code]mini_sponsors[/code], [code]gold_donors[/code], [code]silver_donors[/code], [code]bronze_donors[/code]} </description> </method> <method name="get_frames_drawn"> <return type="int" /> <description> - Returns the total number of frames drawn. On headless platforms, or if the render loop is disabled with [code]--disable-render-loop[/code] via command line, [method get_frames_drawn] always returns [code]0[/code]. See [method get_process_frames]. + Returns the total number of frames drawn since the engine started. + [b]Note:[/b] On headless platforms, or if rendering is disabled with [code]--disable-render-loop[/code] via command line, this method always returns [code]0[/code]. See also [method get_process_frames]. </description> </method> <method name="get_frames_per_second" qualifiers="const"> <return type="float" /> <description> - Returns the frames per second of the running game. + Returns the average frames rendered every second (FPS), also known as the framerate. </description> </method> <method name="get_license_info" qualifiers="const"> <return type="Dictionary" /> <description> - Returns Dictionary of licenses used by Godot and included third party components. + Returns a [Dictionary] of licenses used by Godot and included third party components. Each entry is a license name (such as "[url=https://en.wikipedia.org/wiki/MIT_License#Ambiguity_and_variants]Expat[/url]") and its associated text. </description> </method> <method name="get_license_text" qualifiers="const"> <return type="String" /> <description> - Returns Godot license text. + Returns the full Godot license text. </description> </method> <method name="get_main_loop" qualifiers="const"> <return type="MainLoop" /> <description> - Returns the main loop object (see [MainLoop] and [SceneTree]). + Returns the instance of the [MainLoop]. This is usually the main [SceneTree] and is the same as [method Node.get_tree]. + [b]Note:[/b] The type instantiated as the main loop can changed with [member ProjectSettings.application/run/main_loop_type]. </description> </method> <method name="get_physics_frames" qualifiers="const"> <return type="int" /> <description> - Returns the total number of frames passed since engine initialization which is advanced on each [b]physics frame[/b]. See also [method get_process_frames]. - [method get_physics_frames] can be used to run expensive logic less often without relying on a [Timer]: + Returns the total number of frames passed since the engine started. This number is increased every [b]physics frame[/b]. See also [method get_process_frames]. + This method can be used to run expensive logic less often without relying on a [Timer]: [codeblocks] [gdscript] func _physics_process(_delta): if Engine.get_physics_frames() % 2 == 0: - pass # Run expensive logic only once every 2 physics frames here. + pass # Run expensive logic only once every 2 physics frames here. [/gdscript] [csharp] public override void _PhysicsProcess(double delta) @@ -120,22 +120,22 @@ <method name="get_process_frames" qualifiers="const"> <return type="int" /> <description> - Returns the total number of frames passed since engine initialization which is advanced on each [b]process frame[/b], regardless of whether the render loop is enabled. See also [method get_frames_drawn] and [method get_physics_frames]. - [method get_process_frames] can be used to run expensive logic less often without relying on a [Timer]: + Returns the total number of frames passed since the engine started. This number is increased every [b]process frame[/b], regardless of whether the render loop is enabled. See also [method get_frames_drawn] and [method get_physics_frames]. + This method can be used to run expensive logic less often without relying on a [Timer]: [codeblocks] [gdscript] func _process(_delta): - if Engine.get_process_frames() % 2 == 0: - pass # Run expensive logic only once every 2 process (render) frames here. + if Engine.get_process_frames() % 5 == 0: + pass # Run expensive logic only once every 5 process (render) frames here. [/gdscript] [csharp] public override void _Process(double delta) { base._Process(delta); - if (Engine.GetProcessFrames() % 2 == 0) + if (Engine.GetProcessFrames() % 5 == 0) { - // Run expensive logic only once every 2 physics frames here. + // Run expensive logic only once every 5 process (render) frames here. } } [/csharp] @@ -146,7 +146,7 @@ <return type="ScriptLanguage" /> <param index="0" name="index" type="int" /> <description> - Returns an instance of a [ScriptLanguage] with the given index. + Returns an instance of a [ScriptLanguage] with the given [param index]. </description> </method> <method name="get_script_language_count"> @@ -159,43 +159,46 @@ <return type="Object" /> <param index="0" name="name" type="StringName" /> <description> - Returns a global singleton with given [param name]. Often used for plugins, e.g. GodotPayments. + Returns the global singleton with the given [param name], or [code]null[/code] if it does not exist. Often used for plugins. See also [method has_singleton] and [method get_singleton_list]. + [b]Note:[/b] Global singletons are not the same as autoloaded nodes, which are configurable in the project settings. </description> </method> <method name="get_singleton_list" qualifiers="const"> <return type="PackedStringArray" /> <description> - Returns a list of available global singletons. + Returns a list of names of all available global singletons. See also [method get_singleton]. </description> </method> <method name="get_version_info" qualifiers="const"> <return type="Dictionary" /> <description> - Returns the current engine version information in a Dictionary. - [code]major[/code] - Holds the major version number as an int - [code]minor[/code] - Holds the minor version number as an int - [code]patch[/code] - Holds the patch version number as an int - [code]hex[/code] - Holds the full version number encoded as a hexadecimal int with one byte (2 places) per number (see example below) - [code]status[/code] - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String - [code]build[/code] - Holds the build name (e.g. "custom_build") as a String - [code]hash[/code] - Holds the full Git commit hash as a String - [code]string[/code] - [code]major[/code] + [code]minor[/code] + [code]patch[/code] + [code]status[/code] + [code]build[/code] in a single String - The [code]hex[/code] value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. [b]Note:[/b] It's still an int internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for easy version comparisons from code: + Returns the current engine version information as a [Dictionary] containing the following entries: + - [code]major[/code] - Major version number as an int; + - [code]minor[/code] - Minor version number as an int; + - [code]patch[/code] - Patch version number as an int; + - [code]hex[/code] - Full version encoded as a hexadecimal int with one byte (2 hex digits) per number (see example below); + - [code]status[/code] - Status (such as "beta", "rc1", "rc2", "stable", etc.) as a String; + - [code]build[/code] - Build name (e.g. "custom_build") as a String; + - [code]hash[/code] - Full Git commit hash as a String; + - [code]timestamp[/code] - Holds the Git commit date UNIX timestamp in seconds as an int, or [code]0[/code] if unavailable; + - [code]string[/code] - [code]major[/code], [code]minor[/code], [code]patch[/code], [code]status[/code], and [code]build[/code] in a single String. + The [code]hex[/code] value is encoded as follows, from left to right: one byte for the major, one byte for the minor, one byte for the patch version. For example, "3.1.12" would be [code]0x03010C[/code]. + [b]Note:[/b] The [code]hex[/code] value is still an [int] internally, and printing it will give you its decimal representation, which is not particularly meaningful. Use hexadecimal literals for quick version comparisons from code: [codeblocks] [gdscript] - if Engine.get_version_info().hex >= 0x030200: - # Do things specific to version 3.2 or later + if Engine.get_version_info().hex >= 0x040100: + pass # Do things specific to version 4.1 or later. else: - # Do things specific to versions before 3.2 + pass # Do things specific to versions before 4.1. [/gdscript] [csharp] - if ((int)Engine.GetVersionInfo()["hex"] >= 0x030200) + if ((int)Engine.GetVersionInfo()["hex"] >= 0x040100) { - // Do things specific to version 3.2 or later + // Do things specific to version 4.1 or later. } else { - // Do things specific to versions before 3.2 + // Do things specific to versions before 4.1. } [/csharp] [/codeblocks] @@ -204,20 +207,35 @@ <method name="get_write_movie_path" qualifiers="const"> <return type="String" /> <description> - Returns the path to the [MovieWriter]'s output file, or an empty string if the engine wasn't started in Movie Maker mode. This path can be absolute or relative depending on how the user specified it. + Returns the path to the [MovieWriter]'s output file, or an empty string if the engine wasn't started in Movie Maker mode. The default path can be changed in [member ProjectSettings.editor/movie_writer/movie_file]. </description> </method> <method name="has_singleton" qualifiers="const"> <return type="bool" /> <param index="0" name="name" type="StringName" /> <description> - Returns [code]true[/code] if a singleton with given [param name] exists in global scope. + Returns [code]true[/code] if a singleton with the given [param name] exists in the global scope. See also [method get_singleton]. + [codeblocks] + [gdscript] + print(Engine.has_singleton("OS")) # Prints true + print(Engine.has_singleton("Engine")) # Prints true + print(Engine.has_singleton("AudioServer")) # Prints true + print(Engine.has_singleton("Unknown")) # Prints false + [/gdscript] + [csharp] + GD.Print(Engine.HasSingleton("OS")); // Prints true + GD.Print(Engine.HasSingleton("Engine")); // Prints true + GD.Print(Engine.HasSingleton("AudioServer")); // Prints true + GD.Print(Engine.HasSingleton("Unknown")); // Prints false + [/csharp] + [/codeblocks] + [b]Note:[/b] Global singletons are not the same as autoloaded nodes, which are configurable in the project settings. </description> </method> <method name="is_editor_hint" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the script is currently running inside the editor, [code]false[/code] otherwise. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor: + Returns [code]true[/code] if the script is currently running inside the editor, otherwise returns [code]false[/code]. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor: [codeblocks] [gdscript] if Engine.is_editor_hint(): @@ -233,13 +251,25 @@ [/csharp] [/codeblocks] See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information. - [b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project. + [b]Note:[/b] To detect whether the script is running on an editor [i]build[/i] (such as when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] evaluate to [code]true[/code] both when the script is running in the editor and when running the project from the editor, but returns [code]false[/code] when run from an exported project. </description> </method> <method name="is_in_physics_frame" qualifiers="const"> <return type="bool" /> <description> - Returns [code]true[/code] if the game is inside the fixed process and physics phase of the game loop. + Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop. + [codeblock] + func _enter_tree(): + # Depending on when the node is added to the tree, + # prints either "true" or "false". + print(Engine.is_in_physics_frame()) + + func _process(delta): + print(Engine.is_in_physics_frame()) # Prints false + + func _physics_process(delta): + print(Engine.is_in_physics_frame()) # Prints true + [/codeblock] </description> </method> <method name="register_script_language"> @@ -248,9 +278,9 @@ <description> Registers a [ScriptLanguage] instance to be available with [code]ScriptServer[/code]. Returns: - - [constant OK] on success - - [constant ERR_UNAVAILABLE] if [code]ScriptServer[/code] has reached it limit and cannot register any new language - - [constant ERR_ALREADY_EXISTS] if [code]ScriptServer[/code] already contains a language with similar extension/name/type + - [constant OK] on success; + - [constant ERR_UNAVAILABLE] if [code]ScriptServer[/code] has reached the limit and cannot register any new language; + - [constant ERR_ALREADY_EXISTS] if [code]ScriptServer[/code] already contains a language with similar extension/name/type. </description> </method> <method name="register_singleton"> @@ -258,7 +288,7 @@ <param index="0" name="name" type="StringName" /> <param index="1" name="instance" type="Object" /> <description> - Registers the given object as a singleton, globally available under [param name]. + Registers the given [Object] [param instance] as a singleton, available globally under [param name]. Useful for plugins. </description> </method> <method name="unregister_script_language"> @@ -267,33 +297,36 @@ <description> Unregisters the [ScriptLanguage] instance from [code]ScriptServer[/code]. Returns: - - [constant OK] on success - - [constant ERR_DOES_NOT_EXIST] if the language is already not registered in [code]ScriptServer[/code] + - [constant OK] on success; + - [constant ERR_DOES_NOT_EXIST] if the language is not registered in [code]ScriptServer[/code]. </description> </method> <method name="unregister_singleton"> <return type="void" /> <param index="0" name="name" type="StringName" /> <description> - Unregisters the singleton registered under [param name]. The singleton object is not freed. Only works with user-defined singletons created with [method register_singleton]. + Removes the singleton registered under [param name]. The singleton object is [i]not[/i] freed. Only works with user-defined singletons registered with [method register_singleton]. </description> </method> </methods> <members> <member name="max_fps" type="int" setter="set_max_fps" getter="get_max_fps" default="0"> - The maximum number of frames per second that can be rendered. A value of [code]0[/code] means "no limit". The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project logic and rendering. - Limiting the FPS can be useful to reduce system power consumption, which reduces heat and noise emissions (and improves battery life on mobile devices). - If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate. + The maximum number of frames per second (FPS) that can be rendered. A value of [code]0[/code] means the framerate is uncapped. + Limiting the FPS can be useful to reduce the host machine's power consumption, which reduces heat, noise emissions, and improves battery life. + If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Enabled[/code] or [code]Adaptive[/code], the setting takes precedence and the max FPS number cannot exceed the monitor's refresh rate. If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Enabled[/code], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using a FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url]. - If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Disabled[/code], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios. See also [member physics_ticks_per_second] and [member ProjectSettings.application/run/max_fps]. + [b]Note:[/b] The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project's logic and rendering. + [b]Note:[/b] If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Disabled[/code], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios. </member> <member name="max_physics_steps_per_frame" type="int" setter="set_max_physics_steps_per_frame" getter="get_max_physics_steps_per_frame" default="8"> - Controls the maximum number of physics steps that can be simulated each rendered frame. The default value is tuned to avoid "spiral of death" situations where expensive physics simulations trigger more expensive simulations indefinitely. However, the game will appear to slow down if the rendering FPS is less than [code]1 / max_physics_steps_per_frame[/code] of [member physics_ticks_per_second]. This occurs even if [code]delta[/code] is consistently used in physics calculations. To avoid this, increase [member max_physics_steps_per_frame] if you have increased [member physics_ticks_per_second] significantly above its default value. + The maximum number of physics steps that can be simulated each rendered frame. + [b]Note:[/b] The default value is tuned to prevent expensive physics simulations from triggering even more expensive simulations indefinitely. However, the game will appear to slow down if the rendering FPS is less than [code]1 / max_physics_steps_per_frame[/code] of [member physics_ticks_per_second]. This occurs even if [code]delta[/code] is consistently used in physics calculations. To avoid this, increase [member max_physics_steps_per_frame] if you have increased [member physics_ticks_per_second] significantly above its default value. </member> <member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5"> - Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of the in-game clock and real clock but smooth out framerate jitters. The default value of 0.5 should be good enough for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. - [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code]. + How much physics ticks are synchronized with real time. If [code]0[/code] or less, the ticks are fully synchronized. Higher values cause the in-game clock to deviate more from the real clock, but they smooth out framerate jitters. + [b]Note:[/b] The default value of [code]0.5[/code] should be good enough for most cases; values above [code]2[/code] could cause the game to react to dropped frames with a noticeable delay and are not recommended. + [b]Note:[/b] When using a custom physics interpolation solution, or within a network game, it's recommended to disable the physics jitter fix by setting this property to [code]0[/code]. </member> <member name="physics_ticks_per_second" type="int" setter="set_physics_ticks_per_second" getter="get_physics_ticks_per_second" default="60"> The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around collision tunneling issues, but keep in mind doing so will increase CPU usage. See also [member max_fps] and [member ProjectSettings.physics/common/physics_ticks_per_second]. @@ -301,13 +334,15 @@ </member> <member name="print_error_messages" type="bool" setter="set_print_error_messages" getter="is_printing_error_messages" default="true"> If [code]false[/code], stops printing error and warning messages to the console and editor Output log. This can be used to hide error and warning messages during unit test suite runs. This property is equivalent to the [member ProjectSettings.application/run/disable_stderr] project setting. - [b]Warning:[/b] If you set this to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. If this is set to [code]false[/code] in a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default). [b]Note:[/b] This property does not impact the editor's Errors tab when running a project from the editor. + [b]Warning:[/b] If set to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. In a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default). </member> <member name="time_scale" type="float" setter="set_time_scale" getter="get_time_scale" default="1.0"> - Controls how fast or slow the in-game clock ticks versus the real life one. It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life, whilst a value of 0.5 means the game moves at half the regular speed. This also affects [Timer] and [SceneTreeTimer] (see [method SceneTree.create_timer] for how to control this). + The speed multiplier at which the in-game clock updates, compared to real time. For example, if set to [code]2.0[/code] the game runs twice as fast, and if set to [code]0.5[/code] the game runs half as fast. + This value affects [Timer], [SceneTreeTimer], and all other simulations that make use of [code]delta[/code] time (such as [method Node._process] and [method Node._physics_process]). + [b]Note:[/b] It's recommended to keep this property above [code]0.0[/code], as the game may behave unexpectedly otherwise. [b]Note:[/b] This does not affect audio playback speed. Use [member AudioServer.playback_speed_scale] to adjust audio playback speed independently of [member Engine.time_scale]. - [b]Note:[/b] This does not automatically adjust [member physics_ticks_per_second], which means that with time scales above 1.0, physics simulation may become less precise (as each physics tick will stretch over a larger period of engine time). If you're using [member Engine.time_scale] to speed up simulation by a large factor, consider increasing [member physics_ticks_per_second] as well to improve physics reliability. + [b]Note:[/b] This does not automatically adjust [member physics_ticks_per_second]. With values above [code]1.0[/code] physics simulation may become less precise, as each physics tick will stretch over a larger period of engine time. If you're modifying [member Engine.time_scale] to speed up simulation by a large factor, consider also increasing [member physics_ticks_per_second] to make the simulation more reliable. </member> </members> </class> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 47a1801f58..7c8910d060 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -210,6 +210,9 @@ <theme_item name="back_folder" data_type="icon" type="Texture2D"> Custom icon for the back arrow. </theme_item> + <theme_item name="create_folder" data_type="icon" type="Texture2D"> + Custom icon for the create folder button. + </theme_item> <theme_item name="file" data_type="icon" type="Texture2D"> Custom icon for files. </theme_item> diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index 593f41bc70..a1e5d9cbd9 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -461,7 +461,7 @@ <theme_item name="font_hovered_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> Text [Color] used when the item is hovered and not selected yet. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the item. </theme_item> <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> @@ -483,7 +483,7 @@ The size of the item text outline. [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. </theme_item> - <theme_item name="v_separation" data_type="constant" type="int" default="2"> + <theme_item name="v_separation" data_type="constant" type="int" default="4"> The vertical spacing between items. </theme_item> <theme_item name="font" data_type="font" type="Font"> diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index edd8a3e436..f39f5616f0 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -115,7 +115,7 @@ <theme_item name="font_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> Default text [Color] of the [Label]. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The color of text outline. </theme_item> <theme_item name="font_shadow_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)"> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 1f25e926c9..77fff22157 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -454,7 +454,7 @@ <theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> Default font color. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the [LineEdit]. </theme_item> <theme_item name="font_placeholder_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.6)"> diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml index aa81b6fde0..bcdffcd1ee 100644 --- a/doc/classes/LinkButton.xml +++ b/doc/classes/LinkButton.xml @@ -74,7 +74,7 @@ <theme_item name="font_hover_pressed_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> Text [Color] used when the [LinkButton] is being hovered and pressed. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the [LinkButton]. </theme_item> <theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml index 8812017e49..9e4287331c 100644 --- a/doc/classes/MenuBar.xml +++ b/doc/classes/MenuBar.xml @@ -132,7 +132,7 @@ <theme_item name="font_hover_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the menu item is being hovered and pressed. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the menu item. </theme_item> <theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 2b2dc63a33..3f8ed91ad7 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -237,16 +237,16 @@ [PackedVector2Array] for second UV coordinates. </constant> <constant name="ARRAY_CUSTOM0" value="6" enum="ArrayType"> - Contains custom color channel 0. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM0_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. + Contains custom color channel 0. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM0_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_SNORM], [constant ARRAY_CUSTOM_RG_HALF], or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. </constant> <constant name="ARRAY_CUSTOM1" value="7" enum="ArrayType"> - Contains custom color channel 1. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM1_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. + Contains custom color channel 1. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM1_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_SNORM], [constant ARRAY_CUSTOM_RG_HALF], or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. </constant> <constant name="ARRAY_CUSTOM2" value="8" enum="ArrayType"> - Contains custom color channel 2. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM2_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. + Contains custom color channel 2. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM2_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_SNORM], [constant ARRAY_CUSTOM_RG_HALF], or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. </constant> <constant name="ARRAY_CUSTOM3" value="9" enum="ArrayType"> - Contains custom color channel 3. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM3_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. + Contains custom color channel 3. [PackedByteArray] if [code](format >> Mesh.ARRAY_FORMAT_CUSTOM3_SHIFT) & Mesh.ARRAY_FORMAT_CUSTOM_MASK[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_SNORM], [constant ARRAY_CUSTOM_RG_HALF], or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise. </constant> <constant name="ARRAY_BONES" value="10" enum="ArrayType"> [PackedFloat32Array] or [PackedInt32Array] of bone indices. Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag. diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index fa6f158b6e..6e0799e796 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -199,6 +199,16 @@ Returns [code]true[/code] if the node path has been constructed from an empty [String] ([code]""[/code]). </description> </method> + <method name="slice" qualifiers="const"> + <return type="NodePath" /> + <param index="0" name="begin" type="int" /> + <param index="1" name="end" type="int" default="2147483647" /> + <description> + Returns the slice of the [NodePath], from [param begin] (inclusive) to [param end] (exclusive), as a new [NodePath]. + The absolute value of [param begin] and [param end] will be clamped to the sum of [method get_name_count] and [method get_subname_count], so the default value for [param end] makes it slice to the end of the [NodePath] by default (i.e. [code]path.slice(1)[/code] is a shorthand for [code]path.slice(1, path.get_name_count() + path.get_subname_count())[/code]). + If either [param begin] or [param end] are negative, they will be relative to the end of the [NodePath] (i.e. [code]path.slice(0, -2)[/code] is a shorthand for [code]path.slice(0, path.get_name_count() + path.get_subname_count() - 2)[/code]). + </description> + </method> </methods> <operators> <operator name="operator !="> diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml index b62cebfdad..c3b202e0a5 100644 --- a/doc/classes/PhysicalBone3D.xml +++ b/doc/classes/PhysicalBone3D.xml @@ -61,6 +61,7 @@ </member> <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0"> The body's bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). + [b]Note:[/b] Even with [member bounce] set to [code]1.0[/code], some energy will be lost over time due to linear and angular damping. To have a [PhysicalBone3D] that preserves all its energy over time, set [member bounce] to [code]1.0[/code], [member linear_damp_mode] to [constant DAMP_MODE_REPLACE], [member linear_damp] to [code]0.0[/code], [member angular_damp_mode] to [constant DAMP_MODE_REPLACE], and [member angular_damp] to [code]0.0[/code]. </member> <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true"> If [code]true[/code], the body is deactivated when there is no movement, so it will not take part in the simulation until it is awakened by an external force. diff --git a/doc/classes/PhysicsMaterial.xml b/doc/classes/PhysicsMaterial.xml index 30c2400775..1601a1040e 100644 --- a/doc/classes/PhysicsMaterial.xml +++ b/doc/classes/PhysicsMaterial.xml @@ -14,6 +14,7 @@ </member> <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0"> The body's bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). + [b]Note:[/b] Even with [member bounce] set to [code]1.0[/code], some energy will be lost over time due to linear and angular damping. To have a [PhysicsBody3D] that preserves all its energy over time, set [member bounce] to [code]1.0[/code], the body's linear damp mode to [b]Replace[/b] (if applicable), its linear damp to [code]0.0[/code], its angular damp mode to [b]Replace[/b] (if applicable), and its angular damp to [code]0.0[/code]. </member> <member name="friction" type="float" setter="set_friction" getter="get_friction" default="1.0"> The body's friction. Values range from [code]0[/code] (frictionless) to [code]1[/code] (maximum friction). diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index d884c7806f..266a0940eb 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -680,13 +680,13 @@ <theme_item name="font_hover_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> [Color] used for the hovered text. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the menu item. </theme_item> <theme_item name="font_separator_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> [Color] used for labeled separators' text. See [method add_separator]. </theme_item> - <theme_item name="font_separator_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_separator_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the labeled separator. </theme_item> <theme_item name="h_separation" data_type="constant" type="int" default="4"> diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml index 02f82f6a9a..e562d39bb7 100644 --- a/doc/classes/ProgressBar.xml +++ b/doc/classes/ProgressBar.xml @@ -40,7 +40,7 @@ <theme_item name="font_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> The color of the text. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the [ProgressBar]. </theme_item> <theme_item name="outline_size" data_type="constant" type="int" default="0"> diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml index 6a88adf421..4e20fe150e 100644 --- a/doc/classes/ResourceImporterScene.xml +++ b/doc/classes/ResourceImporterScene.xml @@ -53,6 +53,9 @@ <member name="nodes/apply_root_scale" type="bool" setter="" getter="" default="true"> If [code]true[/code], [member nodes/root_scale] will be applied to the descendant nodes, meshes, animations, bones, etc. This means that if you add a child node later on within the imported scene, it won't be scaled. If [code]false[/code], [member nodes/root_scale] will multiply the scale of the root node instead. </member> + <member name="nodes/import_as_skeleton_bones" type="bool" setter="" getter="" default="false"> + Treat all nodes in the imported scene as if they are bones within a single [Skeleton3D]. Can be used to guarantee that imported animations target skeleton bones rather than nodes. May also be used to assign the [code]"Root"[/code] bone in a [BoneMap]. See [url=$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html]Retargeting 3D Skeletons[/url] for more information. + </member> <member name="nodes/root_name" type="String" setter="" getter="" default=""""> Override for the root node name. If empty, the root node will use what the scene specifies, or the file name if the scene does not specify a root name. </member> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 85dea1485a..36b990b46b 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -430,6 +430,7 @@ <param index="0" name="data" type="Variant" /> <description> Adds a meta tag to the tag stack. Similar to the BBCode [code skip-lint][url=something]{text}[/url][/code], but supports non-[String] metadata types. + [b]Note:[/b] Meta tags do nothing by default when clicked. To assign behavior when clicked, connect [signal meta_clicked] to a function that is called when the meta tag is clicked. </description> </method> <method name="push_mono"> @@ -616,7 +617,7 @@ Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> <member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true"> - If [code]true[/code], the label underlines meta tags such as [code skip-lint][url]{text}[/url][/code]. + If [code]true[/code], the label underlines meta tags such as [code skip-lint][url]{text}[/url][/code]. These tags can call a function when clicked if [signal meta_clicked] is connected to a function. </member> <member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000"> The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely. @@ -674,7 +675,17 @@ <signal name="meta_clicked"> <param index="0" name="meta" type="Variant" /> <description> - Triggered when the user clicks on content between meta tags. If the meta is defined in text, e.g. [code skip-lint][url={"data"="hi"}]hi[/url][/code], then the parameter for this signal will be a [String] type. If a particular type or an object is desired, the [method push_meta] method must be used to manually insert the data into the tag stack. + Triggered when the user clicks on content between meta (URL) tags. If the meta is defined in BBCode, e.g. [code skip-lint][url={"key": "value"}]Text[/url][/code], then the parameter for this signal will always be a [String] type. If a particular type or an object is desired, the [method push_meta] method must be used to manually insert the data into the tag stack. Alternatively, you can convert the [String] input to the desired type based on its contents (such as calling [method JSON.parse] on it). + For example, the following method can be connected to [signal meta_clicked] to open clicked URLs using the user's default web browser: + [codeblocks] + [gdscript] + # This assumes RichTextLabel's `meta_clicked` signal was connected to + # the function below using the signal connection dialog. + func _richtextlabel_on_meta_clicked(meta): + # `meta` is of Variant type, so convert it to a String to avoid script errors at run-time. + OS.shell_open(str(meta)) + [/gdscript] + [/codeblocks] </description> </signal> <signal name="meta_hover_ended"> @@ -741,7 +752,7 @@ <theme_item name="default_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> The default text color. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The default tint of text outline. </theme_item> <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)"> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index 1a846140e5..aad2d853c2 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -4,9 +4,9 @@ Manages the game loop via a hierarchy of nodes. </brief_description> <description> - As one of the most important classes, the [SceneTree] manages the hierarchy of nodes in a scene as well as scenes themselves. Nodes can be added, retrieved and removed. The whole scene tree (and thus the current scene) can be paused. Scenes can be loaded, switched and reloaded. - You can also use the [SceneTree] to organize your nodes into groups: every node can be assigned as many groups as you want to create, e.g. an "enemy" group. You can then iterate these groups or even call methods and set properties on all the group's members at once. - [SceneTree] is the default [MainLoop] implementation used by scenes, and is thus in charge of the game loop. + As one of the most important classes, the [SceneTree] manages the hierarchy of nodes in a scene, as well as scenes themselves. Nodes can be added, fetched and removed. The whole scene tree (and thus the current scene) can be paused. Scenes can be loaded, switched and reloaded. + You can also use the [SceneTree] to organize your nodes into [b]groups[/b]: every node can be added to as many groups as you want to create, e.g. an "enemy" group. You can then iterate these groups or even call methods and set properties on all the nodes belonging to any given group. + [SceneTree] is the default [MainLoop] implementation used by the engine, and is thus in charge of the game loop. </description> <tutorials> <link title="SceneTree">$DOCS_URL/tutorials/scripting/scene_tree.html</link> @@ -18,8 +18,9 @@ <param index="0" name="group" type="StringName" /> <param index="1" name="method" type="StringName" /> <description> - Calls [param method] on each member of the given group. You can pass arguments to [param method] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped. - [b]Note:[/b] [method call_group] will call methods immediately on all members at once, which can cause stuttering if an expensive method is called on lots of members. + Calls [param method] on each node inside this tree added to the given [param group]. You can pass arguments to [param method] by specifying them at the end of this method call. Nodes that cannot call [param method] (either because the method doesn't exist or the arguments do not match) are ignored. See also [method set_group] and [method notify_group]. + [b]Note:[/b] This method acts immediately on all selected nodes at once, which may cause stuttering in some performance-intensive situations. + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="call_group_flags" qualifiers="vararg"> @@ -28,12 +29,14 @@ <param index="1" name="group" type="StringName" /> <param index="2" name="method" type="StringName" /> <description> - Calls [param method] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [param method] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped. + Calls the given [param method] on each node inside this tree added to the given [param group]. Use [param flags] to customize this method's behavior (see [enum GroupCallFlags]). Additional arguments for [param method] can be passed at the end of this method. Nodes that cannot call [param method] (either because the method doesn't exist or the arguments do not match) are ignored. [codeblock] - # Call the method in a deferred manner and in reverse order. - get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE) + # Calls "hide" to all nodes of the "enemies" group, at the end of the frame and in reverse tree order. + get_tree().call_group_flags( + SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE, + "enemies", "hide") [/codeblock] - [b]Note:[/b] Group call flags are used to control the method calling behavior. By default, methods will be called immediately in a way similar to [method call_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param flags] argument, methods will be called at the end of the frame in a way similar to [method Object.set_deferred]. + [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="change_scene_to_file"> @@ -64,11 +67,11 @@ <param index="2" name="process_in_physics" type="bool" default="false" /> <param index="3" name="ignore_time_scale" type="bool" default="false" /> <description> - Returns a [SceneTreeTimer] which will emit [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. - If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer. - If [param process_in_physics] is set to [code]true[/code], will update the [SceneTreeTimer] during the physics frame instead of the process frame (fixed framerate processing). - If [param ignore_time_scale] is set to [code]true[/code], will ignore [member Engine.time_scale] and update the [SceneTreeTimer] with the actual frame delta. - Commonly used to create a one-shot delay timer as in the following example: + Returns a new [SceneTreeTimer]. After [param time_sec] in seconds have passed, the timer will emit [signal SceneTreeTimer.timeout] and will be automatically freed. + If [param process_always] is [code]false[/code], the timer will be paused when setting [member SceneTree.paused] to [code]true[/code]. + If [param process_in_physics] is [code]true[/code], the timer will update at the end of the physics frame, instead of the process frame. + If [param ignore_time_scale] is [code]true[/code], the timer will ignore [member Engine.time_scale] and update with the real, elapsed time. + This method is commonly used to create a one-shot delay timer, as in the following example: [codeblocks] [gdscript] func some_function(): @@ -85,28 +88,27 @@ } [/csharp] [/codeblocks] - The timer will be automatically freed after its time elapses. - [b]Note:[/b] The timer is processed after all of the nodes in the current frame, i.e. node's [method Node._process] method would be called before the timer (or [method Node._physics_process] if [param process_in_physics] is set to [code]true[/code]). + [b]Note:[/b] The timer is always updated [i]after[/i] all of the nodes in the tree. A node's [method Node._process] method would be called before the timer updates (or [method Node._physics_process] if [param process_in_physics] is set to [code]true[/code]). </description> </method> <method name="create_tween"> <return type="Tween" /> <description> - Creates and returns a new [Tween]. The Tween will start automatically on the next process frame or physics frame (depending on [enum Tween.TweenProcessMode]). - [b]Note:[/b] When creating a [Tween] using this method, the [Tween] will not be tied to the [Node] that called it. It will continue to animate even if the [Node] is freed, but it will automatically finish if there's nothing left to animate. If you want the [Tween] to be automatically killed when the [Node] is freed, use [method Node.create_tween] or [method Tween.bind_node]. + Creates and returns a new [Tween] processed in this tree. The Tween will start automatically on the next process frame or physics frame (depending on its [enum Tween.TweenProcessMode]). + [b]Note:[/b] A [Tween] created using this method is not bound to any [Node]. It may keep working until there is nothing left to animate. If you want the [Tween] to be automatically killed when the [Node] is freed, use [method Node.create_tween] or [method Tween.bind_node]. </description> </method> <method name="get_first_node_in_group"> <return type="Node" /> <param index="0" name="group" type="StringName" /> <description> - Returns the first node in the specified group, or [code]null[/code] if the group is empty or does not exist. + Returns the first [Node] found inside the tree, that has been added to the given [param group], in scene hierarchy order. Returns [code]null[/code] if no match is found. See also [method get_nodes_in_group]. </description> </method> <method name="get_frame" qualifiers="const"> <return type="int" /> <description> - Returns the current frame number, i.e. the total frame count since the application started. + Returns how many frames have been processed, since the application started. This is [i]not[/i] a measurement of elapsed time. </description> </method> <method name="get_multiplayer" qualifiers="const"> @@ -119,7 +121,7 @@ <method name="get_node_count" qualifiers="const"> <return type="int" /> <description> - Returns the number of nodes in this [SceneTree]. + Returns the number of nodes inside this tree. </description> </method> <method name="get_node_count_in_group" qualifiers="const"> @@ -133,21 +135,20 @@ <return type="Node[]" /> <param index="0" name="group" type="StringName" /> <description> - Returns a list of all nodes assigned to the given group. + Returns an [Array] containing all nodes inside this tree, that have been added to the given [param group], in scene hierarchy order. </description> </method> <method name="get_processed_tweens"> <return type="Tween[]" /> <description> - Returns an array of currently existing [Tween]s in the [SceneTree] (both running and paused). + Returns an [Array] of currently existing [Tween]s in the tree, including paused tweens. </description> </method> <method name="has_group" qualifiers="const"> <return type="bool" /> <param index="0" name="name" type="StringName" /> <description> - Returns [code]true[/code] if the given group exists. - A group exists if any [Node] in the tree belongs to it (see [method Node.add_to_group]). Groups without nodes are removed automatically. + Returns [code]true[/code] if a node added to the given group [param name] exists in the tree. </description> </method> <method name="notify_group"> @@ -155,8 +156,8 @@ <param index="0" name="group" type="StringName" /> <param index="1" name="notification" type="int" /> <description> - Sends the given notification to all members of the [param group]. - [b]Note:[/b] [method notify_group] will immediately notify all members at once, which can cause stuttering if an expensive method is called as a result of sending the notification to lots of members. + Calls [method Object.notification] with the given [param notification] to all nodes inside this tree added to the [param group]. See also [method call_group] and [method set_group]. + [b]Note:[/b] This method acts immediately on all selected nodes at once, which may cause stuttering in some performance-intensive situations. </description> </method> <method name="notify_group_flags"> @@ -165,32 +166,30 @@ <param index="1" name="group" type="StringName" /> <param index="2" name="notification" type="int" /> <description> - Sends the given notification to all members of the [param group], respecting the given [enum GroupCallFlags]. - [b]Note:[/b] Group call flags are used to control the notification sending behavior. By default, notifications will be sent immediately in a way similar to [method notify_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param call_flags] argument, notifications will be sent at the end of the current frame in a way similar to using [code]Object.call_deferred("notification", ...)[/code]. + Calls [method Object.notification] with the given [param notification] to all nodes inside this tree added to the [param group]. Use [param call_flags] to customize this method's behavior (see [enum GroupCallFlags]). </description> </method> <method name="queue_delete"> <return type="void" /> <param index="0" name="obj" type="Object" /> <description> - Queues the given object for deletion, delaying the call to [method Object.free] to the end of the current frame. + Queues the given [param obj] to be deleted, calling its [method Object.free] at the end of the current frame. This method is similar to [method Node.queue_free]. </description> </method> <method name="quit"> <return type="void" /> <param index="0" name="exit_code" type="int" default="0" /> <description> - Quits the application at the end of the current iteration. Argument [param exit_code] can optionally be given (defaulting to 0) to customize the exit status code. - By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error. - For portability reasons, the exit code should be set between 0 and 125 (inclusive). - [b]Note:[/b] On iOS this method doesn't work. Instead, as recommended by the iOS Human Interface Guidelines, the user is expected to close apps via the Home button. + Quits the application at the end of the current iteration, with the given [param exit_code]. + By convention, an exit code of [code]0[/code] indicates success, whereas any other exit code indicates an error. For portability reasons, it should be between [code]0[/code] and [code]125[/code] (inclusive). + [b]Note:[/b] On iOS this method doesn't work. Instead, as recommended by the [url=https://developer.apple.com/library/archive/qa/qa1561/_index.html]iOS Human Interface Guidelines[/url], the user is expected to close apps via the Home button. </description> </method> <method name="reload_current_scene"> <return type="int" enum="Error" /> <description> - Reloads the currently active scene. - Returns [constant OK] on success, [constant ERR_UNCONFIGURED] if no [member current_scene] was defined yet, [constant ERR_CANT_OPEN] if [member current_scene] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if the scene cannot be instantiated. + Reloads the currently active scene, replacing [member current_scene] with a new instance of its original [PackedScene]. + Returns [constant OK] on success, [constant ERR_UNCONFIGURED] if no [member current_scene] is defined, [constant ERR_CANT_OPEN] if [member current_scene] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if the scene cannot be instantiated. </description> </method> <method name="set_group"> @@ -199,8 +198,9 @@ <param index="1" name="property" type="String" /> <param index="2" name="value" type="Variant" /> <description> - Sets the given [param property] to [param value] on all members of the given group. - [b]Note:[/b] [method set_group] will set the property immediately on all members at once, which can cause stuttering if a property with an expensive setter is set on lots of members. + Sets the given [param property] to [param value] on all nodes inside this tree added to the given [param group]. Nodes that do not have the [param property] are ignored. See also [method call_group] and [method notify_group]. + [b]Note:[/b] This method acts immediately on all selected nodes at once, which may cause stuttering in some performance-intensive situations. + [b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="set_group_flags"> @@ -210,8 +210,8 @@ <param index="2" name="property" type="String" /> <param index="3" name="value" type="Variant" /> <description> - Sets the given [param property] to [param value] on all members of the given group, respecting the given [enum GroupCallFlags]. - [b]Note:[/b] Group call flags are used to control the property setting behavior. By default, properties will be set immediately in a way similar to [method set_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param call_flags] argument, properties will be set at the end of the frame in a way similar to [method Object.call_deferred]. + Sets the given [param property] to [param value] on all nodes inside this tree added to the given [param group]. Nodes that do not have the [param property] are ignored. Use [param call_flags] to customize this method's behavior (see [enum GroupCallFlags]). + [b]Note:[/b] In C#, [param property] must be in snake_case when referring to built-in Godot properties. Prefer using the names exposed in the [code]PropertyName[/code] class to avoid allocating a new [StringName] on each call. </description> </method> <method name="set_multiplayer"> @@ -236,8 +236,8 @@ For mobile platforms, see [member quit_on_go_back]. </member> <member name="current_scene" type="Node" setter="set_current_scene" getter="get_current_scene"> - Returns the root node of the currently running scene, regardless of its structure. - [b]Warning:[/b] Setting this directly might not work as expected, and will [i]not[/i] add or remove any nodes from the tree, consider using [method change_scene_to_file] or [method change_scene_to_packed] instead. + The root node of the currently loaded main scene, usually as a direct child of [member root]. See also [method change_scene_to_file], [method change_scene_to_packed], and [method reload_current_scene]. + [b]Warning:[/b] Setting this property directly may not work as expected, as it does [i]not[/i] add or remove any nodes from this tree. </member> <member name="debug_collisions_hint" type="bool" setter="set_debug_collisions_hint" getter="is_debugging_collisions_hint" default="false"> If [code]true[/code], collision shapes will be visible when running the game from the editor for debugging purposes. @@ -252,84 +252,86 @@ [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_paths_hint] while the project is running will not have the desired effect. </member> <member name="edited_scene_root" type="Node" setter="set_edited_scene_root" getter="get_edited_scene_root"> - The root of the edited scene. + The root of the scene currently being edited in the editor. This is usually a direct child of [member root]. + [b]Note:[/b] This property does nothing in release builds. </member> <member name="multiplayer_poll" type="bool" setter="set_multiplayer_poll_enabled" getter="is_multiplayer_poll_enabled" default="true"> If [code]true[/code] (default value), enables automatic polling of the [MultiplayerAPI] for this SceneTree during [signal process_frame]. If [code]false[/code], you need to manually call [method MultiplayerAPI.poll] to process network packets and deliver RPCs. This allows running RPCs in a different loop (e.g. physics, thread, specific time step) and for manual [Mutex] protection when accessing the [MultiplayerAPI] from threads. </member> <member name="paused" type="bool" setter="set_pause" getter="is_paused" default="false"> - If [code]true[/code], the [SceneTree] is paused. Doing so will have the following behavior: - - 2D and 3D physics will be stopped. This includes signals and collision detection. - - [method Node._process], [method Node._physics_process] and [method Node._input] will not be called anymore in nodes. + If [code]true[/code], the scene tree is considered paused. This causes the following behavior: + - 2D and 3D physics will be stopped, as well as collision detection and related signals. + - Depending on each node's [member Node.process_mode], their [method Node._process], [method Node._physics_process] and [method Node._input] callback methods may not called anymore. </member> <member name="quit_on_go_back" type="bool" setter="set_quit_on_go_back" getter="is_quit_on_go_back" default="true"> If [code]true[/code], the application quits automatically when navigating back (e.g. using the system "Back" button on Android). To handle 'Go Back' button when this option is disabled, use [constant DisplayServer.WINDOW_EVENT_GO_BACK_REQUEST]. </member> <member name="root" type="Window" setter="" getter="get_root"> - The [SceneTree]'s root [Window]. + The tree's root [Window]. This is top-most [Node] of the scene tree, and is always present. An absolute [NodePath] always starts from this node. Children of the root node may include the loaded [member current_scene], as well as any [url=$DOCS_URL/tutorials/scripting/singletons_autoload.html]AutoLoad[/url] configured in the Project Settings. + [b]Warning:[/b] Do not delete this node. This will result in unstable behavior, followed by a crash. </member> </members> <signals> <signal name="node_added"> <param index="0" name="node" type="Node" /> <description> - Emitted whenever a node is added to the [SceneTree]. + Emitted when the [param node] enters this tree. </description> </signal> <signal name="node_configuration_warning_changed"> <param index="0" name="node" type="Node" /> <description> - Emitted when a node's configuration changed. Only emitted in [code]tool[/code] mode. + Emitted when the [param node]'s [method Node.update_configuration_warnings] is called. Only emitted in the editor. </description> </signal> <signal name="node_removed"> <param index="0" name="node" type="Node" /> <description> - Emitted whenever a node is removed from the [SceneTree]. + Emitted when the [param node] exits this tree. </description> </signal> <signal name="node_renamed"> <param index="0" name="node" type="Node" /> <description> - Emitted whenever a node is renamed. + Emitted when the [param node]'s [member Node.name] is changed. </description> </signal> <signal name="physics_frame"> <description> - Emitted immediately before [method Node._physics_process] is called on every node in the [SceneTree]. + Emitted immediately before [method Node._physics_process] is called on every node in this tree. </description> </signal> <signal name="process_frame"> <description> - Emitted immediately before [method Node._process] is called on every node in the [SceneTree]. + Emitted immediately before [method Node._process] is called on every node in this tree. </description> </signal> <signal name="tree_changed"> <description> - Emitted whenever the [SceneTree] hierarchy changed (children being moved or renamed, etc.). + Emitted any time the tree's hierarchy changes (nodes being moved, renamed, etc). </description> </signal> <signal name="tree_process_mode_changed"> <description> - This signal is only emitted in the editor, it allows the editor to update the visibility of disabled nodes. Emitted whenever any node's [member Node.process_mode] is changed. + Emitted when the [member Node.process_mode] of any node inside the tree is changed. Only emitted in the editor, to update the visibility of disabled nodes. </description> </signal> </signals> <constants> <constant name="GROUP_CALL_DEFAULT" value="0" enum="GroupCallFlags"> - Call a group with no flags (default). + Call nodes within a group with no special behavior (default). </constant> <constant name="GROUP_CALL_REVERSE" value="1" enum="GroupCallFlags"> - Call a group in reverse scene order. + Call nodes within a group in reverse tree hierarchy order (all nested children are called before their respective parent nodes). </constant> <constant name="GROUP_CALL_DEFERRED" value="2" enum="GroupCallFlags"> - Call a group at the end of the current frame (process or physics). + Call nodes within a group at the end of the current frame (can be either process or physics frame), similar to [method Object.call_deferred]. </constant> <constant name="GROUP_CALL_UNIQUE" value="4" enum="GroupCallFlags"> - Call a group only once even if the call is executed many times. - [b]Note:[/b] Arguments are not taken into account when deciding whether the call is unique or not. Therefore when the same method is called with different arguments, only the first call will be performed. + Call nodes within a group only once, even if the call is executed many times in the same frame. Must be combined with [constant GROUP_CALL_DEFERRED] to work. + [b]Note:[/b] Different arguments are not taken into account. Therefore, when the same call is executed with different arguments, only the first call will be performed. </constant> </constants> </class> diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml index c59a336bc2..a2beef81eb 100644 --- a/doc/classes/TabBar.xml +++ b/doc/classes/TabBar.xml @@ -360,7 +360,7 @@ <theme_item name="font_hovered_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> Font color of the currently hovered tab. Does not apply to the selected tab. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the tab name. </theme_item> <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index 0c1feae6e0..145afc2a03 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -276,7 +276,7 @@ <theme_item name="font_hovered_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> Font color of the currently hovered tab. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the tab name. </theme_item> <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 001cf06db4..b8a838208b 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -255,7 +255,7 @@ <return type="int" enum="TextEdit.GutterType" /> <param index="0" name="gutter" type="int" /> <description> - Returns the type of the gutter at the given index. + Returns the type of the gutter at the given index. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options. </description> </method> <method name="get_gutter_width" qualifiers="const"> @@ -329,7 +329,7 @@ <param index="0" name="line" type="int" /> <param index="1" name="gutter" type="int" /> <description> - Returns the icon currently in [param gutter] at [param line]. + Returns the icon currently in [param gutter] at [param line]. This only works when the gutter type is [constant GUTTER_TYPE_ICON] (see [method set_gutter_type]). </description> </method> <method name="get_line_gutter_item_color" qualifiers="const"> @@ -353,7 +353,7 @@ <param index="0" name="line" type="int" /> <param index="1" name="gutter" type="int" /> <description> - Returns the text currently in [param gutter] at [param line]. + Returns the text currently in [param gutter] at [param line]. This only works when the gutter type is [constant GUTTER_TYPE_STRING] (see [method set_gutter_type]). </description> </method> <method name="get_line_height" qualifiers="const"> @@ -897,7 +897,7 @@ <param index="0" name="column" type="int" /> <param index="1" name="draw_callback" type="Callable" /> <description> - Set a custom draw method for the gutter. The callback method must take the following args: [code]line: int, gutter: int, Area: Rect2[/code]. + Set a custom draw method for the gutter. The callback method must take the following args: [code]line: int, gutter: int, Area: Rect2[/code]. This only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]). </description> </method> <method name="set_gutter_draw"> @@ -929,7 +929,7 @@ <param index="0" name="gutter" type="int" /> <param index="1" name="type" type="int" enum="TextEdit.GutterType" /> <description> - Sets the type of gutter. + Sets the type of gutter. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options. </description> </method> <method name="set_gutter_width"> @@ -995,7 +995,7 @@ <param index="1" name="gutter" type="int" /> <param index="2" name="icon" type="Texture2D" /> <description> - Sets the icon for [param gutter] on [param line] to [param icon]. + Sets the icon for [param gutter] on [param line] to [param icon]. This only works when the gutter type is [constant GUTTER_TYPE_ICON] (see [method set_gutter_type]). </description> </method> <method name="set_line_gutter_item_color"> @@ -1022,7 +1022,7 @@ <param index="1" name="gutter" type="int" /> <param index="2" name="text" type="String" /> <description> - Sets the text for [param gutter] on [param line] to [param text]. + Sets the text for [param gutter] on [param line] to [param text]. This only works when the gutter type is [constant GUTTER_TYPE_STRING] (see [method set_gutter_type]). </description> </method> <method name="set_overtype_mode_enabled"> @@ -1403,13 +1403,13 @@ Line wrapping occurs at the control boundary, beyond what would normally be visible. </constant> <constant name="GUTTER_TYPE_STRING" value="0" enum="GutterType"> - Draw a string. + When a gutter is set to string using [method set_gutter_type], it is used to contain text set via the [method set_line_gutter_text] method. </constant> <constant name="GUTTER_TYPE_ICON" value="1" enum="GutterType"> - Draw an icon. + When a gutter is set to icon using [method set_gutter_type], it is used to contain an icon set via the [method set_line_gutter_icon] method. </constant> <constant name="GUTTER_TYPE_CUSTOM" value="2" enum="GutterType"> - Custom draw. + When a gutter is set to custom using [method set_gutter_type], it is used to contain custom visuals controlled by a callback method set via the [method set_gutter_custom_draw] method. </constant> </constants> <theme_items> @@ -1428,7 +1428,7 @@ <theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> Sets the font [Color]. </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the [TextEdit]. </theme_item> <theme_item name="font_placeholder_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.6)"> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index daa0eec230..5731c10651 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -5,7 +5,7 @@ </brief_description> <description> Node for 2D tile-based maps. Tilemaps use a [TileSet] which contain a list of tiles which are used to create grid-based maps. A TileMap may have several layers, layouting tiles on top of each other. - For performance reasons, all TileMap updates are batched at the end of a frame. Notably, this means that scene tiles from a [TileSetScenesCollectionSource] may be initialized after their parent. + For performance reasons, all TileMap updates are batched at the end of a frame. Notably, this means that scene tiles from a [TileSetScenesCollectionSource] may be initialized after their parent. This is only queued when inside the scene tree. To force an update earlier on, call [method update_internals]. </description> <tutorials> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 88cda5ae10..0f318efbd1 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -509,7 +509,7 @@ <theme_item name="font_disabled_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)"> Text [Color] for a [constant TreeItem.CELL_MODE_CHECK] mode cell when it's non-editable (see [method TreeItem.set_editable]). </theme_item> - <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The tint of text outline of the item. </theme_item> <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 7a60c23e58..c86a1e949b 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -902,7 +902,7 @@ <theme_item name="title_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> The color of the title's text. </theme_item> - <theme_item name="title_outline_modulate" data_type="color" type="Color" default="Color(1, 1, 1, 1)"> + <theme_item name="title_outline_modulate" data_type="color" type="Color" default="Color(0, 0, 0, 1)"> The color of the title's text outline. </theme_item> <theme_item name="close_h_offset" data_type="constant" type="int" default="18"> diff --git a/doc/classes/XRBodyModifier3D.xml b/doc/classes/XRBodyModifier3D.xml new file mode 100644 index 0000000000..4227bc57df --- /dev/null +++ b/doc/classes/XRBodyModifier3D.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="XRBodyModifier3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + A node for driving body meshes from [XRBodyTracker] data. + </brief_description> + <description> + This node uses body tracking data from a [XRBodyTracker] to animate the skeleton of a body mesh. + </description> + <tutorials> + <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> + </tutorials> + <members> + <member name="body_tracker" type="StringName" setter="set_body_tracker" getter="get_body_tracker" default="&"/user/body""> + The name of the [XRBodyTracker] registered with [XRServer] to obtain the body tracking data from. + </member> + <member name="body_update" type="int" setter="set_body_update" getter="get_body_update" enum="XRBodyModifier3D.BodyUpdate" is_bitfield="true" default="7"> + Specifies the body parts to update. + </member> + <member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="XRBodyModifier3D.BoneUpdate" default="0"> + Specifies the type of updates to perform on the bones. + </member> + <member name="show_when_tracked" type="bool" setter="set_show_when_tracked" getter="get_show_when_tracked" default="true"> + If true then the nodes visibility is determined by whether tracking data is available. + </member> + <member name="target" type="NodePath" setter="set_target" getter="get_target" default="NodePath("")"> + A [NodePath] to a [Skeleton3D] to animate. + </member> + </members> + <constants> + <constant name="BODY_UPDATE_UPPER_BODY" value="1" enum="BodyUpdate" is_bitfield="true"> + The skeleton's upper body joints are updated. + </constant> + <constant name="BODY_UPDATE_LOWER_BODY" value="2" enum="BodyUpdate" is_bitfield="true"> + The skeleton's lower body joints are updated. + </constant> + <constant name="BODY_UPDATE_HANDS" value="4" enum="BodyUpdate" is_bitfield="true"> + The skeleton's hand joints are updated. + </constant> + <constant name="BONE_UPDATE_FULL" value="0" enum="BoneUpdate"> + The skeleton's bones are fully updated (both position and rotation) to match the tracked bones. + </constant> + <constant name="BONE_UPDATE_ROTATION_ONLY" value="1" enum="BoneUpdate"> + The skeleton's bones are only rotated to align with the tracked bones, preserving bone length. + </constant> + <constant name="BONE_UPDATE_MAX" value="2" enum="BoneUpdate"> + Represents the size of the [enum BoneUpdate] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/XRBodyTracker.xml b/doc/classes/XRBodyTracker.xml new file mode 100644 index 0000000000..5d45ad11bd --- /dev/null +++ b/doc/classes/XRBodyTracker.xml @@ -0,0 +1,307 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="XRBodyTracker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + A tracked body in XR. + </brief_description> + <description> + A body tracking system will create an instance of this object and add it to the [XRServer]. This tracking system will then obtain skeleton data, convert it to the Godot Humanoid skeleton and store this data on the [XRBodyTracker] object. + Use [XRBodyModifier3D] to animate a body mesh using body tracking data. + </description> + <tutorials> + <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> + </tutorials> + <methods> + <method name="get_joint_flags" qualifiers="const"> + <return type="int" enum="XRBodyTracker.JointFlags" is_bitfield="true" /> + <param index="0" name="joint" type="int" enum="XRBodyTracker.Joint" /> + <description> + Returns flags about the validity of the tracking data for the given body joint (see [enum XRBodyTracker.JointFlags]). + </description> + </method> + <method name="get_joint_transform" qualifiers="const"> + <return type="Transform3D" /> + <param index="0" name="joint" type="int" enum="XRBodyTracker.Joint" /> + <description> + Returns the transform for the given body joint. + </description> + </method> + <method name="set_joint_flags"> + <return type="void" /> + <param index="0" name="joint" type="int" enum="XRBodyTracker.Joint" /> + <param index="1" name="flags" type="int" enum="XRBodyTracker.JointFlags" is_bitfield="true" /> + <description> + Sets flags about the validity of the tracking data for the given body joint. + </description> + </method> + <method name="set_joint_transform"> + <return type="void" /> + <param index="0" name="joint" type="int" enum="XRBodyTracker.Joint" /> + <param index="1" name="transform" type="Transform3D" /> + <description> + Sets the transform for the given body joint. + </description> + </method> + </methods> + <members> + <member name="body_flags" type="int" setter="set_body_flags" getter="get_body_flags" enum="XRBodyTracker.BodyFlags" is_bitfield="true" default="0"> + The type of body tracking data captured. + </member> + <member name="has_tracking_data" type="bool" setter="set_has_tracking_data" getter="get_has_tracking_data" default="false"> + If [code]true[/code], the body tracking data is valid. + </member> + </members> + <constants> + <constant name="BODY_FLAG_UPPER_BODY_SUPPORTED" value="1" enum="BodyFlags" is_bitfield="true"> + Upper body tracking supported. + </constant> + <constant name="BODY_FLAG_LOWER_BODY_SUPPORTED" value="2" enum="BodyFlags" is_bitfield="true"> + Lower body tracking supported. + </constant> + <constant name="BODY_FLAG_HANDS_SUPPORTED" value="4" enum="BodyFlags" is_bitfield="true"> + Hand tracking supported. + </constant> + <constant name="JOINT_ROOT" value="0" enum="Joint"> + Root joint. + </constant> + <constant name="JOINT_HIPS" value="1" enum="Joint"> + Hips joint. + </constant> + <constant name="JOINT_SPINE" value="2" enum="Joint"> + Spine joint. + </constant> + <constant name="JOINT_CHEST" value="3" enum="Joint"> + Chest joint. + </constant> + <constant name="JOINT_UPPER_CHEST" value="4" enum="Joint"> + Upper chest joint. + </constant> + <constant name="JOINT_NECK" value="5" enum="Joint"> + Neck joint. + </constant> + <constant name="JOINT_HEAD" value="6" enum="Joint"> + Head joint. + </constant> + <constant name="JOINT_HEAD_TIP" value="7" enum="Joint"> + Head tip joint. + </constant> + <constant name="JOINT_LEFT_SHOULDER" value="8" enum="Joint"> + Left shoulder joint. + </constant> + <constant name="JOINT_LEFT_UPPER_ARM" value="9" enum="Joint"> + Left upper arm joint. + </constant> + <constant name="JOINT_LEFT_LOWER_ARM" value="10" enum="Joint"> + Left lower arm joint. + </constant> + <constant name="JOINT_RIGHT_SHOULDER" value="11" enum="Joint"> + Right shoulder joint. + </constant> + <constant name="JOINT_RIGHT_UPPER_ARM" value="12" enum="Joint"> + Right upper arm joint. + </constant> + <constant name="JOINT_RIGHT_LOWER_ARM" value="13" enum="Joint"> + Right lower arm joint. + </constant> + <constant name="JOINT_LEFT_UPPER_LEG" value="14" enum="Joint"> + Left upper leg joint. + </constant> + <constant name="JOINT_LEFT_LOWER_LEG" value="15" enum="Joint"> + Left lower leg joint. + </constant> + <constant name="JOINT_LEFT_FOOT" value="16" enum="Joint"> + Left foot joint. + </constant> + <constant name="JOINT_LEFT_TOES" value="17" enum="Joint"> + Left toes joint. + </constant> + <constant name="JOINT_RIGHT_UPPER_LEG" value="18" enum="Joint"> + Right upper leg joint. + </constant> + <constant name="JOINT_RIGHT_LOWER_LEG" value="19" enum="Joint"> + Right lower leg joint. + </constant> + <constant name="JOINT_RIGHT_FOOT" value="20" enum="Joint"> + Right foot joint. + </constant> + <constant name="JOINT_RIGHT_TOES" value="21" enum="Joint"> + Right toes joint. + </constant> + <constant name="JOINT_LEFT_HAND" value="22" enum="Joint"> + Left hand joint. + </constant> + <constant name="JOINT_LEFT_PALM" value="23" enum="Joint"> + Left palm joint. + </constant> + <constant name="JOINT_LEFT_WRIST" value="24" enum="Joint"> + Left wrist joint. + </constant> + <constant name="JOINT_LEFT_THUMB_METACARPAL" value="25" enum="Joint"> + Left thumb metacarpal joint. + </constant> + <constant name="JOINT_LEFT_THUMB_PHALANX_PROXIMAL" value="26" enum="Joint"> + Left thumb phalanx proximal joint. + </constant> + <constant name="JOINT_LEFT_THUMB_PHALANX_DISTAL" value="27" enum="Joint"> + Left thumb phalanx distal joint. + </constant> + <constant name="JOINT_LEFT_THUMB_TIP" value="28" enum="Joint"> + Left thumb tip joint. + </constant> + <constant name="JOINT_LEFT_INDEX_FINGER_METACARPAL" value="29" enum="Joint"> + Left index finger metacarpal joint. + </constant> + <constant name="JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL" value="30" enum="Joint"> + Left index finger phalanx proximal joint. + </constant> + <constant name="JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE" value="31" enum="Joint"> + Left index finger phalanx intermediate joint. + </constant> + <constant name="JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL" value="32" enum="Joint"> + Left index finger phalanx distal joint. + </constant> + <constant name="JOINT_LEFT_INDEX_FINGER_TIP" value="33" enum="Joint"> + Left index finger tip joint. + </constant> + <constant name="JOINT_LEFT_MIDDLE_FINGER_METACARPAL" value="34" enum="Joint"> + Left middle finger metacarpal joint. + </constant> + <constant name="JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL" value="35" enum="Joint"> + Left middle finger phalanx proximal joint. + </constant> + <constant name="JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE" value="36" enum="Joint"> + Left middle finger phalanx intermediate joint. + </constant> + <constant name="JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL" value="37" enum="Joint"> + Left middle finger phalanx distal joint. + </constant> + <constant name="JOINT_LEFT_MIDDLE_FINGER_TIP" value="38" enum="Joint"> + Left middle finger tip joint. + </constant> + <constant name="JOINT_LEFT_RING_FINGER_METACARPAL" value="39" enum="Joint"> + Left ring finger metacarpal joint. + </constant> + <constant name="JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL" value="40" enum="Joint"> + Left ring finger phalanx proximal joint. + </constant> + <constant name="JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE" value="41" enum="Joint"> + Left ring finger phalanx intermediate joint. + </constant> + <constant name="JOINT_LEFT_RING_FINGER_PHALANX_DISTAL" value="42" enum="Joint"> + Left ring finger phalanx distal joint. + </constant> + <constant name="JOINT_LEFT_RING_FINGER_TIP" value="43" enum="Joint"> + Left ring finger tip joint. + </constant> + <constant name="JOINT_LEFT_PINKY_FINGER_METACARPAL" value="44" enum="Joint"> + Left pinky finger metacarpal joint. + </constant> + <constant name="JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL" value="45" enum="Joint"> + Left pinky finger phalanx proximal joint. + </constant> + <constant name="JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE" value="46" enum="Joint"> + Left pinky finger phalanx intermediate joint. + </constant> + <constant name="JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL" value="47" enum="Joint"> + Left pinky finger phalanx distal joint. + </constant> + <constant name="JOINT_LEFT_PINKY_FINGER_TIP" value="48" enum="Joint"> + Left pinky finger tip joint. + </constant> + <constant name="JOINT_RIGHT_HAND" value="49" enum="Joint"> + Right hand joint. + </constant> + <constant name="JOINT_RIGHT_PALM" value="50" enum="Joint"> + Right palm joint. + </constant> + <constant name="JOINT_RIGHT_WRIST" value="51" enum="Joint"> + Right wrist joint. + </constant> + <constant name="JOINT_RIGHT_THUMB_METACARPAL" value="52" enum="Joint"> + Right thumb metacarpal joint. + </constant> + <constant name="JOINT_RIGHT_THUMB_PHALANX_PROXIMAL" value="53" enum="Joint"> + Right thumb phalanx proximal joint. + </constant> + <constant name="JOINT_RIGHT_THUMB_PHALANX_DISTAL" value="54" enum="Joint"> + Right thumb phalanx distal joint. + </constant> + <constant name="JOINT_RIGHT_THUMB_TIP" value="55" enum="Joint"> + Right thumb tip joint. + </constant> + <constant name="JOINT_RIGHT_INDEX_FINGER_METACARPAL" value="56" enum="Joint"> + Right index finger metacarpal joint. + </constant> + <constant name="JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL" value="57" enum="Joint"> + Right index finger phalanx proximal joint. + </constant> + <constant name="JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE" value="58" enum="Joint"> + Right index finger phalanx intermediate joint. + </constant> + <constant name="JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL" value="59" enum="Joint"> + Right index finger phalanx distal joint. + </constant> + <constant name="JOINT_RIGHT_INDEX_FINGER_TIP" value="60" enum="Joint"> + Right index finger tip joint. + </constant> + <constant name="JOINT_RIGHT_MIDDLE_FINGER_METACARPAL" value="61" enum="Joint"> + Right middle finger metacarpal joint. + </constant> + <constant name="JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL" value="62" enum="Joint"> + Right middle finger phalanx proximal joint. + </constant> + <constant name="JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE" value="63" enum="Joint"> + Right middle finger phalanx intermediate joint. + </constant> + <constant name="JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL" value="64" enum="Joint"> + Right middle finger phalanx distal joint. + </constant> + <constant name="JOINT_RIGHT_MIDDLE_FINGER_TIP" value="65" enum="Joint"> + Right middle finger tip joint. + </constant> + <constant name="JOINT_RIGHT_RING_FINGER_METACARPAL" value="66" enum="Joint"> + Right ring finger metacarpal joint. + </constant> + <constant name="JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL" value="67" enum="Joint"> + Right ring finger phalanx proximal joint. + </constant> + <constant name="JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE" value="68" enum="Joint"> + Right ring finger phalanx intermediate joint. + </constant> + <constant name="JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL" value="69" enum="Joint"> + Right ring finger phalanx distal joint. + </constant> + <constant name="JOINT_RIGHT_RING_FINGER_TIP" value="70" enum="Joint"> + Right ring finger tip joint. + </constant> + <constant name="JOINT_RIGHT_PINKY_FINGER_METACARPAL" value="71" enum="Joint"> + Right pinky finger metacarpal joint. + </constant> + <constant name="JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL" value="72" enum="Joint"> + Right pinky finger phalanx proximal joint. + </constant> + <constant name="JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE" value="73" enum="Joint"> + Right pinky finger phalanx intermediate joint. + </constant> + <constant name="JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL" value="74" enum="Joint"> + Right pinky finger phalanx distal joint. + </constant> + <constant name="JOINT_RIGHT_PINKY_FINGER_TIP" value="75" enum="Joint"> + Right pinky finger tip joint. + </constant> + <constant name="JOINT_MAX" value="76" enum="Joint"> + Represents the size of the [enum Joint] enum. + </constant> + <constant name="JOINT_FLAG_ORIENTATION_VALID" value="1" enum="JointFlags" is_bitfield="true"> + The joint's orientation data is valid. + </constant> + <constant name="JOINT_FLAG_ORIENTATION_TRACKED" value="2" enum="JointFlags" is_bitfield="true"> + The joint's orientation is actively tracked. May not be set if tracking has been temporarily lost. + </constant> + <constant name="JOINT_FLAG_POSITION_VALID" value="4" enum="JointFlags" is_bitfield="true"> + The joint's position data is valid. + </constant> + <constant name="JOINT_FLAG_POSITION_TRACKED" value="8" enum="JointFlags" is_bitfield="true"> + The joint's position is actively tracked. May not be set if tracking has been temporarily lost. + </constant> + </constants> +</class> diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml index 09e14f1b21..671cc8f15c 100644 --- a/doc/classes/XRServer.xml +++ b/doc/classes/XRServer.xml @@ -10,6 +10,14 @@ <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> </tutorials> <methods> + <method name="add_body_tracker"> + <return type="void" /> + <param index="0" name="tracker_name" type="StringName" /> + <param index="1" name="body_tracker" type="XRBodyTracker" /> + <description> + Registers a new [XRBodyTracker] that tracks the joints of a body. + </description> + </method> <method name="add_face_tracker"> <return type="void" /> <param index="0" name="tracker_name" type="StringName" /> @@ -66,6 +74,19 @@ Finds an interface by its [param name]. For example, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it. </description> </method> + <method name="get_body_tracker" qualifiers="const"> + <return type="XRBodyTracker" /> + <param index="0" name="tracker_name" type="StringName" /> + <description> + Returns the [XRBodyTracker] with the given tracker name. + </description> + </method> + <method name="get_body_trackers" qualifiers="const"> + <return type="Dictionary" /> + <description> + Returns a dictionary of the registered body trackers. Each element of the dictionary is a tracker name mapping to the [XRBodyTracker] instance. + </description> + </method> <method name="get_face_tracker" qualifiers="const"> <return type="XRFaceTracker" /> <param index="0" name="tracker_name" type="StringName" /> @@ -137,6 +158,13 @@ Returns a dictionary of trackers for [param tracker_types]. </description> </method> + <method name="remove_body_tracker"> + <return type="void" /> + <param index="0" name="tracker_name" type="StringName" /> + <description> + Removes a registered [XRBodyTracker]. + </description> + </method> <method name="remove_face_tracker"> <return type="void" /> <param index="0" name="tracker_name" type="StringName" /> @@ -179,6 +207,26 @@ </member> </members> <signals> + <signal name="body_tracker_added"> + <param index="0" name="tracker_name" type="StringName" /> + <param index="1" name="body_tracker" type="XRBodyTracker" /> + <description> + Emitted when a new body tracker is added. + </description> + </signal> + <signal name="body_tracker_removed"> + <param index="0" name="tracker_name" type="StringName" /> + <description> + Emitted when a body tracker is removed. + </description> + </signal> + <signal name="body_tracker_updated"> + <param index="0" name="tracker_name" type="StringName" /> + <param index="1" name="body_tracker" type="XRBodyTracker" /> + <description> + Emitted when an existing body tracker is updated. + </description> + </signal> <signal name="face_tracker_added"> <param index="0" name="tracker_name" type="StringName" /> <param index="1" name="face_tracker" type="XRFaceTracker" /> diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index e74ea910a0..381d022a55 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -530,7 +530,7 @@ static const D3D12_RESOURCE_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSIO D3D12_RESOURCE_DIMENSION_TEXTURE2D, }; -void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override) { +void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state) { DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here. #ifdef DEBUG_COUNT_BARRIERS @@ -538,9 +538,16 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso #endif ResourceInfo::States *res_states = p_resource->states_ptr; - D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource]; - ID3D12Resource *res_to_transition = p_resource_override ? p_resource_override : p_resource->resource; + if (p_new_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { + if (unlikely(!res_states->xfamily_fallback.subresources_dirty.is_empty())) { + uint32_t subres_qword = p_subresource / 64; + uint64_t subres_mask = (uint64_t(1) << (p_subresource % 64)); + res_states->xfamily_fallback.subresources_dirty[subres_qword] |= subres_mask; + } + } + + D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource]; // Transitions can be considered redundant if the current state has all the bits of the new state. // This check does not apply to the common state however, which must resort to checking if the state is the same (0). @@ -553,7 +560,7 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso if (res_barriers.size() < res_barriers_count + 1) { res_barriers.resize(res_barriers_count + 1); } - res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(res_to_transition); + res_barriers[res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(p_resource->resource); res_barriers_count++; res_states->last_batch_with_uav_barrier = res_barriers_batch; } @@ -563,7 +570,7 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso if (res_barriers_requests.has(res_states)) { BarrierRequest &br = res_barriers_requests.get(res_states); - DEV_ASSERT(br.dx_resource == res_to_transition); + DEV_ASSERT(br.dx_resource == p_resource->resource); DEV_ASSERT(br.subres_mask_qwords == STEPIFY(res_states->subresource_states.size(), 64) / 64); DEV_ASSERT(br.planes == p_num_planes); @@ -681,7 +688,7 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso } } else { BarrierRequest &br = res_barriers_requests[res_states]; - br.dx_resource = res_to_transition; + br.dx_resource = p_resource->resource; br.subres_mask_qwords = STEPIFY(p_resource->states_ptr->subresource_states.size(), 64) / 64; CRASH_COND(p_resource->states_ptr->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES); br.planes = p_num_planes; @@ -697,10 +704,6 @@ void RenderingDeviceDriverD3D12::_resource_transition_batch(ResourceInfo *p_reso } } - if (p_new_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { - res_states->last_batch_transitioned_to_uav = res_barriers_batch; - } - #ifdef DEBUG_COUNT_BARRIERS frame_barriers_cpu_time += OS::get_singleton()->get_ticks_usec() - start; #endif @@ -1135,19 +1138,13 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p // If views of different families are wanted, special setup is needed for proper sharing among them. // Two options here: - // 1. If ID3DDevice10 is present and driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA). - // 2. Otherwise, fall back to an approach based on abusing aliasing, hoping for the best. [[CROSS_FAMILY_ALIASING]] - if (p_format.shareable_formats.size()) { - if (format_capabilities.relaxed_casting_supported) { - ComPtr<ID3D12Device10> device_10; - device->QueryInterface(device_10.GetAddressOf()); - if (device_10) { - relaxed_casting_available = true; - relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size()); - relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format; - relaxed_casting_format_count++; - } - } + // 1. If the driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA). + // 2. Otherwise, fall back to an approach based on having multiple versions of the resource and copying as needed. [[CROSS_FAMILY_FALLBACK]] + if (p_format.shareable_formats.size() && format_capabilities.relaxed_casting_supported) { + relaxed_casting_available = true; + relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size()); + relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format; + relaxed_casting_format_count++; } HashMap<DataFormat, D3D12_RESOURCE_FLAGS> aliases_forbidden_flags; @@ -1168,9 +1165,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p } if (cross_family_sharing && !relaxed_casting_available) { - // At least guarantee the same layout among aliases. - resource_desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE; - // Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_layout. if (p_format.texture_type == TEXTURE_TYPE_1D) { ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a 1D texture."); @@ -1221,9 +1215,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p // Create. D3D12MA::ALLOCATION_DESC allocation_desc = {}; - if (cross_family_sharing && !relaxed_casting_available) { - allocation_desc.Flags = D3D12MA::ALLOCATION_FLAG_CAN_ALIAS; - } allocation_desc.HeapType = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? D3D12_HEAP_TYPE_READBACK : D3D12_HEAP_TYPE_DEFAULT; if ((resource_desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) { allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES; @@ -1343,53 +1334,6 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = main_uav_desc; uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format; - // Create aliases if needed. [[CROSS_FAMILY_ALIASING]] - - using AliasEntry = Pair<DXGI_FORMAT, ID3D12Resource *>; - AliasEntry *aliases = nullptr; - uint32_t alias_count = 0; - if (cross_family_sharing && !relaxed_casting_available) { - aliases = ALLOCA_ARRAY(AliasEntry, p_format.shareable_formats.size()); - - for (int i = 0; i < p_format.shareable_formats.size(); i++) { - DataFormat curr_format = p_format.shareable_formats[i]; - - DXGI_FORMAT format_family = RD_TO_D3D12_FORMAT[curr_format].family; - if (format_family == RD_TO_D3D12_FORMAT[p_format.format].family) { - continue; - } - - D3D12_RESOURCE_DESC alias_resource_desc = *(D3D12_RESOURCE_DESC *)&resource_desc; - alias_resource_desc.Format = format_family; - clear_value.Format = format_family; - if ((alias_resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) { - if (!texture_get_usages_supported_by_format(curr_format, false).has_flag(TEXTURE_USAGE_STORAGE_BIT)) { - alias_resource_desc.Flags &= ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - } - } - ID3D12Resource *alias = nullptr; - HRESULT res = allocator->CreateAliasingResource( - allocation.Get(), - 0, - &alias_resource_desc, - initial_state, - (alias_resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? clear_value_ptr : nullptr, - IID_PPV_ARGS(&alias)); - if (!SUCCEEDED(res)) { - for (uint32_t j = 0; j < alias_count; j++) { - aliases[j].second->Release(); - } - ERR_FAIL_V_MSG(TextureID(), "CreateAliasingResource failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); - } - aliases[alias_count] = AliasEntry(format_family, alias); - alias_count++; - - if (curr_format == p_view.format) { - texture = alias; - } - } - } - // Bookkeep. TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator); @@ -1409,12 +1353,8 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p tex_info->mipmaps = resource_desc.MipLevels; tex_info->view_descs.srv = srv_desc; tex_info->view_descs.uav = uav_desc; - tex_info->main_texture = main_texture.Get(); - tex_info->aliasing_hack.main_uav_desc = main_uav_desc; - if (alias_count) { - for (uint32_t i = 0; i < alias_count; i++) { - tex_info->aliasing_hack.owner_info.aliases.insert(aliases[i].first, aliases[i].second); - } + if ((p_format.usage_bits & (TEXTURE_USAGE_STORAGE_BIT | TEXTURE_USAGE_COLOR_ATTACHMENT_BIT))) { + textures_pending_clear.add(&tex_info->pending_clear); } return TextureID(tex_info); @@ -1425,75 +1365,59 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create_from_extension(uint64_ } RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) { - const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id; -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID()); -#endif - - ID3D12Resource *texture = nullptr; - if (owner_tex_info->aliasing_hack.owner_info.aliases.is_empty()) { - texture = owner_tex_info->resource; - } else { - texture = owner_tex_info->main_texture; - for (const KeyValue<DXGI_FORMAT, ComPtr<ID3D12Resource>> &E : owner_tex_info->aliasing_hack.owner_info.aliases) { - if (E.key == RD_TO_D3D12_FORMAT[p_view.format].family) { - texture = E.value.Get(); - break; - } - } - } - - // Describe views. - - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = owner_tex_info->view_descs.srv; - { - srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format; - srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view); - } - - D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = owner_tex_info->view_descs.uav; - { - uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format; - } - - // Bookkeep. - - TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator); - tex_info->resource = texture; - tex_info->states_ptr = owner_tex_info->states_ptr; - tex_info->format = p_view.format; - tex_info->desc = owner_tex_info->desc; - tex_info->base_layer = owner_tex_info->base_layer; - tex_info->layers = owner_tex_info->layers; - tex_info->base_mip = owner_tex_info->base_mip; - tex_info->mipmaps = owner_tex_info->mipmaps; - tex_info->view_descs.srv = srv_desc; - tex_info->view_descs.uav = uav_desc; - tex_info->main_texture = owner_tex_info->main_texture; - tex_info->aliasing_hack.main_uav_desc = owner_tex_info->aliasing_hack.main_uav_desc; - - return TextureID(tex_info); + return _texture_create_shared_from_slice(p_original_texture, p_view, (TextureSliceType)-1, 0, 0, 0, 0); } RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) { - const TextureInfo *owner_tex_info = (const TextureInfo *)p_original_texture.id; + return _texture_create_shared_from_slice(p_original_texture, p_view, p_slice_type, p_layer, p_layers, p_mipmap, p_mipmaps); +} + +RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) { + TextureInfo *owner_tex_info = (TextureInfo *)p_original_texture.id; #ifdef DEBUG_ENABLED ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID()); #endif - // Find appropriate resource instance. + ComPtr<ID3D12Resource> new_texture; + ComPtr<D3D12MA::Allocation> new_allocation; + ID3D12Resource *resource = nullptr; + CD3DX12_RESOURCE_DESC new_tex_resource_desc = owner_tex_info->desc; + bool cross_family = RD_TO_D3D12_FORMAT[p_view.format].family != RD_TO_D3D12_FORMAT[owner_tex_info->format].family; + if (cross_family && !format_capabilities.relaxed_casting_supported) { + // [[CROSS_FAMILY_FALLBACK]]. + // We have to create a new texture of the alternative format. - ID3D12Resource *texture = nullptr; - if (owner_tex_info->aliasing_hack.owner_info.aliases.is_empty()) { - texture = owner_tex_info->resource; - } else { - texture = owner_tex_info->main_texture; - for (const KeyValue<DXGI_FORMAT, ComPtr<ID3D12Resource>> &E : owner_tex_info->aliasing_hack.owner_info.aliases) { - if (E.key == RD_TO_D3D12_FORMAT[p_view.format].family) { - texture = E.value.Get(); - break; + D3D12MA::ALLOCATION_DESC allocation_desc = {}; + allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES; + + if (p_slice_type != -1) { +#ifdef DEV_ENABLED + // Actual slicing is not contemplated. If ever needed, let's at least realize. + if (p_slice_type != -1) { + uint32_t new_texture_subresorce_count = owner_tex_info->mipmaps * owner_tex_info->layers; + uint32_t slice_subresorce_count = p_mipmaps * p_layers; + DEV_ASSERT(new_texture_subresorce_count == slice_subresorce_count); } +#endif + new_tex_resource_desc.DepthOrArraySize = p_layers; + new_tex_resource_desc.MipLevels = p_mipmaps; } + new_tex_resource_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].family; + new_tex_resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE; // Alternative formats can only be used as SRVs. + + HRESULT res = allocator->CreateResource( + &allocation_desc, + &new_tex_resource_desc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + new_allocation.GetAddressOf(), + IID_PPV_ARGS(new_texture.GetAddressOf())); + ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), vformat("D3D12MA::CreateResource failed with error 0x%08ux.", (uint64_t)res)); + + resource = new_texture.Get(); + } else { + resource = owner_tex_info->resource; } // Describe views. @@ -1509,103 +1433,169 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared_from_slice(Text uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format; } - // Complete description with slicing. - // (Leveraging aliasing in members of the union as much as possible.) - - srv_desc.Texture1D.MostDetailedMip = p_mipmap; - srv_desc.Texture1D.MipLevels = 1; - - uav_desc.Texture1D.MipSlice = p_mipmap; - - switch (p_slice_type) { - case TEXTURE_SLICE_2D: { - if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) { - DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D); - } else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) { - DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN); - } else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) { - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + if (p_slice_type != -1) { + // Complete description with slicing. + + switch (p_slice_type) { + case TEXTURE_SLICE_2D: { + if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) { + srv_desc.Texture2D.MostDetailedMip = p_mipmap; + srv_desc.Texture2D.MipLevels = p_mipmaps; + + DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D); + uav_desc.Texture1D.MipSlice = p_mipmap; + } else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) { + DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN); + } else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) { + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + srv_desc.Texture2DArray.MostDetailedMip = p_mipmap; + srv_desc.Texture2DArray.MipLevels = p_mipmaps; + srv_desc.Texture2DArray.FirstArraySlice = p_layer; + srv_desc.Texture2DArray.ArraySize = 1; + srv_desc.Texture2DArray.PlaneSlice = 0; + srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f; + + uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; + uav_desc.Texture2DArray.MipSlice = p_mipmap; + uav_desc.Texture2DArray.FirstArraySlice = p_layer; + uav_desc.Texture2DArray.ArraySize = 1; + uav_desc.Texture2DArray.PlaneSlice = 0; + } else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) { + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + srv_desc.Texture2DMSArray.FirstArraySlice = p_layer; + srv_desc.Texture2DMSArray.ArraySize = 1; + + uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN; + } else { + DEV_ASSERT(false); + } + } break; + case TEXTURE_SLICE_CUBEMAP: { + if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) { + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + srv_desc.TextureCube.MostDetailedMip = p_mipmap; + srv_desc.TextureCube.MipLevels = p_mipmaps; + + DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY); + uav_desc.Texture2DArray.MipSlice = p_mipmap; + uav_desc.Texture2DArray.FirstArraySlice = p_layer; + uav_desc.Texture2DArray.ArraySize = 6; + uav_desc.Texture2DArray.PlaneSlice = 0; + } else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) { + srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; + srv_desc.TextureCubeArray.MostDetailedMip = p_mipmap; + srv_desc.TextureCubeArray.MipLevels = p_mipmaps; + srv_desc.TextureCubeArray.First2DArrayFace = p_layer; + srv_desc.TextureCubeArray.NumCubes = 1; + srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f; + + DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY); + uav_desc.Texture2DArray.MipSlice = p_mipmap; + uav_desc.Texture2DArray.FirstArraySlice = p_layer; + uav_desc.Texture2DArray.ArraySize = 6; + uav_desc.Texture2DArray.PlaneSlice = 0; + } else { + DEV_ASSERT(false); + } + } break; + case TEXTURE_SLICE_3D: { + DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D); + srv_desc.Texture3D.MostDetailedMip = p_mipmap; + srv_desc.Texture3D.MipLevels = p_mipmaps; + + DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D); + uav_desc.Texture3D.MipSlice = p_mipmap; + uav_desc.Texture3D.WSize = -1; + } break; + case TEXTURE_SLICE_2D_ARRAY: { + DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY); + srv_desc.Texture2DArray.MostDetailedMip = p_mipmap; + srv_desc.Texture2DArray.MipLevels = p_mipmaps; srv_desc.Texture2DArray.FirstArraySlice = p_layer; - srv_desc.Texture2DArray.ArraySize = 1; - srv_desc.Texture2DArray.PlaneSlice = 0; - srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f; - - uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; - uav_desc.Texture2DArray.FirstArraySlice = p_layer; - uav_desc.Texture2DArray.ArraySize = 1; - uav_desc.Texture2DArray.PlaneSlice = 0; - } else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) { - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - srv_desc.Texture2DMSArray.FirstArraySlice = p_layer; - srv_desc.Texture2DMSArray.ArraySize = 1; - - uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN; - } else { - DEV_ASSERT(false); - } - } break; - case TEXTURE_SLICE_CUBEMAP: { - if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) { - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - srv_desc.TextureCube.MostDetailedMip = p_mipmap; - srv_desc.TextureCube.MipLevels = 1; - - DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY); - uav_desc.Texture2DArray.MipSlice = p_mipmap; - uav_desc.Texture2DArray.FirstArraySlice = 0; - uav_desc.Texture2DArray.ArraySize = 6; - uav_desc.Texture2DArray.PlaneSlice = 0; - } else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) { - srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - srv_desc.TextureCubeArray.MostDetailedMip = p_mipmap; - srv_desc.TextureCubeArray.MipLevels = 1; - srv_desc.TextureCubeArray.First2DArrayFace = p_layer; - srv_desc.TextureCubeArray.NumCubes = 1; - srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f; + srv_desc.Texture2DArray.ArraySize = p_layers; DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY); uav_desc.Texture2DArray.MipSlice = p_mipmap; uav_desc.Texture2DArray.FirstArraySlice = p_layer; - uav_desc.Texture2DArray.ArraySize = 6; - uav_desc.Texture2DArray.PlaneSlice = 0; - } else { - DEV_ASSERT(false); - } - } break; - case TEXTURE_SLICE_3D: { - DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D); - - DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D); - uav_desc.Texture3D.WSize = -1; - } break; - case TEXTURE_SLICE_2D_ARRAY: { - DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY); - srv_desc.Texture2DArray.FirstArraySlice = p_layer; - srv_desc.Texture2DArray.ArraySize = p_layers; - - DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY); - uav_desc.Texture2DArray.FirstArraySlice = p_layer; - uav_desc.Texture2DArray.ArraySize = p_layers; - } break; - default: - break; + uav_desc.Texture2DArray.ArraySize = p_layers; + } break; + default: + break; + } } // Bookkeep. TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator); - tex_info->resource = texture; - tex_info->states_ptr = owner_tex_info->states_ptr; + tex_info->resource = resource; + if (new_texture.Get()) { + // [[CROSS_FAMILY_FALLBACK]]. + + DEV_ASSERT(cross_family && !format_capabilities.relaxed_casting_supported); + + uint32_t new_texture_subresorce_count = owner_tex_info->mipmaps * owner_tex_info->layers; +#ifdef DEV_ENABLED + // Actual slicing is not contemplated. If ever needed, let's at least realize. + if (p_slice_type != -1) { + uint32_t slice_subresorce_count = p_mipmaps * p_layers; + DEV_ASSERT(new_texture_subresorce_count == slice_subresorce_count); + } +#endif + + tex_info->owner_info.resource = new_texture; + tex_info->owner_info.allocation = new_allocation; + tex_info->owner_info.states.subresource_states.resize(new_texture_subresorce_count); + for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) { + tex_info->owner_info.states.subresource_states[i] = D3D12_RESOURCE_STATE_COPY_DEST; + } + tex_info->states_ptr = &tex_info->owner_info.states; + + ResourceInfo::States::CrossFamillyFallback &xfamily = owner_tex_info->owner_info.states.xfamily_fallback; + if (xfamily.subresources_dirty.is_empty()) { + uint32_t items_required = STEPIFY(new_texture_subresorce_count, sizeof(uint64_t)) / sizeof(uint64_t); + xfamily.subresources_dirty.resize(items_required); + memset(xfamily.subresources_dirty.ptr(), 255, sizeof(uint64_t) * xfamily.subresources_dirty.size()); + + // Create buffer for non-direct copy if it's a format not supporting reinterpret-copy. + DEV_ASSERT(!xfamily.interim_buffer.Get()); + if (owner_tex_info->format == DATA_FORMAT_R16_UINT && p_view.format == DATA_FORMAT_R4G4B4A4_UNORM_PACK16) { + uint32_t row_pitch = STEPIFY(owner_tex_info->desc.Width * sizeof(uint16_t), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + uint32_t buffer_size = sizeof(uint16_t) * row_pitch * owner_tex_info->desc.Height * owner_tex_info->desc.Depth(); + CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(STEPIFY(buffer_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)); + resource_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; + + D3D12MA::ALLOCATION_DESC allocation_desc = {}; + allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + HRESULT res = allocator->CreateResource( + &allocation_desc, + &resource_desc, + D3D12_RESOURCE_STATE_COPY_SOURCE, // Makes the code that makes the copy easier. + nullptr, + xfamily.interim_buffer_alloc.GetAddressOf(), + IID_PPV_ARGS(xfamily.interim_buffer.GetAddressOf())); + ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); + } + } + } else { + tex_info->states_ptr = owner_tex_info->states_ptr; + } tex_info->format = p_view.format; - tex_info->desc = owner_tex_info->desc; - tex_info->base_layer = p_layer; - tex_info->layers = p_layers; - tex_info->base_mip = p_mipmap; - tex_info->mipmaps = p_mipmaps; + tex_info->desc = new_tex_resource_desc; + if (p_slice_type == -1) { + tex_info->base_layer = owner_tex_info->base_layer; + tex_info->layers = owner_tex_info->layers; + tex_info->base_mip = owner_tex_info->base_mip; + tex_info->mipmaps = owner_tex_info->mipmaps; + } else { + tex_info->base_layer = p_layer; + tex_info->layers = p_layers; + tex_info->base_mip = p_mipmap; + tex_info->mipmaps = p_mipmaps; + } tex_info->view_descs.srv = srv_desc; tex_info->view_descs.uav = uav_desc; - tex_info->main_texture = owner_tex_info->main_texture; - tex_info->aliasing_hack.main_uav_desc = owner_tex_info->aliasing_hack.main_uav_desc; + tex_info->main_texture = owner_tex_info; return TextureID(tex_info); } @@ -2352,6 +2342,14 @@ D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceDriverD3D12::_make_rtv_for_texture( rtv_desc.Texture3D.FirstWSlice = 0; rtv_desc.Texture3D.WSize = -1; } break; + case D3D12_SRV_DIMENSION_TEXTURECUBE: + case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: { + rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; + rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset; + rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset; + rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->layers : p_layers; + rtv_desc.Texture2DArray.PlaneSlice = 0; + } break; default: { DEV_ASSERT(false); } @@ -2360,6 +2358,36 @@ D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceDriverD3D12::_make_rtv_for_texture( return rtv_desc; } +D3D12_UNORDERED_ACCESS_VIEW_DESC RenderingDeviceDriverD3D12::_make_ranged_uav_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) { + D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = p_texture_info->view_descs.uav; + + uint32_t mip = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset; + switch (p_texture_info->view_descs.uav.ViewDimension) { + case D3D12_UAV_DIMENSION_TEXTURE1D: { + uav_desc.Texture1DArray.MipSlice = mip; + } break; + case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: { + uav_desc.Texture1DArray.MipSlice = mip; + uav_desc.Texture1DArray.FirstArraySlice = mip; + uav_desc.Texture1DArray.ArraySize = p_layers; + } break; + case D3D12_UAV_DIMENSION_TEXTURE2D: { + uav_desc.Texture2D.MipSlice = mip; + } break; + case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: { + uav_desc.Texture2DArray.MipSlice = mip; + uav_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset; + uav_desc.Texture2DArray.ArraySize = p_layers; + } break; + case D3D12_UAV_DIMENSION_TEXTURE3D: { + uav_desc.Texture3D.MipSlice = mip; + uav_desc.Texture3D.WSize >>= p_mipmap_offset; + } break; + } + + return uav_desc; +} + D3D12_DEPTH_STENCIL_VIEW_DESC RenderingDeviceDriverD3D12::_make_dsv_for_texture(const TextureInfo *p_texture_info) { D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {}; dsv_desc.Format = RD_TO_D3D12_FORMAT[p_texture_info->format].dsv_format; @@ -3779,6 +3807,21 @@ void RenderingDeviceDriverD3D12::uniform_set_free(UniformSetID p_uniform_set) { // ----- COMMANDS ----- void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) { + // Perform pending blackouts. + { + SelfList<TextureInfo> *E = textures_pending_clear.first(); + while (E) { + TextureSubresourceRange subresources; + subresources.layer_count = E->self()->layers; + subresources.mipmap_count = E->self()->mipmaps; + command_clear_color_texture(p_cmd_buffer, TextureID(E->self()), TEXTURE_LAYOUT_GENERAL, Color(), subresources); + + SelfList<TextureInfo> *next = E->next(); + E->remove_from_list(); + E = next; + } + } + const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id; const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id; const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index]; @@ -3825,13 +3868,6 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff } DEV_ASSERT((wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == (bool)(wanted_state & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); - - if (wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS || wanted_state == D3D12_RESOURCE_STATE_RENDER_TARGET) { - if (!sr.is_buffer) { - TextureInfo *tex_info = (TextureInfo *)sr.resource; - CRASH_COND_MSG(tex_info->resource != tex_info->main_texture, "The texture format used for UAV or RTV must be the main one."); - } - } } } #endif @@ -3911,7 +3947,35 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff for (uint32_t i = 0; i < tex_info->layers; i++) { for (uint32_t j = 0; j < tex_info->mipmaps; j++) { uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize()); - _resource_transition_batch(tex_info, subresource, planes, wanted_state, tex_info->main_texture); + + if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) { + // [[CROSS_FAMILY_FALLBACK]]. + if (tex_info->owner_info.resource && tex_info->main_texture && tex_info->main_texture != tex_info) { + uint32_t subres_qword = subresource / 64; + uint64_t subres_mask = (uint64_t(1) << (subresource % 64)); + if ((tex_info->main_texture->states_ptr->xfamily_fallback.subresources_dirty[subres_qword] & subres_mask)) { + // Prepare for copying the write-to texture to this one, if out-of-date. + _resource_transition_batch(tex_info->main_texture, subresource, planes, D3D12_RESOURCE_STATE_COPY_SOURCE); + _resource_transition_batch(tex_info, subresource, planes, D3D12_RESOURCE_STATE_COPY_DEST); + + CommandBufferInfo::FamilyFallbackCopy ffc; + ffc.texture = tex_info; + ffc.subresource = subresource; + ffc.mipmap = j; + ffc.dst_wanted_state = wanted_state; + + CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; + cmd_buf_info->family_fallback_copies.resize(cmd_buf_info->family_fallback_copies.size() + 1); + cmd_buf_info->family_fallback_copies[cmd_buf_info->family_fallback_copy_count] = ffc; + cmd_buf_info->family_fallback_copy_count++; + + tex_info->main_texture->states_ptr->xfamily_fallback.subresources_dirty[subres_qword] &= ~subres_mask; + } + continue; + } + } + + _resource_transition_batch(tex_info, subresource, planes, wanted_state); } } } @@ -3920,7 +3984,56 @@ void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBuff } if (p_set_index == shader_info_in->sets.size() - 1) { - const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; + CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id; + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + + // [[CROSS_FAMILY_FALLBACK]]. + for (uint32_t i = 0; i < cmd_buf_info->family_fallback_copy_count; i++) { + const CommandBufferInfo::FamilyFallbackCopy &ffc = cmd_buf_info->family_fallback_copies[i]; + + D3D12_TEXTURE_COPY_LOCATION dst_tex = {}; + dst_tex.pResource = ffc.texture->resource; + dst_tex.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst_tex.SubresourceIndex = ffc.subresource; + + D3D12_TEXTURE_COPY_LOCATION src_tex = {}; + src_tex.pResource = ffc.texture->main_texture->resource; + src_tex.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_tex.SubresourceIndex = ffc.subresource; + + const ResourceInfo::States::CrossFamillyFallback &xfamily = ffc.texture->main_texture->owner_info.states.xfamily_fallback; + if (xfamily.interim_buffer.Get()) { + // Must copy via a buffer due to reinterpret-copy known not to be available for these data types. + D3D12_TEXTURE_COPY_LOCATION buf_loc = {}; + buf_loc.pResource = xfamily.interim_buffer.Get(); + buf_loc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + buf_loc.PlacedFootprint.Offset = 0; + buf_loc.PlacedFootprint.Footprint.Format = ffc.texture->main_texture->desc.Format; + buf_loc.PlacedFootprint.Footprint.Width = MAX(1u, ffc.texture->main_texture->desc.Width >> ffc.mipmap); + buf_loc.PlacedFootprint.Footprint.Height = MAX(1u, ffc.texture->main_texture->desc.Height >> ffc.mipmap); + buf_loc.PlacedFootprint.Footprint.Depth = MAX(1u, (uint32_t)ffc.texture->main_texture->desc.Depth() >> ffc.mipmap); + buf_loc.PlacedFootprint.Footprint.RowPitch = STEPIFY(buf_loc.PlacedFootprint.Footprint.Width * sizeof(uint16_t), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + + D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(xfamily.interim_buffer.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COPY_DEST); + cmd_buf_info->cmd_list->ResourceBarrier(1, &barrier); + + cmd_buf_info->cmd_list->CopyTextureRegion(&buf_loc, 0, 0, 0, &src_tex, nullptr); + + barrier = CD3DX12_RESOURCE_BARRIER::Transition(xfamily.interim_buffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE); + cmd_buf_info->cmd_list->ResourceBarrier(1, &barrier); + + buf_loc.PlacedFootprint.Footprint.Format = ffc.texture->desc.Format; + cmd_buf_info->cmd_list->CopyTextureRegion(&dst_tex, 0, 0, 0, &buf_loc, nullptr); + } else { + // Direct copy is possible. + cmd_buf_info->cmd_list->CopyTextureRegion(&dst_tex, 0, 0, 0, &src_tex, nullptr); + } + + // Set the specific SRV state we wanted from the beginning to the alternative version of the texture. + _resource_transition_batch(ffc.texture, ffc.subresource, 1, ffc.dst_wanted_state); + } + cmd_buf_info->family_fallback_copy_count = 0; + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); } } @@ -4234,17 +4347,17 @@ void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buff frames[frame_idx].desc_heap_walkers.aux.advance(); } -void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_dst_buffer, VectorView<BufferCopyRegion> p_regions) { +void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_buf_locfer, VectorView<BufferCopyRegion> p_regions) { const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id; - BufferInfo *dst_buf_info = (BufferInfo *)p_dst_buffer.id; + BufferInfo *buf_loc_info = (BufferInfo *)p_buf_locfer.id; _resource_transition_batch(src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); - _resource_transition_batch(dst_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); + _resource_transition_batch(buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); for (uint32_t i = 0; i < p_regions.size(); i++) { - cmd_buf_info->cmd_list->CopyBufferRegion(dst_buf_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size); + cmd_buf_info->cmd_list->CopyBufferRegion(buf_loc_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size); } } @@ -4312,12 +4425,29 @@ void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_b void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) { const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; TextureInfo *tex_info = (TextureInfo *)p_texture.id; + if (tex_info->main_texture) { + tex_info = tex_info->main_texture; + } + + auto _transition_subresources = [&](D3D12_RESOURCE_STATES p_new_state) { + for (uint32_t i = 0; i < p_subresources.layer_count; i++) { + for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) { + UINT subresource = D3D12CalcSubresource( + p_subresources.base_mipmap + j, + p_subresources.base_layer + i, + 0, + tex_info->desc.MipLevels, + tex_info->desc.ArraySize()); + _resource_transition_batch(tex_info, subresource, 1, p_new_state); + } + } + _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + }; - ID3D12Resource *res_to_clear = tex_info->main_texture ? tex_info->main_texture : tex_info->resource; if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) { // Clear via RTV. - if (frames[frame_idx].desc_heap_walkers.rtv.is_at_eof()) { + if (frames[frame_idx].desc_heap_walkers.rtv.get_free_handles() < p_subresources.mipmap_count) { if (!frames[frame_idx].desc_heaps_exhausted_reported.rtv) { frames[frame_idx].desc_heaps_exhausted_reported.rtv = true; ERR_FAIL_MSG( @@ -4328,37 +4458,29 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c } } - D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap, p_subresources.base_layer, p_subresources.layer_count, false); - rtv_desc.Format = tex_info->aliasing_hack.main_uav_desc.Format; + _transition_subresources(D3D12_RESOURCE_STATE_RENDER_TARGET); - for (uint32_t i = 0; i < p_subresources.layer_count; i++) { - for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) { - UINT subresource = D3D12CalcSubresource( - p_subresources.base_mipmap + j, - p_subresources.base_layer + i, - 0, - tex_info->desc.MipLevels, - tex_info->desc.ArraySize()); - _resource_transition_batch(tex_info, subresource, 1, D3D12_RESOURCE_STATE_RENDER_TARGET, tex_info->main_texture); - } - } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); + for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) { + D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false); + rtv_desc.Format = tex_info->view_descs.uav.Format; + device->CreateRenderTargetView( + tex_info->resource, + &rtv_desc, + frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle()); - device->CreateRenderTargetView( - res_to_clear, - &rtv_desc, - frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle()); - cmd_buf_info->cmd_list->ClearRenderTargetView( - frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle(), - p_color.components, - 0, - nullptr); - frames[frame_idx].desc_heap_walkers.rtv.advance(); + cmd_buf_info->cmd_list->ClearRenderTargetView( + frames[frame_idx].desc_heap_walkers.rtv.get_curr_cpu_handle(), + p_color.components, + 0, + nullptr); + + frames[frame_idx].desc_heap_walkers.rtv.advance(); + } } else { // Clear via UAV. _command_check_descriptor_sets(p_cmd_buffer); - if (frames[frame_idx].desc_heap_walkers.resources.is_at_eof()) { + if (frames[frame_idx].desc_heap_walkers.resources.get_free_handles() < p_subresources.mipmap_count) { if (!frames[frame_idx].desc_heaps_exhausted_reported.resources) { frames[frame_idx].desc_heaps_exhausted_reported.resources = true; ERR_FAIL_MSG( @@ -4368,7 +4490,7 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c return; } } - if (frames[frame_idx].desc_heap_walkers.aux.is_at_eof()) { + if (frames[frame_idx].desc_heap_walkers.aux.get_free_handles() < p_subresources.mipmap_count) { if (!frames[frame_idx].desc_heaps_exhausted_reported.aux) { frames[frame_idx].desc_heaps_exhausted_reported.aux = true; ERR_FAIL_MSG( @@ -4379,47 +4501,38 @@ void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_c } } - for (uint32_t i = 0; i < p_subresources.layer_count; i++) { - for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) { - UINT subresource = D3D12CalcSubresource( - p_subresources.base_mipmap + j, - p_subresources.base_layer + i, - 0, - tex_info->desc.MipLevels, - tex_info->desc.ArraySize()); - _resource_transition_batch(tex_info, subresource, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, tex_info->main_texture); - } - } - _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); - - device->CreateUnorderedAccessView( - res_to_clear, - nullptr, - &tex_info->aliasing_hack.main_uav_desc, - frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle()); - - device->CopyDescriptorsSimple( - 1, - frames[frame_idx].desc_heap_walkers.resources.get_curr_cpu_handle(), - frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(), - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - UINT values[4] = { - (UINT)p_color.get_r8(), - (UINT)p_color.get_g8(), - (UINT)p_color.get_b8(), - (UINT)p_color.get_a8(), - }; - cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint( - frames[frame_idx].desc_heap_walkers.resources.get_curr_gpu_handle(), - frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(), - res_to_clear, - values, - 0, - nullptr); + _transition_subresources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + + for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) { + D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = _make_ranged_uav_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false); + device->CreateUnorderedAccessView( + tex_info->resource, + nullptr, + &uav_desc, + frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle()); + device->CopyDescriptorsSimple( + 1, + frames[frame_idx].desc_heap_walkers.resources.get_curr_cpu_handle(), + frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(), + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + UINT values[4] = { + (UINT)p_color.get_r8(), + (UINT)p_color.get_g8(), + (UINT)p_color.get_b8(), + (UINT)p_color.get_a8(), + }; + cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint( + frames[frame_idx].desc_heap_walkers.resources.get_curr_gpu_handle(), + frames[frame_idx].desc_heap_walkers.aux.get_curr_cpu_handle(), + tex_info->resource, + values, + 0, + nullptr); - frames[frame_idx].desc_heap_walkers.resources.advance(); - frames[frame_idx].desc_heap_walkers.aux.advance(); + frames[frame_idx].desc_heap_walkers.resources.advance(); + frames[frame_idx].desc_heap_walkers.aux.advance(); + } } } @@ -4429,7 +4542,7 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id; if (buf_info->flags.is_for_upload) { - _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE, nullptr); + _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); } uint32_t pixel_size = get_image_format_pixel_size(tex_info->format); @@ -4465,7 +4578,7 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID tex_info->desc.ArraySize()); CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource); - _resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST, tex_info->main_texture); + _resource_transition_batch(tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST); } _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); @@ -4490,12 +4603,12 @@ void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID } } -void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) { +void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_buf_locfer, VectorView<BufferTextureCopyRegion> p_regions) { const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id; TextureInfo *tex_info = (TextureInfo *)p_src_texture.id; - BufferInfo *buf_info = (BufferInfo *)p_dst_buffer.id; + BufferInfo *buf_info = (BufferInfo *)p_buf_locfer.id; - _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST, nullptr); + _resource_transition_batch(buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST); uint32_t block_w = 0, block_h = 0; get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h); @@ -4509,7 +4622,7 @@ void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID tex_info->desc.MipLevels, tex_info->desc.ArraySize()); - _resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE, tex_info->main_texture); + _resource_transition_batch(tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE); } _resource_transitions_flush(cmd_buf_info->cmd_list.Get()); @@ -4657,7 +4770,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd 0, p_texture_info->desc.MipLevels, p_texture_info->desc.ArraySize()); - _resource_transition_batch(p_texture_info, subresource, planes, p_states, nullptr); + _resource_transition_batch(p_texture_info, subresource, planes, p_states); } } }; @@ -6125,7 +6238,15 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() { } if (format_capabilities.relaxed_casting_supported) { +#if 0 print_verbose("- Relaxed casting supported"); +#else + // Certain configurations (Windows 11 with an updated Nvida driver) crash when using relaxed casting. + // Therefore, we disable it temporarily until we can assure that it's reliable. + // There are fallbacks in place that work in every case, if less efficient. + format_capabilities.relaxed_casting_supported = false; + print_verbose("- Relaxed casting supported (but disabled for now)"); +#endif } else { print_verbose("- Relaxed casting not supported"); } @@ -6171,6 +6292,7 @@ Error RenderingDeviceDriverD3D12::_initialize_allocator() { D3D12MA::ALLOCATOR_DESC allocator_desc = {}; allocator_desc.pDevice = device.Get(); allocator_desc.pAdapter = adapter.Get(); + allocator_desc.Flags = D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED; HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator); ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h index 06d5cb65c4..852cb9db0e 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.h +++ b/drivers/d3d12/rendering_device_driver_d3d12.h @@ -33,6 +33,7 @@ #include "core/templates/hash_map.h" #include "core/templates/paged_allocator.h" +#include "core/templates/self_list.h" #include "servers/rendering/rendering_device_driver.h" #if defined(__GNUC__) && !defined(__clang__) @@ -215,17 +216,21 @@ private: struct States { // As many subresources as mipmaps * layers; planes (for depth-stencil) are tracked together. TightLocalVector<D3D12_RESOURCE_STATES> subresource_states; // Used only if not a view. - uint32_t last_batch_transitioned_to_uav = 0; uint32_t last_batch_with_uav_barrier = 0; + struct CrossFamillyFallback { + TightLocalVector<uint64_t> subresources_dirty; + ComPtr<ID3D12Resource> interim_buffer; + ComPtr<D3D12MA::Allocation> interim_buffer_alloc; + } xfamily_fallback; // [[CROSS_FAMILY_FALLBACK]]. }; - ID3D12Resource *resource = nullptr; // Non-null even if a view. + ID3D12Resource *resource = nullptr; // Non-null even if not owned. struct { ComPtr<ID3D12Resource> resource; ComPtr<D3D12MA::Allocation> allocation; States states; - } owner_info; // All empty if a view. - States *states_ptr = nullptr; // Own or from another if a view. + } owner_info; // All empty if the resource is not owned. + States *states_ptr = nullptr; // Own or from another if it doesn't own the D3D12 resource. }; struct BarrierRequest { @@ -257,7 +262,7 @@ private: uint64_t frame_barriers_cpu_time = 0; #endif - void _resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state, ID3D12Resource *p_resource_override = nullptr); + void _resource_transition_batch(ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state); void _resource_transitions_flush(ID3D12GraphicsCommandList *p_cmd_list); /*****************/ @@ -298,16 +303,12 @@ private: D3D12_UNORDERED_ACCESS_VIEW_DESC uav; } view_descs = {}; - ID3D12Resource *main_texture = nullptr; - struct { - D3D12_UNORDERED_ACCESS_VIEW_DESC main_uav_desc; - struct { - HashMap<DXGI_FORMAT, ComPtr<ID3D12Resource>> aliases; // Key is the DXGI format family. - } owner_info = {}; - } aliasing_hack = {}; // [[CROSS_FAMILY_ALIASING]] + TextureInfo *main_texture = nullptr; UINT mapped_subresource = UINT_MAX; + SelfList<TextureInfo> pending_clear{ this }; }; + SelfList<TextureInfo>::List textures_pending_clear; HashMap<DXGI_FORMAT, uint32_t> format_sample_counts_mask_cache; @@ -331,6 +332,10 @@ public: virtual void texture_unmap(TextureID p_texture) override final; virtual BitField<TextureUsageBits> texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) override final; +private: + TextureID _texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps); + +public: /*****************/ /**** SAMPLER ****/ /*****************/ @@ -459,6 +464,16 @@ private: RenderPassState render_pass_state; bool descriptor_heaps_set = false; + + // [[CROSS_FAMILY_FALLBACK]]. + struct FamilyFallbackCopy { + TextureInfo *texture = nullptr; + uint32_t subresource = 0; + uint32_t mipmap = 0; + D3D12_RESOURCE_STATES dst_wanted_state = {}; + }; + LocalVector<FamilyFallbackCopy> family_fallback_copies; + uint32_t family_fallback_copy_count = 0; }; public: @@ -513,6 +528,7 @@ private: }; D3D12_RENDER_TARGET_VIEW_DESC _make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases = true); + D3D12_UNORDERED_ACCESS_VIEW_DESC _make_ranged_uav_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases = true); D3D12_DEPTH_STENCIL_VIEW_DESC _make_dsv_for_texture(const TextureInfo *p_texture_info); FramebufferID _framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height, bool p_is_screen); @@ -758,6 +774,7 @@ public: virtual void command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) override final; virtual void command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) override final; +public: virtual void command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) override final; virtual void command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_dst_buffer, VectorView<BufferTextureCopyRegion> p_regions) override final; diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp index 43bc6d5476..6e64652982 100644 --- a/drivers/gles3/effects/copy_effects.cpp +++ b/drivers/gles3/effects/copy_effects.cpp @@ -207,8 +207,8 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[i % 2]); source_region = dest_region; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteFramebuffers(2, framebuffers); } @@ -274,7 +274,7 @@ void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, con source_region = dest_region; normalized_source_region = normalized_dest_region; } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteFramebuffers(1, &framebuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/drivers/gles3/effects/glow.cpp b/drivers/gles3/effects/glow.cpp index 9fc2eef65b..9728b089aa 100644 --- a/drivers/gles3/effects/glow.cpp +++ b/drivers/gles3/effects/glow.cpp @@ -31,6 +31,7 @@ #ifdef GLES3_ENABLED #include "glow.h" +#include "../storage/texture_storage.h" using namespace GLES3; @@ -166,7 +167,7 @@ void Glow::process_glow(GLuint p_source_color, Size2i p_size, const Glow::GLOWLE glDepthMask(GL_TRUE); glUseProgram(0); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } #endif // GLES3_ENABLED diff --git a/drivers/gles3/effects/post_effects.cpp b/drivers/gles3/effects/post_effects.cpp index 75af068ab5..8ad872f319 100644 --- a/drivers/gles3/effects/post_effects.cpp +++ b/drivers/gles3/effects/post_effects.cpp @@ -31,6 +31,7 @@ #ifdef GLES3_ENABLED #include "post_effects.h" +#include "../storage/texture_storage.h" using namespace GLES3; @@ -146,7 +147,7 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glUseProgram(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } #endif // GLES3_ENABLED diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 80daa9a907..198160939a 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -629,8 +629,6 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou state.canvas_instance_batches[state.current_batch_index].material_data = material_data; if (shader_data_cache) { state.canvas_instance_batches[state.current_batch_index].vertex_input_mask = shader_data_cache->vertex_input_mask; - } else { - state.canvas_instance_batches[state.current_batch_index].vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_COLOR | RS::ARRAY_TEX_UV; } } @@ -1689,7 +1687,7 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c } glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1797,7 +1795,7 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha cl->shadow.directional_xform = to_shadow * to_light_xform; glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1911,7 +1909,7 @@ void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstanc texture_storage->render_target_sdf_process(p_render_target); //done rendering, process it glBindVertexArray(0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } RID RasterizerCanvasGLES3::occluder_polygon_create() { diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index 2b70df3238..88befa7883 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -269,7 +269,7 @@ public: RID material; GLES3::CanvasMaterialData *material_data = nullptr; CanvasShaderGLES3::ShaderVariant shader_variant = CanvasShaderGLES3::MODE_QUAD; - uint64_t vertex_input_mask; + uint64_t vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_COLOR | RS::ARRAY_FORMAT_TEX_UV; const Item::Command *command = nullptr; Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch. diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index da2320c23d..73ee277074 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -418,7 +418,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display GL_COLOR_BUFFER_BIT, GL_NEAREST); if (read_fbo != 0) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteFramebuffers(1, &read_fbo); } } @@ -442,7 +442,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c Size2i win_size = DisplayServer::get_singleton()->window_get_size(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glViewport(0, 0, win_size.width, win_size.height); glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 59894ca4e3..f9af86e19b 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1107,7 +1107,7 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) { } glBindVertexArray(0); glViewport(0, 0, p_sky->screen_size.x, p_sky->screen_size.y); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { @@ -1148,7 +1148,7 @@ Ref<Image> RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bo copy_effects->copy_cube_to_panorama(p_bake_irradiance ? float(sky->mipmap_count) : 0.0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteFramebuffers(1, &rad_fbo); // Create a dummy texture so we can use texture_2d_get. RID tex_rid = GLES3::TextureStorage::get_singleton()->texture_allocate(); @@ -2303,7 +2303,7 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, scene_state.enable_gl_depth_draw(true); glDisable(GL_CULL_FACE); scene_state.cull_mode = GLES3::SceneShaderData::CULL_DISABLED; - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_compositor, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RenderingMethod::RenderInfo *r_render_info) { @@ -3573,7 +3573,7 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, _render_list_template<PASS_MODE_SHADOW>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_SECONDARY].elements.size()); glColorMask(1, 1, 1, 1); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, GLuint p_framebuffer, const Rect2i &p_region) { @@ -3655,7 +3655,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance * GLuint db = GL_COLOR_ATTACHMENT0; glDrawBuffers(1, &db); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } } @@ -3759,7 +3759,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES copy_effects->copy_to_rect(Rect2(Vector2(), Vector2(0.5, 0.5))); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } } if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) { @@ -3969,6 +3969,10 @@ bool RasterizerSceneGLES3::free(RID p_rid) { } else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) { //not much to delete, just free it RSG::camera_attributes->camera_attributes_free(p_rid); + } else if (is_compositor(p_rid)) { + compositor_free(p_rid); + } else if (is_compositor_effect(p_rid)) { + compositor_effect_free(p_rid); } else { return false; } diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 5421f57646..2259c61e5b 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -1044,7 +1044,7 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i glBindTexture(GL_TEXTURE_2D, 0); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); r_quadrant = qidx; r_shadow = shadow_atlas->quadrants[qidx].textures.size(); @@ -1135,7 +1135,7 @@ void LightStorage::update_directional_shadow_atlas() { glClear(GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index 96e6200219..a6b236f3ec 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -686,7 +686,7 @@ public: glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, atlas->debug_texture, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); return atlas->debug_fbo; } diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 5600449d00..23376b4381 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2607,7 +2607,7 @@ void CanvasShaderData::set_code(const String &p_code) { MaterialStorage::get_singleton()->shaders.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data); ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.canvas_shader.version_is_valid(version)); - vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_COLOR | RS::ARRAY_TEX_UV; + vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_COLOR | RS::ARRAY_FORMAT_TEX_UV; vertex_input_mask |= uses_custom0 << RS::ARRAY_CUSTOM0; vertex_input_mask |= uses_custom1 << RS::ARRAY_CUSTOM1; diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 1dcd29553d..e073db3cfd 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -33,6 +33,7 @@ #include "mesh_storage.h" #include "config.h" #include "material_storage.h" +#include "texture_storage.h" #include "utilities.h" using namespace GLES3; @@ -1248,7 +1249,7 @@ void MeshStorage::update_mesh_instances() { } glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); // Process skeletons and blend shapes using transform feedback while (dirty_mesh_instance_arrays.first()) { MeshInstance *mi = dirty_mesh_instance_arrays.first()->self(); diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index e263acf88b..c5a97bdbd5 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -818,7 +818,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p } glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); _particles_update_instance_buffer(particles, axis, p_up_axis); glDisable(GL_RASTERIZER_DISCARD); } @@ -1002,7 +1002,7 @@ void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, c void ParticlesStorage::update_particles() { glEnable(GL_RASTERIZER_DISCARD); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_shader_parameters_get_uniform_buffer(); @@ -1262,7 +1262,7 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p particles_collision->heightfield_fb_size = size; glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } return particles_collision->heightfield_fb; diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index bd96442328..de0a64f5fe 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -121,7 +121,7 @@ GLuint RenderSceneBuffersGLES3::_rt_get_cached_fbo(GLuint p_color, GLuint p_dept msaa3d.cached_fbos.push_back(new_fbo); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif return new_fbo.fbo; @@ -265,7 +265,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindTexture(texture_target, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } if (msaa3d.mode != RS::VIEWPORT_MSAA_DISABLED) { @@ -316,7 +316,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #if !defined(IOS_ENABLED) && !defined(WEB_ENABLED) } else if (use_multiview && !config->rt_msaa_multiview_supported) { // Render to texture extensions not supported? fall back to MSAA textures through GL_EXT_multiview_texture_multisample. @@ -362,7 +362,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { } glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif #if defined(ANDROID_ENABLED) || defined(WEB_ENABLED) // Only supported on OpenGLES! } else if (!use_internal_buffer) { @@ -390,7 +390,7 @@ void RenderSceneBuffersGLES3::_check_render_buffers() { WARN_PRINT("Could not create 3D MSAA framebuffer, status: " + texture_storage->get_framebuffer_error(status)); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); #endif } else { // HUH? how did we get here? @@ -531,7 +531,7 @@ void RenderSceneBuffersGLES3::check_backbuffer(bool p_need_color, bool p_need_de } glBindTexture(texture_target, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RenderSceneBuffersGLES3::_clear_back_buffers() { @@ -607,7 +607,7 @@ void RenderSceneBuffersGLES3::check_glow_buffers() { } glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } void RenderSceneBuffersGLES3::_clear_glow_buffers() { diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index e9df3c6fc8..ffbad4c83b 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1090,7 +1090,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const { glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1162,7 +1162,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1265,7 +1265,7 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const { Vector<Ref<Image>> ret = _texture_3d_read_framebuffer(texture); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); glDeleteTextures(1, &temp_color_texture); glDeleteFramebuffers(1, &temp_framebuffer); @@ -1920,7 +1920,7 @@ void TextureStorage::update_texture_atlas() { copy_effects->copy_to_rect(t->uv_rect); } } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); } /* DECAL API */ diff --git a/editor/SCsub b/editor/SCsub index aa240a1e01..bbb40ff303 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -104,6 +104,15 @@ if env.editor_build: env.Run(editor_builders.make_doc_translations_header, "Generating translations header."), ) + # Extractable translations + tlist = glob.glob(env.Dir("#editor/translations/extractable").abspath + "/*.po") + env.Depends("#editor/extractable_translations.gen.h", tlist) + env.CommandNoCache( + "#editor/extractable_translations.gen.h", + tlist, + env.Run(editor_builders.make_extractable_translations_header, "Generating extractable translations header."), + ) + env.add_source_files(env.editor_sources, "*.cpp") env.add_source_files(env.editor_sources, "register_exporters.gen.cpp") diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 1652c0b1f1..6f1439a91f 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3828,7 +3828,7 @@ void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_bezi } } -void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value) { +void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant &p_value) { ERR_FAIL_NULL(root); ERR_FAIL_COND_MSG( (p_type != Animation::TYPE_POSITION_3D && p_type != Animation::TYPE_ROTATION_3D && p_type != Animation::TYPE_SCALE_3D), @@ -4986,7 +4986,7 @@ void AnimationTrackEditor::_fetch_value_track_options(const NodePath &p_path, An } } -void AnimationTrackEditor::_new_track_property_selected(String p_name) { +void AnimationTrackEditor::_new_track_property_selected(const String &p_name) { String full_path = String(adding_track_path) + ":" + p_name; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 0d6f93fefc..d0da7b0062 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -440,7 +440,7 @@ class AnimationTrackEditor : public VBoxContainer { void _add_track(int p_type); void _new_track_node_selected(NodePath p_path); - void _new_track_property_selected(String p_name); + void _new_track_property_selected(const String &p_name); void _update_step_spinbox(); @@ -699,7 +699,7 @@ public: void set_anim_pos(float p_pos); void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false); void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance); - void insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value); + void insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant &p_value); bool has_track(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type); void make_insert_queue(); void commit_insert_queue(); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index d3872349e9..3efefe83c3 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1059,7 +1059,6 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_line_length_guidelines(TypedArray<int>()); } - _update_font_ligatures(); set_zoom_factor(zoom_factor); } @@ -1683,10 +1682,6 @@ void CodeTextEditor::goto_error() { } void CodeTextEditor::_update_text_editor_theme() { - if (!EditorThemeManager::is_generated_theme_outdated()) { - return; - } - emit_signal(SNAME("load_theme_settings")); error_button->set_icon(get_editor_theme_icon(SNAME("StatusError"))); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 9fef200611..19474d383d 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -236,7 +236,7 @@ void ConnectDialog::_remove_bind() { /* * Automatically generates a name for the callback method. */ -StringName ConnectDialog::generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target) { +StringName ConnectDialog::generate_method_callback_name(Node *p_source, const String &p_signal_name, Node *p_target) { String node_name = p_source->get_name(); for (int i = 0; i < node_name.length(); i++) { // TODO: Regex filter may be cleaner. char32_t c = node_name[i]; @@ -645,7 +645,7 @@ void ConnectDialog::init(const ConnectionData &p_cd, const PackedStringArray &p_ source_connection_data = p_cd; } -void ConnectDialog::popup_dialog(const String p_for_signal) { +void ConnectDialog::popup_dialog(const String &p_for_signal) { from_signal->set_text(p_for_signal); warning_label->add_theme_color_override("font_color", warning_label->get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); error_label->add_theme_color_override("font_color", error_label->get_theme_color(SNAME("error_color"), EditorStringName(Editor))); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index fb163fbb5f..8aa44dc91d 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -163,7 +163,7 @@ protected: static void _bind_methods(); public: - static StringName generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target); + static StringName generate_method_callback_name(Node *p_source, const String &p_signal_name, Node *p_target); Node *get_source() const; ConnectionData get_source_connection_data() const; StringName get_signal_name() const; @@ -184,7 +184,7 @@ public: void init(const ConnectionData &p_cd, const PackedStringArray &p_signal_args, bool p_edit = false); - void popup_dialog(const String p_for_signal); + void popup_dialog(const String &p_for_signal); ConnectDialog(); ~ConnectDialog(); }; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 604449b04b..603b3505d4 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -343,7 +343,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String } } -String CreateDialog::_top_result(const Vector<String> p_candidates, const String &p_search_text) const { +String CreateDialog::_top_result(const Vector<String> &p_candidates, const String &p_search_text) const { float highest_score = 0; int highest_index = 0; for (int i = 0; i < p_candidates.size(); i++) { diff --git a/editor/create_dialog.h b/editor/create_dialog.h index 694efd1ee1..12385747c2 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -71,7 +71,7 @@ class CreateDialog : public ConfirmationDialog { bool _should_hide_type(const String &p_type) const; void _add_type(const String &p_type, const TypeCategory p_type_category); void _configure_search_option_item(TreeItem *r_item, const String &p_type, const TypeCategory p_type_category); - String _top_result(const Vector<String> p_candidates, const String &p_search_text) const; + String _top_result(const Vector<String> &p_candidates, const String &p_search_text) const; float _score_type(const String &p_type, const String &p_search) const; bool _is_type_preferred(const String &p_type) const; diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 5fe35bde84..b7719f6c97 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -557,7 +557,7 @@ void EditorDebuggerNode::_paused() { }); } -void EditorDebuggerNode::_breaked(bool p_breaked, bool p_can_debug, String p_message, bool p_has_stackdump, int p_debugger) { +void EditorDebuggerNode::_breaked(bool p_breaked, bool p_can_debug, const String &p_message, bool p_has_stackdump, int p_debugger) { if (get_current_debugger() != get_debugger(p_debugger)) { if (!p_breaked) { return; @@ -582,7 +582,7 @@ void EditorDebuggerNode::set_breakpoint(const String &p_path, int p_line, bool p emit_signal(SNAME("breakpoint_toggled"), p_path, p_line, p_enabled); } -void EditorDebuggerNode::set_breakpoints(const String &p_path, Array p_lines) { +void EditorDebuggerNode::set_breakpoints(const String &p_path, const Array &p_lines) { for (int i = 0; i < p_lines.size(); i++) { set_breakpoint(p_path, p_lines[i], true); } diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index d30f29c7c6..01aa522f40 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -149,7 +149,7 @@ protected: void _text_editor_stack_clear(const ScriptEditorDebugger *p_debugger); void _stack_frame_selected(int p_debugger); void _error_selected(const String &p_file, int p_line, int p_debugger); - void _breaked(bool p_breaked, bool p_can_debug, String p_message, bool p_has_stackdump, int p_debugger); + void _breaked(bool p_breaked, bool p_can_debug, const String &p_message, bool p_has_stackdump, int p_debugger); void _paused(); void _break_state_changed(); void _menu_option(int p_id); @@ -186,7 +186,7 @@ public: bool is_skip_breakpoints() const; void set_breakpoint(const String &p_path, int p_line, bool p_enabled); - void set_breakpoints(const String &p_path, Array p_lines); + void set_breakpoints(const String &p_path, const Array &p_lines); void reload_all_scripts(); void reload_scripts(const Vector<String> &p_script_paths); diff --git a/editor/debugger/editor_file_server.cpp b/editor/debugger/editor_file_server.cpp index c12cec1e74..e84eb14636 100644 --- a/editor/debugger/editor_file_server.cpp +++ b/editor/debugger/editor_file_server.cpp @@ -98,7 +98,7 @@ void EditorFileServer::_scan_files_changed(EditorFileSystemDirectory *efd, const } } -static void _add_custom_file(const String f, HashMap<String, uint64_t> &files_to_send, HashMap<String, uint64_t> &cached_files) { +static void _add_custom_file(const String &f, HashMap<String, uint64_t> &files_to_send, HashMap<String, uint64_t> &cached_files) { if (!FileAccess::exists(f)) { return; } diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 37e13b59cc..ffff362a94 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -38,7 +38,7 @@ EditorPerformanceProfiler::Monitor::Monitor() {} -EditorPerformanceProfiler::Monitor::Monitor(String p_name, String p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item) { +EditorPerformanceProfiler::Monitor::Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item) { type = p_type; item = p_item; frame_index = p_frame_index; diff --git a/editor/debugger/editor_performance_profiler.h b/editor/debugger/editor_performance_profiler.h index 6211cc39a4..4afe82b4bd 100644 --- a/editor/debugger/editor_performance_profiler.h +++ b/editor/debugger/editor_performance_profiler.h @@ -54,7 +54,7 @@ private: int frame_index = 0; Monitor(); - Monitor(String p_name, String p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item); + Monitor(const String &p_name, const String &p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item); void update_value(float p_value); void reset(); }; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 93dcc341c1..979834ebab 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -72,7 +72,7 @@ using CameraOverride = EditorDebuggerNode::CameraOverride; -void ScriptEditorDebugger::_put_msg(String p_message, Array p_data, uint64_t p_thread_id) { +void ScriptEditorDebugger::_put_msg(const String &p_message, const Array &p_data, uint64_t p_thread_id) { ERR_FAIL_COND(p_thread_id == Thread::UNASSIGNED_ID); if (is_session_active()) { Array msg; diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index 589e82ef25..bd0b0c7d85 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -222,7 +222,7 @@ private: void _item_menu_id_pressed(int p_option); void _tab_changed(int p_tab); - void _put_msg(String p_message, Array p_data, uint64_t p_thread_id = Thread::MAIN_ID); + void _put_msg(const String &p_message, const Array &p_data, uint64_t p_thread_id = Thread::MAIN_ID); void _export_csv(); void _clear_execution(); diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index b4ef0f8c4a..e594d53d69 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -33,6 +33,7 @@ #include "core/authors.gen.h" #include "core/donors.gen.h" #include "core/license.gen.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/editor_string_names.h" #include "editor/themes/editor_scale.h" @@ -206,7 +207,14 @@ EditorAbout::EditorAbout() { // Set the text to copy in metadata as it slightly differs from the button's text. version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version number."), build_date)); + version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed)); version_info_vbc->add_child(version_btn); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 4d5393299c..0e46990b41 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -382,17 +382,17 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { add_autoload->set_disabled(false); } -void EditorAutoloadSettings::_autoload_text_submitted(const String p_name) { +void EditorAutoloadSettings::_autoload_text_submitted(const String &p_name) { if (!autoload_add_path->get_text().is_empty() && _autoload_name_is_valid(p_name, nullptr)) { _autoload_add(); } } -void EditorAutoloadSettings::_autoload_path_text_changed(const String p_path) { +void EditorAutoloadSettings::_autoload_path_text_changed(const String &p_path) { add_autoload->set_disabled(!_autoload_name_is_valid(autoload_add_name->get_text(), nullptr)); } -void EditorAutoloadSettings::_autoload_text_changed(const String p_name) { +void EditorAutoloadSettings::_autoload_text_changed(const String &p_name) { String error_string; bool is_name_valid = _autoload_name_is_valid(p_name, &error_string); add_autoload->set_disabled(!is_name_valid); diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index cd025e0fc7..11d7cdbe4d 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -83,9 +83,9 @@ class EditorAutoloadSettings : public VBoxContainer { void _autoload_edited(); void _autoload_button_pressed(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button); void _autoload_activated(); - void _autoload_path_text_changed(const String p_path); - void _autoload_text_submitted(const String p_name); - void _autoload_text_changed(const String p_name); + void _autoload_path_text_changed(const String &p_path); + void _autoload_text_submitted(const String &p_name); + void _autoload_text_changed(const String &p_name); void _autoload_open(const String &fpath); void _autoload_file_callback(const String &p_path); Node *_create_autoload(const String &p_path); diff --git a/editor/editor_builders.py b/editor/editor_builders.py index 25004da877..98a64cfd23 100644 --- a/editor/editor_builders.py +++ b/editor/editor_builders.py @@ -140,5 +140,9 @@ def make_doc_translations_header(target, source, env): make_translations_header(target, source, env, "doc") +def make_extractable_translations_header(target, source, env): + make_translations_header(target, source, env, "extractable") + + if __name__ == "__main__": subprocess_main(globals()) diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index b4cf6d8de1..47642c1592 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -266,7 +266,7 @@ Vector<EditorPlugin *> EditorData::get_handling_sub_editors(Object *p_object) { return sub_plugins; } -EditorPlugin *EditorData::get_editor_by_name(String p_name) { +EditorPlugin *EditorData::get_editor_by_name(const String &p_name) { for (int i = editor_plugins.size() - 1; i > -1; i--) { if (editor_plugins[i]->get_name() == p_name) { return editor_plugins[i]; diff --git a/editor/editor_data.h b/editor/editor_data.h index d1af400e87..d71a2b3ed3 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -152,7 +152,7 @@ private: public: EditorPlugin *get_handling_main_editor(Object *p_object); Vector<EditorPlugin *> get_handling_sub_editors(Object *p_object); - EditorPlugin *get_editor_by_name(String p_name); + EditorPlugin *get_editor_by_name(const String &p_name); void copy_object_params(Object *p_object); void paste_object_params(Object *p_object); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 5021b814ea..fa6a02f9d4 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -524,7 +524,7 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo return false; //nothing changed } -bool EditorFileSystem::_scan_import_support(Vector<String> reimports) { +bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) { if (import_support_queries.size() == 0) { return false; } @@ -1161,7 +1161,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const } } -void EditorFileSystem::_delete_internal_files(String p_file) { +void EditorFileSystem::_delete_internal_files(const String &p_file) { if (FileAccess::exists(p_file + ".import")) { List<String> paths; ResourceFormatImporter::get_singleton()->get_internal_resource_path_list(p_file, &paths); diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index d099a6fedc..818d725281 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -221,7 +221,7 @@ class EditorFileSystem : public Node { void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress); - void _delete_internal_files(String p_file); + void _delete_internal_files(const String &p_file); HashSet<String> textfile_extensions; HashSet<String> valid_extensions; @@ -298,7 +298,7 @@ class EditorFileSystem : public Node { static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate); bool _scan_extensions(); - bool _scan_import_support(Vector<String> reimports); + bool _scan_import_support(const Vector<String> &reimports); Vector<Ref<EditorFileSystemImportFormatSupportQuery>> import_support_queries; diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index cc63618f1e..515c32c58f 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1622,9 +1622,9 @@ void EditorHelp::_update_doc() { enum_line[E.key] = class_desc->get_paragraph_count() - 2; class_desc->push_color(theme_cache.title_color); if (E.value.size() && E.value[0].is_bitfield) { - class_desc->add_text("flags "); + class_desc->add_text("flags "); } else { - class_desc->add_text("enum "); + class_desc->add_text("enum "); } class_desc->pop(); // color diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index e4a5ab86d9..02c6925f14 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2066,7 +2066,7 @@ void EditorInspectorArray::_new_size_spin_box_value_changed(float p_value) { resize_dialog->get_ok_button()->set_disabled(int(p_value) == count); } -void EditorInspectorArray::_new_size_spin_box_text_submitted(String p_text) { +void EditorInspectorArray::_new_size_spin_box_text_submitted(const String &p_text) { _resize_dialog_confirmed(); } @@ -2306,7 +2306,7 @@ void EditorInspectorArray::_bind_methods() { ADD_SIGNAL(MethodInfo("page_change_request")); } -void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text) { +void EditorInspectorArray::setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text) { count_property = ""; mode = MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION; array_element_prefix = p_array_element_prefix; @@ -2320,7 +2320,7 @@ void EditorInspectorArray::setup_with_move_element_function(Object *p_object, St _setup(); } -void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) { +void EditorInspectorArray::setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) { count_property = p_count_property; mode = MODE_USE_COUNT_PROPERTY; array_element_prefix = p_array_element_prefix; @@ -2412,7 +2412,7 @@ void EditorPaginator::_prev_page_button_pressed() { emit_signal("page_changed", MAX(0, page - 1)); } -void EditorPaginator::_page_line_edit_text_submitted(String p_text) { +void EditorPaginator::_page_line_edit_text_submitted(const String &p_text) { if (p_text.is_valid_int()) { int new_page = p_text.to_int() - 1; new_page = MIN(MAX(0, new_page), max_page); @@ -3829,7 +3829,7 @@ void EditorInspector::_property_changed(const String &p_path, const Variant &p_v } } -void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array p_values, bool p_changing) { +void EditorInspector::_multiple_properties_changed(const Vector<String> &p_paths, const Array &p_values, bool p_changing) { ERR_FAIL_COND(p_paths.is_empty() || p_values.is_empty()); ERR_FAIL_COND(p_paths.size() != p_values.size()); String names; diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 0e908b7a14..8c55950a2b 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -406,7 +406,7 @@ class EditorInspectorArray : public EditorInspectorSection { int _drop_position() const; void _new_size_spin_box_value_changed(float p_value); - void _new_size_spin_box_text_submitted(String p_text); + void _new_size_spin_box_text_submitted(const String &p_text); void _resize_dialog_confirmed(); void _update_elements_visibility(); @@ -423,8 +423,8 @@ protected: static void _bind_methods(); public: - void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = ""); - void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = ""); + void setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = ""); + void setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = ""); VBoxContainer *get_vbox(int p_index); EditorInspectorArray(bool p_read_only); @@ -444,7 +444,7 @@ class EditorPaginator : public HBoxContainer { void _first_page_button_pressed(); void _prev_page_button_pressed(); - void _page_line_edit_text_submitted(String p_text); + void _page_line_edit_text_submitted(const String &p_text); void _next_page_button_pressed(); void _last_page_button_pressed(); @@ -520,7 +520,7 @@ class EditorInspector : public ScrollContainer { void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field); void _property_changed(const String &p_path, const Variant &p_value, const String &p_name = "", bool p_changing = false, bool p_update_all = false); - void _multiple_properties_changed(Vector<String> p_paths, Array p_values, bool p_changing = false); + void _multiple_properties_changed(const Vector<String> &p_paths, const Array &p_values, bool p_changing = false); void _property_keyed(const String &p_path, bool p_advance); void _property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance); void _property_deleted(const String &p_path); diff --git a/editor/editor_log.h b/editor/editor_log.h index 03a0a071c6..601e63b9fe 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -64,7 +64,7 @@ private: LogMessage() {} - LogMessage(const String p_text, MessageType p_type, bool p_clear) : + LogMessage(const String &p_text, MessageType p_type, bool p_clear) : text(p_text), type(p_type), clear(p_clear) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2cee2c2198..dc90256490 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1285,7 +1285,14 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) { if (p_resource->is_built_in()) { const String scene_path = p_resource->get_path().get_slice("::", 0); if (!scene_path.is_empty()) { - save_scene_if_open(scene_path); + if (ResourceLoader::exists(scene_path) && ResourceLoader::get_resource_type(scene_path) == "PackedScene") { + save_scene_if_open(scene_path); + } else { + // Not a packed scene, so save it as regular resource. + Ref<Resource> parent_resource = ResourceCache::get_ref(scene_path); + ERR_FAIL_COND_MSG(parent_resource.is_null(), "Parent resource not loaded, can't save."); + save_resource(parent_resource); + } return; } } diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 7d0024b1da..2920cf19c0 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -143,7 +143,11 @@ void EditorPluginSettings::_plugin_activity_changed() { ti->set_checked(COLUMN_STATUS, is_enabled); updating = false; } - ti->set_custom_color(COLUMN_NAME, is_enabled ? Color() : get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))); + if (is_enabled) { + ti->clear_custom_color(COLUMN_NAME); + } else { + ti->set_custom_color(COLUMN_NAME, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))); + } } void EditorPluginSettings::_create_clicked() { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 0517abac2b..73a0768a72 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -254,7 +254,7 @@ void EditorPropertyTextEnum::_set_read_only(bool p_read_only) { edit_button->set_disabled(p_read_only); } -void EditorPropertyTextEnum::_emit_changed_value(String p_string) { +void EditorPropertyTextEnum::_emit_changed_value(const String &p_string) { if (string_name) { emit_changed(get_edited_property(), StringName(p_string)); } else { @@ -272,7 +272,7 @@ void EditorPropertyTextEnum::_edit_custom_value() { custom_value_edit->grab_focus(); } -void EditorPropertyTextEnum::_custom_value_submitted(String p_value) { +void EditorPropertyTextEnum::_custom_value_submitted(const String &p_value) { edit_custom_layout->hide(); default_layout->show(); @@ -2897,7 +2897,7 @@ void EditorPropertyNodePath::update_property() { assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node")); } -void EditorPropertyNodePath::setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root, bool p_editing_node) { +void EditorPropertyNodePath::setup(const NodePath &p_base_hint, const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root, bool p_editing_node) { base_hint = p_base_hint; valid_types = p_valid_types; editing_node = p_editing_node; diff --git a/editor/editor_properties.h b/editor/editor_properties.h index b7ae4bd1ca..fa759d5d19 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -116,11 +116,11 @@ class EditorPropertyTextEnum : public EditorProperty { bool string_name = false; bool loose_mode = false; - void _emit_changed_value(String p_string); + void _emit_changed_value(const String &p_string); void _option_selected(int p_which); void _edit_custom_value(); - void _custom_value_submitted(String p_value); + void _custom_value_submitted(const String &p_value); void _custom_value_accepted(); void _custom_value_canceled(); @@ -677,7 +677,7 @@ protected: public: virtual void update_property() override; - void setup(const NodePath &p_base_hint, Vector<StringName> p_valid_types, bool p_use_path_from_scene_root = true, bool p_editing_node = false); + void setup(const NodePath &p_base_hint, const Vector<StringName> &p_valid_types, bool p_use_path_from_scene_root = true, bool p_editing_node = false); EditorPropertyNodePath(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 2d11c2e2d1..8a15f4912a 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -1287,7 +1287,7 @@ EditorPropertyDictionary::EditorPropertyDictionary() { ///////////////////// LOCALIZABLE STRING /////////////////////////// -void EditorPropertyLocalizableString::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void EditorPropertyLocalizableString::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("indices")) { int index = p_property.get_slice("/", 1).to_int(); diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index f157da00c2..0e81a0fae3 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -214,7 +214,7 @@ class EditorPropertyLocalizableString : public EditorProperty { void _page_changed(int p_page); void _edit_pressed(); void _remove_item(Object *p_button, int p_index); - void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _property_changed(const String &p_property, const Variant &p_value, const String &p_name = "", bool p_changing = false); void _add_locale_popup(); void _add_locale(const String &p_locale); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 95436427ad..a9225a3057 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -467,6 +467,8 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { EditorNode::get_editor_data().instantiate_object_properties(obj); + // Prevent freeing of the object until the end of the update of the resource (GH-88286). + Ref<Resource> old_edited_resource = edited_resource; edited_resource = Ref<Resource>(resp); emit_signal(SNAME("resource_changed"), edited_resource); _update_resource(); @@ -654,7 +656,7 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { return false; } -bool EditorResourcePicker::_is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const { +bool EditorResourcePicker::_is_type_valid(const String &p_type_name, const HashSet<StringName> &p_allowed_types) const { for (const StringName &E : p_allowed_types) { String at = E; if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) { diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index fb54455e89..8146c02dff 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -99,7 +99,7 @@ class EditorResourcePicker : public HBoxContainer { String _get_resource_type(const Ref<Resource> &p_resource) const; void _get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const; bool _is_drop_valid(const Dictionary &p_drag_data) const; - bool _is_type_valid(const String p_type_name, const HashSet<StringName> &p_allowed_types) const; + bool _is_type_valid(const String &p_type_name, const HashSet<StringName> &p_allowed_types) const; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index fc1dda9669..94bf15ae66 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -351,7 +351,7 @@ void EditorResourcePreview::_iterate() { _preview_ready(item.path, 0, texture, small_texture, item.id, item.function, item.userdata, preview_metadata); } -void EditorResourcePreview::_write_preview_cache(Ref<FileAccess> p_file, int p_thumbnail_size, bool p_has_small_texture, uint64_t p_modified_time, String p_hash, const Dictionary &p_metadata) { +void EditorResourcePreview::_write_preview_cache(Ref<FileAccess> p_file, int p_thumbnail_size, bool p_has_small_texture, uint64_t p_modified_time, const String &p_hash, const Dictionary &p_metadata) { p_file->store_line(itos(p_thumbnail_size)); p_file->store_line(itos(p_has_small_texture)); p_file->store_line(itos(p_modified_time)); diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 3cad56f75e..8461651732 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -117,7 +117,7 @@ class EditorResourcePreview : public Node { static void _idle_callback(); // For other rendering drivers (i.e., OpenGL). void _iterate(); - void _write_preview_cache(Ref<FileAccess> p_file, int p_thumbnail_size, bool p_has_small_texture, uint64_t p_modified_time, String p_hash, const Dictionary &p_metadata); + void _write_preview_cache(Ref<FileAccess> p_file, int p_thumbnail_size, bool p_has_small_texture, uint64_t p_modified_time, const String &p_hash, const Dictionary &p_metadata); void _read_preview_cache(Ref<FileAccess> p_file, int *r_thumbnail_size, bool *r_has_small_texture, uint64_t *r_modified_time, String *r_hash, Dictionary *r_metadata); Vector<Ref<EditorResourcePreviewGenerator>> preview_generators; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 853a4cd410..b6d8d7b8d6 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -756,6 +756,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Polygon editor _initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8); _initial_set("editors/polygon_editor/show_previous_outline", true); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/polygon_editor/auto_bake_delay", 1.5, "-1.0,10.0,0.01"); // Animation _initial_set("editors/animation/autorename_animation_tracks", true); @@ -934,7 +935,7 @@ void EditorSettings::_load_default_visual_shader_editor_theme() { _initial_set("editors/visual_editors/category_colors/particle_color", Color(0.12, 0.358, 0.8)); } -bool EditorSettings::_save_text_editor_theme(String p_file) { +bool EditorSettings::_save_text_editor_theme(const String &p_file) { String theme_section = "color_theme"; Ref<ConfigFile> cf = memnew(ConfigFile); // hex is better? @@ -957,7 +958,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { return err == OK; } -bool EditorSettings::_is_default_text_editor_theme(String p_theme_name) { +bool EditorSettings::_is_default_text_editor_theme(const String &p_theme_name) { return p_theme_name == "default" || p_theme_name == "godot 2" || p_theme_name == "custom"; } @@ -1059,6 +1060,9 @@ void EditorSettings::setup_language() { // Load class reference translation. load_doc_translations(lang); + + // Load extractable translation for projects. + load_extractable_translations(lang); } void EditorSettings::setup_network() { @@ -1251,7 +1255,7 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { // Metadata -void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { +void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, const Variant &p_data) { const String path = _get_project_metadata_path(); if (project_metadata.is_null()) { @@ -1268,7 +1272,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String ERR_FAIL_COND_MSG(err != OK, "Cannot save project metadata to file '" + path + "'."); } -Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const { +Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, const Variant &p_default) const { if (project_metadata.is_null()) { project_metadata.instantiate(); @@ -1409,7 +1413,7 @@ void EditorSettings::load_text_editor_theme() { // if it doesn't load just use what is currently loaded } -bool EditorSettings::import_text_editor_theme(String p_file) { +bool EditorSettings::import_text_editor_theme(const String &p_file) { if (!p_file.ends_with(".tet")) { return false; } else { diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 5783bac770..4995558e2b 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -111,8 +111,8 @@ private: void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>()); void _load_godot2_text_editor_theme(); void _load_default_visual_shader_editor_theme(); - bool _save_text_editor_theme(String p_file); - bool _is_default_text_editor_theme(String p_theme_name); + bool _save_text_editor_theme(const String &p_file); + bool _is_default_text_editor_theme(const String &p_theme_name); const String _get_project_metadata_path() const; protected: @@ -155,8 +155,8 @@ public: void set_resource_clipboard(const Ref<Resource> &p_resource) { clipboard = p_resource; } Ref<Resource> get_resource_clipboard() const { return clipboard; } - void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); - Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const; + void set_project_metadata(const String &p_section, const String &p_key, const Variant &p_data); + Variant get_project_metadata(const String &p_section, const String &p_key, const Variant &p_default) const; void set_favorites(const Vector<String> &p_favorites); Vector<String> get_favorites() const; @@ -166,7 +166,7 @@ public: void list_text_editor_themes(); void load_text_editor_theme(); - bool import_text_editor_theme(String p_file); + bool import_text_editor_theme(const String &p_file); bool save_text_editor_theme(); bool save_text_editor_theme_as(String p_file); bool is_default_text_editor_theme(); diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index 54a9d2f068..302a81669d 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -35,6 +35,7 @@ #include "core/io/translation_loader_po.h" #include "editor/doc_translations.gen.h" #include "editor/editor_translations.gen.h" +#include "editor/extractable_translations.gen.h" #include "editor/property_translations.gen.h" Vector<String> get_editor_locales() { @@ -77,6 +78,32 @@ void load_editor_translations(const String &p_locale) { } } +void load_property_translations(const String &p_locale) { + PropertyTranslationList *etl = _property_translations; + while (etl->data) { + if (etl->lang == p_locale) { + Vector<uint8_t> data; + data.resize(etl->uncomp_size); + int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); + + Ref<FileAccessMemory> fa; + fa.instantiate(); + fa->open_custom(data.ptr(), data.size()); + + Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); + + if (tr.is_valid()) { + tr->set_locale(etl->lang); + TranslationServer::get_singleton()->set_property_translation(tr); + break; + } + } + + etl++; + } +} + void load_doc_translations(const String &p_locale) { DocTranslationList *dtl = _doc_translations; while (dtl->data) { @@ -103,8 +130,8 @@ void load_doc_translations(const String &p_locale) { } } -void load_property_translations(const String &p_locale) { - PropertyTranslationList *etl = _property_translations; +void load_extractable_translations(const String &p_locale) { + ExtractableTranslationList *etl = _extractable_translations; while (etl->data) { if (etl->lang == p_locale) { Vector<uint8_t> data; @@ -120,7 +147,7 @@ void load_property_translations(const String &p_locale) { if (tr.is_valid()) { tr->set_locale(etl->lang); - TranslationServer::get_singleton()->set_property_translation(tr); + TranslationServer::get_singleton()->set_extractable_translation(tr); break; } } @@ -128,3 +155,29 @@ void load_property_translations(const String &p_locale) { etl++; } } + +List<StringName> get_extractable_message_list() { + ExtractableTranslationList *etl = _extractable_translations; + List<StringName> msgids; + while (etl->data) { + Vector<uint8_t> data; + data.resize(etl->uncomp_size); + int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt."); + + Ref<FileAccessMemory> fa; + fa.instantiate(); + fa->open_custom(data.ptr(), data.size()); + + Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); + + if (tr.is_valid()) { + tr->get_message_list(&msgids); + break; + } + + etl++; + } + + return msgids; +} diff --git a/editor/editor_translation.h b/editor/editor_translation.h index bd6db32536..4785495629 100644 --- a/editor/editor_translation.h +++ b/editor/editor_translation.h @@ -32,11 +32,14 @@ #define EDITOR_TRANSLATION_H #include "core/string/ustring.h" +#include "core/templates/list.h" #include "core/templates/vector.h" Vector<String> get_editor_locales(); void load_editor_translations(const String &p_locale); -void load_doc_translations(const String &p_locale); void load_property_translations(const String &p_locale); +void load_doc_translations(const String &p_locale); +void load_extractable_translations(const String &p_locale); +List<StringName> get_extractable_message_list(); #endif // EDITOR_TRANSLATION_H diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index 1f76c94655..7d39dc8715 100644 --- a/editor/editor_vcs_interface.cpp +++ b/editor/editor_vcs_interface.cpp @@ -34,18 +34,18 @@ EditorVCSInterface *EditorVCSInterface::singleton = nullptr; -void EditorVCSInterface::popup_error(String p_msg) { +void EditorVCSInterface::popup_error(const String &p_msg) { // TRANSLATORS: %s refers to the name of a version control system (e.g. "Git"). EditorNode::get_singleton()->show_warning(p_msg.strip_edges(), vformat(TTR("%s Error"), get_vcs_name())); } -bool EditorVCSInterface::initialize(String p_project_path) { +bool EditorVCSInterface::initialize(const String &p_project_path) { bool result = false; GDVIRTUAL_REQUIRED_CALL(_initialize, p_project_path, result); return result; } -void EditorVCSInterface::set_credentials(String p_username, String p_password, String p_ssh_public_key, String p_ssh_private_key, String p_ssh_passphrase) { +void EditorVCSInterface::set_credentials(const String &p_username, const String &p_password, const String &p_ssh_public_key, const String &p_ssh_private_key, const String &p_ssh_passphrase) { GDVIRTUAL_REQUIRED_CALL(_set_credentials, p_username, p_password, p_ssh_public_key, p_ssh_private_key, p_ssh_passphrase); } @@ -75,23 +75,23 @@ List<EditorVCSInterface::StatusFile> EditorVCSInterface::get_modified_files_data return status_files; } -void EditorVCSInterface::stage_file(String p_file_path) { +void EditorVCSInterface::stage_file(const String &p_file_path) { GDVIRTUAL_REQUIRED_CALL(_stage_file, p_file_path); } -void EditorVCSInterface::unstage_file(String p_file_path) { +void EditorVCSInterface::unstage_file(const String &p_file_path) { GDVIRTUAL_REQUIRED_CALL(_unstage_file, p_file_path); } -void EditorVCSInterface::discard_file(String p_file_path) { +void EditorVCSInterface::discard_file(const String &p_file_path) { GDVIRTUAL_REQUIRED_CALL(_discard_file, p_file_path); } -void EditorVCSInterface::commit(String p_msg) { +void EditorVCSInterface::commit(const String &p_msg) { GDVIRTUAL_REQUIRED_CALL(_commit, p_msg); } -List<EditorVCSInterface::DiffFile> EditorVCSInterface::get_diff(String p_identifier, TreeArea p_area) { +List<EditorVCSInterface::DiffFile> EditorVCSInterface::get_diff(const String &p_identifier, TreeArea p_area) { TypedArray<Dictionary> result; if (!GDVIRTUAL_REQUIRED_CALL(_get_diff, p_identifier, int(p_area), result)) { return {}; @@ -130,19 +130,19 @@ List<String> EditorVCSInterface::get_branch_list() { return branch_list; } -void EditorVCSInterface::create_branch(String p_branch_name) { +void EditorVCSInterface::create_branch(const String &p_branch_name) { GDVIRTUAL_REQUIRED_CALL(_create_branch, p_branch_name); } -void EditorVCSInterface::create_remote(String p_remote_name, String p_remote_url) { +void EditorVCSInterface::create_remote(const String &p_remote_name, const String &p_remote_url) { GDVIRTUAL_REQUIRED_CALL(_create_remote, p_remote_name, p_remote_url); } -void EditorVCSInterface::remove_branch(String p_branch_name) { +void EditorVCSInterface::remove_branch(const String &p_branch_name) { GDVIRTUAL_REQUIRED_CALL(_remove_branch, p_branch_name); } -void EditorVCSInterface::remove_remote(String p_remote_name) { +void EditorVCSInterface::remove_remote(const String &p_remote_name) { GDVIRTUAL_REQUIRED_CALL(_remove_remote, p_remote_name); } @@ -152,25 +152,25 @@ String EditorVCSInterface::get_current_branch_name() { return result; } -bool EditorVCSInterface::checkout_branch(String p_branch_name) { +bool EditorVCSInterface::checkout_branch(const String &p_branch_name) { bool result = false; GDVIRTUAL_REQUIRED_CALL(_checkout_branch, p_branch_name, result); return result; } -void EditorVCSInterface::pull(String p_remote) { +void EditorVCSInterface::pull(const String &p_remote) { GDVIRTUAL_REQUIRED_CALL(_pull, p_remote); } -void EditorVCSInterface::push(String p_remote, bool p_force) { +void EditorVCSInterface::push(const String &p_remote, bool p_force) { GDVIRTUAL_REQUIRED_CALL(_push, p_remote, p_force); } -void EditorVCSInterface::fetch(String p_remote) { +void EditorVCSInterface::fetch(const String &p_remote) { GDVIRTUAL_REQUIRED_CALL(_fetch, p_remote); } -List<EditorVCSInterface::DiffHunk> EditorVCSInterface::get_line_diff(String p_file_path, String p_text) { +List<EditorVCSInterface::DiffHunk> EditorVCSInterface::get_line_diff(const String &p_file_path, const String &p_text) { TypedArray<Dictionary> result; if (!GDVIRTUAL_REQUIRED_CALL(_get_line_diff, p_file_path, p_text, result)) { return {}; @@ -195,7 +195,7 @@ String EditorVCSInterface::get_vcs_name() { return result; } -Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status) { +Dictionary EditorVCSInterface::create_diff_line(int p_new_line_no, int p_old_line_no, const String &p_content, const String &p_status) { Dictionary diff_line; diff_line["new_line_no"] = p_new_line_no; diff_line["old_line_no"] = p_old_line_no; @@ -220,7 +220,7 @@ Dictionary EditorVCSInterface::add_line_diffs_into_diff_hunk(Dictionary p_diff_h return p_diff_hunk; } -Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_file) { +Dictionary EditorVCSInterface::create_diff_file(const String &p_new_file, const String &p_old_file) { Dictionary file_diff; file_diff["new_file"] = p_new_file; file_diff["old_file"] = p_old_file; @@ -228,7 +228,7 @@ Dictionary EditorVCSInterface::create_diff_file(String p_new_file, String p_old_ return file_diff; } -Dictionary EditorVCSInterface::create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes) { +Dictionary EditorVCSInterface::create_commit(const String &p_msg, const String &p_author, const String &p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes) { Dictionary commit_info; commit_info["message"] = p_msg; commit_info["author"] = p_author; @@ -243,7 +243,7 @@ Dictionary EditorVCSInterface::add_diff_hunks_into_diff_file(Dictionary p_diff_f return p_diff_file; } -Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area) { +Dictionary EditorVCSInterface::create_status_file(const String &p_file_path, ChangeType p_change, TreeArea p_area) { Dictionary sf; sf["file_path"] = p_file_path; sf["change_type"] = p_change; @@ -251,7 +251,7 @@ Dictionary EditorVCSInterface::create_status_file(String p_file_path, ChangeType return sf; } -EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p_diff_line) { +EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(const Dictionary &p_diff_line) { DiffLine d; d.new_line_no = p_diff_line["new_line_no"]; d.old_line_no = p_diff_line["old_line_no"]; @@ -260,7 +260,7 @@ EditorVCSInterface::DiffLine EditorVCSInterface::_convert_diff_line(Dictionary p return d; } -EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p_diff_hunk) { +EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(const Dictionary &p_diff_hunk) { DiffHunk dh; dh.new_lines = p_diff_hunk["new_lines"]; dh.old_lines = p_diff_hunk["old_lines"]; @@ -274,7 +274,7 @@ EditorVCSInterface::DiffHunk EditorVCSInterface::_convert_diff_hunk(Dictionary p return dh; } -EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p_diff_file) { +EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(const Dictionary &p_diff_file) { DiffFile df; df.new_file = p_diff_file["new_file"]; df.old_file = p_diff_file["old_file"]; @@ -286,7 +286,7 @@ EditorVCSInterface::DiffFile EditorVCSInterface::_convert_diff_file(Dictionary p return df; } -EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_commit) { +EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(const Dictionary &p_commit) { EditorVCSInterface::Commit c; c.msg = p_commit["message"]; c.author = p_commit["author"]; @@ -296,7 +296,7 @@ EditorVCSInterface::Commit EditorVCSInterface::_convert_commit(Dictionary p_comm return c; } -EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(Dictionary p_status_file) { +EditorVCSInterface::StatusFile EditorVCSInterface::_convert_status_file(const Dictionary &p_status_file) { StatusFile sf; sf.file_path = p_status_file["file_path"]; sf.change_type = (ChangeType)(int)p_status_file["change_type"]; diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h index 84f2cf9281..8fcd45756a 100644 --- a/editor/editor_vcs_interface.h +++ b/editor/editor_vcs_interface.h @@ -99,11 +99,11 @@ protected: static void _bind_methods(); - DiffLine _convert_diff_line(Dictionary p_diff_line); - DiffHunk _convert_diff_hunk(Dictionary p_diff_hunk); - DiffFile _convert_diff_file(Dictionary p_diff_file); - Commit _convert_commit(Dictionary p_commit); - StatusFile _convert_status_file(Dictionary p_status_file); + DiffLine _convert_diff_line(const Dictionary &p_diff_line); + DiffHunk _convert_diff_hunk(const Dictionary &p_diff_hunk); + DiffFile _convert_diff_file(const Dictionary &p_diff_file); + Commit _convert_commit(const Dictionary &p_commit); + StatusFile _convert_status_file(const Dictionary &p_status_file); // Proxy endpoints for extensions to implement GDVIRTUAL1R(bool, _initialize, String); @@ -141,40 +141,40 @@ public: static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir); // Proxies to the editor for use - bool initialize(String p_project_path); - void set_credentials(String p_username, String p_password, String p_ssh_public_key_path, String p_ssh_private_key_path, String p_ssh_passphrase); + bool initialize(const String &p_project_path); + void set_credentials(const String &p_username, const String &p_password, const String &p_ssh_public_key_path, const String &p_ssh_private_key_path, const String &p_ssh_passphrase); List<StatusFile> get_modified_files_data(); - void stage_file(String p_file_path); - void unstage_file(String p_file_path); - void discard_file(String p_file_path); - void commit(String p_msg); - List<DiffFile> get_diff(String p_identifier, TreeArea p_area); + void stage_file(const String &p_file_path); + void unstage_file(const String &p_file_path); + void discard_file(const String &p_file_path); + void commit(const String &p_msg); + List<DiffFile> get_diff(const String &p_identifier, TreeArea p_area); bool shut_down(); String get_vcs_name(); List<Commit> get_previous_commits(int p_max_commits); List<String> get_branch_list(); List<String> get_remotes(); - void create_branch(String p_branch_name); - void remove_branch(String p_branch_name); - void create_remote(String p_remote_name, String p_remote_url); - void remove_remote(String p_remote_name); + void create_branch(const String &p_branch_name); + void remove_branch(const String &p_branch_name); + void create_remote(const String &p_remote_name, const String &p_remote_url); + void remove_remote(const String &p_remote_name); String get_current_branch_name(); - bool checkout_branch(String p_branch_name); - void pull(String p_remote); - void push(String p_remote, bool p_force); - void fetch(String p_remote); - List<DiffHunk> get_line_diff(String p_file_path, String p_text); + bool checkout_branch(const String &p_branch_name); + void pull(const String &p_remote); + void push(const String &p_remote, bool p_force); + void fetch(const String &p_remote); + List<DiffHunk> get_line_diff(const String &p_file_path, const String &p_text); // Helper functions to create and convert Dictionary into data structures - Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, String p_content, String p_status); + Dictionary create_diff_line(int p_new_line_no, int p_old_line_no, const String &p_content, const String &p_status); Dictionary create_diff_hunk(int p_old_start, int p_new_start, int p_old_lines, int p_new_lines); - Dictionary create_diff_file(String p_new_file, String p_old_file); - Dictionary create_commit(String p_msg, String p_author, String p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes); - Dictionary create_status_file(String p_file_path, ChangeType p_change, TreeArea p_area); + Dictionary create_diff_file(const String &p_new_file, const String &p_old_file); + Dictionary create_commit(const String &p_msg, const String &p_author, const String &p_id, int64_t p_unix_timestamp, int64_t p_offset_minutes); + Dictionary create_status_file(const String &p_file_path, ChangeType p_change, TreeArea p_area); Dictionary add_line_diffs_into_diff_hunk(Dictionary p_diff_hunk, TypedArray<Dictionary> p_line_diffs); Dictionary add_diff_hunks_into_diff_file(Dictionary p_diff_file, TypedArray<Dictionary> p_diff_hunks); - void popup_error(String p_msg); + void popup_error(const String &p_msg); }; VARIANT_ENUM_CAST(EditorVCSInterface::ChangeType); diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 9d65821ccd..b9dc52511e 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -329,7 +329,7 @@ Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const { } } -String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { +String EditorExportPlatform::find_export_template(const String &template_file_name, String *err) const { String current_version = VERSION_FULL_CONFIG; String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(current_version).path_join(template_file_name); @@ -344,7 +344,7 @@ String EditorExportPlatform::find_export_template(String template_file_name, Str return String(); } -bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const { +bool EditorExportPlatform::exists_export_template(const String &template_file_name, String *err) const { return find_export_template(template_file_name, err) != ""; } diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index 8f2288d409..26e1f86c8b 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -132,8 +132,8 @@ protected: HashSet<String> get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const; - bool exists_export_template(String template_file_name, String *err) const; - String find_export_template(String template_file_name, String *err = nullptr) const; + bool exists_export_template(const String &template_file_name, String *err) const; + String find_export_template(const String &template_file_name, String *err = nullptr) const; void gen_export_flags(Vector<String> &r_flags, int p_flags); void gen_debug_flags(Vector<String> &r_flags, int p_flags); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 0356d0d3ad..a7e40ce5b9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -80,7 +80,7 @@ Control *FileSystemList::make_custom_tooltip(const String &p_text) const { return FileSystemDock::get_singleton()->create_tooltip_for_path(get_item_metadata(idx)); } -void FileSystemList::_line_editor_submit(String p_text) { +void FileSystemList::_line_editor_submit(const String &p_text) { popup_editor->hide(); emit_signal(SNAME("item_edited")); @@ -173,7 +173,7 @@ FileSystemList::FileSystemList() { FileSystemDock *FileSystemDock::singleton = nullptr; -Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, String p_file_type) { +Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String &p_file_type) { Ref<Texture2D> file_icon; if (!p_is_valid) { file_icon = get_editor_theme_icon(SNAME("ImportFail")); @@ -1678,7 +1678,7 @@ void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) { emit_signal(SNAME("resource_removed"), p_resource); } -void FileSystemDock::_file_removed(String p_file) { +void FileSystemDock::_file_removed(const String &p_file) { emit_signal(SNAME("file_removed"), p_file); // Find the closest parent directory available, in case multiple items were deleted along the same path. @@ -1691,7 +1691,7 @@ void FileSystemDock::_file_removed(String p_file) { current_path_line_edit->set_text(current_path); } -void FileSystemDock::_folder_removed(String p_folder) { +void FileSystemDock::_folder_removed(const String &p_folder) { emit_signal(SNAME("folder_removed"), p_folder); // Find the closest parent directory available, in case multiple items were deleted along the same path. @@ -2986,7 +2986,7 @@ void FileSystemDock::_folder_color_index_pressed(int p_index, PopupMenu *p_menu) _update_file_list(true); } -void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options) { +void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vector<String> &p_paths, bool p_display_path_dependent_options) { // Add options for files and folders. ERR_FAIL_COND_MSG(p_paths.is_empty(), "Path cannot be empty."); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index c9d2bc535e..06bf3eda52 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -64,7 +64,7 @@ class FileSystemList : public ItemList { LineEdit *line_editor = nullptr; virtual Control *make_custom_tooltip(const String &p_text) const override; - void _line_editor_submit(String p_text); + void _line_editor_submit(const String &p_text); void _text_editor_popup_modal_close(); protected: @@ -245,7 +245,7 @@ private: void _tree_mouse_exited(); void _reselect_items_selected_on_drag_begin(bool reset = false); - Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, String p_file_type); + Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type); bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false); void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false); void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false); @@ -281,8 +281,8 @@ private: void _update_folder_colors_setting(); void _resource_removed(const Ref<Resource> &p_resource); - void _file_removed(String p_file); - void _folder_removed(String p_folder); + void _file_removed(const String &p_file); + void _folder_removed(const String &p_folder); void _resource_created(); void _make_scene_confirm(); @@ -313,7 +313,7 @@ private: void _file_sort_popup(int p_id); void _folder_color_index_pressed(int p_index, PopupMenu *p_menu); - void _file_and_folders_fill_popup(PopupMenu *p_popup, Vector<String> p_paths, bool p_display_path_dependent_options = true); + void _file_and_folders_fill_popup(PopupMenu *p_popup, const Vector<String> &p_paths, bool p_display_path_dependent_options = true); void _tree_rmb_select(const Vector2 &p_pos, MouseButton p_button); void _file_list_item_clicked(int p_item, const Vector2 &p_pos, MouseButton p_mouse_button_index); void _file_list_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index c6087f5b13..6d690cf31b 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -55,7 +55,7 @@ inline void pop_back(T &container) { container.resize(container.size() - 1); } -static bool find_next(const String &line, String pattern, int from, bool match_case, bool whole_words, int &out_begin, int &out_end) { +static bool find_next(const String &line, const String &pattern, int from, bool match_case, bool whole_words, int &out_begin, int &out_end) { int end = from; while (true) { @@ -84,7 +84,7 @@ static bool find_next(const String &line, String pattern, int from, bool match_c //-------------------------------------------------------------------------------- -void FindInFiles::set_search_text(String p_pattern) { +void FindInFiles::set_search_text(const String &p_pattern) { _pattern = p_pattern; } @@ -96,7 +96,7 @@ void FindInFiles::set_match_case(bool p_match_case) { _match_case = p_match_case; } -void FindInFiles::set_folder(String folder) { +void FindInFiles::set_folder(const String &folder) { _root_dir = folder; } @@ -213,7 +213,7 @@ float FindInFiles::get_progress() const { return 0; } -void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan) { +void FindInFiles::_scan_dir(const String &path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan) { Ref<DirAccess> dir = DirAccess::open(path); if (dir.is_null()) { print_verbose("Cannot open directory! " + path); @@ -258,7 +258,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders, PackedS } } -void FindInFiles::_scan_file(String fpath) { +void FindInFiles::_scan_file(const String &fpath) { Ref<FileAccess> f = FileAccess::open(fpath, FileAccess::READ); if (f.is_null()) { print_verbose(String("Cannot open file ") + fpath); @@ -397,12 +397,12 @@ FindInFilesDialog::FindInFilesDialog() { _mode = SEARCH_MODE; } -void FindInFilesDialog::set_search_text(String text) { +void FindInFilesDialog::set_search_text(const String &text) { _search_text_line_edit->set_text(text); _on_search_text_modified(text); } -void FindInFilesDialog::set_replace_text(String text) { +void FindInFilesDialog::set_replace_text(const String &text) { _replace_text_line_edit->set_text(text); } @@ -505,7 +505,7 @@ void FindInFilesDialog::custom_action(const String &p_action) { } } -void FindInFilesDialog::_on_search_text_modified(String text) { +void FindInFilesDialog::_on_search_text_modified(const String &text) { ERR_FAIL_NULL(_find_button); ERR_FAIL_NULL(_replace_button); @@ -513,7 +513,7 @@ void FindInFilesDialog::_on_search_text_modified(String text) { _replace_button->set_disabled(get_search_text().is_empty()); } -void FindInFilesDialog::_on_search_text_submitted(String text) { +void FindInFilesDialog::_on_search_text_submitted(const String &text) { // This allows to trigger a global search without leaving the keyboard. if (!_find_button->is_disabled()) { if (_mode == SEARCH_MODE) { @@ -528,7 +528,7 @@ void FindInFilesDialog::_on_search_text_submitted(String text) { } } -void FindInFilesDialog::_on_replace_text_submitted(String text) { +void FindInFilesDialog::_on_replace_text_submitted(const String &text) { // This allows to trigger a global search without leaving the keyboard. if (!_replace_button->is_disabled()) { if (_mode == REPLACE_MODE) { @@ -653,7 +653,7 @@ void FindInFilesPanel::set_with_replace(bool with_replace) { } } -void FindInFilesPanel::set_replace_text(String text) { +void FindInFilesPanel::set_replace_text(const String &text) { _replace_line_edit->set_text(text); } @@ -710,7 +710,7 @@ void FindInFilesPanel::_notification(int p_what) { } } -void FindInFilesPanel::_on_result_found(String fpath, int line_number, int begin, int end, String text) { +void FindInFilesPanel::_on_result_found(const String &fpath, int line_number, int begin, int end, String text) { TreeItem *file_item; HashMap<String, TreeItem *>::Iterator E = _file_items.find(fpath); @@ -844,7 +844,7 @@ void FindInFilesPanel::_on_result_selected() { emit_signal(SNAME(SIGNAL_RESULT_SELECTED), fpath, r.line_number, r.begin, r.end); } -void FindInFilesPanel::_on_replace_text_changed(String text) { +void FindInFilesPanel::_on_replace_text_changed(const String &text) { update_replace_buttons(); } @@ -914,7 +914,7 @@ private: Vector<char> _line_buffer; }; -void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text) { +void FindInFilesPanel::apply_replaces_in_file(const String &fpath, const Vector<Result> &locations, const String &new_text) { // If the file is already open, I assume the editor will reload it. // If there are unsaved changes, the user will be asked on focus, // however that means either losing changes or losing replaces. diff --git a/editor/find_in_files.h b/editor/find_in_files.h index fcf5dd6281..7885931514 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -42,10 +42,10 @@ public: static const char *SIGNAL_RESULT_FOUND; static const char *SIGNAL_FINISHED; - void set_search_text(String p_pattern); + void set_search_text(const String &p_pattern); void set_whole_words(bool p_whole_word); void set_match_case(bool p_match_case); - void set_folder(String folder); + void set_folder(const String &folder); void set_filter(const HashSet<String> &exts); String get_search_text() const { return _pattern; } @@ -67,8 +67,8 @@ protected: private: void _process(); void _iterate(); - void _scan_dir(String path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan); - void _scan_file(String fpath); + void _scan_dir(const String &path, PackedStringArray &out_folders, PackedStringArray &out_files_to_scan); + void _scan_file(const String &fpath); // Config String _pattern; @@ -105,8 +105,8 @@ public: FindInFilesDialog(); - void set_search_text(String text); - void set_replace_text(String text); + void set_search_text(const String &text); + void set_replace_text(const String &text); void set_find_in_files_mode(FindInFilesMode p_mode); @@ -127,9 +127,9 @@ protected: private: void _on_folder_button_pressed(); void _on_folder_selected(String path); - void _on_search_text_modified(String text); - void _on_search_text_submitted(String text); - void _on_replace_text_submitted(String text); + void _on_search_text_modified(const String &text); + void _on_search_text_submitted(const String &text); + void _on_replace_text_submitted(const String &text); FindInFilesMode _mode; LineEdit *_search_text_line_edit = nullptr; @@ -165,7 +165,7 @@ public: FindInFiles *get_finder() const { return _finder; } void set_with_replace(bool with_replace); - void set_replace_text(String text); + void set_replace_text(const String &text); void start_search(); void stop_search(); @@ -176,13 +176,13 @@ protected: void _notification(int p_what); private: - void _on_result_found(String fpath, int line_number, int begin, int end, String text); + void _on_result_found(const String &fpath, int line_number, int begin, int end, String text); void _on_finished(); void _on_refresh_button_clicked(); void _on_cancel_button_clicked(); void _on_result_selected(); void _on_item_edited(); - void _on_replace_text_changed(String text); + void _on_replace_text_changed(const String &text); void _on_replace_all_clicked(); struct Result { @@ -192,7 +192,7 @@ private: int begin_trimmed = 0; }; - void apply_replaces_in_file(String fpath, const Vector<Result> &locations, String new_text); + void apply_replaces_in_file(const String &fpath, const Vector<Result> &locations, const String &new_text); void update_replace_buttons(); String get_replace_text(); diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp index 1cf9daa545..ab7e05b915 100644 --- a/editor/gui/editor_bottom_panel.cpp +++ b/editor/gui/editor_bottom_panel.cpp @@ -30,6 +30,7 @@ #include "editor_bottom_panel.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_about.h" @@ -253,7 +254,13 @@ EditorBottomPanel::EditorBottomPanel() { // Fade out the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.65)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version information."), build_date)); version_btn->connect("pressed", callable_mp(this, &EditorBottomPanel::_version_button_pressed)); version_info_vbox->add_child(version_btn); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index 2dada25728..d0b78a35cf 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -86,6 +86,7 @@ void EditorFileDialog::_update_theme_item_cache() { theme_cache.mode_list = get_editor_theme_icon(SNAME("FileList")); theme_cache.favorites_up = get_editor_theme_icon(SNAME("MoveUp")); theme_cache.favorites_down = get_editor_theme_icon(SNAME("MoveDown")); + theme_cache.create_folder = get_editor_theme_icon(SNAME("FolderCreate")); theme_cache.folder = get_editor_theme_icon(SNAME("Folder")); theme_cache.folder_icon_color = get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")); @@ -287,7 +288,7 @@ void EditorFileDialog::update_dir() { } } -void EditorFileDialog::_dir_submitted(String p_dir) { +void EditorFileDialog::_dir_submitted(const String &p_dir) { dir_access->change_dir(p_dir); invalidate(); update_dir(); @@ -1328,6 +1329,7 @@ void EditorFileDialog::_update_icons() { refresh->set_icon(theme_cache.reload); favorite->set_icon(theme_cache.favorite); show_hidden->set_icon(theme_cache.toggle_hidden); + makedir->set_icon(theme_cache.create_folder); fav_up->set_icon(theme_cache.favorites_up); fav_down->set_icon(theme_cache.favorites_down); @@ -1875,8 +1877,11 @@ EditorFileDialog::EditorFileDialog() { drives->connect("item_selected", callable_mp(this, &EditorFileDialog::_select_drive)); pathhb->add_child(drives); + pathhb->add_child(memnew(VSeparator)); + makedir = memnew(Button); - makedir->set_text(TTR("Create Folder")); + makedir->set_theme_type_variation("FlatButton"); + makedir->set_tooltip_text(TTR("Create a new folder.")); makedir->connect("pressed", callable_mp(this, &EditorFileDialog::_make_dir)); pathhb->add_child(makedir); diff --git a/editor/gui/editor_file_dialog.h b/editor/gui/editor_file_dialog.h index e0f53ace96..1e1c99bc76 100644 --- a/editor/gui/editor_file_dialog.h +++ b/editor/gui/editor_file_dialog.h @@ -155,6 +155,7 @@ private: Ref<Texture2D> favorite; Ref<Texture2D> mode_thumbnails; Ref<Texture2D> mode_list; + Ref<Texture2D> create_folder; Ref<Texture2D> favorites_up; Ref<Texture2D> favorites_down; @@ -199,7 +200,7 @@ private: void _item_menu_id_pressed(int p_option); void _select_drive(int p_idx); - void _dir_submitted(String p_dir); + void _dir_submitted(const String &p_dir); void _action_pressed(); void _save_confirm_pressed(); void _cancel_pressed(); diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp index 69a129e73c..970bf4cb3e 100644 --- a/editor/gui/editor_toaster.cpp +++ b/editor/gui/editor_toaster.cpp @@ -342,7 +342,7 @@ void EditorToaster::_repop_old() { } } -Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_time, String p_tooltip) { +Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_time, const String &p_tooltip) { // Create the panel according to the severity. PanelContainer *panel = memnew(PanelContainer); panel->set_tooltip_text(p_tooltip); @@ -398,7 +398,7 @@ Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_ return panel; } -void EditorToaster::popup_str(String p_message, Severity p_severity, String p_tooltip) { +void EditorToaster::popup_str(const String &p_message, Severity p_severity, const String &p_tooltip) { if (is_processing_error) { return; } @@ -410,7 +410,7 @@ void EditorToaster::popup_str(String p_message, Severity p_severity, String p_to is_processing_error = false; } -void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_tooltip) { +void EditorToaster::_popup_str(const String &p_message, Severity p_severity, const String &p_tooltip) { is_processing_error = true; // Check if we already have a popup with the given message. Control *control = nullptr; diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h index 5034cb66fc..4bf32d94ba 100644 --- a/editor/gui/editor_toaster.h +++ b/editor/gui/editor_toaster.h @@ -100,7 +100,7 @@ private: void _set_notifications_enabled(bool p_enabled); void _repop_old(); - void _popup_str(String p_message, Severity p_severity, String p_tooltip); + void _popup_str(const String &p_message, Severity p_severity, const String &p_tooltip); void _close_button_theme_changed(Control *p_close_button); protected: @@ -111,8 +111,8 @@ protected: public: static EditorToaster *get_singleton(); - Control *popup(Control *p_control, Severity p_severity = SEVERITY_INFO, double p_time = 0.0, String p_tooltip = String()); - void popup_str(String p_message, Severity p_severity = SEVERITY_INFO, String p_tooltip = String()); + Control *popup(Control *p_control, Severity p_severity = SEVERITY_INFO, double p_time = 0.0, const String &p_tooltip = String()); + void popup_str(const String &p_message, Severity p_severity = SEVERITY_INFO, const String &p_tooltip = String()); void close(Control *p_control); EditorToaster(); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index f54ded7c74..766566bf2b 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -750,7 +750,7 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select return p_parent->is_visible(); } -bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms) { +bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, const PackedStringArray &p_terms) { if (p_terms.is_empty()) { return true; } diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index 179050daeb..fe2396d438 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -79,7 +79,7 @@ class SceneTreeEditor : public Control { void _add_nodes(Node *p_node, TreeItem *p_parent); void _test_update_tree(); bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false); - bool _item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms); + bool _item_matches_all_terms(TreeItem *p_item, const PackedStringArray &p_terms); void _tree_changed(); void _tree_process_mode_changed(); void _node_removed(Node *p_node); diff --git a/editor/icons/FolderCreate.svg b/editor/icons/FolderCreate.svg new file mode 100644 index 0000000000..80a3f90e2a --- /dev/null +++ b/editor/icons/FolderCreate.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M2 3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8v-1H8v-4h2V8h4v2h1V7a1 1 0 0 0-1-1h-4a1 1 0 0 1-1-1V4a1 1 0 0 0-1-1Z" fill="#e0e0e0"/><path d="M13 13h2v-2h-2V9h-2v2H9v2h2v2h2z" fill="#5fff97"/></svg>
\ No newline at end of file diff --git a/editor/import/3d/collada.cpp b/editor/import/3d/collada.cpp index d484476b35..29c373be96 100644 --- a/editor/import/3d/collada.cpp +++ b/editor/import/3d/collada.cpp @@ -834,7 +834,7 @@ void Collada::_parse_light(XMLParser &p_parser) { COLLADA_PRINT("Light ID:" + id); } -void Collada::_parse_curve_geometry(XMLParser &p_parser, String p_id, String p_name) { +void Collada::_parse_curve_geometry(XMLParser &p_parser, const String &p_id, const String &p_name) { if (!(state.import_flags & IMPORT_FLAG_SCENE)) { if (!p_parser.is_empty()) { p_parser.skip_section(); @@ -916,7 +916,7 @@ void Collada::_parse_curve_geometry(XMLParser &p_parser, String p_id, String p_n } } -void Collada::_parse_mesh_geometry(XMLParser &p_parser, String p_id, String p_name) { +void Collada::_parse_mesh_geometry(XMLParser &p_parser, const String &p_id, const String &p_name) { if (!(state.import_flags & IMPORT_FLAG_SCENE)) { if (!p_parser.is_empty()) { p_parser.skip_section(); @@ -1070,7 +1070,7 @@ void Collada::_parse_mesh_geometry(XMLParser &p_parser, String p_id, String p_na } } -void Collada::_parse_skin_controller(XMLParser &p_parser, String p_id) { +void Collada::_parse_skin_controller(XMLParser &p_parser, const String &p_id) { state.skin_controller_data_map[p_id] = SkinControllerData(); SkinControllerData &skindata = state.skin_controller_data_map[p_id]; @@ -1224,7 +1224,7 @@ void Collada::_parse_skin_controller(XMLParser &p_parser, String p_id) { } } -void Collada::_parse_morph_controller(XMLParser &p_parser, String p_id) { +void Collada::_parse_morph_controller(XMLParser &p_parser, const String &p_id) { state.morph_controller_data_map[p_id] = MorphControllerData(); MorphControllerData &morphdata = state.morph_controller_data_map[p_id]; @@ -2311,7 +2311,7 @@ void Collada::_optimize() { } } -int Collada::get_uv_channel(String p_name) { +int Collada::get_uv_channel(const String &p_name) { if (!channel_map.has(p_name)) { ERR_FAIL_COND_V(channel_map.size() == 2, 0); diff --git a/editor/import/3d/collada.h b/editor/import/3d/collada.h index 7877b1e86d..416b917a46 100644 --- a/editor/import/3d/collada.h +++ b/editor/import/3d/collada.h @@ -521,7 +521,7 @@ public: Transform3D get_root_transform() const; - int get_uv_channel(String p_name); + int get_uv_channel(const String &p_name); private: // private stuff HashMap<String, int> channel_map; @@ -535,11 +535,11 @@ private: // private stuff void _parse_light(XMLParser &p_parser); void _parse_animation_clip(XMLParser &p_parser); - void _parse_mesh_geometry(XMLParser &p_parser, String p_id, String p_name); - void _parse_curve_geometry(XMLParser &p_parser, String p_id, String p_name); + void _parse_mesh_geometry(XMLParser &p_parser, const String &p_id, const String &p_name); + void _parse_curve_geometry(XMLParser &p_parser, const String &p_id, const String &p_name); - void _parse_skin_controller(XMLParser &p_parser, String p_id); - void _parse_morph_controller(XMLParser &p_parser, String p_id); + void _parse_skin_controller(XMLParser &p_parser, const String &p_id); + void _parse_morph_controller(XMLParser &p_parser, const String &p_id); void _parse_controller(XMLParser &p_parser); Node *_parse_visual_instance_geometry(XMLParser &p_parser); diff --git a/editor/import/3d/editor_import_collada.cpp b/editor/import/3d/editor_import_collada.cpp index b7dabf027b..58aa6a462d 100644 --- a/editor/import/3d/editor_import_collada.cpp +++ b/editor/import/3d/editor_import_collada.cpp @@ -88,7 +88,7 @@ struct ColladaImport { Error _create_scene(Collada::Node *p_node, Node3D *p_parent); Error _create_resources(Collada::Node *p_node, bool p_use_compression); Error _create_material(const String &p_target); - Error _create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const HashMap<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes = Vector<Ref<ImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); + Error _create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const HashMap<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, const Vector<Ref<ImporterMesh>> &p_morph_meshes = Vector<Ref<ImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false); void _fix_param_animation_tracks(); void create_animation(int p_clip, bool p_import_value_tracks); @@ -467,7 +467,7 @@ Error ColladaImport::_create_material(const String &p_target) { return OK; } -Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const HashMap<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { +Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const HashMap<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, const Vector<Ref<ImporterMesh>> &p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { bool local_xform_mirror = p_local_xform.basis.determinant() < 0; if (p_morph_data) { @@ -938,11 +938,11 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p if (binormal_src && tangent_src) { surftool->set_tangent(vertex_array[k].tangent); } else if (generate_dummy_tangents) { - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(vertex_array[k].normal); + Vector3 tan = Vector3(vertex_array[k].normal.z, -vertex_array[k].normal.x, vertex_array[k].normal.y).cross(vertex_array[k].normal.normalized()).normalized(); surftool->set_tangent(Plane(tan.x, tan.y, tan.z, 1.0)); } } else { - // No normals, use a dummy normal since normals will be generated. + // No normals, use a dummy tangent since normals will be generated. if (generate_dummy_tangents) { surftool->set_tangent(Plane(1.0, 0.0, 0.0, 1.0)); } @@ -1008,6 +1008,19 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p Array d = surftool->commit_to_arrays(); d.resize(RS::ARRAY_MAX); + if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && (generate_dummy_tangents || generate_tangents)) { + // Compression is enabled, so let's validate that the normals and tangents are correct. + Vector<Vector3> normals = d[Mesh::ARRAY_NORMAL]; + Vector<float> tangents = d[Mesh::ARRAY_TANGENT]; + for (int vert = 0; vert < normals.size(); vert++) { + Vector3 tan = Vector3(tangents[vert * 4 + 0], tangents[vert * 4 + 1], tangents[vert * 4 + 2]); + if (abs(tan.dot(normals[vert])) > 0.0001) { + // Tangent is not perpendicular to the normal, so we can't use compression. + mesh_flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + } + } + } + Array mr; //////////////////////////// diff --git a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp index 53bf24fb7e..d2318c0c69 100644 --- a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp @@ -42,6 +42,7 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true)); + r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/reset_all_bone_poses_after_import"), true)); r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false)); // TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options). // get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values. @@ -113,6 +114,10 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory Vector<int> bones_to_process = src_skeleton->get_parentless_bones(); for (int i = 0; i < bones_to_process.size(); i++) { src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i])); + + src_skeleton->set_bone_pose_position(bones_to_process[i], global_transform.orthonormalized().xform(src_skeleton->get_bone_pose_position(bones_to_process[i]))); + src_skeleton->set_bone_pose_rotation(bones_to_process[i], global_transform.basis.get_rotation_quaternion() * src_skeleton->get_bone_pose_rotation(bones_to_process[i])); + src_skeleton->set_bone_pose_scale(bones_to_process[i], (global_transform.orthonormalized().basis * Basis().scaled(src_skeleton->get_bone_pose_scale((bones_to_process[i])))).get_scale()); } while (bones_to_process.size() > 0) { @@ -123,6 +128,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory bones_to_process.push_back(src_children[i]); } src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl)); + src_skeleton->set_bone_pose_position(src_idx, src_skeleton->get_bone_pose_position(src_idx) * scl); } // Fix animation. @@ -603,6 +609,30 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } } + if (p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") && !bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) { + // If Reset All Bone Poses After Import is disabled, preserve the original bone pose, adjusted for the new bone rolls. + for (int bone_idx = 0; bone_idx < src_skeleton->get_bone_count(); bone_idx++) { + Transform3D old_rest = old_skeleton_rest[bone_idx]; + Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx); + Transform3D old_pg; + Transform3D new_pg; + int parent_idx = src_skeleton->get_bone_parent(bone_idx); + if (parent_idx >= 0) { + old_pg = old_skeleton_global_rest[parent_idx]; + new_pg = src_skeleton->get_bone_global_rest(parent_idx); + } + + Quaternion old_pg_q = old_pg.basis.get_rotation_quaternion(); + Quaternion new_pg_q = new_pg.basis.get_rotation_quaternion(); + Quaternion qt = src_skeleton->get_bone_pose_rotation(bone_idx); + src_skeleton->set_bone_pose_rotation(bone_idx, new_pg_q.inverse() * old_pg_q * qt * old_rest.basis.get_rotation_quaternion().inverse() * old_pg_q.inverse() * new_pg_q * new_rest.basis.get_rotation_quaternion()); + + Basis sc = Basis().scaled(src_skeleton->get_bone_pose_scale(bone_idx)); + src_skeleton->set_bone_pose_scale(bone_idx, (new_pg.basis.inverse() * old_pg.basis * sc * old_rest.basis.inverse() * old_pg.basis.inverse() * new_pg.basis * new_rest.basis).get_scale()); + Vector3 ps = src_skeleton->get_bone_pose_position(bone_idx); + src_skeleton->set_bone_pose_position(bone_idx, new_pg_q.xform_inv(old_pg_q.xform(ps - old_rest.origin)) + new_rest.origin); + } + } is_rest_changed = true; } @@ -669,12 +699,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } } - // Init skeleton pose to new rest. - for (int i = 0; i < src_skeleton->get_bone_count(); i++) { - Transform3D fixed_rest = src_skeleton->get_bone_rest(i); - src_skeleton->set_bone_pose_position(i, fixed_rest.origin); - src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion()); - src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale()); + if (!p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") || bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) { + // Init skeleton pose to new rest. + for (int i = 0; i < src_skeleton->get_bone_count(); i++) { + Transform3D fixed_rest = src_skeleton->get_bone_rest(i); + src_skeleton->set_bone_pose_position(i, fixed_rest.origin); + src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion()); + src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale()); + } } } diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp index 52d1b45ac2..62643eaa25 100644 --- a/editor/import/3d/resource_importer_obj.cpp +++ b/editor/import/3d/resource_importer_obj.cpp @@ -329,11 +329,11 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, surf_tool->set_normal(normals[norm]); if (generate_tangents && uvs.is_empty()) { // We can't generate tangents without UVs, so create dummy tangents. - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[norm]); + Vector3 tan = Vector3(normals[norm].z, -normals[norm].x, normals[norm].y).cross(normals[norm].normalized()).normalized(); surf_tool->set_tangent(Plane(tan.x, tan.y, tan.z, 1.0)); } } else { - // No normals, use a dummy normal since normals will be generated. + // No normals, use a dummy tangent since normals and tangents will be generated. if (generate_tangents && uvs.is_empty()) { // We can't generate tangents without UVs, so create dummy tangents. surf_tool->set_tangent(Plane(1.0, 0.0, 0.0, 1.0)); @@ -415,6 +415,20 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes, mesh->set_surface_name(mesh->get_surface_count() - 1, current_group); } Array array = surf_tool->commit_to_arrays(); + + if (mesh_flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && generate_tangents) { + // Compression is enabled, so let's validate that the normals and tangents are correct. + Vector<Vector3> norms = array[Mesh::ARRAY_NORMAL]; + Vector<float> tangents = array[Mesh::ARRAY_TANGENT]; + for (int vert = 0; vert < norms.size(); vert++) { + Vector3 tan = Vector3(tangents[vert * 4 + 0], tangents[vert * 4 + 1], tangents[vert * 4 + 2]); + if (abs(tan.dot(norms[vert])) > 0.0001) { + // Tangent is not perpendicular to the normal, so we can't use compression. + mesh_flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + } + } + } + mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, array, TypedArray<Array>(), Dictionary(), material, name, mesh_flags); print_verbose("OBJ: Added surface :" + mesh->get_surface_name(mesh->get_surface_count() - 1)); diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 3310d6f298..ca128968de 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -37,14 +37,15 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/import/3d/scene_import_settings.h" -#include "scene/3d/area_3d.h" -#include "scene/3d/collision_shape_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" #include "scene/3d/occluder_instance_3d.h" -#include "scene/3d/physics_body_3d.h" -#include "scene/3d/vehicle_body_3d.h" +#include "scene/3d/physics/area_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/static_body_3d.h" +#include "scene/3d/physics/vehicle_body_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/3d/box_shape_3d.h" #include "scene/resources/3d/importer_mesh.h" @@ -156,11 +157,11 @@ Variant EditorScenePostImportPlugin::get_option_value(const StringName &p_name) } return Variant(); } -void EditorScenePostImportPlugin::add_import_option(const String &p_name, Variant p_default_value) { +void EditorScenePostImportPlugin::add_import_option(const String &p_name, const Variant &p_default_value) { ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options()."); add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value); } -void EditorScenePostImportPlugin::add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) { +void EditorScenePostImportPlugin::add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) { ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options()."); current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value)); } @@ -1445,7 +1446,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< return p_node; } -Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks) { +Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, const String &p_save_to_path, bool p_keep_custom_tracks) { if (!p_save_to_file || !p_save_to_path.is_resource_file()) { return anim; } @@ -1932,6 +1933,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/import_as_skeleton_bones"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true)); diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h index dbf7794b61..2e682350bc 100644 --- a/editor/import/3d/resource_importer_scene.h +++ b/editor/import/3d/resource_importer_scene.h @@ -54,8 +54,8 @@ class EditorSceneFormatImporter : public RefCounted { protected: static void _bind_methods(); - Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); - Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); + Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, const Dictionary &p_options); + Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, const Dictionary &p_options); GDVIRTUAL0RC(uint32_t, _get_import_flags) GDVIRTUAL0RC(Vector<String>, _get_extensions) @@ -136,8 +136,8 @@ protected: public: Variant get_option_value(const StringName &p_name) const; - void add_import_option(const String &p_name, Variant p_default_value); - void add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT); + void add_import_option(const String &p_name, const Variant &p_default_value); + void add_import_option_advanced(Variant::Type p_type, const String &p_name, const Variant &p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT); virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options); virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options) const; @@ -287,7 +287,7 @@ public: Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale); Node *_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); - Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks); + Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, const String &p_save_to_path, bool p_keep_custom_tracks); void _create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_clips, bool p_bake_all); void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error); void _compress_animations(AnimationPlayer *anim, int p_page_size_kb); diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index aeff01fc85..f0de608cf5 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -432,6 +432,16 @@ void SceneImportSettingsDialog::_update_view_gizmos() { if (!is_visible()) { return; } + const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current; + if (main_settings.has("nodes/import_as_skeleton_bones")) { + bool new_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"]; + if (new_import_as_skeleton != previous_import_as_skeleton) { + previous_import_as_skeleton = new_import_as_skeleton; + _re_import(); + open_settings(base_path); + } + return; + } for (const KeyValue<String, NodeData> &e : node_map) { bool show_collider_view = false; if (e.value.settings.has(SNAME("generate/physics"))) { @@ -591,6 +601,7 @@ void SceneImportSettingsDialog::update_view() { void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_animation) { if (scene) { + _cleanup(); memdelete(scene); scene = nullptr; } @@ -667,6 +678,10 @@ void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_a first_aabb = false; } + const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current; + if (main_settings.has("nodes/import_as_skeleton_bones")) { + previous_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"]; + } popup_centered_ratio(); _update_view_gizmos(); _update_camera(); @@ -694,7 +709,7 @@ Node *SceneImportSettingsDialog::get_selected_node() { return node_map[selected_id].node; } -void SceneImportSettingsDialog::_select(Tree *p_from, String p_type, String p_id) { +void SceneImportSettingsDialog::_select(Tree *p_from, const String &p_type, const String &p_id) { selecting = true; scene_import_settings_data->hide_options = false; @@ -1137,6 +1152,7 @@ void SceneImportSettingsDialog::_re_import() { main_settings["_subresources"] = subresources; } + _cleanup(); // Prevent skeletons and other pointers from pointing to dangling references. EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, editing_animation ? "animation_library" : "scene", main_settings); } diff --git a/editor/import/3d/scene_import_settings.h b/editor/import/3d/scene_import_settings.h index 05682551b7..e1183dc5b0 100644 --- a/editor/import/3d/scene_import_settings.h +++ b/editor/import/3d/scene_import_settings.h @@ -96,6 +96,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog { Button *animation_stop_button = nullptr; Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE; bool animation_pingpong = false; + bool previous_import_as_skeleton = false; Ref<StandardMaterial3D> collider_mat; @@ -162,7 +163,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog { void _update_view_gizmos(); void _update_camera(); - void _select(Tree *p_from, String p_type, String p_id); + void _select(Tree *p_from, const String &p_type, const String &p_id); void _inspector_property_edited(const String &p_name); void _reset_bone_transforms(); void _play_animation(); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 8a7eb80281..78ceb2ef6d 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -244,7 +244,7 @@ void InspectorDock::_load_resource(const String &p_type) { load_resource_dialog->popup_file_dialog(); } -void InspectorDock::_resource_file_selected(String p_file) { +void InspectorDock::_resource_file_selected(const String &p_file) { Ref<Resource> res; if (ResourceLoader::exists(p_file, "")) { res = ResourceLoader::load(p_file); diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h index 1ad4b52b7d..60ce8100aa 100644 --- a/editor/inspector_dock.h +++ b/editor/inspector_dock.h @@ -114,7 +114,7 @@ class InspectorDock : public VBoxContainer { void _new_resource(); void _load_resource(const String &p_type = ""); void _open_resource_selector() { _load_resource(); }; // just used to call from arg-less signal - void _resource_file_selected(String p_file); + void _resource_file_selected(const String &p_file); void _save_resource(bool save_as); void _unref_resource(); void _copy_resource(); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 8bdd5a3102..eb7f508695 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -45,6 +45,7 @@ void LocalizationEditor::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { translation_list->connect("button_clicked", callable_mp(this, &LocalizationEditor::_translation_delete)); translation_pot_list->connect("button_clicked", callable_mp(this, &LocalizationEditor::_pot_delete)); + translation_pot_add_builtin->set_pressed(GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")); List<String> tfn; ResourceLoader::get_recognized_extensions_for_type("Translation", &tfn); @@ -377,6 +378,11 @@ void LocalizationEditor::_pot_generate_open() { pot_generate_dialog->popup_file_dialog(); } +void LocalizationEditor::_pot_add_builtin_toggled() { + ProjectSettings::get_singleton()->set_setting("internationalization/locale/translation_add_builtin_strings_to_pot", translation_pot_add_builtin->is_pressed()); + ProjectSettings::get_singleton()->save(); +} + void LocalizationEditor::_pot_generate(const String &p_file) { POTGenerator::get_singleton()->generate_pot(p_file); } @@ -730,13 +736,14 @@ LocalizationEditor::LocalizationEditor() { pot_generate_button->connect("pressed", callable_mp(this, &LocalizationEditor::_pot_generate_open)); thb->add_child(pot_generate_button); - VBoxContainer *tmc = memnew(VBoxContainer); - tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tvb->add_child(tmc); - translation_pot_list = memnew(Tree); translation_pot_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tmc->add_child(translation_pot_list); + tvb->add_child(translation_pot_list); + + translation_pot_add_builtin = memnew(CheckBox(TTR("Add Built-in Strings to POT"))); + translation_pot_add_builtin->set_tooltip_text(TTR("Add strings from built-in components such as certain Control nodes.")); + translation_pot_add_builtin->connect("pressed", callable_mp(this, &LocalizationEditor::_pot_add_builtin_toggled)); + tvb->add_child(translation_pot_add_builtin); pot_generate_dialog = memnew(EditorFileDialog); pot_generate_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); diff --git a/editor/localization_editor.h b/editor/localization_editor.h index b9a78a3c82..eb6e5b93c7 100644 --- a/editor/localization_editor.h +++ b/editor/localization_editor.h @@ -32,6 +32,7 @@ #define LOCALIZATION_EDITOR_H #include "editor/editor_locale_dialog.h" +#include "scene/gui/check_box.h" #include "scene/gui/tree.h" class EditorFileDialog; @@ -52,6 +53,7 @@ class LocalizationEditor : public VBoxContainer { Tree *translation_remap_options = nullptr; Tree *translation_pot_list = nullptr; + CheckBox *translation_pot_add_builtin = nullptr; EditorFileDialog *pot_file_open_dialog = nullptr; EditorFileDialog *pot_generate_dialog = nullptr; Button *pot_generate_button = nullptr; @@ -78,6 +80,7 @@ class LocalizationEditor : public VBoxContainer { void _pot_delete(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button); void _pot_file_open(); void _pot_generate_open(); + void _pot_add_builtin_toggled(); void _pot_generate(const String &p_file); void _update_pot_file_extensions(); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 2c86314ae2..e7a1d2735e 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -233,7 +233,7 @@ void AbstractPolygon2DEditor::_wip_close() { selected_point = Vertex(); } -void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_reason) { +void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, const String &p_reason) { _polygon_editing_enabled = !p_disable; button_create->set_disabled(p_disable); @@ -766,7 +766,7 @@ void AbstractPolygon2DEditorPlugin::make_visible(bool p_visible) { } } -AbstractPolygon2DEditorPlugin::AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, String p_class) : +AbstractPolygon2DEditorPlugin::AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, const String &p_class) : polygon_editor(p_polygon_editor), klass(p_class) { CanvasItemEditor::get_singleton()->add_control_to_menu_panel(polygon_editor); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 31c20ac146..25b2e2603e 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -137,7 +137,7 @@ protected: virtual void _create_resource(); public: - void disable_polygon_editing(bool p_disable, String p_reason); + void disable_polygon_editing(bool p_disable, const String &p_reason); bool forward_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); @@ -162,7 +162,7 @@ public: virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; - AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, String p_class); + AbstractPolygon2DEditorPlugin(AbstractPolygon2DEditor *p_polygon_editor, const String &p_class); ~AbstractPolygon2DEditorPlugin(); }; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 22813124d0..0412141775 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -494,7 +494,7 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, updating = false; } -void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, const String &p_node) { +void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, const Array &p_options, const String &p_node) { String option = p_options[p_index]; Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 690b127938..ee6f087e07 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -111,7 +111,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _scroll_changed(const Vector2 &p_scroll); void _node_selected(Object *p_node); void _open_in_editor(const String &p_which); - void _anim_selected(int p_index, Array p_options, const String &p_node); + void _anim_selected(int p_index, const Array &p_options, const String &p_node); void _delete_node_request(const String &p_which); void _delete_nodes_request(const TypedArray<StringName> &p_nodes); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 58b1dbde8a..2af3811863 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -300,7 +300,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { } } -void AnimationLibraryEditor::_load_file(String p_path) { +void AnimationLibraryEditor::_load_file(const String &p_path) { switch (file_dialog_action) { case FILE_DIALOG_ACTION_SAVE_LIBRARY: { Ref<AnimationLibrary> al = mixer->get_animation_library(file_dialog_library); diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h index c003e9a10b..a268e68932 100644 --- a/editor/plugins/animation_library_editor.h +++ b/editor/plugins/animation_library_editor.h @@ -100,7 +100,7 @@ class AnimationLibraryEditor : public AcceptDialog { void _add_library_validate(const String &p_name); void _add_library_confirm(); void _load_library(); - void _load_file(String p_path); + void _load_file(const String &p_path); void _load_files(const PackedStringArray &p_paths); void _item_renamed(); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 6b8943ee84..dbfb143b22 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1184,7 +1184,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { state_machine_play_pos->queue_redraw(); } -void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String p_name, float p_ratio) { +void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(const String &p_name, float p_ratio) { AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); if (!tree) { return; diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 949fa84bce..860d0ed35d 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -134,7 +134,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { void _state_machine_draw(); - void _state_machine_pos_draw_individual(String p_name, float p_ratio); + void _state_machine_pos_draw_individual(const String &p_name, float p_ratio); void _state_machine_pos_draw_all(); void _update_graph(); diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp index e2ad69ac15..9c76b86d6a 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp @@ -43,7 +43,7 @@ bool AudioStreamRandomizerEditorPlugin::handles(Object *p_object) const { void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) { } -void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { +void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.h b/editor/plugins/audio_stream_randomizer_editor_plugin.h index 72cdaeee30..535ab4114b 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.h +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.h @@ -38,7 +38,7 @@ class AudioStreamRandomizerEditorPlugin : public EditorPlugin { GDCLASS(AudioStreamRandomizerEditorPlugin, EditorPlugin); private: - void _move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos); + void _move_stream_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos); public: virtual String get_name() const override { return "AudioStreamRandomizer"; } diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 3256b90aba..d8c020eb29 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -136,7 +136,7 @@ void BoneMapperItem::_open_picker() { emit_signal(SNAME("pick"), profile_bone_name); } -void BoneMapperItem::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void BoneMapperItem::_value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { bone_map->set(p_property, p_value); } @@ -534,12 +534,12 @@ void BoneMapper::_clear_mapping_current_group() { } #ifdef MODULE_REGEX_ENABLED -bool BoneMapper::is_match_with_bone_name(String p_bone_name, String p_word) { +bool BoneMapper::is_match_with_bone_name(const String &p_bone_name, const String &p_word) { RegEx re = RegEx(p_word); return !re.search(p_bone_name.to_lower()).is_null(); } -int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) { +int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, const Vector<String> &p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) { // There may be multiple candidates hit by existing the subsidiary bone. // The one with the shortest name is probably the original. LocalVector<String> hit_list; @@ -617,7 +617,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic return skeleton->find_bone(shortest); } -BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) { +BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(const String &p_bone_name) { String fixed_bn = p_bone_name.to_snake_case(); LocalVector<String> left_words; @@ -1279,12 +1279,12 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) { } #endif // MODULE_REGEX_ENABLED -void BoneMapper::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void BoneMapper::_value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { set(p_property, p_value); recreate_editor(); } -void BoneMapper::_profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void BoneMapper::_profile_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { bone_map->set(p_property, p_value); // Run auto mapping when setting SkeletonProfileHumanoid by GUI Editor. diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 9479ed3730..2e7d1ff124 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -99,7 +99,7 @@ class BoneMapperItem : public VBoxContainer { protected: void _notification(int p_what); static void _bind_methods(); - virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); + virtual void _value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing); virtual void create_editor(); public: @@ -179,9 +179,9 @@ class BoneMapper : public VBoxContainer { BONE_SEGREGATION_LEFT, BONE_SEGREGATION_RIGHT }; - bool is_match_with_bone_name(String p_bone_name, String p_word); - int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1); - BoneSegregation guess_bone_segregation(String p_bone_name); + bool is_match_with_bone_name(const String &p_bone_name, const String &p_word); + int search_bone_by_name(Skeleton3D *p_skeleton, const Vector<String> &p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1); + BoneSegregation guess_bone_segregation(const String &p_bone_name); void auto_mapping_process(Ref<BoneMap> &p_bone_map); void _run_auto_mapping(); #endif // MODULE_REGEX_ENABLED @@ -189,8 +189,8 @@ class BoneMapper : public VBoxContainer { protected: void _notification(int p_what); static void _bind_methods(); - virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); - virtual void _profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); + virtual void _value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing); + virtual void _profile_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing); public: void set_current_group_idx(int p_group_idx); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 3bcc316f84..7446857582 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -861,7 +861,7 @@ void CanvasItemEditor::_restore_canvas_item_state(const List<CanvasItem *> &p_ca } } -void CanvasItemEditor::_commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones) { +void CanvasItemEditor::_commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, const String &action_name, bool commit_bones) { List<CanvasItem *> modified_canvas_items; for (CanvasItem *ci : p_canvas_items) { Dictionary old_state = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci)->undo_state; @@ -2708,7 +2708,7 @@ Control::CursorShape CanvasItemEditor::get_cursor_shape(const Point2 &p_pos) con return c; } -void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Side p_side) { +void CanvasItemEditor::_draw_text_at_position(Point2 p_position, const String &p_string, Side p_side) { Color color = get_theme_color(SNAME("font_color"), EditorStringName(Editor)); color.a = 0.8; Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); @@ -3684,65 +3684,63 @@ void CanvasItemEditor::_draw_hover() { } } -void CanvasItemEditor::_draw_transform_message() { - if (drag_type == DRAG_NONE || drag_selection.is_empty() || !drag_selection.front()->get()) { - return; - } - String transform_message; - Transform2D current_transform = drag_selection.front()->get()->get_global_transform(); +void CanvasItemEditor::_draw_message() { + if (drag_type != DRAG_NONE && !drag_selection.is_empty() && drag_selection.front()->get()) { + Transform2D current_transform = drag_selection.front()->get()->get_global_transform(); - double snap = EDITOR_GET("interface/inspector/default_float_step"); - int snap_step_decimals = Math::range_step_decimals(snap); + double snap = EDITOR_GET("interface/inspector/default_float_step"); + int snap_step_decimals = Math::range_step_decimals(snap); #define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals))) - switch (drag_type) { - case DRAG_MOVE: - case DRAG_MOVE_X: - case DRAG_MOVE_Y: { - Vector2 delta = current_transform.get_origin() - original_transform.get_origin(); - if (drag_type == DRAG_MOVE) { - transform_message = TTR("Moving:") + " (" + FORMAT(delta.x) + ", " + FORMAT(delta.y) + ") px"; - } else if (drag_type == DRAG_MOVE_X) { - transform_message = TTR("Moving:") + " " + FORMAT(delta.x) + " px"; - } else if (drag_type == DRAG_MOVE_Y) { - transform_message = TTR("Moving:") + " " + FORMAT(delta.y) + " px"; - } - } break; - - case DRAG_ROTATE: { - real_t delta = Math::rad_to_deg(current_transform.get_rotation() - original_transform.get_rotation()); - transform_message = TTR("Rotating:") + " " + FORMAT(delta) + String::utf8(" °"); - } break; - - case DRAG_SCALE_X: - case DRAG_SCALE_Y: - case DRAG_SCALE_BOTH: { - Vector2 original_scale = (Math::is_zero_approx(original_transform.get_scale().x) || Math::is_zero_approx(original_transform.get_scale().y)) ? Vector2(CMP_EPSILON, CMP_EPSILON) : original_transform.get_scale(); - Vector2 delta = current_transform.get_scale() / original_scale; - if (drag_type == DRAG_SCALE_BOTH) { - transform_message = TTR("Scaling:") + String::utf8(" ×(") + FORMAT(delta.x) + ", " + FORMAT(delta.y) + ")"; - } else if (drag_type == DRAG_SCALE_X) { - transform_message = TTR("Scaling:") + String::utf8(" ×") + FORMAT(delta.x); - } else if (drag_type == DRAG_SCALE_Y) { - transform_message = TTR("Scaling:") + String::utf8(" ×") + FORMAT(delta.y); - } - } break; + switch (drag_type) { + case DRAG_MOVE: + case DRAG_MOVE_X: + case DRAG_MOVE_Y: { + Vector2 delta = current_transform.get_origin() - original_transform.get_origin(); + if (drag_type == DRAG_MOVE) { + message = TTR("Moving:") + " (" + FORMAT(delta.x) + ", " + FORMAT(delta.y) + ") px"; + } else if (drag_type == DRAG_MOVE_X) { + message = TTR("Moving:") + " " + FORMAT(delta.x) + " px"; + } else if (drag_type == DRAG_MOVE_Y) { + message = TTR("Moving:") + " " + FORMAT(delta.y) + " px"; + } + } break; + + case DRAG_ROTATE: { + real_t delta = Math::rad_to_deg(current_transform.get_rotation() - original_transform.get_rotation()); + message = TTR("Rotating:") + " " + FORMAT(delta) + String::utf8(" °"); + } break; + + case DRAG_SCALE_X: + case DRAG_SCALE_Y: + case DRAG_SCALE_BOTH: { + Vector2 original_scale = (Math::is_zero_approx(original_transform.get_scale().x) || Math::is_zero_approx(original_transform.get_scale().y)) ? Vector2(CMP_EPSILON, CMP_EPSILON) : original_transform.get_scale(); + Vector2 delta = current_transform.get_scale() / original_scale; + if (drag_type == DRAG_SCALE_BOTH) { + message = TTR("Scaling:") + String::utf8(" ×(") + FORMAT(delta.x) + ", " + FORMAT(delta.y) + ")"; + } else if (drag_type == DRAG_SCALE_X) { + message = TTR("Scaling:") + String::utf8(" ×") + FORMAT(delta.x); + } else if (drag_type == DRAG_SCALE_Y) { + message = TTR("Scaling:") + String::utf8(" ×") + FORMAT(delta.y); + } + } break; - default: - break; - } + default: + break; + } #undef FORMAT + } - if (transform_message.is_empty()) { + if (message.is_empty()) { return; } Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); Point2 msgpos = Point2(RULER_WIDTH + 5 * EDSCALE, viewport->get_size().y - 20 * EDSCALE); - viewport->draw_string(font, msgpos + Point2(1, 1), transform_message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); - viewport->draw_string(font, msgpos + Point2(-1, -1), transform_message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); - viewport->draw_string(font, msgpos, transform_message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1)); + viewport->draw_string(font, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); + viewport->draw_string(font, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); + viewport->draw_string(font, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1)); } void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { @@ -3856,7 +3854,7 @@ void CanvasItemEditor::_draw_viewport() { _draw_smart_snapping(); _draw_focus(); _draw_hover(); - _draw_transform_message(); + _draw_message(); } void CanvasItemEditor::update_viewport() { @@ -4740,6 +4738,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { } void CanvasItemEditor::_reset_drag() { + message = ""; drag_type = DRAG_NONE; drag_selection.clear(); } @@ -5693,6 +5692,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons void CanvasItemEditorViewport::_remove_preview() { if (preview_node->get_parent()) { + canvas_item_editor->message = ""; for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { Node *node = preview_node->get_child(i); node->queue_free(); @@ -5938,7 +5938,19 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian } Transform2D trans = canvas_item_editor->get_canvas_transform(); preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x); - label->set_text(vformat(TTR("Adding %s..."), default_texture_node_type)); + String scene_file_path = preview_node->get_child(0)->get_scene_file_path(); + if (scene_file_path.is_empty() || preview_node->get_tree()->get_edited_scene_root()) { + double snap = EDITOR_GET("interface/inspector/default_float_step"); + int snap_step_decimals = Math::range_step_decimals(snap); +#define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals))) + Vector2 preview_node_pos = preview_node->get_global_position(); + canvas_item_editor->message = TTR("Instantiating:") + " (" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px"; + label->set_text(vformat(TTR("Adding %s..."), default_texture_node_type)); + } else { + canvas_item_editor->message = TTR("Creating inherited scene from: ") + scene_file_path; + } + + canvas_item_editor->update_viewport(); } return can_instantiate; } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index bf36b6ec1d..4e160dde47 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -394,7 +394,7 @@ private: void _save_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool save_bones = false); void _restore_canvas_item_state(const List<CanvasItem *> &p_canvas_items, bool restore_bones = false); - void _commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, String action_name, bool commit_bones = false); + void _commit_canvas_item_state(const List<CanvasItem *> &p_canvas_items, const String &action_name, bool commit_bones = false); Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor); Vector2 _position_to_anchor(const Control *p_control, Vector2 position); @@ -440,7 +440,7 @@ private: virtual void shortcut_input(const Ref<InputEvent> &p_ev) override; - void _draw_text_at_position(Point2 p_position, String p_string, Side p_side); + void _draw_text_at_position(Point2 p_position, const String &p_string, Side p_side); void _draw_margin_at_position(int p_value, Point2 p_position, Side p_side); void _draw_percentage_at_position(real_t p_value, Point2 p_position, Side p_side); void _draw_straight_line(Point2 p_from, Point2 p_to, Color p_color); @@ -458,7 +458,7 @@ private: void _draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _draw_hover(); - void _draw_transform_message(); + void _draw_message(); void _draw_viewport(); @@ -544,6 +544,8 @@ public: SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL, }; + String message; + Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, const List<CanvasItem *> &p_other_nodes_exceptions = List<CanvasItem *>()); real_t snap_angle(real_t p_target, real_t p_start = 0) const; diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp index a6457e38a7..64db19d85e 100644 --- a/editor/plugins/cast_2d_editor_plugin.cpp +++ b/editor/plugins/cast_2d_editor_plugin.cpp @@ -33,8 +33,8 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" #include "editor/editor_undo_redo_manager.h" -#include "scene/2d/ray_cast_2d.h" -#include "scene/2d/shape_cast_2d.h" +#include "scene/2d/physics/ray_cast_2d.h" +#include "scene/2d/physics/shape_cast_2d.h" void Cast2DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.h b/editor/plugins/collision_polygon_2d_editor_plugin.h index 070a01f651..61e6cc3dda 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.h +++ b/editor/plugins/collision_polygon_2d_editor_plugin.h @@ -32,7 +32,7 @@ #define COLLISION_POLYGON_2D_EDITOR_PLUGIN_H #include "editor/plugins/abstract_polygon_2d_editor.h" -#include "scene/2d/collision_polygon_2d.h" +#include "scene/2d/physics/collision_polygon_2d.h" class CollisionPolygon2DEditor : public AbstractPolygon2DEditor { GDCLASS(CollisionPolygon2DEditor, AbstractPolygon2DEditor); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index d58f5d511f..0e454799d6 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -32,7 +32,7 @@ #define COLLISION_SHAPE_2D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/2d/collision_shape_2d.h" +#include "scene/2d/physics/collision_shape_2d.h" class CanvasItemEditor; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h index 5077827ce8..ffcf53af66 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -32,8 +32,8 @@ #define CPU_PARTICLES_2D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/2d/collision_polygon_2d.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/2d/physics/collision_polygon_2d.h" #include "scene/gui/box_container.h" class CheckBox; diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp index 9f495d5cd2..af9ff5056a 100644 --- a/editor/plugins/editor_debugger_plugin.cpp +++ b/editor/plugins/editor_debugger_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/debugger/script_editor_debugger.h" -void EditorDebuggerSession::_breaked(bool p_really_did, bool p_can_debug, String p_message, bool p_has_stackdump) { +void EditorDebuggerSession::_breaked(bool p_really_did, bool p_can_debug, const String &p_message, bool p_has_stackdump) { if (p_really_did) { emit_signal(SNAME("breaked"), p_can_debug); } else { diff --git a/editor/plugins/editor_debugger_plugin.h b/editor/plugins/editor_debugger_plugin.h index 10c0e29f6e..41f34f67cf 100644 --- a/editor/plugins/editor_debugger_plugin.h +++ b/editor/plugins/editor_debugger_plugin.h @@ -43,7 +43,7 @@ private: ScriptEditorDebugger *debugger = nullptr; - void _breaked(bool p_really_did, bool p_can_debug, String p_message, bool p_has_stackdump); + void _breaked(bool p_really_did, bool p_can_debug, const String &p_message, bool p_has_stackdump); void _started(); void _stopped(); void _debugger_gone_away(); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index f9b5e280c9..4011d36456 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -163,7 +163,7 @@ void EditorPropertyFontMetaOverride::_notification(int p_what) { } } -void EditorPropertyFontMetaOverride::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void EditorPropertyFontMetaOverride::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("keys")) { Dictionary dict = object->get_dict(); String key = p_property.get_slice("/", 1); @@ -391,7 +391,7 @@ void EditorPropertyOTVariation::_notification(int p_what) { } } -void EditorPropertyOTVariation::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void EditorPropertyOTVariation::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("keys")) { Dictionary dict = object->get_dict(); Dictionary defaults_dict = object->get_defaults(); @@ -559,7 +559,7 @@ void EditorPropertyOTFeatures::_notification(int p_what) { } } -void EditorPropertyOTFeatures::_property_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void EditorPropertyOTFeatures::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("keys")) { Dictionary dict = object->get_dict(); int key = p_property.get_slice("/", 1).to_int(); diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h index 6cea5967b2..dc17a7717e 100644 --- a/editor/plugins/font_config_plugin.h +++ b/editor/plugins/font_config_plugin.h @@ -108,7 +108,7 @@ protected: void _edit_pressed(); void _page_changed(int p_page); - void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _property_changed(const String &p_property, const Variant &p_value, const String &p_name = "", bool p_changing = false); void _remove(Object *p_button, const String &p_key); void _add_menu(); void _add_script(int p_option); @@ -144,7 +144,7 @@ protected: void _edit_pressed(); void _page_changed(int p_page); - void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _property_changed(const String &p_property, const Variant &p_value, const String &p_name = "", bool p_changing = false); void _object_id_selected(const StringName &p_property, ObjectID p_id); public: @@ -193,7 +193,7 @@ protected: void _edit_pressed(); void _page_changed(int p_page); - void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); + void _property_changed(const String &p_property, const Variant &p_value, const String &p_name = "", bool p_changing = false); void _remove(Object *p_button, int p_key); void _add_menu(); void _add_feature(int p_option); diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index c56591cc3a..28080ed559 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -93,7 +93,7 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p for (const String &arch_tag : archs) { PackedStringArray tags; String library_path = GDExtension::find_extension_library( - p_path, config, [features_wo_arch, arch_tag](String p_feature) { return features_wo_arch.has(p_feature) || (p_feature == arch_tag); }, &tags); + p_path, config, [features_wo_arch, arch_tag](const String &p_feature) { return features_wo_arch.has(p_feature) || (p_feature == arch_tag); }, &tags); if (libs_added.has(library_path)) { continue; // Universal library, already added for another arch, do not duplicate. } diff --git a/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp index 63f2883ed7..caac143f23 100644 --- a/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/collision_object_3d_gizmo_plugin.cpp @@ -32,9 +32,9 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/collision_object_3d.h" -#include "scene/3d/collision_polygon_3d.h" -#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/physics/collision_object_3d.h" +#include "scene/3d/physics/collision_polygon_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" #include "scene/resources/surface_tool.h" CollisionObject3DGizmoPlugin::CollisionObject3DGizmoPlugin() { diff --git a/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp index 50c10be11d..7d19e8f677 100644 --- a/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/collision_polygon_3d_gizmo_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/collision_polygon_3d.h" +#include "scene/3d/physics/collision_polygon_3d.h" CollisionPolygon3DGizmoPlugin::CollisionPolygon3DGizmoPlugin() { const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp index 3cf9164460..9d4c08ed57 100644 --- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp @@ -36,7 +36,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/gizmos/gizmo_3d_helper.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" #include "scene/resources/3d/box_shape_3d.h" #include "scene/resources/3d/capsule_shape_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp index 3a8a0cff96..c15ddef933 100644 --- a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp @@ -33,7 +33,11 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/joint_3d.h" +#include "scene/3d/physics/joints/cone_twist_joint_3d.h" +#include "scene/3d/physics/joints/generic_6dof_joint_3d.h" +#include "scene/3d/physics/joints/hinge_joint_3d.h" +#include "scene/3d/physics/joints/pin_joint_3d.h" +#include "scene/3d/physics/joints/slider_joint_3d.h" #define BODY_A_RADIUS 0.25 #define BODY_B_RADIUS 0.27 diff --git a/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp index d1511a5f76..b15f9bec3f 100644 --- a/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/physics_bone_3d_gizmo_plugin.cpp @@ -33,7 +33,8 @@ #include "editor/editor_settings.h" #include "editor/plugins/gizmos/joint_3d_gizmo_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physical_bone_3d.h" +#include "scene/3d/physics/physics_body_3d.h" PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() { create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); diff --git a/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp index eb9e54fe1d..d783c4e4a7 100644 --- a/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/ray_cast_3d_gizmo_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/ray_cast_3d.h" +#include "scene/3d/physics/ray_cast_3d.h" RayCast3DGizmoPlugin::RayCast3DGizmoPlugin() { const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); diff --git a/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp index 23a224fc01..909f5b5f9a 100644 --- a/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/shape_cast_3d.h" +#include "scene/3d/physics/shape_cast_3d.h" ShapeCast3DGizmoPlugin::ShapeCast3DGizmoPlugin() { const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); diff --git a/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp index 69acac5a89..85e2c86947 100644 --- a/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/spring_arm_3d.h" +#include "scene/3d/physics/spring_arm_3d.h" #include "scene/resources/3d/shape_3d.h" void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { diff --git a/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp index ef6cd88868..69e87a55c0 100644 --- a/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.cpp @@ -32,7 +32,7 @@ #include "editor/editor_settings.h" #include "editor/plugins/node_3d_editor_plugin.h" -#include "scene/3d/vehicle_body_3d.h" +#include "scene/3d/physics/vehicle_body_3d.h" VehicleWheel3DGizmoPlugin::VehicleWheel3DGizmoPlugin() { Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h index 237a005ab7..f202179eff 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.h +++ b/editor/plugins/gpu_particles_2d_editor_plugin.h @@ -32,8 +32,8 @@ #define GPU_PARTICLES_2D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/2d/collision_polygon_2d.h" #include "scene/2d/gpu_particles_2d.h" +#include "scene/2d/physics/collision_polygon_2d.h" #include "scene/gui/box_container.h" #include "scene/gui/spin_box.h" diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index ba64c85b37..d3a0d56ec9 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -303,7 +303,7 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { add_custom_control(editor); } -void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { +void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo); diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 5d79d94aaf..c60de1ade9 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -110,7 +110,7 @@ public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); + void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value); EditorInspectorPluginMaterial(); }; diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 061b839ee3..d62eddeeea 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -35,9 +35,10 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/themes/editor_scale.h" -#include "scene/3d/collision_shape_3d.h" #include "scene/3d/navigation_region_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/static_body_3d.h" #include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 4e45714174..8bfd3d0957 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -40,7 +40,8 @@ #include "main/main.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/static_body_3d.h" #include "scene/gui/menu_button.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp index 5118f1d458..869f5b3b10 100644 --- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp +++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp @@ -348,7 +348,7 @@ PackedVector2Array NavigationObstacle3DEditor::_get_polygon() { return PackedVector2Array(obstacle_node->call("get_polygon")); } -void NavigationObstacle3DEditor::_set_polygon(PackedVector2Array p_poly) { +void NavigationObstacle3DEditor::_set_polygon(const PackedVector2Array &p_poly) { ERR_FAIL_NULL_MSG(obstacle_node, "Edited object is not valid."); obstacle_node->call("set_polygon", p_poly); } diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.h b/editor/plugins/navigation_obstacle_3d_editor_plugin.h index 1b125873d1..74094dc86f 100644 --- a/editor/plugins/navigation_obstacle_3d_editor_plugin.h +++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.h @@ -32,8 +32,8 @@ #define NAVIGATION_OBSTACLE_3D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/3d/collision_polygon_3d.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics/collision_polygon_3d.h" #include "scene/gui/box_container.h" #include "scene/resources/immediate_mesh.h" @@ -82,7 +82,7 @@ class NavigationObstacle3DEditor : public HBoxContainer { void _menu_option(int p_option); PackedVector2Array _get_polygon(); - void _set_polygon(PackedVector2Array p_poly); + void _set_polygon(const PackedVector2Array &p_poly); protected: void _notification(int p_what); diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index 48335f3b94..04133072be 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "navigation_polygon_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/2d/navigation_region_2d.h" #include "scene/gui/dialogs.h" @@ -50,6 +51,13 @@ Node2D *NavigationPolygonEditor::_get_node() const { void NavigationPolygonEditor::_set_node(Node *p_polygon) { node = Object::cast_to<NavigationRegion2D>(p_polygon); + if (node) { + Ref<NavigationPolygon> navpoly = node->get_navigation_polygon(); + if (navpoly.is_valid() && navpoly->get_outline_count() > 0 && navpoly->get_polygon_count() == 0) { + // We have outlines drawn / added by the user but no polygons were created for this navmesh yet so let's bake once immediately. + _rebake_timer_timeout(); + } + } } int NavigationPolygonEditor::_get_polygon_count() const { @@ -73,6 +81,10 @@ Variant NavigationPolygonEditor::_get_polygon(int p_idx) const { void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { Ref<NavigationPolygon> navpoly = _ensure_navpoly(); navpoly->set_outline(p_idx, p_polygon); + + if (rebake_timer && _rebake_timer_delay >= 0.0) { + rebake_timer->start(); + } } void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { @@ -80,6 +92,10 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count()); + + if (rebake_timer && _rebake_timer_delay >= 0.0) { + rebake_timer->start(); + } } void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { @@ -87,6 +103,10 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx); undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx); + + if (rebake_timer && _rebake_timer_delay >= 0.0) { + rebake_timer->start(); + } } void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { @@ -94,6 +114,10 @@ void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_pr EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous); + + if (rebake_timer && _rebake_timer_delay >= 0.0) { + rebake_timer->start(); + } } bool NavigationPolygonEditor::_has_resource() const { @@ -136,6 +160,15 @@ NavigationPolygonEditor::NavigationPolygonEditor() { bake_info = memnew(Label); bake_hbox->add_child(bake_info); + rebake_timer = memnew(Timer); + add_child(rebake_timer); + rebake_timer->set_one_shot(true); + _rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay"); + if (_rebake_timer_delay >= 0.0) { + rebake_timer->set_wait_time(_rebake_timer_delay); + } + rebake_timer->connect("timeout", callable_mp(this, &NavigationPolygonEditor::_rebake_timer_timeout)); + err_dialog = memnew(AcceptDialog); add_child(err_dialog); node = nullptr; @@ -147,15 +180,26 @@ void NavigationPolygonEditor::_notification(int p_what) { button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (rebake_timer) { + _rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay"); + if (_rebake_timer_delay >= 0.0) { + rebake_timer->set_wait_time(_rebake_timer_delay); + } + } + } break; } } void NavigationPolygonEditor::_bake_pressed() { + if (rebake_timer) { + rebake_timer->stop(); + } button_bake->set_pressed(false); ERR_FAIL_NULL(node); Ref<NavigationPolygon> navigation_polygon = node->get_navigation_polygon(); - if (!navigation_polygon.is_valid()) { + if (navigation_polygon.is_null()) { err_dialog->set_text(TTR("A NavigationPolygon resource must be set or created for this node to work.")); err_dialog->popup_centered(); return; @@ -167,6 +211,9 @@ void NavigationPolygonEditor::_bake_pressed() { } void NavigationPolygonEditor::_clear_pressed() { + if (rebake_timer) { + rebake_timer->stop(); + } if (node) { if (node->get_navigation_polygon().is_valid()) { node->get_navigation_polygon()->clear(); @@ -193,6 +240,19 @@ void NavigationPolygonEditor::_update_polygon_editing_state() { } } +void NavigationPolygonEditor::_rebake_timer_timeout() { + if (!node) { + return; + } + Ref<NavigationPolygon> navigation_polygon = node->get_navigation_polygon(); + if (!navigation_polygon.is_valid()) { + return; + } + + node->bake_navigation_polygon(true); + node->queue_redraw(); +} + NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() : AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") { } diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h index f1d0cd8751..bf2474bc55 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.h +++ b/editor/plugins/navigation_polygon_editor_plugin.h @@ -56,6 +56,10 @@ class NavigationPolygonEditor : public AbstractPolygon2DEditor { Button *button_reset = nullptr; Label *bake_info = nullptr; + Timer *rebake_timer = nullptr; + float _rebake_timer_delay = 1.5; + void _rebake_timer_timeout(); + void _bake_pressed(); void _clear_pressed(); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 4e462cfe34..aa0069979c 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -78,11 +78,11 @@ #include "editor/plugins/node_3d_editor_gizmos.h" #include "editor/scene_tree_dock.h" #include "scene/3d/camera_3d.h" -#include "scene/3d/collision_shape_3d.h" #include "scene/3d/decal.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/physics_body_3d.h" #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" @@ -2663,7 +2663,7 @@ void Node3DEditorViewport::_update_freelook(real_t delta) { cursor.eye_pos += motion; } -void Node3DEditorViewport::set_message(String p_message, float p_time) { +void Node3DEditorViewport::set_message(const String &p_message, float p_time) { message = p_message; message_time = p_time; } @@ -2972,6 +2972,10 @@ void Node3DEditorViewport::_notification(int p_what) { } if (preview_node->is_inside_tree()) { preview_node_pos = spatial_editor->snap_point(_get_instance_position(preview_node_viewport_pos)); + double snap = EDITOR_GET("interface/inspector/default_float_step"); + int snap_step_decimals = Math::range_step_decimals(snap); + set_message(TTR("Instantiating:") + " (" + String::num(preview_node_pos.x, snap_step_decimals) + ", " + + String::num(preview_node_pos.y, snap_step_decimals) + ", " + String::num(preview_node_pos.z, snap_step_decimals) + ")"); Transform3D preview_gl_transform = Transform3D(Basis(), preview_node_pos); preview_node->set_global_transform(preview_gl_transform); if (!preview_node->is_visible()) { @@ -4213,6 +4217,7 @@ void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) con } void Node3DEditorViewport::_remove_preview_node() { + set_message(""); if (preview_node->get_parent()) { for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { Node *node = preview_node->get_child(i); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 003d462552..13b51289a9 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -400,7 +400,7 @@ private: String message; double message_time; - void set_message(String p_message, float p_time = 5); + void set_message(const String &p_message, float p_time = 5); void _view_settings_confirmed(real_t p_interp_delta); void _update_camera(real_t p_interp_delta); diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp index 37092f924e..b7c12ab5c0 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.cpp +++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_string_names.h" #include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/physics/physical_bone_3d.h" #include "scene/gui/separator.h" void PhysicalBone3DEditor::_bind_methods() { diff --git a/editor/plugins/physical_bone_3d_editor_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h index c9799d3faa..5c49e641a5 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.h +++ b/editor/plugins/physical_bone_3d_editor_plugin.h @@ -32,10 +32,11 @@ #define PHYSICAL_BONE_3D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/3d/physics_body_3d.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" +class PhysicalBone3D; + class PhysicalBone3DEditor : public Object { GDCLASS(PhysicalBone3DEditor, Object); diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 2ea251c455..da84afc4d7 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -364,7 +364,7 @@ PackedVector2Array Polygon3DEditor::_get_polygon() { return PackedVector2Array(obj->call("get_polygon")); } -void Polygon3DEditor::_set_polygon(PackedVector2Array p_poly) { +void Polygon3DEditor::_set_polygon(const PackedVector2Array &p_poly) { Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node; ERR_FAIL_NULL_MSG(obj, "Edited object is not valid."); obj->call("set_polygon", p_poly); diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h index 6cb9275dd6..85cfd807e4 100644 --- a/editor/plugins/polygon_3d_editor_plugin.h +++ b/editor/plugins/polygon_3d_editor_plugin.h @@ -32,8 +32,8 @@ #define POLYGON_3D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/3d/collision_polygon_3d.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics/collision_polygon_3d.h" #include "scene/gui/box_container.h" #include "scene/resources/immediate_mesh.h" @@ -82,7 +82,7 @@ class Polygon3DEditor : public HBoxContainer { float _get_depth(); PackedVector2Array _get_polygon(); - void _set_polygon(PackedVector2Array p_poly); + void _set_polygon(const PackedVector2Array &p_poly); protected: void _notification(int p_what); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index d639121ae0..e986510895 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -60,6 +60,7 @@ #include "editor/plugins/shader_editor_plugin.h" #include "editor/plugins/text_shader_editor.h" #include "editor/themes/editor_scale.h" +#include "editor/themes/editor_theme_manager.h" #include "editor/window_wrapper.h" #include "scene/main/node.h" #include "scene/main/window.h" @@ -696,7 +697,7 @@ void ScriptEditor::_go_to_tab(int p_idx) { _update_help_overview_visibility(); } -void ScriptEditor::_add_recent_script(String p_path) { +void ScriptEditor::_add_recent_script(const String &p_path) { if (p_path.is_empty()) { return; } @@ -790,7 +791,7 @@ void ScriptEditor::_open_recent_script(int p_idx) { _show_error_dialog(path); } -void ScriptEditor::_show_error_dialog(String p_path) { +void ScriptEditor::_show_error_dialog(const String &p_path) { error_dialog->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_path)); error_dialog->popup_centered(); } @@ -1000,6 +1001,11 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { } } + if (p_res.is_valid()) { + // In case the Resource has built-in scripts. + _mark_built_in_scripts_as_saved(p_res->get_path()); + } + _update_script_names(); Ref<Script> scr = p_res; if (scr.is_valid()) { @@ -1009,6 +1015,10 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { void ScriptEditor::_scene_saved_callback(const String &p_path) { // If scene was saved, mark all built-in scripts from that scene as saved. + _mark_built_in_scripts_as_saved(p_path); +} + +void ScriptEditor::_mark_built_in_scripts_as_saved(const String &p_parent_path) { for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); if (!se) { @@ -1021,7 +1031,7 @@ void ScriptEditor::_scene_saved_callback(const String &p_path) { continue; // External script, who cares. } - if (edited_res->get_path().get_slice("::", 0) == p_path) { + if (edited_res->get_path().get_slice("::", 0) == p_parent_path) { se->tag_saved_version(); } @@ -1109,7 +1119,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Resource> p_for_script) { return need_reload; } -void ScriptEditor::_file_dialog_action(String p_file) { +void ScriptEditor::_file_dialog_action(const String &p_file) { switch (file_dialog_option) { case FILE_NEW_TEXTFILE: { Error err; @@ -2784,7 +2794,8 @@ void ScriptEditor::_save_layout() { } void ScriptEditor::_editor_settings_changed() { - if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && + if (!EditorThemeManager::is_generated_theme_outdated() && + !EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && !EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor") && !EditorSettings::get_singleton()->check_changed_settings_in_group("docks/filesystem")) { return; @@ -3628,7 +3639,7 @@ void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) { auto_reload_running_scripts = p_enabled; } -void ScriptEditor::_help_search(String p_text) { +void ScriptEditor::_help_search(const String &p_text) { help_search_dialog->popup_dialog(p_text); } @@ -3679,20 +3690,20 @@ void ScriptEditor::_script_changed() { NodeDock::get_singleton()->update_lists(); } -void ScriptEditor::_on_find_in_files_requested(String text) { +void ScriptEditor::_on_find_in_files_requested(const String &text) { find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::SEARCH_MODE); find_in_files_dialog->set_search_text(text); find_in_files_dialog->popup_centered(); } -void ScriptEditor::_on_replace_in_files_requested(String text) { +void ScriptEditor::_on_replace_in_files_requested(const String &text) { find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::REPLACE_MODE); find_in_files_dialog->set_search_text(text); find_in_files_dialog->set_replace_text(""); find_in_files_dialog->popup_centered(); } -void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) { +void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end) { if (ResourceLoader::exists(fpath)) { Ref<Resource> res = ResourceLoader::load(fpath); @@ -3814,7 +3825,7 @@ void ScriptEditor::_start_find_in_files(bool with_replace) { EditorNode::get_bottom_panel()->make_item_visible(find_in_files); } -void ScriptEditor::_on_find_in_files_modified_files(PackedStringArray paths) { +void ScriptEditor::_on_find_in_files_modified_files(const PackedStringArray &paths) { _test_script_times_on_disk(); _update_modified_scripts_for_external_editor(); } @@ -4217,7 +4228,7 @@ void ScriptEditorPlugin::_focus_another_editor() { } } -void ScriptEditorPlugin::_save_last_editor(String p_editor) { +void ScriptEditorPlugin::_save_last_editor(const String &p_editor) { if (p_editor != get_name()) { last_editor = p_editor; } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 752c1a6a05..d5c33c73b4 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -179,7 +179,7 @@ public: virtual PackedInt32Array get_breakpoints() = 0; virtual void set_breakpoint(int p_line, bool p_enabled) = 0; virtual void clear_breakpoints() = 0; - virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0; + virtual void add_callback(const String &p_function, const PackedStringArray &p_args) = 0; virtual void update_settings() = 0; virtual void set_debugger_active(bool p_active) = 0; virtual bool can_lose_focus_on_node_selection() { return true; } @@ -362,11 +362,11 @@ class ScriptEditor : public PanelContainer { bool _test_script_times_on_disk(Ref<Resource> p_for_script = Ref<Resource>()); - void _add_recent_script(String p_path); + void _add_recent_script(const String &p_path); void _update_recent_scripts(); void _open_recent_script(int p_idx); - void _show_error_dialog(String p_path); + void _show_error_dialog(const String &p_path); void _close_tab(int p_idx, bool p_save = true, bool p_history_back = true); void _update_find_replace_bar(); @@ -401,6 +401,7 @@ class ScriptEditor : public PanelContainer { void _add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args); void _res_saved_callback(const Ref<Resource> &p_res); void _scene_saved_callback(const String &p_path); + void _mark_built_in_scripts_as_saved(const String &p_parent_path); bool open_textfile_after_create = true; bool trim_trailing_whitespace_on_save; @@ -462,7 +463,7 @@ class ScriptEditor : public PanelContainer { void _script_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index); void _make_script_list_context_menu(); - void _help_search(String p_text); + void _help_search(const String &p_text); void _history_forward(); void _history_back(); @@ -481,7 +482,7 @@ class ScriptEditor : public PanelContainer { void _script_changed(); int file_dialog_option; - void _file_dialog_action(String p_file); + void _file_dialog_action(const String &p_file); Ref<Script> _get_current_script(); TypedArray<Script> _get_open_scripts() const; @@ -490,11 +491,11 @@ class ScriptEditor : public PanelContainer { Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const; Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path); - void _on_find_in_files_requested(String text); - void _on_replace_in_files_requested(String text); - void _on_find_in_files_result_selected(String fpath, int line_number, int begin, int end); + void _on_find_in_files_requested(const String &text); + void _on_replace_in_files_requested(const String &text); + void _on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end); void _start_find_in_files(bool with_replace); - void _on_find_in_files_modified_files(PackedStringArray paths); + void _on_find_in_files_modified_files(const PackedStringArray &paths); void _set_zoom_factor(float p_zoom_factor); @@ -579,7 +580,7 @@ class ScriptEditorPlugin : public EditorPlugin { void _focus_another_editor(); - void _save_last_editor(String p_editor); + void _save_last_editor(const String &p_editor); void _window_visibility_changed(bool p_visible); protected: diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ee347538a4..4c08449b8d 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -46,7 +46,7 @@ void ConnectionInfoDialog::ok_pressed() { } -void ConnectionInfoDialog::popup_connections(String p_method, Vector<Node *> p_nodes) { +void ConnectionInfoDialog::popup_connections(const String &p_method, const Vector<Node *> &p_nodes) { method->set_text(p_method); tree->clear(); @@ -269,7 +269,7 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) { warnings_panel->set_visible(p_show); } -void ScriptTextEditor::_warning_clicked(Variant p_line) { +void ScriptTextEditor::_warning_clicked(const Variant &p_line) { if (p_line.get_type() == Variant::INT) { goto_line_centered(p_line.operator int64_t()); } else if (p_line.get_type() == Variant::DICTIONARY) { @@ -300,7 +300,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { } } -void ScriptTextEditor::_error_clicked(Variant p_line) { +void ScriptTextEditor::_error_clicked(const Variant &p_line) { if (p_line.get_type() == Variant::INT) { code_editor->get_text_editor()->remove_secondary_carets(); code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); @@ -344,7 +344,7 @@ void ScriptTextEditor::reload_text() { _validate_script(); } -void ScriptTextEditor::add_callback(const String &p_function, PackedStringArray p_args) { +void ScriptTextEditor::add_callback(const String &p_function, const PackedStringArray &p_args) { ScriptLanguage *language = script->get_language(); if (!language->can_make_function()) { return; diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 820e86df61..2ea73d4c73 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -49,7 +49,7 @@ class ConnectionInfoDialog : public AcceptDialog { virtual void ok_pressed() override; public: - void popup_connections(String p_method, Vector<Node *> p_nodes); + void popup_connections(const String &p_method, const Vector<Node *> &p_nodes); ConnectionInfoDialog(); }; @@ -177,8 +177,8 @@ protected: void _set_theme_for_script(); void _show_errors_panel(bool p_show); void _show_warnings_panel(bool p_show); - void _error_clicked(Variant p_line); - void _warning_clicked(Variant p_line); + void _error_clicked(const Variant &p_line); + void _warning_clicked(const Variant &p_line); void _notification(int p_what); @@ -240,7 +240,7 @@ public: virtual void set_breakpoint(int p_line, bool p_enabled) override; virtual void clear_breakpoints() override; - virtual void add_callback(const String &p_function, PackedStringArray p_args) override; + virtual void add_callback(const String &p_function, const PackedStringArray &p_args) override; virtual void update_settings() override; virtual bool show_members_overview() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 9321c6dafc..213a332bab 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -625,12 +625,37 @@ void ShaderEditorPlugin::_file_removed(const String &p_removed_file) { } } +void ShaderEditorPlugin::_res_saved_callback(const Ref<Resource> &p_res) { + if (p_res.is_null()) { + return; + } + const String &path = p_res->get_path(); + + for (EditedShader &edited : edited_shaders) { + Ref<Resource> shader_res = edited.shader; + if (shader_res.is_null()) { + shader_res = edited.shader_inc; + } + ERR_FAIL_COND(shader_res.is_null()); + + if (!edited.shader_editor || !shader_res->is_built_in()) { + continue; + } + + if (shader_res->get_path().get_slice("::", 0) == path) { + edited.shader_editor->tag_saved_version(); + _update_shader_list(); + } + } +} + void ShaderEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ShaderEditorPlugin::_resource_saved), CONNECT_DEFERRED); EditorNode::get_singleton()->connect("scene_closed", callable_mp(this, &ShaderEditorPlugin::_close_builtin_shaders_from_scene)); FileSystemDock::get_singleton()->connect("file_removed", callable_mp(this, &ShaderEditorPlugin::_file_removed)); + EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &ShaderEditorPlugin::_res_saved_callback)); } break; } } diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 84c5a620a7..2558184982 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -96,6 +96,7 @@ class ShaderEditorPlugin : public EditorPlugin { void _close_shader(int p_index); void _close_builtin_shaders_from_scene(const String &p_scene); void _file_removed(const String &p_removed_file); + void _res_saved_callback(const Ref<Resource> &p_res); void _shader_created(Ref<Shader> p_shader); void _shader_include_created(Ref<ShaderInclude> p_shader_inc); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index b6a6c8968e..ffc59a3429 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -40,10 +40,11 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/themes/editor_scale.h" -#include "scene/3d/collision_shape_3d.h" -#include "scene/3d/joint_3d.h" #include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/joints/joint_3d.h" +#include "scene/3d/physics/physical_bone_3d.h" +#include "scene/3d/physics/physics_body_3d.h" #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" #include "scene/resources/3d/capsule_shape_3d.h" @@ -113,7 +114,7 @@ void BoneTransformEditor::_notification(int p_what) { } } -void BoneTransformEditor::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) { +void BoneTransformEditor::_value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (updating) { return; } diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 839061a2fe..f62d017c40 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -75,7 +75,7 @@ class BoneTransformEditor : public VBoxContainer { void create_editors(); - void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing); + void _value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing); void _property_keyed(const String &p_path, bool p_advance); diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 3e98f3d64f..de81264f13 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -38,9 +38,9 @@ #include "editor/gui/editor_zoom_widget.h" #include "editor/scene_tree_dock.h" #include "editor/themes/editor_scale.h" -#include "scene/2d/collision_polygon_2d.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/mesh_instance_2d.h" +#include "scene/2d/physics/collision_polygon_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/gui/box_container.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 2eb914e976..6070e08739 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -140,7 +140,7 @@ void TextEditor::enable_editor(Control *p_shortcut_context) { } } -void TextEditor::add_callback(const String &p_function, PackedStringArray p_args) { +void TextEditor::add_callback(const String &p_function, const PackedStringArray &p_args) { } void TextEditor::set_debugger_active(bool p_active) { diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 38dca9eb28..38fddc45df 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -142,7 +142,7 @@ public: virtual bool can_lose_focus_on_node_selection() override { return true; } virtual void set_debugger_active(bool p_active) override; virtual void set_tooltip_request_func(const Callable &p_toolip_callback) override; - virtual void add_callback(const String &p_function, PackedStringArray p_args) override; + virtual void add_callback(const String &p_function, const PackedStringArray &p_args) override; void update_toggle_scripts_button() override; virtual Control *get_edit_menu() override; diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index ad8674207b..5a1fe833d6 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -37,6 +37,7 @@ #include "editor/filesystem_dock.h" #include "editor/project_settings_editor.h" #include "editor/themes/editor_scale.h" +#include "editor/themes/editor_theme_manager.h" #include "scene/gui/split_container.h" #include "servers/rendering/shader_preprocessor.h" #include "servers/rendering/shader_types.h" @@ -740,7 +741,8 @@ void TextShaderEditor::_notification(int p_what) { } void TextShaderEditor::_editor_settings_changed() { - if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && + if (!EditorThemeManager::is_generated_theme_outdated() && + !EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor") && !EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor")) { return; } @@ -758,7 +760,7 @@ void TextShaderEditor::_show_warnings_panel(bool p_show) { warnings_panel->set_visible(p_show); } -void TextShaderEditor::_warning_clicked(Variant p_line) { +void TextShaderEditor::_warning_clicked(const Variant &p_line) { if (p_line.get_type() == Variant::INT) { code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t()); } diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h index 73d7de98e4..be16148744 100644 --- a/editor/plugins/text_shader_editor.h +++ b/editor/plugins/text_shader_editor.h @@ -165,7 +165,7 @@ class TextShaderEditor : public MarginContainer { void _reload_shader_include_from_disk(); void _reload(); void _show_warnings_panel(bool p_show); - void _warning_clicked(Variant p_line); + void _warning_clicked(const Variant &p_line); void _update_warnings(bool p_validate); void _script_validated(bool p_valid) { diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index e49ba5844a..e25005f996 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -42,7 +42,7 @@ void AtlasMergingDialog::_property_changed(const StringName &p_property, const V _set(p_property, p_value); } -void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atlas_sources, int p_max_columns) { +void AtlasMergingDialog::_generate_merged(const Vector<Ref<TileSetAtlasSource>> &p_atlas_sources, int p_max_columns) { merged.instantiate(); merged_mapping.clear(); @@ -177,7 +177,7 @@ void AtlasMergingDialog::_update_texture() { } } -void AtlasMergingDialog::_merge_confirmed(String p_path) { +void AtlasMergingDialog::_merge_confirmed(const String &p_path) { ERR_FAIL_COND(!merged.is_valid()); Ref<ImageTexture> output_image_texture = merged->get_texture(); diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h index 2517db2ccd..83389c2e29 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.h +++ b/editor/plugins/tiles/atlas_merging_dialog.h @@ -64,9 +64,9 @@ private: void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing); - void _generate_merged(Vector<Ref<TileSetAtlasSource>> p_atlas_sources, int p_max_columns); + void _generate_merged(const Vector<Ref<TileSetAtlasSource>> &p_atlas_sources, int p_max_columns); void _update_texture(); - void _merge_confirmed(String p_path); + void _merge_confirmed(const String &p_path); protected: virtual void ok_pressed() override; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index bd44c2965b..5845ddbb6e 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -641,6 +641,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) undo_redo->add_undo_method(base_control, "queue_redraw"); undo_redo->commit_action(false); emit_signal(SNAME("polygons_changed")); + drag_type = DRAG_TYPE_NONE; } else { drag_type = DRAG_TYPE_PAN; drag_last_pos = mb->get_position(); @@ -750,7 +751,7 @@ int GenericTilePolygonEditor::get_polygon_count() { return polygons.size(); } -int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index) { +int GenericTilePolygonEditor::add_polygon(const Vector<Point2> &p_polygon, int p_index) { ERR_FAIL_COND_V(p_polygon.size() < 3, -1); ERR_FAIL_COND_V(!multiple_polygon_mode && polygons.size() >= 1, -1); @@ -782,7 +783,7 @@ void GenericTilePolygonEditor::clear_polygons() { base_control->queue_redraw(); } -void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) { +void GenericTilePolygonEditor::set_polygon(int p_polygon_index, const Vector<Point2> &p_polygon) { ERR_FAIL_INDEX(p_polygon_index, (int)polygons.size()); ERR_FAIL_COND(p_polygon.size() < 3); polygons[p_polygon_index] = p_polygon; @@ -954,7 +955,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { _set_snap_option(EditorSettings::get_singleton()->get_project_metadata("editor_metadata", "tile_snap_option", SNAP_NONE)); } -void TileDataDefaultEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { +void TileDataDefaultEditor::_property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field) { ERR_FAIL_NULL(dummy_object); dummy_object->set(p_property, p_value); emit_signal(SNAME("needs_redraw")); @@ -975,7 +976,7 @@ void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_at } } -void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { +void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile); ERR_FAIL_NULL(tile_data); tile_data->set(property, p_value); @@ -987,7 +988,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s return tile_data->get(property); } -void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { +void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); @@ -1250,7 +1251,7 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2 } } -void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p_property, String p_label, Variant p_default_value) { +void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, const String &p_property, const String &p_label, const Variant &p_default_value) { ERR_FAIL_COND_MSG(!property.is_empty(), "Cannot setup TileDataDefaultEditor twice"); property = p_property; property_type = p_type; @@ -1446,7 +1447,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } -void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { +void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile); ERR_FAIL_NULL(tile_data); Ref<OccluderPolygon2D> occluder_polygon = p_value; @@ -1461,7 +1462,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_ return tile_data->get_occluder(occlusion_layer); } -void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { +void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); @@ -1487,7 +1488,7 @@ TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() { add_child(polygon_editor); } -void TileDataCollisionEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { +void TileDataCollisionEditor::_property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field) { dummy_object->set(p_property, p_value); } @@ -1602,7 +1603,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } -void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { +void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile); ERR_FAIL_NULL(tile_data); @@ -1640,7 +1641,7 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas return dict; } -void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { +void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) { Dictionary new_dict = p_new_value; EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { @@ -1808,7 +1809,7 @@ void TileDataTerrainsEditor::_update_terrain_selector() { } } -void TileDataTerrainsEditor::_property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field) { +void TileDataTerrainsEditor::_property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field) { Variant old_value = dummy_object->get(p_property); dummy_object->set(p_property, p_value); if (p_property == "terrain_set") { @@ -2862,7 +2863,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } -void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { +void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) { TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile); ERR_FAIL_NULL(tile_data); Ref<NavigationPolygon> nav_polygon = p_value; @@ -2877,7 +2878,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla return tile_data->get_navigation_polygon(navigation_layer); } -void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) { +void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) { Vector2i coords = E.key.get_atlas_coords(); diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 27fe4316a0..40c049f70c 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -185,10 +185,10 @@ public: void set_background(Ref<Texture2D> p_texture, Rect2 p_region = Rect2(), Vector2 p_offset = Vector2(), bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, Color p_modulate = Color(1.0, 1.0, 1.0, 0.0)); int get_polygon_count(); - int add_polygon(Vector<Point2> p_polygon, int p_index = -1); + int add_polygon(const Vector<Point2> &p_polygon, int p_index = -1); void remove_polygon(int p_index); void clear_polygons(); - void set_polygon(int p_polygon_index, Vector<Point2> p_polygon); + void set_polygon(int p_polygon_index, const Vector<Point2> &p_polygon); Vector<Point2> get_polygon(int p_polygon_index); void set_polygons_color(Color p_color); @@ -224,7 +224,7 @@ private: HashMap<TileMapCell, Variant, TileMapCell> drag_modified; Variant drag_painted_value; - void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); + void _property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field); protected: DummyObject *dummy_object = memnew(DummyObject); @@ -236,9 +236,9 @@ protected: virtual Variant _get_painted_value(); virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); - virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value); + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value); virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value); + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value); public: virtual Control *get_toolbar() override { return toolbar; }; @@ -248,7 +248,7 @@ public: virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override; virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; - void setup_property_editor(Variant::Type p_type, String p_property, String p_label = "", Variant p_default_value = Variant()); + void setup_property_editor(Variant::Type p_type, const String &p_property, const String &p_label = "", const Variant &p_default_value = Variant()); Variant::Type get_property_type(); TileDataDefaultEditor(); @@ -285,13 +285,13 @@ private: // UI GenericTilePolygonEditor *polygon_editor = nullptr; - void _polygon_changed(PackedVector2Array p_polygon); + void _polygon_changed(const PackedVector2Array &p_polygon); virtual Variant _get_painted_value() override; virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) override; protected: virtual void _tile_set_changed() override; @@ -316,15 +316,15 @@ class TileDataCollisionEditor : public TileDataDefaultEditor { DummyObject *dummy_object = memnew(DummyObject); HashMap<StringName, EditorProperty *> property_editors; - void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); + void _property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field); void _property_selected(const StringName &p_path, int p_focusable); void _polygons_changed(); virtual Variant _get_painted_value() override; virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) override; protected: virtual void _tile_set_changed() override; @@ -368,7 +368,7 @@ private: EditorPropertyEnum *terrain_set_property_editor = nullptr; EditorPropertyEnum *terrain_property_editor = nullptr; - void _property_value_changed(const StringName &p_property, Variant p_value, const StringName &p_field); + void _property_value_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field); void _update_terrain_selector(); @@ -399,13 +399,13 @@ private: // UI GenericTilePolygonEditor *polygon_editor = nullptr; - void _polygon_changed(PackedVector2Array p_polygon); + void _polygon_changed(const PackedVector2Array &p_polygon); virtual Variant _get_painted_value() override; virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, const Variant &p_value) override; virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; - virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, Variant p_new_value) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, const HashMap<TileMapCell, Variant, TileMapCell> &p_previous_values, const Variant &p_new_value) override; protected: virtual void _tile_set_changed() override; diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index d24e7faeaf..ccadc0643b 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -445,7 +445,7 @@ void TileMapLayerEditorTilesPlugin::_update_scenes_collection_view() { scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size)); } -void TileMapLayerEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) { +void TileMapLayerEditorTilesPlugin::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_ud) { int index = p_ud; if (index >= 0 && index < scene_tiles_list->get_item_count()) { @@ -3874,7 +3874,7 @@ void TileMapLayerEditor::_update_highlighting_toggle() { } } -void TileMapLayerEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { +void TileMapLayerEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); diff --git a/editor/plugins/tiles/tile_map_layer_editor.h b/editor/plugins/tiles/tile_map_layer_editor.h index 2a01a3c17a..a7fea2abcf 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.h +++ b/editor/plugins/tiles/tile_map_layer_editor.h @@ -209,7 +209,7 @@ private: ItemList *scene_tiles_list = nullptr; void _update_scenes_collection_view(); - void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud); + void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_ud); void _scenes_list_multi_selected(int p_index, bool p_selected); void _scenes_list_lmb_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index); @@ -382,7 +382,7 @@ private: void _update_highlighting_toggle(); // Inspector undo/redo callback. - void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos); + void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos); protected: void _notification(int p_what); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 176e8b7fee..d5aba35a8f 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -551,7 +551,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_bind_methods() { ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what"))); } -void TileSetAtlasSourceEditor::_inspector_property_selected(String p_property) { +void TileSetAtlasSourceEditor::_inspector_property_selected(const String &p_property) { selected_property = p_property; _update_atlas_view(); _update_current_tile_data_editor(); @@ -1701,7 +1701,7 @@ void TileSetAtlasSourceEditor::shortcut_input(const Ref<InputEvent> &p_event) { } } -void TileSetAtlasSourceEditor::_set_selection_from_array(Array p_selection) { +void TileSetAtlasSourceEditor::_set_selection_from_array(const Array &p_selection) { ERR_FAIL_COND((p_selection.size() % 2) != 0); selection.clear(); for (int i = 0; i < p_selection.size() / 2; i++) { @@ -2100,12 +2100,12 @@ void TileSetAtlasSourceEditor::_tile_set_changed() { tile_set_changed_needs_update = true; } -void TileSetAtlasSourceEditor::_tile_proxy_object_changed(String p_what) { +void TileSetAtlasSourceEditor::_tile_proxy_object_changed(const String &p_what) { tile_set_changed_needs_update = false; // Avoid updating too many things. _update_atlas_view(); } -void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) { +void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(const String &p_what) { if (p_what == "texture" && !atlas_source_proxy_object->get("texture").is_null()) { atlases_to_auto_create_tiles.clear(); atlases_to_auto_create_tiles.append(tile_set_atlas_source); @@ -2115,7 +2115,7 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) } } -void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { +void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 322de81045..34077a55ad 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -153,7 +153,7 @@ private: EditorInspector *tile_inspector = nullptr; Label *tile_inspector_no_tile_selected_label = nullptr; String selected_property; - void _inspector_property_selected(String p_property); + void _inspector_property_selected(const String &p_property); TileSetAtlasSourceProxyObject *atlas_source_proxy_object = nullptr; EditorInspector *atlas_source_inspector = nullptr; @@ -229,7 +229,7 @@ private: // Selection. RBSet<TileSelection> selection; - void _set_selection_from_array(Array p_selection); + void _set_selection_from_array(const Array &p_selection); Array _get_selection_as_array(); // A control on the tile atlas to draw and handle input events. @@ -283,10 +283,10 @@ private: void _cleanup_outside_tiles(); void _tile_set_changed(); - void _tile_proxy_object_changed(String p_what); - void _atlas_source_proxy_object_changed(String p_what); + void _tile_proxy_object_changed(const String &p_what); + void _atlas_source_proxy_object_changed(const String &p_what); - void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); + void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value); protected: void _notification(int p_what); diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 06fcfbfb41..fe02e3096c 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -458,7 +458,7 @@ void TileSetEditor::_tab_changed(int p_tab_changed) { patterns_item_list->set_visible(p_tab_changed == 1); } -void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { +void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); @@ -668,7 +668,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_ } } -void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { +void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value) { EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); ERR_FAIL_NULL(undo_redo_man); diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index 68ab046ecf..106be5acbd 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -108,8 +108,8 @@ private: void _tile_set_changed(); void _tab_changed(int p_tab_changed); - void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos); - void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); + void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos); + void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value); protected: void _notification(int p_what); diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 1529ddadb6..e0151351b5 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -214,7 +214,7 @@ void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_bind_methods() ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what"))); } -void TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed(String p_what) { +void TileSetScenesCollectionSourceEditor::_scenes_collection_source_proxy_object_changed(const String &p_what) { if (p_what == "id") { emit_signal(SNAME("source_id_changed"), scenes_collection_source_proxy_object->get_id()); } @@ -224,7 +224,7 @@ void TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_cha tile_set_scenes_collection_source_changed_needs_update = true; } -void TileSetScenesCollectionSourceEditor::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) { +void TileSetScenesCollectionSourceEditor::_scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_ud) { int index = p_ud; if (index >= 0 && index < scene_tiles_list->get_item_count()) { diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h index 5527685b24..b969421b29 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h @@ -118,8 +118,8 @@ private: EditorFileDialog *scene_select_dialog = nullptr; void _tile_set_scenes_collection_source_changed(); - void _scenes_collection_source_proxy_object_changed(String p_what); - void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud); + void _scenes_collection_source_proxy_object_changed(const String &p_what); + void _scene_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_ud); void _scenes_list_item_activated(int p_index); void _source_add_pressed(); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index e7bf812a6c..fb31ace2e0 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -69,9 +69,6 @@ void TilesEditorUtils::_thread_func(void *ud) { } void TilesEditorUtils::_thread() { - CallQueue queue; - MessageQueue::set_thread_singleton_override(&queue); - pattern_thread_exited.clear(); while (!pattern_thread_exit.is_set()) { pattern_preview_sem.wait(); @@ -131,8 +128,6 @@ void TilesEditorUtils::_thread() { // Add the viewport at the last moment to avoid rendering too early. callable_mp((Node *)EditorNode::get_singleton(), &Node::add_child).call_deferred(viewport, false, Node::INTERNAL_MODE_DISABLED); - MessageQueue::get_singleton()->flush(); - RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorUtils *>(this), &TilesEditorUtils::_preview_frame_started), Object::CONNECT_ONE_SHOT); pattern_preview_done.wait(); @@ -145,11 +140,7 @@ void TilesEditorUtils::_thread() { viewport->queue_free(); } } - - MessageQueue::get_singleton()->flush(); } - - MessageQueue::get_singleton()->flush(); pattern_thread_exited.set(); } diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 06526fea28..86c7e31740 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -144,7 +144,7 @@ void VersionControlEditorPlugin::_set_credentials() { EditorSettings::get_singleton()->set_setting("version_control/ssh_private_key_path", ssh_private_key); } -bool VersionControlEditorPlugin::_load_plugin(String p_name) { +bool VersionControlEditorPlugin::_load_plugin(const String &p_name) { Object *extension_instance = ClassDB::instantiate(p_name); ERR_FAIL_NULL_V_MSG(extension_instance, false, "Received a nullptr VCS extension instance during construction."); @@ -168,7 +168,7 @@ bool VersionControlEditorPlugin::_load_plugin(String p_name) { return true; } -void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) { +void VersionControlEditorPlugin::_update_set_up_warning(const String &p_new_text) { bool empty_settings = set_up_username->get_text().strip_edges().is_empty() && set_up_password->get_text().is_empty() && set_up_ssh_public_key_path->get_text().strip_edges().is_empty() && @@ -305,15 +305,15 @@ void VersionControlEditorPlugin::_remote_selected(int p_index) { _refresh_remote_list(); } -void VersionControlEditorPlugin::_ssh_public_key_selected(String p_path) { +void VersionControlEditorPlugin::_ssh_public_key_selected(const String &p_path) { set_up_ssh_public_key_path->set_text(p_path); } -void VersionControlEditorPlugin::_ssh_private_key_selected(String p_path) { +void VersionControlEditorPlugin::_ssh_private_key_selected(const String &p_path) { set_up_ssh_private_key_path->set_text(p_path); } -void VersionControlEditorPlugin::_popup_file_dialog(Variant p_file_dialog_variant) { +void VersionControlEditorPlugin::_popup_file_dialog(const Variant &p_file_dialog_variant) { FileDialog *file_dialog = Object::cast_to<FileDialog>(p_file_dialog_variant); ERR_FAIL_NULL(file_dialog); @@ -345,11 +345,11 @@ void VersionControlEditorPlugin::_create_remote() { _refresh_remote_list(); } -void VersionControlEditorPlugin::_update_branch_create_button(String p_new_text) { +void VersionControlEditorPlugin::_update_branch_create_button(const String &p_new_text) { branch_create_ok->set_disabled(p_new_text.strip_edges().is_empty()); } -void VersionControlEditorPlugin::_update_remote_create_button(String p_new_text) { +void VersionControlEditorPlugin::_update_remote_create_button(const String &p_new_text) { remote_create_ok->set_disabled(p_new_text.strip_edges().is_empty()); } @@ -384,7 +384,7 @@ void VersionControlEditorPlugin::_refresh_stage_area() { version_commit_dock->set_name(commit_tab_title); } -void VersionControlEditorPlugin::_discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change) { +void VersionControlEditorPlugin::_discard_file(const String &p_file_path, EditorVCSInterface::ChangeType p_change) { CHECK_PLUGIN_INITIALIZED(); if (p_change == EditorVCSInterface::CHANGE_TYPE_NEW) { @@ -414,7 +414,7 @@ void VersionControlEditorPlugin::_discard_all() { _refresh_stage_area(); } -void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change) { +void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, const String &p_file_path, EditorVCSInterface::ChangeType p_change) { String change_text = p_file_path + " (" + change_type_to_strings[p_change] + ")"; TreeItem *new_item = p_tree->create_item(); diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index ca55b86578..8ecb7c5029 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -142,15 +142,15 @@ private: void _initialize_vcs(); void _set_vcs_ui_state(bool p_enabled); void _set_credentials(); - void _ssh_public_key_selected(String p_path); - void _ssh_private_key_selected(String p_path); + void _ssh_public_key_selected(const String &p_path); + void _ssh_private_key_selected(const String &p_path); void _populate_available_vcs_names(); void _update_remotes_list(); - void _update_set_up_warning(String p_new_text); + void _update_set_up_warning(const String &p_new_text); void _update_opened_tabs(); void _update_extra_options(); - bool _load_plugin(String p_name); + bool _load_plugin(const String &p_name); void _pull(); void _push(); @@ -172,8 +172,8 @@ private: void _item_activated(Object *p_tree); void _create_branch(); void _create_remote(); - void _update_branch_create_button(String p_new_text); - void _update_remote_create_button(String p_new_text); + void _update_branch_create_button(const String &p_new_text); + void _update_remote_create_button(const String &p_new_text); void _branch_item_selected(int p_index); void _remote_selected(int p_index); void _remove_branch(); @@ -183,16 +183,16 @@ private: void _move_item(Tree *p_tree, TreeItem *p_itme); void _display_diff_split_view(List<EditorVCSInterface::DiffLine> &p_diff_content); void _display_diff_unified_view(List<EditorVCSInterface::DiffLine> &p_diff_content); - void _discard_file(String p_file_path, EditorVCSInterface::ChangeType p_change); + void _discard_file(const String &p_file_path, EditorVCSInterface::ChangeType p_change); void _cell_button_pressed(Object *p_item, int p_column, int p_id, int p_mouse_button_index); - void _add_new_item(Tree *p_tree, String p_file_path, EditorVCSInterface::ChangeType p_change); + void _add_new_item(Tree *p_tree, const String &p_file_path, EditorVCSInterface::ChangeType p_change); void _update_commit_button(); void _commit_message_gui_input(const Ref<InputEvent> &p_event); void _extra_option_selected(int p_index); bool _is_staging_area_empty(); String _get_date_string_from(int64_t p_unix_timestamp, int64_t p_offset_minutes) const; void _create_vcs_metadata_files(); - void _popup_file_dialog(Variant p_file_dialog_variant); + void _popup_file_dialog(const Variant &p_file_dialog_variant); void _toggle_vcs_integration(bool p_toggled); friend class EditorVCSInterface; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 4261f6f32e..f5fadc2f1b 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -194,7 +194,7 @@ void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_ add_node(p_type, p_node_id, true); } -void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value) { +void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) { if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { return; } @@ -1211,7 +1211,7 @@ void VisualShaderEditedProperty::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property"); } -void VisualShaderEditedProperty::set_edited_property(Variant p_variant) { +void VisualShaderEditedProperty::set_edited_property(const Variant &p_variant) { edited_property = p_variant; } @@ -3116,7 +3116,7 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vector<Vari } } -void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, String p_resource_path, int p_node_idx) { +void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, const String &p_resource_path, int p_node_idx) { ERR_FAIL_INDEX(p_idx, add_options.size()); VisualShader::Type type = get_current_shader_type(); @@ -3799,7 +3799,7 @@ void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_ undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from); } -void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) { +void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) { Ref<VisualShaderNode> node = visual_shader->get_node(p_type_id, p_node_id); ERR_FAIL_COND(!node.is_valid()); ERR_FAIL_COND(!node->has_method("set_constant")); @@ -3809,7 +3809,7 @@ void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_no } } -void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) { +void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port) { Ref<VisualShaderNodeParameter> parameter = visual_shader->get_node(p_type_id, p_node_id); ERR_FAIL_COND(!parameter.is_valid()); @@ -4715,7 +4715,7 @@ void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) { _update_graph(); } -void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) { +void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name) { String prev_name = p_input->get_input_name(); if (p_name == prev_name) { @@ -4787,7 +4787,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, undo_redo_man->commit_action(); } -void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name) { +void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, const String &p_name) { String prev_name = p_parameter_ref->get_parameter_name(); if (p_name == prev_name) { @@ -4831,7 +4831,7 @@ void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParamete undo_redo_man->commit_action(); } -void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name) { +void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, const String &p_name) { String prev_name = p_varying->get_varying_name(); if (p_name == prev_name) { @@ -6780,7 +6780,7 @@ public: } } - void setup(VisualShaderEditor *p_editor, Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, const HashMap<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) { + void setup(VisualShaderEditor *p_editor, Ref<Resource> p_parent_resource, const Vector<EditorProperty *> &p_properties, const Vector<StringName> &p_names, const HashMap<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) { editor = p_editor; parent_resource = p_parent_resource; updating = false; diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2575866b10..683a6bc883 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -127,7 +127,7 @@ public: void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid); void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position); void refresh_node_ports(VisualShader::Type p_type, int p_node); - void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value); + void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value); void update_parameter_refs(); void set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name); void update_curve(int p_node_id); @@ -154,7 +154,7 @@ protected: static void _bind_methods(); public: - void set_edited_property(Variant p_variant); + void set_edited_property(const Variant &p_variant); Variant get_edited_property() const; VisualShaderEditedProperty() {} @@ -360,7 +360,7 @@ class VisualShaderEditor : public VBoxContainer { void _draw_color_over_button(Object *p_obj, Color p_color); void _setup_node(VisualShaderNode *p_node, const Vector<Variant> &p_ops); - void _add_node(int p_idx, const Vector<Variant> &p_ops, String p_resource_path = "", int p_node_idx = -1); + void _add_node(int p_idx, const Vector<Variant> &p_ops, const String &p_resource_path = "", int p_node_idx = -1); void _add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type); void _remove_varying(const String &p_name); void _update_options_menu(); @@ -416,8 +416,8 @@ class VisualShaderEditor : public VBoxContainer { void _convert_constants_to_parameters(bool p_vice_versa); void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to); - void _update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port); - void _update_parameter(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port); + void _update_constant(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port); + void _update_parameter(VisualShader::Type p_type_id, int p_node_id, const Variant &p_var, int p_preview_port); void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position); void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position); @@ -470,9 +470,9 @@ class VisualShaderEditor : public VBoxContainer { void _mode_selected(int p_id); void _custom_mode_toggled(bool p_enabled); - void _input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name); - void _parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name); - void _varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name); + void _input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name); + void _parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, const String &p_name); + void _varying_select_item(Ref<VisualShaderNodeVarying> p_varying, const String &p_name); void _float_constant_selected(int p_which); diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp index 3804bd8d5b..b85099ca2e 100644 --- a/editor/pot_generator.cpp +++ b/editor/pot_generator.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/error/error_macros.h" +#include "editor/editor_translation.h" #include "editor/editor_translation_parser.h" #include "plugins/packed_scene_translation_parser_plugin.h" @@ -65,6 +66,8 @@ void POTGenerator::generate_pot(const String &p_file) { // Clear all_translation_strings of the previous round. all_translation_strings.clear(); + List<StringName> extractable_msgids = get_extractable_message_list(); + // Collect all translatable strings according to files order in "POT Generation" setting. for (int i = 0; i < files.size(); i++) { Vector<String> msgids; @@ -88,6 +91,12 @@ void POTGenerator::generate_pot(const String &p_file) { } } + if (GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")) { + for (int i = 0; i < extractable_msgids.size(); i++) { + _add_new_msgid(extractable_msgids[i], "", "", ""); + } + } + _write_to_pot(p_file); } @@ -136,7 +145,9 @@ void POTGenerator::_write_to_pot(const String &p_file) { // Write file locations. for (const String &E : locations) { - file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n")); + if (!E.is_empty()) { + file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n")); + } } // Write context. diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index c8197e2246..b295e5733e 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -47,15 +47,15 @@ #include "modules/regex/regex.h" // Find "OS.set_property(x)", capturing x into $1. -static String make_regex_gds_os_property_set(String name_set) { +static String make_regex_gds_os_property_set(const String &name_set) { return String("\\bOS\\.") + name_set + "\\s*\\((.*)\\)"; } // Find "OS.property = x", capturing x into $1 or $2. -static String make_regex_gds_os_property_assign(String name) { +static String make_regex_gds_os_property_assign(const String &name) { return String("\\bOS\\.") + name + "\\s*=\\s*([^#]+)"; } // Find "OS.property" OR "OS.get_property()" / "OS.is_property()". -static String make_regex_gds_os_property_get(String name, String get) { +static String make_regex_gds_os_property_get(const String &name, const String &get) { return String("\\bOS\\.(") + get + "_)?" + name + "(\\s*\\(\\s*\\))?"; } @@ -746,7 +746,7 @@ Vector<SourceLine> ProjectConverter3To4::split_lines(const String &text) { } // Test expected results of gdscript -bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { +bool ProjectConverter3To4::test_conversion_gdscript_builtin(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), const String &what, const RegExContainer ®_container, bool builtin_script) { Vector<SourceLine> got = split_lines(name); (this->*func)(got, reg_container, builtin_script); @@ -756,7 +756,7 @@ bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String return true; } -bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), String what, const RegExContainer ®_container) { +bool ProjectConverter3To4::test_conversion_with_regex(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), const String &what, const RegExContainer ®_container) { Vector<SourceLine> got = split_lines(name); (this->*func)(got, reg_container); @@ -766,7 +766,7 @@ bool ProjectConverter3To4::test_conversion_with_regex(String name, String expect return true; } -bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what) { +bool ProjectConverter3To4::test_conversion_basic(const String &name, const String &expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, const String &what) { Vector<SourceLine> got = split_lines(name); rename_common(array, regex_cache, got); @@ -1638,7 +1638,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector< return found_renames; } -bool ProjectConverter3To4::contains_function_call(String &line, String function) const { +bool ProjectConverter3To4::contains_function_call(const String &line, const String &function) const { // We want to convert the function only if it is completely standalone. // For example, when we search for "connect(", we don't want to accidentally convert "reconnect(". if (!line.contains(function)) { @@ -2834,7 +2834,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_input_map_scancode(Vector< return found_renames; } -void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, String from, String to) { +void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, const String &from, const String &to) { RegEx reg = RegEx(String("\\b") + from + "\\b"); CRASH_COND(!reg.is_valid()); for (SourceLine &source_line : source_lines) { @@ -2849,7 +2849,7 @@ void ProjectConverter3To4::custom_rename(Vector<SourceLine> &source_lines, Strin } }; -Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) { +Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, const String &from, const String &to) { Vector<String> found_renames; RegEx reg = RegEx(String("\\b") + from + "\\b"); diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index 2afd0a24e8..0f90028bc8 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -101,8 +101,8 @@ class ProjectConverter3To4 { void rename_joypad_buttons_and_axes(Vector<SourceLine> &source_lines, const RegExContainer ®_container); Vector<String> check_for_rename_joypad_buttons_and_axes(Vector<String> &lines, const RegExContainer ®_container); - void custom_rename(Vector<SourceLine> &source_lines, String from, String to); - Vector<String> check_for_custom_rename(Vector<String> &lines, String from, String to); + void custom_rename(Vector<SourceLine> &source_lines, const String &from, const String &to); + Vector<String> check_for_custom_rename(Vector<String> &lines, const String &from, const String &to); void rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<SourceLine> &source_lines); Vector<String> check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines); @@ -114,7 +114,7 @@ class ProjectConverter3To4 { String connect_arguments(const Vector<String> &line, int from, int to = -1) const; String get_starting_space(const String &line) const; String get_object_of_execution(const String &line) const; - bool contains_function_call(String &line, String function) const; + bool contains_function_call(const String &line, const String &function) const; String line_formatter(int current_line, String from, String to, String line); String simple_line_formatter(int current_line, String old_line, String line); @@ -122,9 +122,9 @@ class ProjectConverter3To4 { Vector<SourceLine> split_lines(const String &text); bool test_single_array(const char *array[][2], bool ignore_second_check = false); - bool test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); - bool test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), String what, const RegExContainer ®_container); - bool test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what); + bool test_conversion_gdscript_builtin(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &, bool), const String &what, const RegExContainer ®_container, bool builtin); + bool test_conversion_with_regex(const String &name, const String &expected, void (ProjectConverter3To4::*func)(Vector<SourceLine> &, const RegExContainer &), const String &what, const RegExContainer ®_container); + bool test_conversion_basic(const String &name, const String &expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, const String &what); bool test_array_names(); bool test_conversion(RegExContainer ®_container); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 6f7d571792..4187bf5a32 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -38,6 +38,7 @@ #include "core/io/stream_peer_tls.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/version.h" #include "editor/editor_about.h" #include "editor/editor_settings.h" @@ -1350,7 +1351,13 @@ ProjectManager::ProjectManager() { // Fade the version label to be less prominent, but still readable. version_btn->set_self_modulate(Color(1, 1, 1, 0.6)); version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - version_btn->set_tooltip_text(TTR("Click to copy the version information.")); + String build_date; + if (VERSION_TIMESTAMP > 0) { + build_date = Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC"; + } else { + build_date = TTR("(unknown)"); + } + version_btn->set_tooltip_text(vformat(TTR("Git commit date: %s\nClick to copy the version information."), build_date)); version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed)); footer_bar->add_child(version_btn); } diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 367dd324c2..6a43d60cc7 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -380,7 +380,7 @@ void RenameDialog::_update_preview_int(int new_value) { _update_preview(); } -void RenameDialog::_update_preview(String new_text) { +void RenameDialog::_update_preview(const String &new_text) { if (lock_preview_update || preview_node == nullptr) { return; } @@ -637,7 +637,7 @@ bool RenameDialog::_is_main_field(LineEdit *line_edit) { (line_edit == lne_search || line_edit == lne_replace || line_edit == lne_prefix || line_edit == lne_suffix); } -void RenameDialog::_insert_text(String text) { +void RenameDialog::_insert_text(const String &text) { LineEdit *focus_owner = Object::cast_to<LineEdit>(get_viewport()->gui_get_focus_owner()); if (_is_main_field(focus_owner)) { diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h index 6821cab982..37d159b4e2 100644 --- a/editor/rename_dialog.h +++ b/editor/rename_dialog.h @@ -52,7 +52,7 @@ class RenameDialog : public ConfirmationDialog { virtual void ok_pressed() override { rename(); }; void _cancel_pressed() {} void _features_toggled(bool pressed); - void _insert_text(String text); + void _insert_text(const String &text); void _update_substitute(); bool _is_main_field(LineEdit *line_edit); @@ -61,7 +61,7 @@ class RenameDialog : public ConfirmationDialog { String _substitute(const String &subject, const Node *node, int count); String _regex(const String &pattern, const String &subject, const String &replacement); String _postprocess(const String &subject); - void _update_preview(String new_text = ""); + void _update_preview(const String &new_text = ""); void _update_preview_int(int new_value = 0); static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f8e0628072..66b82ee648 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1356,7 +1356,7 @@ void SceneTreeDock::_property_selected(int p_idx) { property_drop_node = nullptr; } -void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) { +void SceneTreeDock::_perform_property_drop(Node *p_node, const String &p_property, Ref<Resource> p_res) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Set %s"), p_property)); undo_redo->add_do_property(p_node, p_property, p_res); @@ -2957,7 +2957,7 @@ void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected) { scene_tree->set_selected(p_node, p_emit_selected); } -void SceneTreeDock::_new_scene_from(String p_file) { +void SceneTreeDock::_new_scene_from(const String &p_file) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.size() != 1) { @@ -3105,7 +3105,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) { } } -void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_type) { +void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, int p_type) { Node *node = get_node(p_to); ERR_FAIL_NULL(node); @@ -3156,7 +3156,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ } } -void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { +void SceneTreeDock::_script_dropped(const String &p_file, NodePath p_to) { Ref<Script> scr = ResourceLoader::load(p_file); ERR_FAIL_COND(!scr.is_valid()); Node *n = get_node(p_to); @@ -3206,7 +3206,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { } } -void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) { +void SceneTreeDock::_nodes_dragged(const Array &p_nodes, NodePath p_to, int p_type) { if (!_validate_no_foreign()) { return; } @@ -3581,7 +3581,7 @@ void SceneTreeDock::set_filter(const String &p_filter) { scene_tree->set_filter(p_filter); } -void SceneTreeDock::save_branch_to_file(String p_directory) { +void SceneTreeDock::save_branch_to_file(const String &p_directory) { new_scene_from_dialog->set_current_dir(p_directory); _tool_selected(TOOL_NEW_SCENE_FROM); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index a6d2eab2e2..4c1eb5715a 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -139,7 +139,7 @@ class SceneTreeDock : public VBoxContainer { Node *property_drop_node = nullptr; String resource_drop_path; - void _perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res); + void _perform_property_drop(Node *p_node, const String &p_property, Ref<Resource> p_res); EditorData *editor_data = nullptr; EditorSelection *editor_selection = nullptr; @@ -238,7 +238,7 @@ class SceneTreeDock : public VBoxContainer { virtual void shortcut_input(const Ref<InputEvent> &p_event) override; void _scene_tree_gui_input(Ref<InputEvent> p_event); - void _new_scene_from(String p_file); + void _new_scene_from(const String &p_file); void _set_node_owner_recursive(Node *p_node, Node *p_owner, const HashMap<const Node *, Node *> &p_inverse_duplimap); bool _validate_no_foreign(); @@ -251,9 +251,9 @@ class SceneTreeDock : public VBoxContainer { void _normalize_drop(Node *&to_node, int &to_pos, int p_type); - void _nodes_dragged(Array p_nodes, NodePath p_to, int p_type); - void _files_dropped(Vector<String> p_files, NodePath p_to, int p_type); - void _script_dropped(String p_file, NodePath p_to); + void _nodes_dragged(const Array &p_nodes, NodePath p_to, int p_type); + void _files_dropped(const Vector<String> &p_files, NodePath p_to, int p_type); + void _script_dropped(const String &p_file, NodePath p_to); void _quick_open(); void _tree_rmb(const Vector2 &p_menu_pos); @@ -306,7 +306,7 @@ protected: public: String get_filter(); void set_filter(const String &p_filter); - void save_branch_to_file(String p_directory); + void save_branch_to_file(const String &p_directory); void _focus_node(); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 1da8fa49b4..d111fe8f36 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -46,7 +46,7 @@ #include "scene/gui/grid_container.h" #include "scene/gui/line_edit.h" -static String _get_parent_class_of_script(String p_path) { +static String _get_parent_class_of_script(const String &p_path) { if (!ResourceLoader::exists(p_path, "Script")) { return "Object"; // A script eventually inherits from Object. } @@ -73,7 +73,7 @@ static String _get_parent_class_of_script(String p_path) { return _get_parent_class_of_script(base->get_path()); } -static Vector<String> _get_hierarchy(String p_class_name) { +static Vector<String> _get_hierarchy(const String &p_class_name) { Vector<String> hierarchy; String class_name = p_class_name; diff --git a/editor/themes/editor_color_map.cpp b/editor/themes/editor_color_map.cpp index 0b3a237244..99bcf109d0 100644 --- a/editor/themes/editor_color_map.cpp +++ b/editor/themes/editor_color_map.cpp @@ -33,7 +33,7 @@ HashMap<Color, Color> EditorColorMap::color_conversion_map; HashSet<StringName> EditorColorMap::color_conversion_exceptions; -void EditorColorMap::add_conversion_color_pair(const String p_from_color, const String p_to_color) { +void EditorColorMap::add_conversion_color_pair(const String &p_from_color, const String &p_to_color) { color_conversion_map[Color::html(p_from_color)] = Color::html(p_to_color); } diff --git a/editor/themes/editor_color_map.h b/editor/themes/editor_color_map.h index 4debd37faf..c1176749f2 100644 --- a/editor/themes/editor_color_map.h +++ b/editor/themes/editor_color_map.h @@ -47,7 +47,7 @@ class EditorColorMap { static HashSet<StringName> color_conversion_exceptions; public: - static void add_conversion_color_pair(const String p_from_color, const String p_to_color); + static void add_conversion_color_pair(const String &p_from_color, const String &p_to_color); static void add_conversion_exception(const StringName &p_icon_name); static HashMap<Color, Color> &get_color_conversion_map() { return color_conversion_map; }; diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index 4a67bd6b31..6849d87923 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -1035,8 +1035,8 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_color("font_hovered_color", "ItemList", p_config.mono_color); p_theme->set_color("font_selected_color", "ItemList", p_config.mono_color); p_theme->set_color("font_outline_color", "ItemList", p_config.font_outline_color); - p_theme->set_color("guide_color", "ItemList", guide_color); - p_theme->set_constant("v_separation", "ItemList", p_config.forced_even_separation * 0.5 * EDSCALE); + p_theme->set_color("guide_color", "ItemList", Color(1, 1, 1, 0)); + p_theme->set_constant("v_separation", "ItemList", p_config.forced_even_separation * EDSCALE); p_theme->set_constant("h_separation", "ItemList", (p_config.increased_margin + 2) * EDSCALE); p_theme->set_constant("icon_margin", "ItemList", (p_config.increased_margin + 2) * EDSCALE); p_theme->set_constant("line_separation", "ItemList", p_config.separation_margin); @@ -1279,6 +1279,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the p_theme->set_icon("forward_folder", "FileDialog", p_theme->get_icon(SNAME("Forward"), EditorStringName(EditorIcons))); p_theme->set_icon("reload", "FileDialog", p_theme->get_icon(SNAME("Reload"), EditorStringName(EditorIcons))); p_theme->set_icon("toggle_hidden", "FileDialog", p_theme->get_icon(SNAME("GuiVisibilityVisible"), EditorStringName(EditorIcons))); + p_theme->set_icon("create_folder", "FileDialog", p_theme->get_icon(SNAME("FolderCreate"), EditorStringName(EditorIcons))); // Use a different color for folder icons to make them easier to distinguish from files. // On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color. p_theme->set_color("folder_icon_color", "FileDialog", (p_config.dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(p_config.accent_color, 0.7)); @@ -1748,10 +1749,14 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme Ref<StyleBoxFlat> menu_transparent_style = p_config.button_style->duplicate(); menu_transparent_style->set_bg_color(Color(1, 1, 1, 0)); menu_transparent_style->set_border_width_all(0); + Ref<StyleBoxFlat> main_screen_button_transparent = menu_transparent_style->duplicate(); + for (int i = 0; i < 4; i++) { + menu_transparent_style->set_content_margin((Side)i, p_config.button_style->get_margin((Side)i) + p_config.button_style->get_border_width((Side)i)); + } p_theme->set_stylebox("MenuTransparent", EditorStringName(EditorStyles), menu_transparent_style); p_theme->set_stylebox("MenuHover", EditorStringName(EditorStyles), p_config.button_style_hover); - p_theme->set_stylebox("normal", "MainScreenButton", menu_transparent_style); - p_theme->set_stylebox("pressed", "MainScreenButton", menu_transparent_style); + p_theme->set_stylebox("normal", "MainScreenButton", main_screen_button_transparent); + p_theme->set_stylebox("pressed", "MainScreenButton", main_screen_button_transparent); p_theme->set_stylebox("hover_pressed", "MainScreenButton", p_config.button_style_hover); // Run bar. @@ -1810,11 +1815,14 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme // Flat button variations. { Ref<StyleBoxEmpty> style_flat_button = make_empty_stylebox(); + Ref<StyleBoxFlat> style_flat_button_hover = p_config.button_style_hover->duplicate(); + Ref<StyleBoxFlat> style_flat_button_pressed = p_config.button_style_pressed->duplicate(); + for (int i = 0; i < 4; i++) { style_flat_button->set_content_margin((Side)i, p_config.button_style->get_margin((Side)i) + p_config.button_style->get_border_width((Side)i)); + style_flat_button_hover->set_content_margin((Side)i, p_config.button_style->get_margin((Side)i) + p_config.button_style->get_border_width((Side)i)); + style_flat_button_pressed->set_content_margin((Side)i, p_config.button_style->get_margin((Side)i) + p_config.button_style->get_border_width((Side)i)); } - - Ref<StyleBoxFlat> style_flat_button_pressed = p_config.button_style_pressed->duplicate(); Color flat_pressed_color = p_config.dark_color_1.lightened(0.24).lerp(p_config.accent_color, 0.2) * Color(0.8, 0.8, 0.8, 0.85); if (p_config.dark_theme) { flat_pressed_color = p_config.dark_color_1.lerp(p_config.accent_color, 0.12) * Color(0.6, 0.6, 0.6, 0.85); @@ -1822,12 +1830,12 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme style_flat_button_pressed->set_bg_color(flat_pressed_color); p_theme->set_stylebox("normal", "FlatButton", style_flat_button); - p_theme->set_stylebox("hover", "FlatButton", p_config.button_style_hover); + p_theme->set_stylebox("hover", "FlatButton", style_flat_button_hover); p_theme->set_stylebox("pressed", "FlatButton", style_flat_button_pressed); p_theme->set_stylebox("disabled", "FlatButton", style_flat_button); p_theme->set_stylebox("normal", "FlatMenuButton", style_flat_button); - p_theme->set_stylebox("hover", "FlatMenuButton", p_config.button_style_hover); + p_theme->set_stylebox("hover", "FlatMenuButton", style_flat_button_hover); p_theme->set_stylebox("pressed", "FlatMenuButton", style_flat_button_pressed); p_theme->set_stylebox("disabled", "FlatMenuButton", style_flat_button); diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp index b2b237269a..b810ec7fa2 100644 --- a/editor/window_wrapper.cpp +++ b/editor/window_wrapper.cpp @@ -286,7 +286,7 @@ void WindowWrapper::enable_window_on_screen(int p_screen, bool p_auto_scale) { } } -void WindowWrapper::set_window_title(const String p_title) { +void WindowWrapper::set_window_title(const String &p_title) { if (!is_window_available()) { return; } diff --git a/editor/window_wrapper.h b/editor/window_wrapper.h index e8fcb13c92..a07e95f09e 100644 --- a/editor/window_wrapper.h +++ b/editor/window_wrapper.h @@ -78,7 +78,7 @@ public: void restore_window_from_saved_position(const Rect2 p_window_rect, int p_screen, const Rect2 p_screen_rect); void enable_window_on_screen(int p_screen = -1, bool p_auto_scale = false); - void set_window_title(const String p_title); + void set_window_title(const String &p_title); void set_margins_enabled(bool p_enabled); WindowWrapper(); diff --git a/main/main.cpp b/main/main.cpp index c520ebecd3..91ccbe6766 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -393,6 +393,23 @@ void finalize_theme_db() { #define MAIN_PRINT(m_txt) #endif +void Main::print_header(bool p_rich) { + if (VERSION_TIMESTAMP > 0) { + // Version timestamp available. + if (p_rich) { + print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - \u001b[4m" + String(VERSION_WEBSITE)); + } else { + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - " + String(VERSION_WEBSITE)); + } + } else { + if (p_rich) { + print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE)); + } else { + print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + } + } +} + /** * Prints a copyright notice in the command-line help with colored text. A newline is * automatically added at the end. @@ -463,7 +480,7 @@ void Main::print_help_option(const char *p_option, const char *p_description, CL } void Main::print_help(const char *p_binary) { - print_line("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE) + "\u001b[0m"); + print_header(true); print_help_copyright("Free and open source software under the terms of the MIT license."); print_help_copyright("(c) 2014-present Godot Engine contributors. (c) 2007-present Juan Linietsky, Ariel Manzur."); @@ -2468,8 +2485,8 @@ Error Main::setup2() { Thread::make_main_thread(); // Make whatever thread call this the main thread. set_current_thread_safe_for_nodes(true); - // Print engine name and version - Engine::get_singleton()->print_header(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + // Don't use rich formatting to prevent ANSI escape codes from being written to log files. + print_header(false); #ifdef TOOLS_ENABLED if (editor || project_manager || cmdline_tool) { diff --git a/main/main.h b/main/main.h index 09cc0feae6..062af73d57 100644 --- a/main/main.h +++ b/main/main.h @@ -46,6 +46,7 @@ class Main { CLI_OPTION_AVAILABILITY_HIDDEN, }; + static void print_header(bool p_rich); static void print_help_copyright(const char *p_notice); static void print_help_title(const char *p_title); static void print_help_option(const char *p_option, const char *p_description, CLIOptionAvailability p_availability = CLI_OPTION_AVAILABILITY_TEMPLATE_RELEASE); diff --git a/methods.py b/methods.py index 69d8df1d72..c85e6825da 100644 --- a/methods.py +++ b/methods.py @@ -209,6 +209,18 @@ def get_version_info(module_version_string="", silent=False): githash = head version_info["git_hash"] = githash + # Fallback to 0 as a timestamp (will be treated as "unknown" in the engine). + version_info["git_timestamp"] = 0 + + # Get the UNIX timestamp of the build commit. + if os.path.exists(".git"): + try: + version_info["git_timestamp"] = subprocess.check_output( + ["git", "log", "-1", "--pretty=format:%ct", githash] + ).decode("utf-8") + except (subprocess.CalledProcessError, OSError): + # `git` not found in PATH. + pass return version_info @@ -246,6 +258,7 @@ def generate_version_header(module_version_string=""): """/* THIS FILE IS GENERATED DO NOT EDIT */ #include "core/version.h" const char *const VERSION_HASH = "{git_hash}"; +const uint64_t VERSION_TIMESTAMP = {git_timestamp}; """.format( **version_info ) diff --git a/misc/hooks/README.md b/misc/hooks/README.md deleted file mode 100644 index 573f8fe350..0000000000 --- a/misc/hooks/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Git hooks for Godot Engine - -This folder contains Git hooks meant to be installed locally by Godot Engine -contributors to make sure they comply with our requirements. - -## List of hooks - -- Pre-commit hook for `clang-format`: Applies `clang-format` to the staged - files before accepting a commit; blocks the commit and generates a patch if - the style is not respected. - You may need to edit the file if your `clang-format` binary is not in the - `PATH`, or if you want to enable colored output with `pygmentize`. -- Pre-commit hook for `black`: Applies `black` to the staged Python files - before accepting a commit. -- Pre-commit hook for `make_rst`: Checks the class reference syntax using - `make_rst.py`. - -## Installation - -Copy all the files from this folder into your `.git/hooks` folder, and make -sure the hooks and helper scripts are executable. - -#### Linux/macOS - -The hooks rely on bash scripts and tools which should be in the system `PATH`, -so they should work out of the box on Linux/macOS. - -#### Windows - -##### clang-format -- Download LLVM for Windows (version 13 or later) from - <https://github.com/llvm/llvm-project/releases> -- Make sure LLVM is added to the `PATH` during installation - -##### black -- Python installation: make sure Python is added to the `PATH` -- Install `black` - in any console: `pip3 install black` - -## Custom hooks - -The pre-commit hook will run any other script in `.git/hooks` whose filename -matches `pre-commit-custom-*`, after the Godot ones. diff --git a/misc/hooks/asmessage.applescript b/misc/hooks/asmessage.applescript deleted file mode 100644 index 15ba94dc37..0000000000 --- a/misc/hooks/asmessage.applescript +++ /dev/null @@ -1,59 +0,0 @@ -on run argv - set vButtons to { "OK" } - set vButtonCodes to { 0 } - set vDbutton to "OK" - set vText to "" - set vTitle to "" - set vTimeout to -1 - - repeat with i from 1 to length of argv - try - set vArg to item i of argv - if vArg = "-buttons" then - set vButtonsAndCodes to my fSplit(item (i + 1) of argv, ",") - set vButtons to {} - set vButtonCodes to {} - repeat with j from 1 to length of vButtonsAndCodes - set vBtn to my fSplit(item j of vButtonsAndCodes, ":") - copy (item 1 of vBtn) to the end of the vButtons - copy (item 2 of vBtn) to the end of the vButtonCodes - end repeat - else if vArg = "-title" then - set vTitle to item (i + 1) of argv - else if vArg = "-center" then - -- not supported - else if vArg = "-default" then - set vDbutton to item (i + 1) of argv - else if vArg = "-geometry" then - -- not supported - else if vArg = "-nearmouse" then - -- not supported - else if vArg = "-timeout" then - set vTimeout to item (i + 1) of argv as integer - else if vArg = "-file" then - set vText to read (item (i + 1) of argv) as string - else if vArg = "-text" then - set vText to item (i + 1) of argv - end if - end try - end repeat - - set vDlg to display dialog vText buttons vButtons default button vDbutton with title vTitle giving up after vTimeout with icon stop - set vRet to button returned of vDlg - repeat with i from 1 to length of vButtons - set vBtn to item i of vButtons - if vBtn = vRet - return item i of vButtonCodes - end if - end repeat - - return 0 -end run - -on fSplit(vString, vDelimiter) - set oldDelimiters to AppleScript's text item delimiters - set AppleScript's text item delimiters to vDelimiter - set vArray to every text item of vString - set AppleScript's text item delimiters to oldDelimiters - return vArray -end fSplit diff --git a/misc/hooks/canonicalize_filename.sh b/misc/hooks/canonicalize_filename.sh deleted file mode 100755 index fe66999d8c..0000000000 --- a/misc/hooks/canonicalize_filename.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -# Provide the canonicalize filename (physical filename with out any symlinks) -# like the GNU version readlink with the -f option regardless of the version of -# readlink (GNU or BSD). - -# This file is part of a set of unofficial pre-commit hooks available -# at github. -# Link: https://github.com/githubbrowser/Pre-commit-hooks -# Contact: David Martin, david.martin.mailbox@googlemail.com - -########################################################### -# There should be no need to change anything below this line. - -# Canonicalize by recursively following every symlink in every component of the -# specified filename. This should reproduce the results of the GNU version of -# readlink with the -f option. -# -# Reference: https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac -canonicalize_filename () { - local target_file="$1" - local physical_directory="" - local result="" - - # Need to restore the working directory after work. - local working_dir="`pwd`" - - cd -- "$(dirname -- "$target_file")" - target_file="$(basename -- "$target_file")" - - # Iterate down a (possible) chain of symlinks - while [ -L "$target_file" ] - do - target_file="$(readlink -- "$target_file")" - cd -- "$(dirname -- "$target_file")" - target_file="$(basename -- "$target_file")" - done - - # Compute the canonicalized name by finding the physical path - # for the directory we're in and appending the target file. - physical_directory="`pwd -P`" - result="$physical_directory/$target_file" - - # restore the working directory after work. - cd -- "$working_dir" - - echo "$result" -} diff --git a/misc/hooks/pre-commit b/misc/hooks/pre-commit deleted file mode 100755 index 6359161260..0000000000 --- a/misc/hooks/pre-commit +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh -# Git pre-commit hook that runs multiple hooks specified in $HOOKS. -# Make sure this script is executable. Bypass hooks with git commit --no-verify. - -# This file is part of a set of unofficial pre-commit hooks available -# at github. -# Link: https://github.com/githubbrowser/Pre-commit-hooks -# Contact: David Martin, david.martin.mailbox@googlemail.com - - -########################################################### -# CONFIGURATION: -# pre-commit hooks to be executed. They should be in the same .git/hooks/ folder -# as this script. Hooks should return 0 if successful and nonzero to cancel the -# commit. They are executed in the order in which they are listed. -HOOKS="pre-commit-clang-format pre-commit-black pre-commit-make-rst" -HOOKS="$HOOKS $(find $(dirname -- "$0") -type f -name 'pre-commit-custom-*' -exec basename {} \;)" -########################################################### -# There should be no need to change anything below this line. - -. "$(dirname -- "$0")/canonicalize_filename.sh" - -# exit on error -set -e - -# Absolute path to this script, e.g. /home/user/bin/foo.sh -SCRIPT="$(canonicalize_filename "$0")" - -# Absolute path this script is in, thus /home/user/bin -SCRIPTPATH="$(dirname -- "$SCRIPT")" - - -for hook in $HOOKS -do - echo "Running hook: $hook" - # run hook if it exists - # if it returns with nonzero exit with 1 and thus abort the commit - if [ -f "$SCRIPTPATH/$hook" ]; then - "$SCRIPTPATH/$hook" - if [ $? != 0 ]; then - exit 1 - fi - else - echo "Error: file $hook not found." - echo "Aborting commit. Make sure the hook is in $SCRIPTPATH and executable." - echo "You can disable it by removing it from the list in $SCRIPT." - echo "You can skip all pre-commit hooks with --no-verify (not recommended)." - exit 1 - fi -done diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black deleted file mode 100755 index bbad6a690a..0000000000 --- a/misc/hooks/pre-commit-black +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env bash - -# git pre-commit hook that runs a black stylecheck. -# Based on pre-commit-clang-format. - -################################################################## -# SETTINGS -# Set path to black binary. -BLACK=`which black 2>/dev/null` -BLACK_OPTIONS="-l 120" - -# Remove any older patches from previous commits. Set to true or false. -DELETE_OLD_PATCHES=false - -# File types to parse. -FILE_NAMES="SConstruct SCsub" -FILE_EXTS=".py" - -# Use pygmentize instead of cat to parse diff with highlighting. -# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac) -PYGMENTIZE=`which pygmentize 2>/dev/null` -if [ ! -z "$PYGMENTIZE" ]; then - READER="pygmentize -l diff" -else - READER=cat -fi - -# Path to zenity -ZENITY=`which zenity 2>/dev/null` - -# Path to xmessage -XMSG=`which xmessage 2>/dev/null` - -# Path to powershell (Windows only) -PWSH=`which powershell 2>/dev/null` - -# Path to osascript (macOS only) -OSA=`which osascript 2>/dev/null` - -################################################################## -# There should be no need to change anything below this line. - -. "$(dirname -- "$0")/canonicalize_filename.sh" - -# exit on error -set -e - -# check whether the given file matches any of the set extensions -matches_name_or_extension() { - local filename=$(basename "$1") - local extension=".${filename##*.}" - - for name in $FILE_NAMES; do [[ "$name" == "$filename" ]] && return 0; done - for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done - - return 1 -} - -# necessary check for initial commit -if git rev-parse --verify HEAD >/dev/null 2>&1 ; then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -if [ ! -x "$BLACK" ] ; then - if [ ! -t 1 ] ; then - if [ -x "$ZENITY" ] ; then - $ZENITY --error --title="Error" --text="Error: black executable not found." - exit 1 - elif [ -x "$XMSG" ] ; then - $XMSG -center -title "Error" "Error: black executable not found." - exit 1 - elif [ -x "$OSA" ] ; then - asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" - $OSA "$asmessage" -center -title "Error" --text "Error: black executable not found." - exit 1 - elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" - $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found." - exit 1 - fi - fi - printf "Error: black executable not found.\n" - printf "Set the correct path in $(canonicalize_filename "$0").\n" - exit 1 -fi - -# create a random filename to store our generated patch -prefix="pre-commit-black" -suffix="$(date +%s)" -patch="/tmp/$prefix-$suffix.patch" - -# clean up any older black patches -$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch - -# create one patch containing all changes to the files -git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; -do - # ignore thirdparty files - if grep -q "thirdparty" <<< $file; then - continue; - fi - - # ignore file if not one of the names or extensions we handle - if ! matches_name_or_extension "$file"; then - continue; - fi - - # format our file with black, create a patch with diff and append it to our $patch - # The sed call is necessary to transform the patch from - # --- $file timestamp - # +++ $file timestamp - # to both lines working on the same file and having a/ and b/ prefix. - # Else it can not be applied with 'git apply'. - "$BLACK" "$BLACK_OPTIONS" --diff "$file" | \ - sed -e "1s|--- |--- a/|" -e "2s|+++ |+++ b/|" >> "$patch" -done - -# if no patch has been generated all is ok, clean up the file stub and exit -if [ ! -s "$patch" ] ; then - printf "Files in this commit comply with the black formatter rules.\n" - rm -f "$patch" - exit 0 -fi - -# a patch has been created, notify the user and exit -printf "\nThe following differences were found between the code to commit " -printf "and the black formatter rules:\n\n" - -if [ -t 1 ] ; then - $READER "$patch" - printf "\n" - # Allows us to read user input below, assigns stdin to keyboard - exec < /dev/tty - terminal="1" -else - cat "$patch" - printf "\n" - # Allows non zero zenity/powershell output - set +e - terminal="0" -fi - -while true; do - if [ $terminal = "0" ] ; then - if [ -x "$ZENITY" ] ; then - choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage") - if [ "$?" = "0" ] ; then - yn="Y" - else - if [ "$choice" = "Apply and stage" ] ; then - yn="S" - else - yn="N" - fi - fi - elif [ -x "$XMSG" ] ; then - $XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" - choice=$? - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - elif [ -x "$OSA" ] ; then - asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" - choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"` - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" - $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" - choice=$? - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - else - printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n" - exit 1 - fi - else - read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn - fi - case $yn in - [Yy] ) git apply $patch; - printf "The patch was applied. You can now stage the changes and commit again.\n\n"; - break - ;; - [Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n"; - printf "(may need to be called from the root directory of your repository)\n"; - printf "Aborting commit. Apply changes and commit again or skip checking with"; - printf " --no-verify (not recommended).\n\n"; - break - ;; - [Ss] ) git apply $patch; - git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; - do git add $file; - done - printf "The patch was applied and the changed files staged. You can now commit.\n\n"; - break - ;; - * ) echo "Please answer yes or no." - ;; - esac -done -exit 1 # we don't commit in any case diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format deleted file mode 100755 index eddbc59364..0000000000 --- a/misc/hooks/pre-commit-clang-format +++ /dev/null @@ -1,262 +0,0 @@ -#!/usr/bin/env bash - -# git pre-commit hook that runs a clang-format stylecheck. -# Features: -# - abort commit when commit does not comply with the style guidelines -# - create a patch of the proposed style changes -# Modifications for clang-format by rene.milk@wwu.de - -# This file is part of a set of unofficial pre-commit hooks available -# at github. -# Link: https://github.com/githubbrowser/Pre-commit-hooks -# Contact: David Martin, david.martin.mailbox@googlemail.com - -# Some quality of life modifications made for Godot Engine. - -################################################################## -# SETTINGS -# Set path to clang-format binary. -CLANG_FORMAT=`which clang-format 2>/dev/null` - -# Remove any older patches from previous commits. Set to true or false. -DELETE_OLD_PATCHES=false - -# Only parse files with the extensions in FILE_EXTS. Set to true or false. -# If false every changed file in the commit will be parsed with clang-format. -# If true only files matching one of the extensions are parsed with clang-format. -PARSE_EXTS=true - -# File types to parse. Only effective when PARSE_EXTS is true. -FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m .mm .inc .java .glsl" - -# Use pygmentize instead of cat to parse diff with highlighting. -# Install it with `pip install pygments` (Linux) or `easy_install Pygments` (Mac) -PYGMENTIZE=`which pygmentize 2>/dev/null` -if [ ! -z "$PYGMENTIZE" ]; then - READER="pygmentize -l diff" -else - READER=cat -fi - -# Path to zenity -ZENITY=`which zenity 2>/dev/null` - -# Path to xmessage -XMSG=`which xmessage 2>/dev/null` - -# Path to powershell (Windows only) -PWSH=`which powershell 2>/dev/null` - -# Path to osascript (macOS only) -OSA=`which osascript 2>/dev/null` - -################################################################## -# There should be no need to change anything below this line. - -. "$(dirname -- "$0")/canonicalize_filename.sh" - -# exit on error -set -e - -# check whether the given file matches any of the set extensions -matches_extension() { - local filename=$(basename "$1") - local extension=".${filename##*.}" - local ext - - for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done - - return 1 -} - -# necessary check for initial commit -if git rev-parse --verify HEAD >/dev/null 2>&1 ; then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -# To get consistent formatting, we recommend contributors to use the same -# clang-format version as CI. -RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="13" -RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="16" - -if [ ! -x "$CLANG_FORMAT" ] ; then - message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX." - - if [ ! -t 1 ] ; then - if [ -x "$ZENITY" ] ; then - $ZENITY --error --title="Error" --text="$message" - exit 1 - elif [ -x "$XMSG" ] ; then - $XMSG -center -title "Error" "$message" - exit 1 - elif [ -x "$OSA" ] ; then - asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" - $OSA "$asmessage" -center -title "Error" --text "$message" - exit 1 - elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" - $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message" - exit 1 - fi - fi - printf "$message\n" - printf "Set the correct path in $(canonicalize_filename "$0").\n" - exit 1 -fi - -# The returned string can be inconsistent depending on where clang-format comes from. -# Example output strings reported by `clang-format --version`: -# - Ubuntu: "Ubuntu clang-format version 11.0.0-2" -# - Fedora: "clang-format version 11.0.0 (Fedora 11.0.0-2.fc33)" -CLANG_FORMAT_VERSION="$(clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/")" -CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d. -f1)" - -if [[ "$CLANG_FORMAT_MAJOR" -lt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MIN" || "$CLANG_FORMAT_MAJOR" -gt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MAX" ]]; then - echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX)." - echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly." -fi - -# create a random filename to store our generated patch -prefix="pre-commit-clang-format" -suffix="$(date +%s)" -patch="/tmp/$prefix-$suffix.patch" - -# clean up any older clang-format patches -$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch - -# create one patch containing all changes to the files -git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; -do - # ignore thirdparty files - if grep -q "thirdparty" <<< $file; then - continue; - fi - if grep -q "platform/android/java/lib/src/com" <<< $file; then - continue; - fi - if grep -q "\-so_wrap." <<< $file; then - continue; - fi - if grep -q "tests/python_build" <<< $file; then - continue; - fi - - # ignore file if we do check for file extensions and the file - # does not match any of the extensions specified in $FILE_EXTS - if $PARSE_EXTS && ! matches_extension "$file"; then - continue; - fi - - # clang-format our sourcefile, create a patch with diff and append it to our $patch - # The sed call is necessary to transform the patch from - # --- $file timestamp - # +++ - timestamp - # to both lines working on the same file and having a/ and b/ prefix. - # Else it can not be applied with 'git apply'. - "$CLANG_FORMAT" -style=file "$file" --Wno-error=unknown | \ - diff -u "$file" - | \ - sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch" -done - -# if no patch has been generated all is ok, clean up the file stub and exit -if [ ! -s "$patch" ] ; then - printf "Files in this commit comply with the clang-format rules.\n" - rm -f "$patch" - exit 0 -fi - -# a patch has been created, notify the user and exit -printf "\nThe following differences were found between the code to commit " -printf "and the clang-format rules:\n\n" - -if [ -t 1 ] ; then - $READER "$patch" - printf "\n" - # Allows us to read user input below, assigns stdin to keyboard - exec < /dev/tty - terminal="1" -else - cat "$patch" - printf "\n" - # Allows non zero zenity/powershell output - set +e - terminal="0" -fi - -while true; do - if [ $terminal = "0" ] ; then - if [ -x "$ZENITY" ] ; then - choice=$($ZENITY --text-info --filename="$patch" --width=800 --height=600 --title="Do you want to apply that patch?" --ok-label="Apply" --cancel-label="Do not apply" --extra-button="Apply and stage") - if [ "$?" = "0" ] ; then - yn="Y" - else - if [ "$choice" = "Apply and stage" ] ; then - yn="S" - else - yn="N" - fi - fi - elif [ -x "$XMSG" ] ; then - $XMSG -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" - choice=$? - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - elif [ -x "$OSA" ] ; then - asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")" - choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"` - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" - $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" - choice=$? - if [ "$choice" = "100" ] ; then - yn="Y" - elif [ "$choice" = "200" ] ; then - yn="S" - else - yn="N" - fi - else - printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n" - exit 1 - fi - else - read -p "Do you want to apply that patch (Y - Apply, N - Do not apply, S - Apply and stage files)? [Y/N/S] " yn - fi - case $yn in - [Yy] ) git apply $patch; - printf "The patch was applied. You can now stage the changes and commit again.\n\n"; - break - ;; - [Nn] ) printf "\nYou can apply these changes with:\n git apply $patch\n"; - printf "(may need to be called from the root directory of your repository)\n"; - printf "Aborting commit. Apply changes and commit again or skip checking with"; - printf " --no-verify (not recommended).\n\n"; - break - ;; - [Ss] ) git apply $patch; - git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file; - do git add $file; - done - printf "The patch was applied and the changed files staged. You can now commit.\n\n"; - break - ;; - * ) echo "Please answer yes or no." - ;; - esac -done -exit 1 # we don't commit in any case diff --git a/misc/hooks/pre-commit-make-rst b/misc/hooks/pre-commit-make-rst deleted file mode 100755 index 3737272a6d..0000000000 --- a/misc/hooks/pre-commit-make-rst +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -# Git pre-commit hook that checks the class reference syntax using make_rst.py. - -# Workaround because we can't execute the .py file directly on windows -PYTHON=python -py_ver=$($PYTHON -c "import sys; print(sys.version_info.major)") -if [[ "$py_ver" != "3" ]]; then - PYTHON+=3 -fi - -$PYTHON doc/tools/make_rst.py doc/classes modules platform --dry-run --color diff --git a/misc/hooks/winmessage.ps1 b/misc/hooks/winmessage.ps1 deleted file mode 100644 index 3672579544..0000000000 --- a/misc/hooks/winmessage.ps1 +++ /dev/null @@ -1,103 +0,0 @@ -Param ( - [string]$file = "", - [string]$text = "", - [string]$buttons = "OK:0", - [string]$default = "", - [switch]$nearmouse = $false, - [switch]$center = $false, - [string]$geometry = "", - [int32]$timeout = 0, - [string]$title = "Message" -) -Add-Type -assembly System.Windows.Forms - -$global:Result = 0 - -$main_form = New-Object System.Windows.Forms.Form -$main_form.Text = $title - -$geometry_data = $geometry.Split("+") -if ($geometry_data.Length -ge 1) { - $size_data = $geometry_data[0].Split("x") - if ($size_data.Length -eq 2) { - $main_form.Width = $size_data[0] - $main_form.Height = $size_data[1] - } -} -if ($geometry_data.Length -eq 3) { - $main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual - $main_form.Location = New-Object System.Drawing.Point($geometry_data[1], $geometry_data[2]) -} -if ($nearmouse) { - $main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual - $main_form.Location = System.Windows.Forms.Cursor.Position -} -if ($center) { - $main_form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen -} - -$main_form.SuspendLayout() - -$button_panel = New-Object System.Windows.Forms.FlowLayoutPanel -$button_panel.SuspendLayout() -$button_panel.FlowDirection = [System.Windows.Forms.FlowDirection]::RightToLeft -$button_panel.Dock = [System.Windows.Forms.DockStyle]::Bottom -$button_panel.Autosize = $true - -if ($file -ne "") { - $text = [IO.File]::ReadAllText($file).replace("`n", "`r`n") -} - -if ($text -ne "") { - $text_box = New-Object System.Windows.Forms.TextBox - $text_box.Multiline = $true - $text_box.ReadOnly = $true - $text_box.Autosize = $true - $text_box.Text = $text - $text_box.Select(0,0) - $text_box.Dock = [System.Windows.Forms.DockStyle]::Fill - $main_form.Controls.Add($text_box) -} - -$buttons_array = $buttons.Split(",") -foreach ($button in $buttons_array) { - $button_data = $button.Split(":") - $button_ctl = New-Object System.Windows.Forms.Button - if ($button_data.Length -eq 2) { - $button_ctl.Tag = $button_data[1] - } else { - $button_ctl.Tag = 100 + $buttons_array.IndexOf($button) - } - if ($default -eq $button_data[0]) { - $main_form.AcceptButton = $button_ctl - } - $button_ctl.Autosize = $true - $button_ctl.Text = $button_data[0] - $button_ctl.Add_Click( - { - Param($sender) - $global:Result = $sender.Tag - $main_form.Close() - } - ) - $button_panel.Controls.Add($button_ctl) -} -$main_form.Controls.Add($button_panel) - -$button_panel.ResumeLayout($false) -$main_form.ResumeLayout($false) - -if ($timeout -gt 0) { - $timer = New-Object System.Windows.Forms.Timer - $timer.Add_Tick( - { - $global:Result = 0 - $main_form.Close() - } - ) - $timer.Interval = $timeout - $timer.Start() -} -$dlg_res = $main_form.ShowDialog() - -[Environment]::Exit($global:Result) diff --git a/misc/scripts/black_format.sh b/misc/scripts/black_format.sh deleted file mode 100755 index 48dc14c734..0000000000 --- a/misc/scripts/black_format.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# This script runs black on all Python files in the repo. - -set -uo pipefail - -# Apply black. -echo -e "Formatting Python files..." -PY_FILES=$(git ls-files -- '*SConstruct' '*SCsub' '*.py' ':!:.git/*' ':!:thirdparty/*') -black -l 120 $PY_FILES - -diff=$(git diff --color) - -# If no diff has been generated all is OK, clean up, and exit. -if [ -z "$diff" ] ; then - printf "\e[1;32m*** Files in this commit comply with the black style rules.\e[0m\n" - exit 0 -fi - -# A diff has been created, notify the user, clean up, and exit. -printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" -# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`. -printf "%s\n" "$diff" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge' - -printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n" -exit 1 diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh deleted file mode 100755 index 8b59519606..0000000000 --- a/misc/scripts/clang_format.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -# This script runs clang-format and fixes copyright headers on all relevant files in the repo. -# This is the primary script responsible for fixing style violations. - -set -uo pipefail - -if [ $# -eq 0 ]; then - # Loop through all code files tracked by Git. - files=$(git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \ - ':!:.git/*' ':!:thirdparty/*' ':!:*/thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' \ - ':!:*-so_wrap.*' ':!:tests/python_build/*') -else - # $1 should be a file listing file paths to process. Used in CI. - files=$(cat "$1" | grep -v "thirdparty/" | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$" | grep -v "platform/android/java/lib/src/com/google/" | grep -v "\-so_wrap\." | grep -v "tests/python_build/") -fi - -if [ ! -z "$files" ]; then - clang-format --Wno-error=unknown -i $files -fi - -# Fix copyright headers, but not all files get them. -for f in $files; do - if [[ "$f" == *"inc" && "$f" != *"compat.inc" ]]; then - continue - elif [[ "$f" == *"glsl" ]]; then - continue - elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView"* ]]; then - continue - elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper"* ]]; then - continue - elif [[ "$f" == "platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix"* ]]; then - continue - fi - - python misc/scripts/copyright_headers.py "$f" -done - -diff=$(git diff --color) - -# If no diff has been generated all is OK, clean up, and exit. -if [ -z "$diff" ] ; then - printf "\e[1;32m*** Files in this commit comply with the clang-format style rules.\e[0m\n" - exit 0 -fi - -# A diff has been created, notify the user, clean up, and exit. -printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n" -# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`. -printf "%s\n" "$diff" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge' - -printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n" -exit 1 diff --git a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp index 8207149d16..3ef54ec0df 100644 --- a/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp +++ b/modules/fbx/editor/editor_scene_importer_fbx2gltf.cpp @@ -104,6 +104,9 @@ Node *EditorSceneFormatImporterFBX2GLTF::import_scene(const String &p_path, uint gltf.instantiate(); Ref<GLTFState> state; state.instantiate(); + if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { + state->set_import_as_skeleton_bones(true); + } print_verbose(vformat("glTF path: %s", sink)); Error err = gltf->append_from_file(sink, state, p_flags, p_path.get_base_dir()); if (err != OK) { diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp index 721caedc7c..241fdba0c5 100644 --- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp +++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp @@ -73,6 +73,12 @@ Node *EditorSceneFormatImporterUFBX::import_scene(const String &p_path, uint32_t int32_t enum_option = p_options["fbx/embedded_image_handling"]; state->set_handle_binary_image(enum_option); } + if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { + state->set_import_as_skeleton_bones(true); + } + if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { + state->set_import_as_skeleton_bones(true); + } p_flags |= EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS; Error err = fbx->append_from_file(path, state, p_flags, p_path.get_base_dir()); if (err != OK) { diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index 2f8fd79be5..367117edcb 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -2086,7 +2086,7 @@ Error FBXDocument::_parse_fbx_state(Ref<FBXState> p_state, const String &p_searc ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* DETERMINE SKELETONS */ - err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons); + err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons, p_state->get_import_as_skeleton_bones() ? p_state->root_nodes : Vector<GLTFNodeIndex>()); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* CREATE SKELETONS */ diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 4b009f1866..7ececce613 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -597,6 +597,17 @@ [/codeblock] </description> </annotation> + <annotation name="@export_storage"> + <return type="void" /> + <description> + Export a property with [constant PROPERTY_USAGE_STORAGE] flag. The property is not displayed in the editor, but it is serialized and stored in the scene or resource file. This can be useful for [annotation @tool] scripts. Also the property value is copied when [method Resource.duplicate] or [method Node.duplicate] is called, unlike non-exported variables. + [codeblock] + var a # Not stored in the file, not displayed in the editor. + @export_storage var b # Stored in the file, not displayed in the editor. + @export var c: int # Stored in the file, displayed in the editor. + [/codeblock] + </description> + </annotation> <annotation name="@export_subgroup"> <return type="void" /> <param index="0" name="name" type="String" /> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 426565bb68..439555bacb 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -532,12 +532,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - in_function_declaration = false; - in_var_const_declaration = false; - in_signal_declaration = false; - in_function_name = false; - in_lambda = false; - in_member_variable = false; + if (!is_whitespace(str[j])) { + in_function_declaration = false; + in_var_const_declaration = false; + in_signal_declaration = false; + in_function_name = false; + in_lambda = false; + in_member_variable = false; + } } if (!in_raw_string && in_region == -1 && str[j] == 'r' && j < line_length - 1 && (str[j + 1] == '"' || str[j + 1] == '\'')) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index f63b2ce0ee..4d4eadf0fa 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -101,6 +101,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); + register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true); register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); @@ -4085,11 +4086,11 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } hint_string += arg_string; } - variable->export_info.hint_string = hint_string; // This is called after the analyzer is done finding the type, so this should be set here. DataType export_type = variable->get_datatype(); + bool use_default_variable_type_check = true; if (p_annotation->name == SNAME("@export_range")) { if (export_type.builtin_type == Variant::INT) { @@ -4121,11 +4122,9 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node return true; } - } + } else if (p_annotation->name == SNAME("@export")) { + use_default_variable_type_check = false; - // WARNING: Do not merge with the previous `else if`! Otherwise `else` (default variable type check) - // will not work for the above annotations. `@export` and `@export_enum` validate the type separately. - if (p_annotation->name == SNAME("@export")) { if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) { push_error(R"(Cannot use simple "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation); return false; @@ -4243,6 +4242,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.type = Variant::ARRAY; } } else if (p_annotation->name == SNAME("@export_enum")) { + use_default_variable_type_check = false; + Variant::Type enum_type = Variant::INT; if (export_type.kind == DataType::BUILTIN && export_type.builtin_type == Variant::STRING) { @@ -4260,7 +4261,15 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node push_error(vformat(R"("@export_enum" annotation requires a variable of type "int" or "String" but type "%s" was given instead.)", export_type.to_string()), variable); return false; } - } else { + } else if (p_annotation->name == SNAME("@export_storage")) { + use_default_variable_type_check = false; // Can be applied to a variable of any type. + + // Save the info because the compiler uses export info for overwriting member info. + variable->export_info = export_type.to_property_info(variable->identifier->name); + variable->export_info.usage |= PROPERTY_USAGE_STORAGE; + } + + if (use_default_variable_type_check) { // Validate variable type with export. if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) { // Allow float/int conversion. diff --git a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd index dafd2ec0c8..39f490c4b3 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd @@ -4,14 +4,13 @@ enum MyEnum {A, B, C} const Utils = preload("../../utils.notest.gd") -@export var x1 = MyEnum -@export var x2 = MyEnum.A -@export var x3 := MyEnum -@export var x4 := MyEnum.A -@export var x5: MyEnum +@export var test_1 = MyEnum +@export var test_2 = MyEnum.A +@export var test_3 := MyEnum +@export var test_4 := MyEnum.A +@export var test_5: MyEnum func test(): for property in get_property_list(): - if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE: - print(Utils.get_property_signature(property)) - print(" ", Utils.get_property_additional_info(property)) + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property) diff --git a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out index f1a13f1045..505af5f1f3 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out +++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out @@ -1,11 +1,11 @@ GDTEST_OK -@export var x1: Dictionary +var test_1: Dictionary hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE -@export var x2: TestExportEnumAsDictionary.MyEnum +var test_2: TestExportEnumAsDictionary.MyEnum hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM -@export var x3: Dictionary +var test_3: Dictionary hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE -@export var x4: TestExportEnumAsDictionary.MyEnum +var test_4: TestExportEnumAsDictionary.MyEnum hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM -@export var x5: TestExportEnumAsDictionary.MyEnum +var test_5: TestExportEnumAsDictionary.MyEnum hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM diff --git a/modules/gdscript/tests/scripts/parser/features/annotations.gd b/modules/gdscript/tests/scripts/parser/features/annotations.gd index 13c89a0a09..7a7d6d953e 100644 --- a/modules/gdscript/tests/scripts/parser/features/annotations.gd +++ b/modules/gdscript/tests/scripts/parser/features/annotations.gd @@ -1,48 +1,49 @@ extends Node -@export_enum("A", "B", "C") var a0 -@export_enum("A", "B", "C",) var a1 +const Utils = preload("../../utils.notest.gd") + +@export_enum("A", "B", "C") var test_1 +@export_enum("A", "B", "C",) var test_2 @export_enum( "A", "B", "C" -) var a2 +) var test_3 @export_enum( "A", "B", "C", -) var a3 +) var test_4 @export -var a4: int +var test_5: int @export() -var a5: int +var test_6: int -@export() var a6: int -@warning_ignore("onready_with_export") @onready @export var a7: int -@warning_ignore("onready_with_export") @onready() @export() var a8: int +@export() var test_7: int = 42 +@warning_ignore("onready_with_export") @onready @export var test_8: int = 42 +@warning_ignore("onready_with_export") @onready() @export() var test_9: int = 42 @warning_ignore("onready_with_export") @onready @export -var a9: int +var test_10: int = 42 @warning_ignore("onready_with_export") @onready() @export() -var a10: int +var test_11: int = 42 @warning_ignore("onready_with_export") @onready() @export() -var a11: int - +var test_12: int = 42 func test(): for property in get_property_list(): - if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE: - print(property) + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property, self) diff --git a/modules/gdscript/tests/scripts/parser/features/annotations.out b/modules/gdscript/tests/scripts/parser/features/annotations.out index 3af0436c53..2ba9dd7496 100644 --- a/modules/gdscript/tests/scripts/parser/features/annotations.out +++ b/modules/gdscript/tests/scripts/parser/features/annotations.out @@ -1,13 +1,25 @@ GDTEST_OK -{ "name": "a0", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 } -{ "name": "a1", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 } -{ "name": "a2", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 } -{ "name": "a3", "class_name": &"", "type": 2, "hint": 2, "hint_string": "A,B,C", "usage": 4102 } -{ "name": "a4", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a5", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a6", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a7", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a8", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a9", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a10", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "a11", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } +var test_1: int = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_2: int = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_3: int = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_4: int = null + hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE +var test_5: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_6: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_7: int = 42 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_8: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_9: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_10: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_11: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_12: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.gd b/modules/gdscript/tests/scripts/parser/features/export_enum.gd index 9b2c22dea1..4f2a43f4fe 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.gd @@ -1,15 +1,16 @@ -@export_enum("Red", "Green", "Blue") var untyped +const Utils = preload("../../utils.notest.gd") -@export_enum("Red", "Green", "Blue") var weak_int = 0 -@export_enum("Red", "Green", "Blue") var weak_string = "" +@export_enum("Red", "Green", "Blue") var test_untyped -@export_enum("Red", "Green", "Blue") var hard_int: int -@export_enum("Red", "Green", "Blue") var hard_string: String +@export_enum("Red", "Green", "Blue") var test_weak_int = 0 +@export_enum("Red", "Green", "Blue") var test_weak_string = "" -@export_enum("Red:10", "Green:20", "Blue:30") var with_values +@export_enum("Red", "Green", "Blue") var test_hard_int: int +@export_enum("Red", "Green", "Blue") var test_hard_string: String + +@export_enum("Red:10", "Green:20", "Blue:30") var test_with_values func test(): for property in get_property_list(): - if property.name in ["untyped", "weak_int", "weak_string", "hard_int", - "hard_string", "with_values"]: - prints(property.name, property.type, property.hint_string) + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property, self) diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.out b/modules/gdscript/tests/scripts/parser/features/export_enum.out index 330b7eaf01..43f5e197ad 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_enum.out +++ b/modules/gdscript/tests/scripts/parser/features/export_enum.out @@ -1,7 +1,13 @@ GDTEST_OK -untyped 2 Red,Green,Blue -weak_int 2 Red,Green,Blue -weak_string 4 Red,Green,Blue -hard_int 2 Red,Green,Blue -hard_string 4 Red,Green,Blue -with_values 2 Red:10,Green:20,Blue:30 +var test_untyped: int = null + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_int: int = 0 + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_weak_string: String = "" + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_int: int = 0 + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_string: String = "" + hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE +var test_with_values: int = null + hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd index c9d05a7e68..2a218774de 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.gd +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd @@ -1,23 +1,22 @@ extends Node -@export var example = 99 -@export_range(0, 100) var example_range = 100 -@export_range(0, 100, 1) var example_range_step = 101 -@export_range(0, 100, 1, "or_greater") var example_range_step_or_greater = 102 +const Utils = preload("../../utils.notest.gd") -@export var color: Color -@export_color_no_alpha var color_no_alpha: Color -@export_node_path("Sprite2D", "Sprite3D", "Control", "Node") var nodepath := ^"hello" -@export var node: Node -@export var node_array: Array[Node] +@export var test_weak_int = 1 +@export var test_hard_int: int = 2 +@export_storage var test_storage_untyped +@export_storage var test_storage_weak_int = 3 # Property info still `Variant`, unlike `@export`. +@export_storage var test_storage_hard_int: int = 4 +@export_range(0, 100) var test_range = 100 +@export_range(0, 100, 1) var test_range_step = 101 +@export_range(0, 100, 1, "or_greater") var test_range_step_or_greater = 102 +@export var test_color: Color +@export_color_no_alpha var test_color_no_alpha: Color +@export_node_path("Sprite2D", "Sprite3D", "Control", "Node") var test_node_path := ^"hello" +@export var test_node: Node +@export var test_node_array: Array[Node] func test(): - print(example) - print(example_range) - print(example_range_step) - print(example_range_step_or_greater) - print(color) - print(color_no_alpha) - print(nodepath) - print(node) - print(var_to_str(node_array)) + for property in get_property_list(): + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property, self) diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index 5430c975f4..baadcd4ee8 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -1,10 +1,27 @@ GDTEST_OK -99 -100 -101 -102 -(0, 0, 0, 1) -(0, 0, 0, 1) -hello -<null> -Array[Node]([]) +var test_weak_int: int = 1 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_hard_int: int = 2 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +var test_storage_untyped: Variant = null + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT +var test_storage_weak_int: Variant = 3 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE|NIL_IS_VARIANT +var test_storage_hard_int: int = 4 + hint=NONE hint_string="" usage=STORAGE|SCRIPT_VARIABLE +var test_range: int = 100 + hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_step: int = 101 + hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE +var test_range_step_or_greater: int = 102 + hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE +var test_color: Color = Color(0, 0, 0, 1) + hint=NONE hint_string="Color" usage=DEFAULT|SCRIPT_VARIABLE +var test_color_no_alpha: Color = Color(0, 0, 0, 1) + hint=COLOR_NO_ALPHA hint_string="" usage=DEFAULT|SCRIPT_VARIABLE +var test_node_path: NodePath = NodePath("hello") + hint=NODE_PATH_VALID_TYPES hint_string="Sprite2D,Sprite3D,Control,Node" usage=DEFAULT|SCRIPT_VARIABLE +var test_node: Node = null + hint=NODE_TYPE hint_string="Node" usage=DEFAULT|SCRIPT_VARIABLE +var test_node_array: Array = Array[Node]([]) + hint=TYPE_STRING hint_string="24/34:Node" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.gd b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.gd index e46f24cc5f..0133d7fcfc 100644 --- a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.gd +++ b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.gd @@ -1,17 +1,17 @@ -extends RefCounted # TODO: Fix standalone annotations parsing. +const Utils = preload("../../utils.notest.gd") # GH-73843 @export_group("Resource") # GH-78252 -@export var prop_1: int -@export_category("prop_1") -@export var prop_2: int +@export var test_1: int +@export_category("test_1") +@export var test_2: int func test(): var resource := Resource.new() prints("Not shadowed:", resource.get_class()) for property in get_property_list(): - if property.name in ["prop_1", "prop_2"]: - print(property) + if str(property.name).begins_with("test_"): + Utils.print_property_extended_info(property, self) diff --git a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out index 96ae84e986..9387ec50d7 100644 --- a/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out +++ b/modules/gdscript/tests/scripts/runtime/features/export_group_no_name_conflict_with_properties.out @@ -1,5 +1,8 @@ GDTEST_OK Not shadowed: Resource -{ "name": "prop_1", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } -{ "name": "prop_1", "class_name": &"", "type": 0, "hint": 0, "hint_string": "", "usage": 128 } -{ "name": "prop_2", "class_name": &"", "type": 2, "hint": 0, "hint_string": "int", "usage": 4102 } +var test_1: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE +@export_category("test_1") + hint=NONE hint_string="" usage=CATEGORY +var test_2: int = 0 + hint=NONE hint_string="int" usage=DEFAULT|SCRIPT_VARIABLE diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd index 805ea42455..6fe9647b4d 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.gd +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd @@ -60,7 +60,7 @@ func test(): var script: Script = get_script() for property in script.get_property_list(): if str(property.name).begins_with("test_"): - print(Utils.get_property_signature(property, true)) + print(Utils.get_property_signature(property, null, true)) for property in get_property_list(): if str(property.name).begins_with("test_"): print(Utils.get_property_signature(property)) diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.out b/modules/gdscript/tests/scripts/runtime/features/member_info.out index 3a91507da9..7c826ac05a 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info.out +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.out @@ -6,13 +6,13 @@ static var test_static_var_hard_int: int var test_var_untyped: Variant var test_var_weak_null: Variant var test_var_weak_int: Variant -@export var test_var_weak_int_exported: int +var test_var_weak_int_exported: int var test_var_weak_variant_type: Variant -@export var test_var_weak_variant_type_exported: Variant.Type +var test_var_weak_variant_type_exported: Variant.Type var test_var_hard_variant: Variant var test_var_hard_int: int var test_var_hard_variant_type: Variant.Type -@export var test_var_hard_variant_type_exported: Variant.Type +var test_var_hard_variant_type_exported: Variant.Type var test_var_hard_node_process_mode: Node.ProcessMode var test_var_hard_my_enum: TestMemberInfo.MyEnum var test_var_hard_array: Array diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd index d0cbeeab85..563c6ce569 100644 --- a/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd +++ b/modules/gdscript/tests/scripts/runtime/features/member_info_inheritance.gd @@ -30,7 +30,7 @@ func test(): var b := B.new() for property in (B as GDScript).get_property_list(): if str(property.name).begins_with("test_"): - print(Utils.get_property_signature(property, true)) + print(Utils.get_property_signature(property, null, true)) print("---") for property in b.get_property_list(): if str(property.name).begins_with("test_"): diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index 781843b8e2..31818c9d01 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -20,24 +20,32 @@ static func get_type(property: Dictionary, is_return: bool = false) -> String: return type_string(property.type) -static func get_property_signature(property: Dictionary, is_static: bool = false) -> String: +static func get_property_signature(property: Dictionary, base: Object = null, is_static: bool = false) -> String: + if property.usage & PROPERTY_USAGE_CATEGORY: + return '@export_category("%s")' % str(property.name).c_escape() + if property.usage & PROPERTY_USAGE_GROUP: + return '@export_group("%s")' % str(property.name).c_escape() + if property.usage & PROPERTY_USAGE_SUBGROUP: + return '@export_subgroup("%s")' % str(property.name).c_escape() + var result: String = "" if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE): printerr("Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.") - if property.usage & PROPERTY_USAGE_DEFAULT: - result += "@export " if is_static: result += "static " result += "var " + property.name + ": " + get_type(property) + if is_instance_valid(base): + result += " = " + var_to_str(base.get(property.name)) return result -static func get_property_additional_info(property: Dictionary) -> String: - return 'hint=%s hint_string="%s" usage=%s' % [ +static func print_property_extended_info(property: Dictionary, base: Object = null, is_static: bool = false) -> void: + print(get_property_signature(property, base, is_static)) + print(' hint=%s hint_string="%s" usage=%s' % [ get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"), str(property.hint_string).c_escape(), get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""), - ] + ]) static func get_method_signature(method: Dictionary, is_signal: bool = false) -> String: @@ -153,7 +161,6 @@ static func get_property_usage_string(usage: int) -> String: return "PROPERTY_USAGE_NONE" const FLAGS: Array[Array] = [ - [PROPERTY_USAGE_DEFAULT, "PROPERTY_USAGE_DEFAULT"], [PROPERTY_USAGE_STORAGE, "PROPERTY_USAGE_STORAGE"], [PROPERTY_USAGE_EDITOR, "PROPERTY_USAGE_EDITOR"], [PROPERTY_USAGE_INTERNAL, "PROPERTY_USAGE_INTERNAL"], @@ -187,6 +194,10 @@ static func get_property_usage_string(usage: int) -> String: var result: String = "" + if (usage & PROPERTY_USAGE_DEFAULT) == PROPERTY_USAGE_DEFAULT: + result += "PROPERTY_USAGE_DEFAULT|" + usage &= ~PROPERTY_USAGE_DEFAULT + for flag in FLAGS: if usage & flag[0]: result += flag[1] + "|" diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 100750f400..6c7c5ee0e6 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -289,8 +289,13 @@ The file name associated with this GLTF data. If it ends with [code].gltf[/code], this is text-based GLTF, otherwise this is binary GLB. This will be set during import when appending from a file, and will be set during export when writing to a file. If writing to a buffer, this will be an empty string. </member> <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()"> + The binary buffer attached to a .glb file. + </member> + <member name="import_as_skeleton_bones" type="bool" setter="set_import_as_skeleton_bones" getter="get_import_as_skeleton_bones" default="false"> + True to force all GLTFNodes in the document to be bones of a single Skeleton3D godot node. </member> <member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}"> + The original raw JSON document corresponding to this GLTFState. </member> <member name="major_version" type="int" setter="set_major_version" getter="get_major_version" default="0"> </member> diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index a91856c4a1..c6e92de762 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -287,6 +287,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ if (p_options.has(SNAME("blender/materials/unpack_enabled")) && p_options[SNAME("blender/materials/unpack_enabled")]) { base_dir = sink.get_base_dir(); } + if (p_options.has(SNAME("nodes/import_as_skeleton_bones")) ? (bool)p_options[SNAME("nodes/import_as_skeleton_bones")] : false) { + state->set_import_as_skeleton_bones(true); + } state->set_scene_name(blend_basename); err = gltf->append_from_file(sink.get_basename() + ".gltf", state, p_flags, base_dir); if (err != OK) { diff --git a/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp b/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp index a9033de7ae..c6e34cc023 100644 --- a/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp +++ b/modules/gltf/extensions/physics/gltf_document_extension_physics.cpp @@ -30,7 +30,8 @@ #include "gltf_document_extension_physics.h" -#include "scene/3d/area_3d.h" +#include "scene/3d/physics/area_3d.h" +#include "scene/3d/physics/static_body_3d.h" // Import process. Error GLTFDocumentExtensionPhysics::import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) { diff --git a/modules/gltf/extensions/physics/gltf_physics_body.cpp b/modules/gltf/extensions/physics/gltf_physics_body.cpp index 271bb9b332..7929b46542 100644 --- a/modules/gltf/extensions/physics/gltf_physics_body.cpp +++ b/modules/gltf/extensions/physics/gltf_physics_body.cpp @@ -30,8 +30,11 @@ #include "gltf_physics_body.h" -#include "scene/3d/area_3d.h" -#include "scene/3d/vehicle_body_3d.h" +#include "scene/3d/physics/animatable_body_3d.h" +#include "scene/3d/physics/area_3d.h" +#include "scene/3d/physics/character_body_3d.h" +#include "scene/3d/physics/static_body_3d.h" +#include "scene/3d/physics/vehicle_body_3d.h" void GLTFPhysicsBody::_bind_methods() { ClassDB::bind_static_method("GLTFPhysicsBody", D_METHOD("from_node", "body_node"), &GLTFPhysicsBody::from_node); diff --git a/modules/gltf/extensions/physics/gltf_physics_body.h b/modules/gltf/extensions/physics/gltf_physics_body.h index 6b21639a7b..ec139054ff 100644 --- a/modules/gltf/extensions/physics/gltf_physics_body.h +++ b/modules/gltf/extensions/physics/gltf_physics_body.h @@ -31,7 +31,7 @@ #ifndef GLTF_PHYSICS_BODY_H #define GLTF_PHYSICS_BODY_H -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" // GLTFPhysicsBody is an intermediary between Godot's physics body nodes // and the OMI_physics_body extension. diff --git a/modules/gltf/extensions/physics/gltf_physics_shape.cpp b/modules/gltf/extensions/physics/gltf_physics_shape.cpp index 467499a03f..35c99adbe5 100644 --- a/modules/gltf/extensions/physics/gltf_physics_shape.cpp +++ b/modules/gltf/extensions/physics/gltf_physics_shape.cpp @@ -33,7 +33,7 @@ #include "../../gltf_state.h" #include "core/math/convex_hull.h" -#include "scene/3d/area_3d.h" +#include "scene/3d/physics/area_3d.h" #include "scene/resources/3d/box_shape_3d.h" #include "scene/resources/3d/capsule_shape_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" diff --git a/modules/gltf/extensions/physics/gltf_physics_shape.h b/modules/gltf/extensions/physics/gltf_physics_shape.h index 4f7ac39292..ec0a8931f1 100644 --- a/modules/gltf/extensions/physics/gltf_physics_shape.h +++ b/modules/gltf/extensions/physics/gltf_physics_shape.h @@ -33,7 +33,7 @@ #include "../../gltf_defines.h" -#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" class ImporterMesh; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 740c9a2aa7..eece6afdcc 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2796,7 +2796,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { Vector<Vector3> normals = array[Mesh::ARRAY_NORMAL]; for (int k = 0; k < vertex_num; k++) { - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[k]); + Vector3 tan = Vector3(normals[k].z, -normals[k].x, normals[k].y).cross(normals[k].normalized()).normalized(); tangentsw[k * 4 + 0] = tan.x; tangentsw[k * 4 + 1] = tan.y; tangentsw[k * 4 + 2] = tan.z; @@ -2822,6 +2822,19 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) { } array = mesh_surface_tool->commit_to_arrays(); + if ((flags & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && a.has("NORMAL") && (a.has("TANGENT") || generate_tangents)) { + // Compression is enabled, so let's validate that the normals and tangents are correct. + Vector<Vector3> normals = array[Mesh::ARRAY_NORMAL]; + Vector<float> tangents = array[Mesh::ARRAY_TANGENT]; + for (int vert = 0; vert < normals.size(); vert++) { + Vector3 tan = Vector3(tangents[vert * 4 + 0], tangents[vert * 4 + 1], tangents[vert * 4 + 2]); + if (abs(tan.dot(normals[vert])) > 0.0001) { + // Tangent is not perpendicular to the normal, so we can't use compression. + flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + } + } + } + Array morphs; //blend shapes if (p.has("targets")) { @@ -6924,7 +6937,7 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_se ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* DETERMINE SKELETONS */ - err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons); + err = SkinTool::_determine_skeletons(p_state->skins, p_state->nodes, p_state->skeletons, p_state->get_import_as_skeleton_bones() ? p_state->root_nodes : Vector<GLTFNodeIndex>()); ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); /* PARSE MESHES (we have enough info now) */ diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 0c47d5777c..ed31aadc01 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -90,6 +90,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skeletons", "skeletons"), &GLTFState::set_skeletons); ClassDB::bind_method(D_METHOD("get_create_animations"), &GLTFState::get_create_animations); ClassDB::bind_method(D_METHOD("set_create_animations", "create_animations"), &GLTFState::set_create_animations); + ClassDB::bind_method(D_METHOD("get_import_as_skeleton_bones"), &GLTFState::get_import_as_skeleton_bones); + ClassDB::bind_method(D_METHOD("set_import_as_skeleton_bones", "import_as_skeleton_bones"), &GLTFState::set_import_as_skeleton_bones); ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations); ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations); ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node); @@ -125,6 +127,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>> ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "import_as_skeleton_bones"), "set_import_as_skeleton_bones", "get_import_as_skeleton_bones"); // bool ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> ADD_PROPERTY(PropertyInfo(Variant::INT, "handle_binary_image", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_handle_binary_image", "get_handle_binary_image"); // enum @@ -337,6 +340,14 @@ void GLTFState::set_create_animations(bool p_create_animations) { create_animations = p_create_animations; } +bool GLTFState::get_import_as_skeleton_bones() { + return import_as_skeleton_bones; +} + +void GLTFState::set_import_as_skeleton_bones(bool p_import_as_skeleton_bones) { + import_as_skeleton_bones = p_import_as_skeleton_bones; +} + TypedArray<GLTFAnimation> GLTFState::get_animations() { return GLTFTemplateConvert::to_array(animations); } diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index c7171e0e68..c9efffa3ae 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -64,6 +64,7 @@ protected: bool force_generate_tangents = false; bool create_animations = true; bool force_disable_compression = false; + bool import_as_skeleton_bones = false; int handle_binary_image = HANDLE_BINARY_EXTRACT_TEXTURES; @@ -213,6 +214,9 @@ public: bool get_create_animations(); void set_create_animations(bool p_create_animations); + bool get_import_as_skeleton_bones(); + void set_import_as_skeleton_bones(bool p_import_as_skeleton_bones); + TypedArray<GLTFAnimation> get_animations(); void set_animations(TypedArray<GLTFAnimation> p_animations); diff --git a/modules/gltf/skin_tool.cpp b/modules/gltf/skin_tool.cpp index a008e870e6..2fb55a5f9e 100644 --- a/modules/gltf/skin_tool.cpp +++ b/modules/gltf/skin_tool.cpp @@ -285,7 +285,18 @@ void SkinTool::_recurse_children( Error SkinTool::_determine_skeletons( Vector<Ref<GLTFSkin>> &skins, Vector<Ref<GLTFNode>> &nodes, - Vector<Ref<GLTFSkeleton>> &skeletons) { + Vector<Ref<GLTFSkeleton>> &skeletons, + const Vector<GLTFNodeIndex> &p_single_skeleton_roots) { + if (!p_single_skeleton_roots.is_empty()) { + Ref<GLTFSkin> skin; + skin.instantiate(); + skin->set_name("godot_single_skeleton_root"); + for (GLTFNodeIndex i = 0; i < p_single_skeleton_roots.size(); i++) { + skin->joints.push_back(p_single_skeleton_roots[i]); + } + skins.push_back(skin); + } + // Using a disjoint set, we are going to potentially combine all skins that are actually branches // of a main skeleton, or treat skins defining the same set of nodes as ONE skeleton. // This is another unclear issue caused by the current glTF specification. diff --git a/modules/gltf/skin_tool.h b/modules/gltf/skin_tool.h index 8f7ab011ba..1ba95853f3 100644 --- a/modules/gltf/skin_tool.h +++ b/modules/gltf/skin_tool.h @@ -84,7 +84,8 @@ public: static Error _determine_skeletons( Vector<Ref<GLTFSkin>> &r_skins, Vector<Ref<GLTFNode>> &r_nodes, - Vector<Ref<GLTFSkeleton>> &r_skeletons); + Vector<Ref<GLTFSkeleton>> &r_skeletons, + const Vector<GLTFNodeIndex> &p_single_skeleton_roots); static Error _create_skeletons( HashSet<String> &r_unique_names, Vector<Ref<GLTFSkin>> &r_skins, diff --git a/modules/mono/.editorconfig b/modules/mono/.editorconfig index db8fb2921c..1e5ae28396 100644 --- a/modules/mono/.editorconfig +++ b/modules/mono/.editorconfig @@ -13,22 +13,59 @@ trim_trailing_whitespace = true max_line_length = 120 csharp_indent_case_contents_when_block = false -[*.cs] -# CA1707: Identifiers should not contain underscores -# TODO: -# Maybe we could disable this selectively only -# where it's not desired and for generated code. -dotnet_diagnostic.CA1707.severity = none -# CA1711: Identifiers should not have incorrect suffix -# Disable warning for suffixes like EventHandler, Flags, Enum, etc. -dotnet_diagnostic.CA1711.severity = none -# CA1716: Identifiers should not match keywords -# TODO: We should look into this. -dotnet_diagnostic.CA1716.severity = warning -# CA1720: Identifiers should not contain type names -dotnet_diagnostic.CA1720.severity = none -# CA1805: Do not initialize unnecessarily -# Don't tell me what to do. -dotnet_diagnostic.CA1805.severity = none +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true + +dotnet_style_require_accessibility_modifiers = always + # Diagnostics to prevent defensive copies of `in` struct parameters resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# IDE1006: Naming rule violation +dotnet_diagnostic.IDE1006.severity = suggestion + +# Severity levels for dotnet_naming_rule only affect IDE environments. +# To have them extra visible to people, we can set them as 'warning' here without affecting compilation. + +# Everything should be PascalCase by default +dotnet_naming_rule.all_should_be_camel_case.severity = warning +dotnet_naming_rule.all_should_be_camel_case.symbols = all +dotnet_naming_rule.all_should_be_camel_case.style = pascal_case_style +# Non-public fields should be _camelCase +dotnet_naming_rule.non_public_fields_should_be_underscore_camel_case.severity = warning +dotnet_naming_rule.non_public_fields_should_be_underscore_camel_case.symbols = non_public_fields +dotnet_naming_rule.non_public_fields_should_be_underscore_camel_case.style = underscore_camel_case_style +# Constant fields (and local vars) should be PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = warning +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = pascal_case_style +# Locals variables should be camelCase +dotnet_naming_rule.local_vars_should_be_camel_case.severity = warning +dotnet_naming_rule.local_vars_should_be_camel_case.symbols = local_vars +dotnet_naming_rule.local_vars_should_be_camel_case.style = camel_case_style +# Parameters should be camelCase +dotnet_naming_rule.parameters_should_be_camel_case.severity = warning +dotnet_naming_rule.parameters_should_be_camel_case.symbols = parameters +dotnet_naming_rule.parameters_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.all.applicable_kinds = * +dotnet_naming_symbols.local_vars.applicable_kinds = local +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const +dotnet_naming_symbols.non_public_fields.applicable_kinds = field +dotnet_naming_symbols.non_public_fields.applicable_accessibilities = private, protected, private_protected + +dotnet_naming_style.camel_case_style.capitalization = camel_case +dotnet_naming_style.camel_case_style.required_prefix = +dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case +dotnet_naming_style.underscore_camel_case_style.required_prefix = _ +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +dotnet_naming_style.pascal_case_style.required_prefix = diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index 90a517cc40..aa6f6ef05e 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -312,7 +312,7 @@ def generate_sdk_package_versions(): ) # We write in ../SdkPackageVersions.props. - with open(os.path.join(dirname(script_path), "SdkPackageVersions.props"), "w") as f: + with open(os.path.join(dirname(script_path), "SdkPackageVersions.props"), "w", encoding="utf-8") as f: f.write(props) f.close() @@ -320,6 +320,8 @@ def generate_sdk_package_versions(): constants = """namespace Godot.SourceGenerators {{ +// TODO: This is currently disabled because of https://github.com/dotnet/roslyn/issues/52904 +#pragma warning disable IDE0040 // Add accessibility modifiers. partial class Common {{ public const string VersionDocsUrl = "https://docs.godotengine.org/en/{docs_branch}"; @@ -338,7 +340,7 @@ def generate_sdk_package_versions(): ) os.makedirs(generators_dir, exist_ok=True) - with open(os.path.join(generators_dir, "Common.Constants.cs"), "w") as f: + with open(os.path.join(generators_dir, "Common.Constants.cs"), "w", newline="\n", encoding="utf-8") as f: f.write(constants) f.close() diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs index 2d797e2f46..bf37651787 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Bar.cs @@ -1,15 +1,15 @@ namespace Godot.SourceGenerators.Sample { - partial class Bar : GodotObject + public partial class Bar : GodotObject { } // Foo in another file - partial class Foo + public partial class Foo { } - partial class NotSameNameAsFile : GodotObject + public partial class NotSameNameAsFile : GodotObject { } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs index 31e66ac306..c9e504fec7 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs @@ -13,106 +13,106 @@ namespace Godot.SourceGenerators.Sample [SuppressMessage("ReSharper", "InconsistentNaming")] public partial class ExportedFields : GodotObject { - [Export] private Boolean field_Boolean = true; - [Export] private Char field_Char = 'f'; - [Export] private SByte field_SByte = 10; - [Export] private Int16 field_Int16 = 10; - [Export] private Int32 field_Int32 = 10; - [Export] private Int64 field_Int64 = 10; - [Export] private Byte field_Byte = 10; - [Export] private UInt16 field_UInt16 = 10; - [Export] private UInt32 field_UInt32 = 10; - [Export] private UInt64 field_UInt64 = 10; - [Export] private Single field_Single = 10; - [Export] private Double field_Double = 10; - [Export] private String field_String = "foo"; + [Export] private Boolean _fieldBoolean = true; + [Export] private Char _fieldChar = 'f'; + [Export] private SByte _fieldSByte = 10; + [Export] private Int16 _fieldInt16 = 10; + [Export] private Int32 _fieldInt32 = 10; + [Export] private Int64 _fieldInt64 = 10; + [Export] private Byte _fieldByte = 10; + [Export] private UInt16 _fieldUInt16 = 10; + [Export] private UInt32 _fieldUInt32 = 10; + [Export] private UInt64 _fieldUInt64 = 10; + [Export] private Single _fieldSingle = 10; + [Export] private Double _fieldDouble = 10; + [Export] private String _fieldString = "foo"; // Godot structs - [Export] private Vector2 field_Vector2 = new(10f, 10f); - [Export] private Vector2I field_Vector2I = Vector2I.Up; - [Export] private Rect2 field_Rect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); - [Export] private Rect2I field_Rect2I = new(new Vector2I(10, 10), new Vector2I(10, 10)); - [Export] private Transform2D field_Transform2D = Transform2D.Identity; - [Export] private Vector3 field_Vector3 = new(10f, 10f, 10f); - [Export] private Vector3I field_Vector3I = Vector3I.Back; - [Export] private Basis field_Basis = new Basis(Quaternion.Identity); - [Export] private Quaternion field_Quaternion = new Quaternion(Basis.Identity); - [Export] private Transform3D field_Transform3D = Transform3D.Identity; - [Export] private Vector4 field_Vector4 = new(10f, 10f, 10f, 10f); - [Export] private Vector4I field_Vector4I = Vector4I.One; - [Export] private Projection field_Projection = Projection.Identity; - [Export] private Aabb field_Aabb = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); - [Export] private Color field_Color = Colors.Aquamarine; - [Export] private Plane field_Plane = Plane.PlaneXZ; - [Export] private Callable field_Callable = new Callable(Engine.GetMainLoop(), "_process"); - [Export] private Signal field_Signal = new Signal(Engine.GetMainLoop(), "property_list_changed"); + [Export] private Vector2 _fieldVector2 = new(10f, 10f); + [Export] private Vector2I _fieldVector2I = Vector2I.Up; + [Export] private Rect2 _fieldRect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I _fieldRect2I = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D _fieldTransform2D = Transform2D.Identity; + [Export] private Vector3 _fieldVector3 = new(10f, 10f, 10f); + [Export] private Vector3I _fieldVector3I = Vector3I.Back; + [Export] private Basis _fieldBasis = new Basis(Quaternion.Identity); + [Export] private Quaternion _fieldQuaternion = new Quaternion(Basis.Identity); + [Export] private Transform3D _fieldTransform3D = Transform3D.Identity; + [Export] private Vector4 _fieldVector4 = new(10f, 10f, 10f, 10f); + [Export] private Vector4I _fieldVector4I = Vector4I.One; + [Export] private Projection _fieldProjection = Projection.Identity; + [Export] private Aabb _fieldAabb = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color _fieldColor = Colors.Aquamarine; + [Export] private Plane _fieldPlane = Plane.PlaneXZ; + [Export] private Callable _fieldCallable = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal _fieldSignal = new Signal(Engine.GetMainLoop(), "property_list_changed"); // Enums [SuppressMessage("ReSharper", "UnusedMember.Local")] - enum MyEnum + public enum MyEnum { A, B, C } - [Export] private MyEnum field_Enum = MyEnum.C; + [Export] private MyEnum _fieldEnum = MyEnum.C; [Flags] [SuppressMessage("ReSharper", "UnusedMember.Local")] - enum MyFlagsEnum + public enum MyFlagsEnum { A, B, C } - [Export] private MyFlagsEnum field_FlagsEnum = MyFlagsEnum.C; + [Export] private MyFlagsEnum _fieldFlagsEnum = MyFlagsEnum.C; // Arrays - [Export] private Byte[] field_ByteArray = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int32[] field_Int32Array = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int64[] field_Int64Array = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Single[] field_SingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - [Export] private Double[] field_DoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - [Export] private String[] field_StringArray = { "foo", "bar" }; - [Export(PropertyHint.Enum, "A,B,C")] private String[] field_StringArrayEnum = { "foo", "bar" }; - [Export] private Vector2[] field_Vector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; - [Export] private Vector3[] field_Vector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; - [Export] private Color[] field_ColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; - [Export] private GodotObject[] field_GodotObjectOrDerivedArray = { null }; - [Export] private StringName[] field_StringNameArray = { "foo", "bar" }; - [Export] private NodePath[] field_NodePathArray = { "foo", "bar" }; - [Export] private Rid[] field_RidArray = { default, default, default }; + [Export] private Byte[] _fieldByteArray = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] _fieldInt32Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] _fieldInt64Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] _fieldSingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] _fieldDoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] _fieldStringArray = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] _fieldStringArrayEnum = { "foo", "bar" }; + [Export] private Vector2[] _fieldVector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] _fieldVector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] _fieldColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] _fieldGodotObjectOrDerivedArray = { null }; + [Export] private StringName[] _fieldStringNameArray = { "foo", "bar" }; + [Export] private NodePath[] _fieldNodePathArray = { "foo", "bar" }; + [Export] private Rid[] _fieldRidArray = { default, default, default }; // Note we use Array and not System.Array. This tests the generated namespace qualification. - [Export] private Int32[] field_empty_Int32Array = Array.Empty<Int32>(); + [Export] private Int32[] _fieldEmptyInt32Array = Array.Empty<Int32>(); // Note we use List and not System.Collections.Generic. - [Export] private int[] field_array_from_list = new List<int>(Array.Empty<int>()).ToArray(); + [Export] private int[] _fieldArrayFromList = new List<int>(Array.Empty<int>()).ToArray(); // Variant - [Export] private Variant field_Variant = "foo"; + [Export] private Variant _fieldVariant = "foo"; // Classes - [Export] private GodotObject field_GodotObjectOrDerived; - [Export] private Godot.Texture field_GodotResourceTexture; - [Export] private StringName field_StringName = new StringName("foo"); - [Export] private NodePath field_NodePath = new NodePath("foo"); - [Export] private Rid field_Rid; + [Export] private GodotObject _fieldGodotObjectOrDerived; + [Export] private Godot.Texture _fieldGodotResourceTexture; + [Export] private StringName _fieldStringName = new StringName("foo"); + [Export] private NodePath _fieldNodePath = new NodePath("foo"); + [Export] private Rid _fieldRid; [Export] - private Godot.Collections.Dictionary field_GodotDictionary = + private Godot.Collections.Dictionary _fieldGodotDictionary = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; [Export] - private Godot.Collections.Array field_GodotArray = + private Godot.Collections.Array _fieldGodotArray = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; [Export] - private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary = + private Godot.Collections.Dictionary<string, bool> _fieldGodotGenericDictionary = new() { { "foo", true }, { "bar", false } }; [Export] - private Godot.Collections.Array<int> field_GodotGenericArray = + private Godot.Collections.Array<int> _fieldGodotGenericArray = new() { 0, 1, 2, 3, 4, 5, 6 }; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs index aef2a8824e..91f33383ab 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs @@ -13,41 +13,41 @@ namespace Godot.SourceGenerators.Sample public partial class ExportedProperties : GodotObject { // Do not generate default value - private String _notGenerate_Property_String = new string("not generate"); + private String _notGeneratePropertyString = new string("not generate"); [Export] - public String NotGenerate_Complex_Lamda_Property + public String NotGenerateComplexLambdaProperty { - get => _notGenerate_Property_String + Convert.ToInt32("1"); - set => _notGenerate_Property_String = value; + get => _notGeneratePropertyString + Convert.ToInt32("1"); + set => _notGeneratePropertyString = value; } [Export] - public String NotGenerate_Lamda_NoField_Property + public String NotGenerateLambdaNoFieldProperty { get => new string("not generate"); - set => _notGenerate_Property_String = value; + set => _notGeneratePropertyString = value; } [Export] - public String NotGenerate_Complex_Return_Property + public String NotGenerateComplexReturnProperty { get { - return _notGenerate_Property_String + Convert.ToInt32("1"); + return _notGeneratePropertyString + Convert.ToInt32("1"); } set { - _notGenerate_Property_String = value; + _notGeneratePropertyString = value; } } - private int _notGenerate_Property_Int = 1; + private int _notGeneratePropertyInt = 1; [Export] public string NotGenerate_Returns_Property { get { - if (_notGenerate_Property_Int == 1) + if (_notGeneratePropertyInt == 1) { return "a"; } @@ -58,145 +58,145 @@ namespace Godot.SourceGenerators.Sample } set { - _notGenerate_Property_Int = value == "a" ? 1 : 2; + _notGeneratePropertyInt = value == "a" ? 1 : 2; } } // Full Property - private String _fullProperty_String = "FullProperty_String"; + private String _fullPropertyString = "FullPropertyString"; [Export] - public String FullProperty_String + public String FullPropertyString { get { - return _fullProperty_String; + return _fullPropertyString; } set { - _fullProperty_String = value; + _fullPropertyString = value; } } - private String _fullProperty_String_Complex = new string("FullProperty_String_Complex") + Convert.ToInt32("1"); + private String _fullPropertyStringComplex = new string("FullPropertyString_Complex") + Convert.ToInt32("1"); [Export] - public String FullProperty_String_Complex + public String FullPropertyStringComplex { get { - return _fullProperty_String_Complex; + return _fullPropertyStringComplex; } set { - _fullProperty_String_Complex = value; + _fullPropertyStringComplex = value; } } // Lambda Property - private String _lamdaProperty_String = "LamdaProperty_String"; + private String _lamdaPropertyString = "LamdaPropertyString"; [Export] - public String LamdaProperty_String + public String LamdaPropertyString { - get => _lamdaProperty_String; - set => _lamdaProperty_String = value; + get => _lamdaPropertyString; + set => _lamdaPropertyString = value; } // Auto Property - [Export] private Boolean property_Boolean { get; set; } = true; - [Export] private Char property_Char { get; set; } = 'f'; - [Export] private SByte property_SByte { get; set; } = 10; - [Export] private Int16 property_Int16 { get; set; } = 10; - [Export] private Int32 property_Int32 { get; set; } = 10; - [Export] private Int64 property_Int64 { get; set; } = 10; - [Export] private Byte property_Byte { get; set; } = 10; - [Export] private UInt16 property_UInt16 { get; set; } = 10; - [Export] private UInt32 property_UInt32 { get; set; } = 10; - [Export] private UInt64 property_UInt64 { get; set; } = 10; - [Export] private Single property_Single { get; set; } = 10; - [Export] private Double property_Double { get; set; } = 10; - [Export] private String property_String { get; set; } = "foo"; + [Export] private Boolean PropertyBoolean { get; set; } = true; + [Export] private Char PropertyChar { get; set; } = 'f'; + [Export] private SByte PropertySByte { get; set; } = 10; + [Export] private Int16 PropertyInt16 { get; set; } = 10; + [Export] private Int32 PropertyInt32 { get; set; } = 10; + [Export] private Int64 PropertyInt64 { get; set; } = 10; + [Export] private Byte PropertyByte { get; set; } = 10; + [Export] private UInt16 PropertyUInt16 { get; set; } = 10; + [Export] private UInt32 PropertyUInt32 { get; set; } = 10; + [Export] private UInt64 PropertyUInt64 { get; set; } = 10; + [Export] private Single PropertySingle { get; set; } = 10; + [Export] private Double PropertyDouble { get; set; } = 10; + [Export] private String PropertyString { get; set; } = "foo"; // Godot structs - [Export] private Vector2 property_Vector2 { get; set; } = new(10f, 10f); - [Export] private Vector2I property_Vector2I { get; set; } = Vector2I.Up; - [Export] private Rect2 property_Rect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); - [Export] private Rect2I property_Rect2I { get; set; } = new(new Vector2I(10, 10), new Vector2I(10, 10)); - [Export] private Transform2D property_Transform2D { get; set; } = Transform2D.Identity; - [Export] private Vector3 property_Vector3 { get; set; } = new(10f, 10f, 10f); - [Export] private Vector3I property_Vector3I { get; set; } = Vector3I.Back; - [Export] private Basis property_Basis { get; set; } = new Basis(Quaternion.Identity); - [Export] private Quaternion property_Quaternion { get; set; } = new Quaternion(Basis.Identity); - [Export] private Transform3D property_Transform3D { get; set; } = Transform3D.Identity; - [Export] private Vector4 property_Vector4 { get; set; } = new(10f, 10f, 10f, 10f); - [Export] private Vector4I property_Vector4I { get; set; } = Vector4I.One; - [Export] private Projection property_Projection { get; set; } = Projection.Identity; - [Export] private Aabb property_Aabb { get; set; } = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); - [Export] private Color property_Color { get; set; } = Colors.Aquamarine; - [Export] private Plane property_Plane { get; set; } = Plane.PlaneXZ; - [Export] private Callable property_Callable { get; set; } = new Callable(Engine.GetMainLoop(), "_process"); - [Export] private Signal property_Signal { get; set; } = new Signal(Engine.GetMainLoop(), "property_list_changed"); + [Export] private Vector2 PropertyVector2 { get; set; } = new(10f, 10f); + [Export] private Vector2I PropertyVector2I { get; set; } = Vector2I.Up; + [Export] private Rect2 PropertyRect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I PropertyRect2I { get; set; } = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D PropertyTransform2D { get; set; } = Transform2D.Identity; + [Export] private Vector3 PropertyVector3 { get; set; } = new(10f, 10f, 10f); + [Export] private Vector3I PropertyVector3I { get; set; } = Vector3I.Back; + [Export] private Basis PropertyBasis { get; set; } = new Basis(Quaternion.Identity); + [Export] private Quaternion PropertyQuaternion { get; set; } = new Quaternion(Basis.Identity); + [Export] private Transform3D PropertyTransform3D { get; set; } = Transform3D.Identity; + [Export] private Vector4 PropertyVector4 { get; set; } = new(10f, 10f, 10f, 10f); + [Export] private Vector4I PropertyVector4I { get; set; } = Vector4I.One; + [Export] private Projection PropertyProjection { get; set; } = Projection.Identity; + [Export] private Aabb PropertyAabb { get; set; } = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color PropertyColor { get; set; } = Colors.Aquamarine; + [Export] private Plane PropertyPlane { get; set; } = Plane.PlaneXZ; + [Export] private Callable PropertyCallable { get; set; } = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal PropertySignal { get; set; } = new Signal(Engine.GetMainLoop(), "Propertylist_changed"); // Enums [SuppressMessage("ReSharper", "UnusedMember.Local")] - enum MyEnum + public enum MyEnum { A, B, C } - [Export] private MyEnum property_Enum { get; set; } = MyEnum.C; + [Export] private MyEnum PropertyEnum { get; set; } = MyEnum.C; [Flags] [SuppressMessage("ReSharper", "UnusedMember.Local")] - enum MyFlagsEnum + public enum MyFlagsEnum { A, B, C } - [Export] private MyFlagsEnum property_FlagsEnum { get; set; } = MyFlagsEnum.C; + [Export] private MyFlagsEnum PropertyFlagsEnum { get; set; } = MyFlagsEnum.C; // Arrays - [Export] private Byte[] property_ByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int32[] property_Int32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int64[] property_Int64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Single[] property_SingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - [Export] private Double[] property_DoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - [Export] private String[] property_StringArray { get; set; } = { "foo", "bar" }; - [Export(PropertyHint.Enum, "A,B,C")] private String[] property_StringArrayEnum { get; set; } = { "foo", "bar" }; - [Export] private Vector2[] property_Vector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; - [Export] private Vector3[] property_Vector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; - [Export] private Color[] property_ColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; - [Export] private GodotObject[] property_GodotObjectOrDerivedArray { get; set; } = { null }; - [Export] private StringName[] field_StringNameArray { get; set; } = { "foo", "bar" }; - [Export] private NodePath[] field_NodePathArray { get; set; } = { "foo", "bar" }; - [Export] private Rid[] field_RidArray { get; set; } = { default, default, default }; + [Export] private Byte[] PropertyByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] PropertyInt32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] PropertyInt64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] PropertySingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] PropertyDoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] PropertyStringArray { get; set; } = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] PropertyStringArrayEnum { get; set; } = { "foo", "bar" }; + [Export] private Vector2[] PropertyVector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] PropertyVector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] PropertyColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] PropertyGodotObjectOrDerivedArray { get; set; } = { null }; + [Export] private StringName[] PropertyStringNameArray { get; set; } = { "foo", "bar" }; + [Export] private NodePath[] PropertyNodePathArray { get; set; } = { "foo", "bar" }; + [Export] private Rid[] PropertyRidArray { get; set; } = { default, default, default }; // Variant - [Export] private Variant property_Variant { get; set; } = "foo"; + [Export] private Variant PropertyVariant { get; set; } = "foo"; // Classes - [Export] private GodotObject property_GodotObjectOrDerived { get; set; } - [Export] private Godot.Texture property_GodotResourceTexture { get; set; } - [Export] private StringName property_StringName { get; set; } = new StringName("foo"); - [Export] private NodePath property_NodePath { get; set; } = new NodePath("foo"); - [Export] private Rid property_Rid { get; set; } + [Export] private GodotObject PropertyGodotObjectOrDerived { get; set; } + [Export] private Godot.Texture PropertyGodotResourceTexture { get; set; } + [Export] private StringName PropertyStringName { get; set; } = new StringName("foo"); + [Export] private NodePath PropertyNodePath { get; set; } = new NodePath("foo"); + [Export] private Rid PropertyRid { get; set; } [Export] - private Godot.Collections.Dictionary property_GodotDictionary { get; set; } = + private Godot.Collections.Dictionary PropertyGodotDictionary { get; set; } = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; [Export] - private Godot.Collections.Array property_GodotArray { get; set; } = + private Godot.Collections.Array PropertyGodotArray { get; set; } = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; [Export] - private Godot.Collections.Dictionary<string, bool> property_GodotGenericDictionary { get; set; } = + private Godot.Collections.Dictionary<string, bool> PropertyGodotGenericDictionary { get; set; } = new() { { "foo", true }, { "bar", false } }; [Export] - private Godot.Collections.Array<int> property_GodotGenericArray { get; set; } = + private Godot.Collections.Array<int> PropertyGodotGenericArray { get; set; } = new() { 0, 1, 2, 3, 4, 5, 6 }; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs index 9ef72d9e02..d2293e0731 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Foo.cs @@ -1,11 +1,11 @@ namespace Godot.SourceGenerators.Sample { - partial class Foo : GodotObject + public partial class Foo : GodotObject { } // Foo again in the same file - partial class Foo + public partial class Foo { } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs index 457d8daa8e..9d16a3170b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs @@ -3,7 +3,7 @@ namespace Godot.SourceGenerators.Sample { // Generic again but without generic parameters - partial class Generic : GodotObject + public partial class Generic : GodotObject { private int _field; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs index 9c4f8ee1e1..6d92ff1b0b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs @@ -2,7 +2,7 @@ namespace Godot.SourceGenerators.Sample { - partial class Generic1T<T> : GodotObject + public partial class Generic1T<T> : GodotObject { private int _field; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs index 80551a0b42..eef80ff951 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs @@ -3,7 +3,7 @@ namespace Godot.SourceGenerators.Sample { // Generic again but different generic parameters - partial class Generic2T<T, R> : GodotObject + public partial class Generic2T<T, R> : GodotObject { private int _field; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs index 64088215e9..28685ac87a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/MoreExportedFields.cs @@ -14,6 +14,6 @@ namespace Godot.SourceGenerators.Sample public partial class ExportedFields : GodotObject { // Note we use Array and not System.Array. This tests the generated namespace qualification. - [Export] private Int64[] field_empty_Int64Array = Array.Empty<Int64>(); + [Export] private Int64[] _fieldEmptyInt64Array = Array.Empty<Int64>(); } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/NestedClass.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/NestedClass.cs index 3021f57115..3c533b712d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/NestedClass.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/NestedClass.cs @@ -11,8 +11,8 @@ public partial class NestedClass : GodotObject [Signal] public delegate void MySignalEventHandler(string str, int num); - [Export] private String field_String = "foo"; - [Export] private String property_String { get; set; } = "foo"; + [Export] private String _fieldString = "foo"; + [Export] private String PropertyString { get; set; } = "foo"; private void Method() { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs index 0c374169b9..c36aa55eef 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllReadOnly.cs @@ -2,9 +2,9 @@ namespace Godot.SourceGenerators.Sample { public partial class AllReadOnly : GodotObject { - public readonly string readonly_field = "foo"; - public string readonly_auto_property { get; } = "foo"; - public string readonly_property { get => "foo"; } - public string initonly_auto_property { get; init; } + public readonly string ReadonlyField = "foo"; + public string ReadonlyAutoProperty { get; } = "foo"; + public string ReadonlyProperty { get => "foo"; } + public string InitonlyAutoProperty { get; init; } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs index 14a1802330..48acfa6c95 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/AllWriteOnly.cs @@ -4,7 +4,7 @@ namespace Godot.SourceGenerators.Sample { public partial class AllWriteOnly : GodotObject { - bool writeonly_backing_field = false; - public bool writeonly_property { set => writeonly_backing_field = value; } + private bool _writeOnlyBackingField = false; + public bool WriteOnlyProperty { set => _writeOnlyBackingField = value; } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs index f556bdc7e4..c6ce6efe78 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/OneWayProperties/MixedReadOnlyWriteOnly.cs @@ -2,12 +2,12 @@ namespace Godot.SourceGenerators.Sample { public partial class MixedReadonlyWriteOnly : GodotObject { - public readonly string readonly_field = "foo"; - public string readonly_auto_property { get; } = "foo"; - public string readonly_property { get => "foo"; } - public string initonly_auto_property { get; init; } + public readonly string ReadOnlyField = "foo"; + public string ReadOnlyAutoProperty { get; } = "foo"; + public string ReadOnlyProperty { get => "foo"; } + public string InitOnlyAutoProperty { get; init; } - bool writeonly_backing_field = false; - public bool writeonly_property { set => writeonly_backing_field = value; } + private bool _writeOnlyBackingField = false; + public bool WriteOnlyProperty { set => _writeOnlyBackingField = value; } } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs index e43a3469ae..1266f6d853 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs @@ -26,7 +26,7 @@ namespace Godot.SourceGenerators.Sample } } - partial struct OuterClass + public partial struct OuterClass { public partial class NesterClass : RefCounted { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs index d20b354b9e..3cc5841097 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs @@ -41,7 +41,7 @@ public class ScriptPropertiesGeneratorTests } [Fact] - public async void OneWayPropertiesMixedReadonlyWriteOnly() + public async void OneWayPropertiesMixedReadOnlyWriteOnly() { await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify( "MixedReadOnlyWriteOnly.cs", diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs index db56ac30a3..96ff0f75e9 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllReadOnly_ScriptProperties.generated.cs @@ -9,40 +9,40 @@ partial class AllReadOnly /// </summary> public new class PropertyName : global::Godot.GodotObject.PropertyName { /// <summary> - /// Cached name for the 'readonly_auto_property' property. + /// Cached name for the 'ReadOnlyAutoProperty' property. /// </summary> - public new static readonly global::Godot.StringName readonly_auto_property = "readonly_auto_property"; + public new static readonly global::Godot.StringName ReadOnlyAutoProperty = "ReadOnlyAutoProperty"; /// <summary> - /// Cached name for the 'readonly_property' property. + /// Cached name for the 'ReadOnlyProperty' property. /// </summary> - public new static readonly global::Godot.StringName readonly_property = "readonly_property"; + public new static readonly global::Godot.StringName ReadOnlyProperty = "ReadOnlyProperty"; /// <summary> - /// Cached name for the 'initonly_auto_property' property. + /// Cached name for the 'InitOnlyAutoProperty' property. /// </summary> - public new static readonly global::Godot.StringName initonly_auto_property = "initonly_auto_property"; + public new static readonly global::Godot.StringName InitOnlyAutoProperty = "InitOnlyAutoProperty"; /// <summary> - /// Cached name for the 'readonly_field' field. + /// Cached name for the 'ReadOnlyField' field. /// </summary> - public new static readonly global::Godot.StringName readonly_field = "readonly_field"; + public new static readonly global::Godot.StringName ReadOnlyField = "ReadOnlyField"; } /// <inheritdoc/> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) { - if (name == PropertyName.readonly_auto_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_auto_property); + if (name == PropertyName.ReadOnlyAutoProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyAutoProperty); return true; } - else if (name == PropertyName.readonly_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_property); + else if (name == PropertyName.ReadOnlyProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyProperty); return true; } - else if (name == PropertyName.initonly_auto_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.initonly_auto_property); + else if (name == PropertyName.InitOnlyAutoProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.InitOnlyAutoProperty); return true; } - else if (name == PropertyName.readonly_field) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_field); + else if (name == PropertyName.ReadOnlyField) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyField); return true; } return base.GetGodotClassPropertyValue(name, out value); @@ -56,10 +56,10 @@ partial class AllReadOnly internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() { var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.initonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyField, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyAutoProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.InitOnlyAutoProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); return properties; } #pragma warning restore CS0109 diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs index 256420fe87..91dd282b99 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/AllWriteOnly_ScriptProperties.generated.cs @@ -9,24 +9,24 @@ partial class AllWriteOnly /// </summary> public new class PropertyName : global::Godot.GodotObject.PropertyName { /// <summary> - /// Cached name for the 'writeonly_property' property. + /// Cached name for the 'WriteOnlyProperty' property. /// </summary> - public new static readonly global::Godot.StringName writeonly_property = "writeonly_property"; + public new static readonly global::Godot.StringName WriteOnlyProperty = "WriteOnlyProperty"; /// <summary> - /// Cached name for the 'writeonly_backing_field' field. + /// Cached name for the '_writeOnlyBackingField' field. /// </summary> - public new static readonly global::Godot.StringName writeonly_backing_field = "writeonly_backing_field"; + public new static readonly global::Godot.StringName _writeOnlyBackingField = "_writeOnlyBackingField"; } /// <inheritdoc/> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) { - if (name == PropertyName.writeonly_property) { - this.writeonly_property = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + if (name == PropertyName.WriteOnlyProperty) { + this.WriteOnlyProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName.writeonly_backing_field) { - this.writeonly_backing_field = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + else if (name == PropertyName._writeOnlyBackingField) { + this._writeOnlyBackingField = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } return base.SetGodotClassPropertyValue(name, value); @@ -35,8 +35,8 @@ partial class AllWriteOnly [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) { - if (name == PropertyName.writeonly_backing_field) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.writeonly_backing_field); + if (name == PropertyName._writeOnlyBackingField) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this._writeOnlyBackingField); return true; } return base.GetGodotClassPropertyValue(name, out value); @@ -50,8 +50,8 @@ partial class AllWriteOnly internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() { var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_backing_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName._writeOnlyBackingField, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.WriteOnlyProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); return properties; } #pragma warning restore CS0109 diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs index 915c36525b..334adc1243 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptProperties.generated.cs @@ -9,488 +9,488 @@ partial class ExportedFields /// </summary> public new class PropertyName : global::Godot.GodotObject.PropertyName { /// <summary> - /// Cached name for the 'field_Boolean' field. + /// Cached name for the '_fieldBoolean' field. /// </summary> - public new static readonly global::Godot.StringName field_Boolean = "field_Boolean"; + public new static readonly global::Godot.StringName _fieldBoolean = "_fieldBoolean"; /// <summary> - /// Cached name for the 'field_Char' field. + /// Cached name for the '_fieldChar' field. /// </summary> - public new static readonly global::Godot.StringName field_Char = "field_Char"; + public new static readonly global::Godot.StringName _fieldChar = "_fieldChar"; /// <summary> - /// Cached name for the 'field_SByte' field. + /// Cached name for the '_fieldSByte' field. /// </summary> - public new static readonly global::Godot.StringName field_SByte = "field_SByte"; + public new static readonly global::Godot.StringName _fieldSByte = "_fieldSByte"; /// <summary> - /// Cached name for the 'field_Int16' field. + /// Cached name for the '_fieldInt16' field. /// </summary> - public new static readonly global::Godot.StringName field_Int16 = "field_Int16"; + public new static readonly global::Godot.StringName _fieldInt16 = "_fieldInt16"; /// <summary> - /// Cached name for the 'field_Int32' field. + /// Cached name for the '_fieldInt32' field. /// </summary> - public new static readonly global::Godot.StringName field_Int32 = "field_Int32"; + public new static readonly global::Godot.StringName _fieldInt32 = "_fieldInt32"; /// <summary> - /// Cached name for the 'field_Int64' field. + /// Cached name for the '_fieldInt64' field. /// </summary> - public new static readonly global::Godot.StringName field_Int64 = "field_Int64"; + public new static readonly global::Godot.StringName _fieldInt64 = "_fieldInt64"; /// <summary> - /// Cached name for the 'field_Byte' field. + /// Cached name for the '_fieldByte' field. /// </summary> - public new static readonly global::Godot.StringName field_Byte = "field_Byte"; + public new static readonly global::Godot.StringName _fieldByte = "_fieldByte"; /// <summary> - /// Cached name for the 'field_UInt16' field. + /// Cached name for the '_fieldUInt16' field. /// </summary> - public new static readonly global::Godot.StringName field_UInt16 = "field_UInt16"; + public new static readonly global::Godot.StringName _fieldUInt16 = "_fieldUInt16"; /// <summary> - /// Cached name for the 'field_UInt32' field. + /// Cached name for the '_fieldUInt32' field. /// </summary> - public new static readonly global::Godot.StringName field_UInt32 = "field_UInt32"; + public new static readonly global::Godot.StringName _fieldUInt32 = "_fieldUInt32"; /// <summary> - /// Cached name for the 'field_UInt64' field. + /// Cached name for the '_fieldUInt64' field. /// </summary> - public new static readonly global::Godot.StringName field_UInt64 = "field_UInt64"; + public new static readonly global::Godot.StringName _fieldUInt64 = "_fieldUInt64"; /// <summary> - /// Cached name for the 'field_Single' field. + /// Cached name for the '_fieldSingle' field. /// </summary> - public new static readonly global::Godot.StringName field_Single = "field_Single"; + public new static readonly global::Godot.StringName _fieldSingle = "_fieldSingle"; /// <summary> - /// Cached name for the 'field_Double' field. + /// Cached name for the '_fieldDouble' field. /// </summary> - public new static readonly global::Godot.StringName field_Double = "field_Double"; + public new static readonly global::Godot.StringName _fieldDouble = "_fieldDouble"; /// <summary> - /// Cached name for the 'field_String' field. + /// Cached name for the '_fieldString' field. /// </summary> - public new static readonly global::Godot.StringName field_String = "field_String"; + public new static readonly global::Godot.StringName _fieldString = "_fieldString"; /// <summary> - /// Cached name for the 'field_Vector2' field. + /// Cached name for the '_fieldVector2' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector2 = "field_Vector2"; + public new static readonly global::Godot.StringName _fieldVector2 = "_fieldVector2"; /// <summary> - /// Cached name for the 'field_Vector2I' field. + /// Cached name for the '_fieldVector2I' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector2I = "field_Vector2I"; + public new static readonly global::Godot.StringName _fieldVector2I = "_fieldVector2I"; /// <summary> - /// Cached name for the 'field_Rect2' field. + /// Cached name for the '_fieldRect2' field. /// </summary> - public new static readonly global::Godot.StringName field_Rect2 = "field_Rect2"; + public new static readonly global::Godot.StringName _fieldRect2 = "_fieldRect2"; /// <summary> - /// Cached name for the 'field_Rect2I' field. + /// Cached name for the '_fieldRect2I' field. /// </summary> - public new static readonly global::Godot.StringName field_Rect2I = "field_Rect2I"; + public new static readonly global::Godot.StringName _fieldRect2I = "_fieldRect2I"; /// <summary> - /// Cached name for the 'field_Transform2D' field. + /// Cached name for the '_fieldTransform2D' field. /// </summary> - public new static readonly global::Godot.StringName field_Transform2D = "field_Transform2D"; + public new static readonly global::Godot.StringName _fieldTransform2D = "_fieldTransform2D"; /// <summary> - /// Cached name for the 'field_Vector3' field. + /// Cached name for the '_fieldVector3' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector3 = "field_Vector3"; + public new static readonly global::Godot.StringName _fieldVector3 = "_fieldVector3"; /// <summary> - /// Cached name for the 'field_Vector3I' field. + /// Cached name for the '_fieldVector3I' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector3I = "field_Vector3I"; + public new static readonly global::Godot.StringName _fieldVector3I = "_fieldVector3I"; /// <summary> - /// Cached name for the 'field_Basis' field. + /// Cached name for the '_fieldBasis' field. /// </summary> - public new static readonly global::Godot.StringName field_Basis = "field_Basis"; + public new static readonly global::Godot.StringName _fieldBasis = "_fieldBasis"; /// <summary> - /// Cached name for the 'field_Quaternion' field. + /// Cached name for the '_fieldQuaternion' field. /// </summary> - public new static readonly global::Godot.StringName field_Quaternion = "field_Quaternion"; + public new static readonly global::Godot.StringName _fieldQuaternion = "_fieldQuaternion"; /// <summary> - /// Cached name for the 'field_Transform3D' field. + /// Cached name for the '_fieldTransform3D' field. /// </summary> - public new static readonly global::Godot.StringName field_Transform3D = "field_Transform3D"; + public new static readonly global::Godot.StringName _fieldTransform3D = "_fieldTransform3D"; /// <summary> - /// Cached name for the 'field_Vector4' field. + /// Cached name for the '_fieldVector4' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector4 = "field_Vector4"; + public new static readonly global::Godot.StringName _fieldVector4 = "_fieldVector4"; /// <summary> - /// Cached name for the 'field_Vector4I' field. + /// Cached name for the '_fieldVector4I' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector4I = "field_Vector4I"; + public new static readonly global::Godot.StringName _fieldVector4I = "_fieldVector4I"; /// <summary> - /// Cached name for the 'field_Projection' field. + /// Cached name for the '_fieldProjection' field. /// </summary> - public new static readonly global::Godot.StringName field_Projection = "field_Projection"; + public new static readonly global::Godot.StringName _fieldProjection = "_fieldProjection"; /// <summary> - /// Cached name for the 'field_Aabb' field. + /// Cached name for the '_fieldAabb' field. /// </summary> - public new static readonly global::Godot.StringName field_Aabb = "field_Aabb"; + public new static readonly global::Godot.StringName _fieldAabb = "_fieldAabb"; /// <summary> - /// Cached name for the 'field_Color' field. + /// Cached name for the '_fieldColor' field. /// </summary> - public new static readonly global::Godot.StringName field_Color = "field_Color"; + public new static readonly global::Godot.StringName _fieldColor = "_fieldColor"; /// <summary> - /// Cached name for the 'field_Plane' field. + /// Cached name for the '_fieldPlane' field. /// </summary> - public new static readonly global::Godot.StringName field_Plane = "field_Plane"; + public new static readonly global::Godot.StringName _fieldPlane = "_fieldPlane"; /// <summary> - /// Cached name for the 'field_Callable' field. + /// Cached name for the '_fieldCallable' field. /// </summary> - public new static readonly global::Godot.StringName field_Callable = "field_Callable"; + public new static readonly global::Godot.StringName _fieldCallable = "_fieldCallable"; /// <summary> - /// Cached name for the 'field_Signal' field. + /// Cached name for the '_fieldSignal' field. /// </summary> - public new static readonly global::Godot.StringName field_Signal = "field_Signal"; + public new static readonly global::Godot.StringName _fieldSignal = "_fieldSignal"; /// <summary> - /// Cached name for the 'field_Enum' field. + /// Cached name for the '_fieldEnum' field. /// </summary> - public new static readonly global::Godot.StringName field_Enum = "field_Enum"; + public new static readonly global::Godot.StringName _fieldEnum = "_fieldEnum"; /// <summary> - /// Cached name for the 'field_FlagsEnum' field. + /// Cached name for the '_fieldFlagsEnum' field. /// </summary> - public new static readonly global::Godot.StringName field_FlagsEnum = "field_FlagsEnum"; + public new static readonly global::Godot.StringName _fieldFlagsEnum = "_fieldFlagsEnum"; /// <summary> - /// Cached name for the 'field_ByteArray' field. + /// Cached name for the '_fieldByteArray' field. /// </summary> - public new static readonly global::Godot.StringName field_ByteArray = "field_ByteArray"; + public new static readonly global::Godot.StringName _fieldByteArray = "_fieldByteArray"; /// <summary> - /// Cached name for the 'field_Int32Array' field. + /// Cached name for the '_fieldInt32Array' field. /// </summary> - public new static readonly global::Godot.StringName field_Int32Array = "field_Int32Array"; + public new static readonly global::Godot.StringName _fieldInt32Array = "_fieldInt32Array"; /// <summary> - /// Cached name for the 'field_Int64Array' field. + /// Cached name for the '_fieldInt64Array' field. /// </summary> - public new static readonly global::Godot.StringName field_Int64Array = "field_Int64Array"; + public new static readonly global::Godot.StringName _fieldInt64Array = "_fieldInt64Array"; /// <summary> - /// Cached name for the 'field_SingleArray' field. + /// Cached name for the '_fieldSingleArray' field. /// </summary> - public new static readonly global::Godot.StringName field_SingleArray = "field_SingleArray"; + public new static readonly global::Godot.StringName _fieldSingleArray = "_fieldSingleArray"; /// <summary> - /// Cached name for the 'field_DoubleArray' field. + /// Cached name for the '_fieldDoubleArray' field. /// </summary> - public new static readonly global::Godot.StringName field_DoubleArray = "field_DoubleArray"; + public new static readonly global::Godot.StringName _fieldDoubleArray = "_fieldDoubleArray"; /// <summary> - /// Cached name for the 'field_StringArray' field. + /// Cached name for the '_fieldStringArray' field. /// </summary> - public new static readonly global::Godot.StringName field_StringArray = "field_StringArray"; + public new static readonly global::Godot.StringName _fieldStringArray = "_fieldStringArray"; /// <summary> - /// Cached name for the 'field_StringArrayEnum' field. + /// Cached name for the '_fieldStringArrayEnum' field. /// </summary> - public new static readonly global::Godot.StringName field_StringArrayEnum = "field_StringArrayEnum"; + public new static readonly global::Godot.StringName _fieldStringArrayEnum = "_fieldStringArrayEnum"; /// <summary> - /// Cached name for the 'field_Vector2Array' field. + /// Cached name for the '_fieldVector2Array' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector2Array = "field_Vector2Array"; + public new static readonly global::Godot.StringName _fieldVector2Array = "_fieldVector2Array"; /// <summary> - /// Cached name for the 'field_Vector3Array' field. + /// Cached name for the '_fieldVector3Array' field. /// </summary> - public new static readonly global::Godot.StringName field_Vector3Array = "field_Vector3Array"; + public new static readonly global::Godot.StringName _fieldVector3Array = "_fieldVector3Array"; /// <summary> - /// Cached name for the 'field_ColorArray' field. + /// Cached name for the '_fieldColorArray' field. /// </summary> - public new static readonly global::Godot.StringName field_ColorArray = "field_ColorArray"; + public new static readonly global::Godot.StringName _fieldColorArray = "_fieldColorArray"; /// <summary> - /// Cached name for the 'field_GodotObjectOrDerivedArray' field. + /// Cached name for the '_fieldGodotObjectOrDerivedArray' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotObjectOrDerivedArray = "field_GodotObjectOrDerivedArray"; + public new static readonly global::Godot.StringName _fieldGodotObjectOrDerivedArray = "_fieldGodotObjectOrDerivedArray"; /// <summary> - /// Cached name for the 'field_StringNameArray' field. + /// Cached name for the '_fieldStringNameArray' field. /// </summary> - public new static readonly global::Godot.StringName field_StringNameArray = "field_StringNameArray"; + public new static readonly global::Godot.StringName _fieldStringNameArray = "_fieldStringNameArray"; /// <summary> - /// Cached name for the 'field_NodePathArray' field. + /// Cached name for the '_fieldNodePathArray' field. /// </summary> - public new static readonly global::Godot.StringName field_NodePathArray = "field_NodePathArray"; + public new static readonly global::Godot.StringName _fieldNodePathArray = "_fieldNodePathArray"; /// <summary> - /// Cached name for the 'field_RidArray' field. + /// Cached name for the '_fieldRidArray' field. /// </summary> - public new static readonly global::Godot.StringName field_RidArray = "field_RidArray"; + public new static readonly global::Godot.StringName _fieldRidArray = "_fieldRidArray"; /// <summary> - /// Cached name for the 'field_empty_Int32Array' field. + /// Cached name for the '_fieldEmptyInt32Array' field. /// </summary> - public new static readonly global::Godot.StringName field_empty_Int32Array = "field_empty_Int32Array"; + public new static readonly global::Godot.StringName _fieldEmptyInt32Array = "_fieldEmptyInt32Array"; /// <summary> - /// Cached name for the 'field_array_from_list' field. + /// Cached name for the '_fieldArrayFromList' field. /// </summary> - public new static readonly global::Godot.StringName field_array_from_list = "field_array_from_list"; + public new static readonly global::Godot.StringName _fieldArrayFromList = "_fieldArrayFromList"; /// <summary> - /// Cached name for the 'field_Variant' field. + /// Cached name for the '_fieldVariant' field. /// </summary> - public new static readonly global::Godot.StringName field_Variant = "field_Variant"; + public new static readonly global::Godot.StringName _fieldVariant = "_fieldVariant"; /// <summary> - /// Cached name for the 'field_GodotObjectOrDerived' field. + /// Cached name for the '_fieldGodotObjectOrDerived' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotObjectOrDerived = "field_GodotObjectOrDerived"; + public new static readonly global::Godot.StringName _fieldGodotObjectOrDerived = "_fieldGodotObjectOrDerived"; /// <summary> - /// Cached name for the 'field_GodotResourceTexture' field. + /// Cached name for the '_fieldGodotResourceTexture' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotResourceTexture = "field_GodotResourceTexture"; + public new static readonly global::Godot.StringName _fieldGodotResourceTexture = "_fieldGodotResourceTexture"; /// <summary> - /// Cached name for the 'field_StringName' field. + /// Cached name for the '_fieldStringName' field. /// </summary> - public new static readonly global::Godot.StringName field_StringName = "field_StringName"; + public new static readonly global::Godot.StringName _fieldStringName = "_fieldStringName"; /// <summary> - /// Cached name for the 'field_NodePath' field. + /// Cached name for the '_fieldNodePath' field. /// </summary> - public new static readonly global::Godot.StringName field_NodePath = "field_NodePath"; + public new static readonly global::Godot.StringName _fieldNodePath = "_fieldNodePath"; /// <summary> - /// Cached name for the 'field_Rid' field. + /// Cached name for the '_fieldRid' field. /// </summary> - public new static readonly global::Godot.StringName field_Rid = "field_Rid"; + public new static readonly global::Godot.StringName _fieldRid = "_fieldRid"; /// <summary> - /// Cached name for the 'field_GodotDictionary' field. + /// Cached name for the '_fieldGodotDictionary' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotDictionary = "field_GodotDictionary"; + public new static readonly global::Godot.StringName _fieldGodotDictionary = "_fieldGodotDictionary"; /// <summary> - /// Cached name for the 'field_GodotArray' field. + /// Cached name for the '_fieldGodotArray' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotArray = "field_GodotArray"; + public new static readonly global::Godot.StringName _fieldGodotArray = "_fieldGodotArray"; /// <summary> - /// Cached name for the 'field_GodotGenericDictionary' field. + /// Cached name for the '_fieldGodotGenericDictionary' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotGenericDictionary = "field_GodotGenericDictionary"; + public new static readonly global::Godot.StringName _fieldGodotGenericDictionary = "_fieldGodotGenericDictionary"; /// <summary> - /// Cached name for the 'field_GodotGenericArray' field. + /// Cached name for the '_fieldGodotGenericArray' field. /// </summary> - public new static readonly global::Godot.StringName field_GodotGenericArray = "field_GodotGenericArray"; + public new static readonly global::Godot.StringName _fieldGodotGenericArray = "_fieldGodotGenericArray"; /// <summary> - /// Cached name for the 'field_empty_Int64Array' field. + /// Cached name for the '_fieldEmptyInt64Array' field. /// </summary> - public new static readonly global::Godot.StringName field_empty_Int64Array = "field_empty_Int64Array"; + public new static readonly global::Godot.StringName _fieldEmptyInt64Array = "_fieldEmptyInt64Array"; } /// <inheritdoc/> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) { - if (name == PropertyName.field_Boolean) { - this.field_Boolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + if (name == PropertyName._fieldBoolean) { + this._fieldBoolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName.field_Char) { - this.field_Char = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); + else if (name == PropertyName._fieldChar) { + this._fieldChar = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); return true; } - else if (name == PropertyName.field_SByte) { - this.field_SByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); + else if (name == PropertyName._fieldSByte) { + this._fieldSByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); return true; } - else if (name == PropertyName.field_Int16) { - this.field_Int16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); + else if (name == PropertyName._fieldInt16) { + this._fieldInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); return true; } - else if (name == PropertyName.field_Int32) { - this.field_Int32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + else if (name == PropertyName._fieldInt32) { + this._fieldInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName.field_Int64) { - this.field_Int64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); + else if (name == PropertyName._fieldInt64) { + this._fieldInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); return true; } - else if (name == PropertyName.field_Byte) { - this.field_Byte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); + else if (name == PropertyName._fieldByte) { + this._fieldByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); return true; } - else if (name == PropertyName.field_UInt16) { - this.field_UInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); + else if (name == PropertyName._fieldUInt16) { + this._fieldUInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); return true; } - else if (name == PropertyName.field_UInt32) { - this.field_UInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); + else if (name == PropertyName._fieldUInt32) { + this._fieldUInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); return true; } - else if (name == PropertyName.field_UInt64) { - this.field_UInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); + else if (name == PropertyName._fieldUInt64) { + this._fieldUInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); return true; } - else if (name == PropertyName.field_Single) { - this.field_Single = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); + else if (name == PropertyName._fieldSingle) { + this._fieldSingle = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); return true; } - else if (name == PropertyName.field_Double) { - this.field_Double = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); + else if (name == PropertyName._fieldDouble) { + this._fieldDouble = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); return true; } - else if (name == PropertyName.field_String) { - this.field_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName._fieldString) { + this._fieldString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.field_Vector2) { - this.field_Vector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); + else if (name == PropertyName._fieldVector2) { + this._fieldVector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); return true; } - else if (name == PropertyName.field_Vector2I) { - this.field_Vector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); + else if (name == PropertyName._fieldVector2I) { + this._fieldVector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); return true; } - else if (name == PropertyName.field_Rect2) { - this.field_Rect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); + else if (name == PropertyName._fieldRect2) { + this._fieldRect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); return true; } - else if (name == PropertyName.field_Rect2I) { - this.field_Rect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); + else if (name == PropertyName._fieldRect2I) { + this._fieldRect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); return true; } - else if (name == PropertyName.field_Transform2D) { - this.field_Transform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); + else if (name == PropertyName._fieldTransform2D) { + this._fieldTransform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); return true; } - else if (name == PropertyName.field_Vector3) { - this.field_Vector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); + else if (name == PropertyName._fieldVector3) { + this._fieldVector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); return true; } - else if (name == PropertyName.field_Vector3I) { - this.field_Vector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); + else if (name == PropertyName._fieldVector3I) { + this._fieldVector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); return true; } - else if (name == PropertyName.field_Basis) { - this.field_Basis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); + else if (name == PropertyName._fieldBasis) { + this._fieldBasis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); return true; } - else if (name == PropertyName.field_Quaternion) { - this.field_Quaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); + else if (name == PropertyName._fieldQuaternion) { + this._fieldQuaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); return true; } - else if (name == PropertyName.field_Transform3D) { - this.field_Transform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); + else if (name == PropertyName._fieldTransform3D) { + this._fieldTransform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); return true; } - else if (name == PropertyName.field_Vector4) { - this.field_Vector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); + else if (name == PropertyName._fieldVector4) { + this._fieldVector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); return true; } - else if (name == PropertyName.field_Vector4I) { - this.field_Vector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); + else if (name == PropertyName._fieldVector4I) { + this._fieldVector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); return true; } - else if (name == PropertyName.field_Projection) { - this.field_Projection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); + else if (name == PropertyName._fieldProjection) { + this._fieldProjection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); return true; } - else if (name == PropertyName.field_Aabb) { - this.field_Aabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); + else if (name == PropertyName._fieldAabb) { + this._fieldAabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); return true; } - else if (name == PropertyName.field_Color) { - this.field_Color = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); + else if (name == PropertyName._fieldColor) { + this._fieldColor = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); return true; } - else if (name == PropertyName.field_Plane) { - this.field_Plane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); + else if (name == PropertyName._fieldPlane) { + this._fieldPlane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); return true; } - else if (name == PropertyName.field_Callable) { - this.field_Callable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); + else if (name == PropertyName._fieldCallable) { + this._fieldCallable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); return true; } - else if (name == PropertyName.field_Signal) { - this.field_Signal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); + else if (name == PropertyName._fieldSignal) { + this._fieldSignal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); return true; } - else if (name == PropertyName.field_Enum) { - this.field_Enum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyEnum>(value); + else if (name == PropertyName._fieldEnum) { + this._fieldEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyEnum>(value); return true; } - else if (name == PropertyName.field_FlagsEnum) { - this.field_FlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyFlagsEnum>(value); + else if (name == PropertyName._fieldFlagsEnum) { + this._fieldFlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedFields.MyFlagsEnum>(value); return true; } - else if (name == PropertyName.field_ByteArray) { - this.field_ByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); + else if (name == PropertyName._fieldByteArray) { + this._fieldByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); return true; } - else if (name == PropertyName.field_Int32Array) { - this.field_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + else if (name == PropertyName._fieldInt32Array) { + this._fieldInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName.field_Int64Array) { - this.field_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); + else if (name == PropertyName._fieldInt64Array) { + this._fieldInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } - else if (name == PropertyName.field_SingleArray) { - this.field_SingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); + else if (name == PropertyName._fieldSingleArray) { + this._fieldSingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); return true; } - else if (name == PropertyName.field_DoubleArray) { - this.field_DoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); + else if (name == PropertyName._fieldDoubleArray) { + this._fieldDoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); return true; } - else if (name == PropertyName.field_StringArray) { - this.field_StringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + else if (name == PropertyName._fieldStringArray) { + this._fieldStringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.field_StringArrayEnum) { - this.field_StringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + else if (name == PropertyName._fieldStringArrayEnum) { + this._fieldStringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.field_Vector2Array) { - this.field_Vector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); + else if (name == PropertyName._fieldVector2Array) { + this._fieldVector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); return true; } - else if (name == PropertyName.field_Vector3Array) { - this.field_Vector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); + else if (name == PropertyName._fieldVector3Array) { + this._fieldVector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); return true; } - else if (name == PropertyName.field_ColorArray) { - this.field_ColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); + else if (name == PropertyName._fieldColorArray) { + this._fieldColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); return true; } - else if (name == PropertyName.field_GodotObjectOrDerivedArray) { - this.field_GodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); + else if (name == PropertyName._fieldGodotObjectOrDerivedArray) { + this._fieldGodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName.field_StringNameArray) { - this.field_StringNameArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName[]>(value); + else if (name == PropertyName._fieldStringNameArray) { + this._fieldStringNameArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName[]>(value); return true; } - else if (name == PropertyName.field_NodePathArray) { - this.field_NodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); + else if (name == PropertyName._fieldNodePathArray) { + this._fieldNodePathArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath[]>(value); return true; } - else if (name == PropertyName.field_RidArray) { - this.field_RidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); + else if (name == PropertyName._fieldRidArray) { + this._fieldRidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); return true; } - else if (name == PropertyName.field_empty_Int32Array) { - this.field_empty_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + else if (name == PropertyName._fieldEmptyInt32Array) { + this._fieldEmptyInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName.field_array_from_list) { - this.field_array_from_list = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + else if (name == PropertyName._fieldArrayFromList) { + this._fieldArrayFromList = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName.field_Variant) { - this.field_Variant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); + else if (name == PropertyName._fieldVariant) { + this._fieldVariant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); return true; } - else if (name == PropertyName.field_GodotObjectOrDerived) { - this.field_GodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); + else if (name == PropertyName._fieldGodotObjectOrDerived) { + this._fieldGodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName.field_GodotResourceTexture) { - this.field_GodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); + else if (name == PropertyName._fieldGodotResourceTexture) { + this._fieldGodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); return true; } - else if (name == PropertyName.field_StringName) { - this.field_StringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); + else if (name == PropertyName._fieldStringName) { + this._fieldStringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); return true; } - else if (name == PropertyName.field_NodePath) { - this.field_NodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); + else if (name == PropertyName._fieldNodePath) { + this._fieldNodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); return true; } - else if (name == PropertyName.field_Rid) { - this.field_Rid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); + else if (name == PropertyName._fieldRid) { + this._fieldRid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); return true; } - else if (name == PropertyName.field_GodotDictionary) { - this.field_GodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); + else if (name == PropertyName._fieldGodotDictionary) { + this._fieldGodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); return true; } - else if (name == PropertyName.field_GodotArray) { - this.field_GodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); + else if (name == PropertyName._fieldGodotArray) { + this._fieldGodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); return true; } - else if (name == PropertyName.field_GodotGenericDictionary) { - this.field_GodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); + else if (name == PropertyName._fieldGodotGenericDictionary) { + this._fieldGodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); return true; } - else if (name == PropertyName.field_GodotGenericArray) { - this.field_GodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); + else if (name == PropertyName._fieldGodotGenericArray) { + this._fieldGodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); return true; } - else if (name == PropertyName.field_empty_Int64Array) { - this.field_empty_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); + else if (name == PropertyName._fieldEmptyInt64Array) { + this._fieldEmptyInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } return base.SetGodotClassPropertyValue(name, value); @@ -499,244 +499,244 @@ partial class ExportedFields [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) { - if (name == PropertyName.field_Boolean) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.field_Boolean); + if (name == PropertyName._fieldBoolean) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this._fieldBoolean); return true; } - else if (name == PropertyName.field_Char) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.field_Char); + else if (name == PropertyName._fieldChar) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this._fieldChar); return true; } - else if (name == PropertyName.field_SByte) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.field_SByte); + else if (name == PropertyName._fieldSByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this._fieldSByte); return true; } - else if (name == PropertyName.field_Int16) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.field_Int16); + else if (name == PropertyName._fieldInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this._fieldInt16); return true; } - else if (name == PropertyName.field_Int32) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.field_Int32); + else if (name == PropertyName._fieldInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._fieldInt32); return true; } - else if (name == PropertyName.field_Int64) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.field_Int64); + else if (name == PropertyName._fieldInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this._fieldInt64); return true; } - else if (name == PropertyName.field_Byte) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.field_Byte); + else if (name == PropertyName._fieldByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this._fieldByte); return true; } - else if (name == PropertyName.field_UInt16) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.field_UInt16); + else if (name == PropertyName._fieldUInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this._fieldUInt16); return true; } - else if (name == PropertyName.field_UInt32) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.field_UInt32); + else if (name == PropertyName._fieldUInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this._fieldUInt32); return true; } - else if (name == PropertyName.field_UInt64) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.field_UInt64); + else if (name == PropertyName._fieldUInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this._fieldUInt64); return true; } - else if (name == PropertyName.field_Single) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.field_Single); + else if (name == PropertyName._fieldSingle) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this._fieldSingle); return true; } - else if (name == PropertyName.field_Double) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.field_Double); + else if (name == PropertyName._fieldDouble) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this._fieldDouble); return true; } - else if (name == PropertyName.field_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.field_String); + else if (name == PropertyName._fieldString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fieldString); return true; } - else if (name == PropertyName.field_Vector2) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.field_Vector2); + else if (name == PropertyName._fieldVector2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this._fieldVector2); return true; } - else if (name == PropertyName.field_Vector2I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.field_Vector2I); + else if (name == PropertyName._fieldVector2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this._fieldVector2I); return true; } - else if (name == PropertyName.field_Rect2) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.field_Rect2); + else if (name == PropertyName._fieldRect2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this._fieldRect2); return true; } - else if (name == PropertyName.field_Rect2I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.field_Rect2I); + else if (name == PropertyName._fieldRect2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this._fieldRect2I); return true; } - else if (name == PropertyName.field_Transform2D) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.field_Transform2D); + else if (name == PropertyName._fieldTransform2D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this._fieldTransform2D); return true; } - else if (name == PropertyName.field_Vector3) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.field_Vector3); + else if (name == PropertyName._fieldVector3) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this._fieldVector3); return true; } - else if (name == PropertyName.field_Vector3I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.field_Vector3I); + else if (name == PropertyName._fieldVector3I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this._fieldVector3I); return true; } - else if (name == PropertyName.field_Basis) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.field_Basis); + else if (name == PropertyName._fieldBasis) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this._fieldBasis); return true; } - else if (name == PropertyName.field_Quaternion) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.field_Quaternion); + else if (name == PropertyName._fieldQuaternion) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this._fieldQuaternion); return true; } - else if (name == PropertyName.field_Transform3D) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.field_Transform3D); + else if (name == PropertyName._fieldTransform3D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this._fieldTransform3D); return true; } - else if (name == PropertyName.field_Vector4) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.field_Vector4); + else if (name == PropertyName._fieldVector4) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this._fieldVector4); return true; } - else if (name == PropertyName.field_Vector4I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.field_Vector4I); + else if (name == PropertyName._fieldVector4I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this._fieldVector4I); return true; } - else if (name == PropertyName.field_Projection) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.field_Projection); + else if (name == PropertyName._fieldProjection) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this._fieldProjection); return true; } - else if (name == PropertyName.field_Aabb) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.field_Aabb); + else if (name == PropertyName._fieldAabb) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this._fieldAabb); return true; } - else if (name == PropertyName.field_Color) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.field_Color); + else if (name == PropertyName._fieldColor) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this._fieldColor); return true; } - else if (name == PropertyName.field_Plane) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.field_Plane); + else if (name == PropertyName._fieldPlane) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this._fieldPlane); return true; } - else if (name == PropertyName.field_Callable) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.field_Callable); + else if (name == PropertyName._fieldCallable) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this._fieldCallable); return true; } - else if (name == PropertyName.field_Signal) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.field_Signal); + else if (name == PropertyName._fieldSignal) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this._fieldSignal); return true; } - else if (name == PropertyName.field_Enum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyEnum>(this.field_Enum); + else if (name == PropertyName._fieldEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyEnum>(this._fieldEnum); return true; } - else if (name == PropertyName.field_FlagsEnum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyFlagsEnum>(this.field_FlagsEnum); + else if (name == PropertyName._fieldFlagsEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedFields.MyFlagsEnum>(this._fieldFlagsEnum); return true; } - else if (name == PropertyName.field_ByteArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.field_ByteArray); + else if (name == PropertyName._fieldByteArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this._fieldByteArray); return true; } - else if (name == PropertyName.field_Int32Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_Int32Array); + else if (name == PropertyName._fieldInt32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldInt32Array); return true; } - else if (name == PropertyName.field_Int64Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.field_Int64Array); + else if (name == PropertyName._fieldInt64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this._fieldInt64Array); return true; } - else if (name == PropertyName.field_SingleArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.field_SingleArray); + else if (name == PropertyName._fieldSingleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this._fieldSingleArray); return true; } - else if (name == PropertyName.field_DoubleArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.field_DoubleArray); + else if (name == PropertyName._fieldDoubleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this._fieldDoubleArray); return true; } - else if (name == PropertyName.field_StringArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.field_StringArray); + else if (name == PropertyName._fieldStringArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this._fieldStringArray); return true; } - else if (name == PropertyName.field_StringArrayEnum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.field_StringArrayEnum); + else if (name == PropertyName._fieldStringArrayEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this._fieldStringArrayEnum); return true; } - else if (name == PropertyName.field_Vector2Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.field_Vector2Array); + else if (name == PropertyName._fieldVector2Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this._fieldVector2Array); return true; } - else if (name == PropertyName.field_Vector3Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.field_Vector3Array); + else if (name == PropertyName._fieldVector3Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this._fieldVector3Array); return true; } - else if (name == PropertyName.field_ColorArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.field_ColorArray); + else if (name == PropertyName._fieldColorArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this._fieldColorArray); return true; } - else if (name == PropertyName.field_GodotObjectOrDerivedArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.field_GodotObjectOrDerivedArray); + else if (name == PropertyName._fieldGodotObjectOrDerivedArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this._fieldGodotObjectOrDerivedArray); return true; } - else if (name == PropertyName.field_StringNameArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName[]>(this.field_StringNameArray); + else if (name == PropertyName._fieldStringNameArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName[]>(this._fieldStringNameArray); return true; } - else if (name == PropertyName.field_NodePathArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this.field_NodePathArray); + else if (name == PropertyName._fieldNodePathArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath[]>(this._fieldNodePathArray); return true; } - else if (name == PropertyName.field_RidArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this.field_RidArray); + else if (name == PropertyName._fieldRidArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this._fieldRidArray); return true; } - else if (name == PropertyName.field_empty_Int32Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_empty_Int32Array); + else if (name == PropertyName._fieldEmptyInt32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldEmptyInt32Array); return true; } - else if (name == PropertyName.field_array_from_list) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.field_array_from_list); + else if (name == PropertyName._fieldArrayFromList) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this._fieldArrayFromList); return true; } - else if (name == PropertyName.field_Variant) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.field_Variant); + else if (name == PropertyName._fieldVariant) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this._fieldVariant); return true; } - else if (name == PropertyName.field_GodotObjectOrDerived) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.field_GodotObjectOrDerived); + else if (name == PropertyName._fieldGodotObjectOrDerived) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this._fieldGodotObjectOrDerived); return true; } - else if (name == PropertyName.field_GodotResourceTexture) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.field_GodotResourceTexture); + else if (name == PropertyName._fieldGodotResourceTexture) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this._fieldGodotResourceTexture); return true; } - else if (name == PropertyName.field_StringName) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.field_StringName); + else if (name == PropertyName._fieldStringName) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this._fieldStringName); return true; } - else if (name == PropertyName.field_NodePath) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.field_NodePath); + else if (name == PropertyName._fieldNodePath) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this._fieldNodePath); return true; } - else if (name == PropertyName.field_Rid) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.field_Rid); + else if (name == PropertyName._fieldRid) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this._fieldRid); return true; } - else if (name == PropertyName.field_GodotDictionary) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.field_GodotDictionary); + else if (name == PropertyName._fieldGodotDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this._fieldGodotDictionary); return true; } - else if (name == PropertyName.field_GodotArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.field_GodotArray); + else if (name == PropertyName._fieldGodotArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this._fieldGodotArray); return true; } - else if (name == PropertyName.field_GodotGenericDictionary) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.field_GodotGenericDictionary); + else if (name == PropertyName._fieldGodotGenericDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this._fieldGodotGenericDictionary); return true; } - else if (name == PropertyName.field_GodotGenericArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.field_GodotGenericArray); + else if (name == PropertyName._fieldGodotGenericArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this._fieldGodotGenericArray); return true; } - else if (name == PropertyName.field_empty_Int64Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.field_empty_Int64Array); + else if (name == PropertyName._fieldEmptyInt64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this._fieldEmptyInt64Array); return true; } return base.GetGodotClassPropertyValue(name, out value); @@ -750,66 +750,66 @@ partial class ExportedFields internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() { var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.field_Boolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Char, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_SByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Int64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Byte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_UInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.field_Single, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.field_Double, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.field_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName.field_Vector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName.field_Vector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName.field_Rect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName.field_Rect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName.field_Transform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName.field_Vector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName.field_Vector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName.field_Basis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName.field_Quaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName.field_Transform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName.field_Vector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName.field_Vector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName.field_Projection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName.field_Aabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName.field_Color, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName.field_Plane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.field_Callable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName.field_Signal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_Enum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.field_FlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName.field_ByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.field_Int64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName.field_SingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName.field_DoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.field_StringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.field_StringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName.field_Vector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName.field_Vector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName.field_ColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_StringNameArray, hint: (global::Godot.PropertyHint)23, hintString: "21/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_NodePathArray, hint: (global::Godot.PropertyHint)23, hintString: "22/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_RidArray, hint: (global::Godot.PropertyHint)23, hintString: "23/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_empty_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.field_array_from_list, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName.field_Variant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.field_GodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.field_GodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName.field_StringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName.field_NodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.field_Rid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.field_GodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.field_GodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_GodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.field_empty_Int64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName._fieldBoolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldChar, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldSByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldUInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldUInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldUInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName._fieldSingle, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName._fieldDouble, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fieldString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName._fieldVector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName._fieldVector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName._fieldRect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName._fieldRect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName._fieldTransform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName._fieldVector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName._fieldVector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName._fieldBasis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName._fieldQuaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName._fieldTransform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName._fieldVector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName._fieldVector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName._fieldProjection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName._fieldAabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName._fieldColor, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName._fieldPlane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName._fieldCallable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName._fieldSignal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldEnum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._fieldFlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName._fieldByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName._fieldInt32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName._fieldInt64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName._fieldSingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName._fieldDoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName._fieldStringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName._fieldStringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName._fieldVector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName._fieldVector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName._fieldColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldGodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldStringNameArray, hint: (global::Godot.PropertyHint)23, hintString: "21/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldNodePathArray, hint: (global::Godot.PropertyHint)23, hintString: "22/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldRidArray, hint: (global::Godot.PropertyHint)23, hintString: "23/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName._fieldEmptyInt32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName._fieldArrayFromList, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName._fieldVariant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName._fieldGodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName._fieldGodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName._fieldStringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName._fieldNodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName._fieldRid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName._fieldGodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldGodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName._fieldGodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName._fieldGodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName._fieldEmptyInt64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); return properties; } #pragma warning restore CS0109 diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs index 185b8e4ac6..367cb073c0 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedFields_ScriptPropertyDefVal.generated.cs @@ -12,126 +12,126 @@ partial class ExportedFields internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues() { var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(60); - bool __field_Boolean_default_value = true; - values.Add(PropertyName.field_Boolean, global::Godot.Variant.From<bool>(__field_Boolean_default_value)); - char __field_Char_default_value = 'f'; - values.Add(PropertyName.field_Char, global::Godot.Variant.From<char>(__field_Char_default_value)); - sbyte __field_SByte_default_value = 10; - values.Add(PropertyName.field_SByte, global::Godot.Variant.From<sbyte>(__field_SByte_default_value)); - short __field_Int16_default_value = 10; - values.Add(PropertyName.field_Int16, global::Godot.Variant.From<short>(__field_Int16_default_value)); - int __field_Int32_default_value = 10; - values.Add(PropertyName.field_Int32, global::Godot.Variant.From<int>(__field_Int32_default_value)); - long __field_Int64_default_value = 10; - values.Add(PropertyName.field_Int64, global::Godot.Variant.From<long>(__field_Int64_default_value)); - byte __field_Byte_default_value = 10; - values.Add(PropertyName.field_Byte, global::Godot.Variant.From<byte>(__field_Byte_default_value)); - ushort __field_UInt16_default_value = 10; - values.Add(PropertyName.field_UInt16, global::Godot.Variant.From<ushort>(__field_UInt16_default_value)); - uint __field_UInt32_default_value = 10; - values.Add(PropertyName.field_UInt32, global::Godot.Variant.From<uint>(__field_UInt32_default_value)); - ulong __field_UInt64_default_value = 10; - values.Add(PropertyName.field_UInt64, global::Godot.Variant.From<ulong>(__field_UInt64_default_value)); - float __field_Single_default_value = 10; - values.Add(PropertyName.field_Single, global::Godot.Variant.From<float>(__field_Single_default_value)); - double __field_Double_default_value = 10; - values.Add(PropertyName.field_Double, global::Godot.Variant.From<double>(__field_Double_default_value)); - string __field_String_default_value = "foo"; - values.Add(PropertyName.field_String, global::Godot.Variant.From<string>(__field_String_default_value)); - global::Godot.Vector2 __field_Vector2_default_value = new(10f, 10f); - values.Add(PropertyName.field_Vector2, global::Godot.Variant.From<global::Godot.Vector2>(__field_Vector2_default_value)); - global::Godot.Vector2I __field_Vector2I_default_value = global::Godot.Vector2I.Up; - values.Add(PropertyName.field_Vector2I, global::Godot.Variant.From<global::Godot.Vector2I>(__field_Vector2I_default_value)); - global::Godot.Rect2 __field_Rect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); - values.Add(PropertyName.field_Rect2, global::Godot.Variant.From<global::Godot.Rect2>(__field_Rect2_default_value)); - global::Godot.Rect2I __field_Rect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); - values.Add(PropertyName.field_Rect2I, global::Godot.Variant.From<global::Godot.Rect2I>(__field_Rect2I_default_value)); - global::Godot.Transform2D __field_Transform2D_default_value = global::Godot.Transform2D.Identity; - values.Add(PropertyName.field_Transform2D, global::Godot.Variant.From<global::Godot.Transform2D>(__field_Transform2D_default_value)); - global::Godot.Vector3 __field_Vector3_default_value = new(10f, 10f, 10f); - values.Add(PropertyName.field_Vector3, global::Godot.Variant.From<global::Godot.Vector3>(__field_Vector3_default_value)); - global::Godot.Vector3I __field_Vector3I_default_value = global::Godot.Vector3I.Back; - values.Add(PropertyName.field_Vector3I, global::Godot.Variant.From<global::Godot.Vector3I>(__field_Vector3I_default_value)); - global::Godot.Basis __field_Basis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); - values.Add(PropertyName.field_Basis, global::Godot.Variant.From<global::Godot.Basis>(__field_Basis_default_value)); - global::Godot.Quaternion __field_Quaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); - values.Add(PropertyName.field_Quaternion, global::Godot.Variant.From<global::Godot.Quaternion>(__field_Quaternion_default_value)); - global::Godot.Transform3D __field_Transform3D_default_value = global::Godot.Transform3D.Identity; - values.Add(PropertyName.field_Transform3D, global::Godot.Variant.From<global::Godot.Transform3D>(__field_Transform3D_default_value)); - global::Godot.Vector4 __field_Vector4_default_value = new(10f, 10f, 10f, 10f); - values.Add(PropertyName.field_Vector4, global::Godot.Variant.From<global::Godot.Vector4>(__field_Vector4_default_value)); - global::Godot.Vector4I __field_Vector4I_default_value = global::Godot.Vector4I.One; - values.Add(PropertyName.field_Vector4I, global::Godot.Variant.From<global::Godot.Vector4I>(__field_Vector4I_default_value)); - global::Godot.Projection __field_Projection_default_value = global::Godot.Projection.Identity; - values.Add(PropertyName.field_Projection, global::Godot.Variant.From<global::Godot.Projection>(__field_Projection_default_value)); - global::Godot.Aabb __field_Aabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); - values.Add(PropertyName.field_Aabb, global::Godot.Variant.From<global::Godot.Aabb>(__field_Aabb_default_value)); - global::Godot.Color __field_Color_default_value = global::Godot.Colors.Aquamarine; - values.Add(PropertyName.field_Color, global::Godot.Variant.From<global::Godot.Color>(__field_Color_default_value)); - global::Godot.Plane __field_Plane_default_value = global::Godot.Plane.PlaneXZ; - values.Add(PropertyName.field_Plane, global::Godot.Variant.From<global::Godot.Plane>(__field_Plane_default_value)); - global::Godot.Callable __field_Callable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); - values.Add(PropertyName.field_Callable, global::Godot.Variant.From<global::Godot.Callable>(__field_Callable_default_value)); - global::Godot.Signal __field_Signal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "property_list_changed"); - values.Add(PropertyName.field_Signal, global::Godot.Variant.From<global::Godot.Signal>(__field_Signal_default_value)); - global::ExportedFields.MyEnum __field_Enum_default_value = global::ExportedFields.MyEnum.C; - values.Add(PropertyName.field_Enum, global::Godot.Variant.From<global::ExportedFields.MyEnum>(__field_Enum_default_value)); - global::ExportedFields.MyFlagsEnum __field_FlagsEnum_default_value = global::ExportedFields.MyFlagsEnum.C; - values.Add(PropertyName.field_FlagsEnum, global::Godot.Variant.From<global::ExportedFields.MyFlagsEnum>(__field_FlagsEnum_default_value)); - byte[] __field_ByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.field_ByteArray, global::Godot.Variant.From<byte[]>(__field_ByteArray_default_value)); - int[] __field_Int32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.field_Int32Array, global::Godot.Variant.From<int[]>(__field_Int32Array_default_value)); - long[] __field_Int64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.field_Int64Array, global::Godot.Variant.From<long[]>(__field_Int64Array_default_value)); - float[] __field_SingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - values.Add(PropertyName.field_SingleArray, global::Godot.Variant.From<float[]>(__field_SingleArray_default_value)); - double[] __field_DoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - values.Add(PropertyName.field_DoubleArray, global::Godot.Variant.From<double[]>(__field_DoubleArray_default_value)); - string[] __field_StringArray_default_value = { "foo", "bar" }; - values.Add(PropertyName.field_StringArray, global::Godot.Variant.From<string[]>(__field_StringArray_default_value)); - string[] __field_StringArrayEnum_default_value = { "foo", "bar" }; - values.Add(PropertyName.field_StringArrayEnum, global::Godot.Variant.From<string[]>(__field_StringArrayEnum_default_value)); - global::Godot.Vector2[] __field_Vector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; - values.Add(PropertyName.field_Vector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(__field_Vector2Array_default_value)); - global::Godot.Vector3[] __field_Vector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; - values.Add(PropertyName.field_Vector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(__field_Vector3Array_default_value)); - global::Godot.Color[] __field_ColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; - values.Add(PropertyName.field_ColorArray, global::Godot.Variant.From<global::Godot.Color[]>(__field_ColorArray_default_value)); - global::Godot.GodotObject[] __field_GodotObjectOrDerivedArray_default_value = { null }; - values.Add(PropertyName.field_GodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(__field_GodotObjectOrDerivedArray_default_value)); - global::Godot.StringName[] __field_StringNameArray_default_value = { "foo", "bar" }; - values.Add(PropertyName.field_StringNameArray, global::Godot.Variant.From<global::Godot.StringName[]>(__field_StringNameArray_default_value)); - global::Godot.NodePath[] __field_NodePathArray_default_value = { "foo", "bar" }; - values.Add(PropertyName.field_NodePathArray, global::Godot.Variant.From<global::Godot.NodePath[]>(__field_NodePathArray_default_value)); - global::Godot.Rid[] __field_RidArray_default_value = { default, default, default }; - values.Add(PropertyName.field_RidArray, global::Godot.Variant.From<global::Godot.Rid[]>(__field_RidArray_default_value)); - int[] __field_empty_Int32Array_default_value = global::System.Array.Empty<int>(); - values.Add(PropertyName.field_empty_Int32Array, global::Godot.Variant.From<int[]>(__field_empty_Int32Array_default_value)); - int[] __field_array_from_list_default_value = new global::System.Collections.Generic.List<int>(global::System.Array.Empty<int>()).ToArray(); - values.Add(PropertyName.field_array_from_list, global::Godot.Variant.From<int[]>(__field_array_from_list_default_value)); - global::Godot.Variant __field_Variant_default_value = "foo"; - values.Add(PropertyName.field_Variant, global::Godot.Variant.From<global::Godot.Variant>(__field_Variant_default_value)); - global::Godot.GodotObject __field_GodotObjectOrDerived_default_value = default; - values.Add(PropertyName.field_GodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(__field_GodotObjectOrDerived_default_value)); - global::Godot.Texture __field_GodotResourceTexture_default_value = default; - values.Add(PropertyName.field_GodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(__field_GodotResourceTexture_default_value)); - global::Godot.StringName __field_StringName_default_value = new global::Godot.StringName("foo"); - values.Add(PropertyName.field_StringName, global::Godot.Variant.From<global::Godot.StringName>(__field_StringName_default_value)); - global::Godot.NodePath __field_NodePath_default_value = new global::Godot.NodePath("foo"); - values.Add(PropertyName.field_NodePath, global::Godot.Variant.From<global::Godot.NodePath>(__field_NodePath_default_value)); - global::Godot.Rid __field_Rid_default_value = default; - values.Add(PropertyName.field_Rid, global::Godot.Variant.From<global::Godot.Rid>(__field_Rid_default_value)); - global::Godot.Collections.Dictionary __field_GodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; - values.Add(PropertyName.field_GodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(__field_GodotDictionary_default_value)); - global::Godot.Collections.Array __field_GodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; - values.Add(PropertyName.field_GodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(__field_GodotArray_default_value)); - global::Godot.Collections.Dictionary<string, bool> __field_GodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; - values.Add(PropertyName.field_GodotGenericDictionary, global::Godot.Variant.CreateFrom(__field_GodotGenericDictionary_default_value)); - global::Godot.Collections.Array<int> __field_GodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.field_GodotGenericArray, global::Godot.Variant.CreateFrom(__field_GodotGenericArray_default_value)); - long[] __field_empty_Int64Array_default_value = global::System.Array.Empty<long>(); - values.Add(PropertyName.field_empty_Int64Array, global::Godot.Variant.From<long[]>(__field_empty_Int64Array_default_value)); + bool ___fieldBoolean_default_value = true; + values.Add(PropertyName._fieldBoolean, global::Godot.Variant.From<bool>(___fieldBoolean_default_value)); + char ___fieldChar_default_value = 'f'; + values.Add(PropertyName._fieldChar, global::Godot.Variant.From<char>(___fieldChar_default_value)); + sbyte ___fieldSByte_default_value = 10; + values.Add(PropertyName._fieldSByte, global::Godot.Variant.From<sbyte>(___fieldSByte_default_value)); + short ___fieldInt16_default_value = 10; + values.Add(PropertyName._fieldInt16, global::Godot.Variant.From<short>(___fieldInt16_default_value)); + int ___fieldInt32_default_value = 10; + values.Add(PropertyName._fieldInt32, global::Godot.Variant.From<int>(___fieldInt32_default_value)); + long ___fieldInt64_default_value = 10; + values.Add(PropertyName._fieldInt64, global::Godot.Variant.From<long>(___fieldInt64_default_value)); + byte ___fieldByte_default_value = 10; + values.Add(PropertyName._fieldByte, global::Godot.Variant.From<byte>(___fieldByte_default_value)); + ushort ___fieldUInt16_default_value = 10; + values.Add(PropertyName._fieldUInt16, global::Godot.Variant.From<ushort>(___fieldUInt16_default_value)); + uint ___fieldUInt32_default_value = 10; + values.Add(PropertyName._fieldUInt32, global::Godot.Variant.From<uint>(___fieldUInt32_default_value)); + ulong ___fieldUInt64_default_value = 10; + values.Add(PropertyName._fieldUInt64, global::Godot.Variant.From<ulong>(___fieldUInt64_default_value)); + float ___fieldSingle_default_value = 10; + values.Add(PropertyName._fieldSingle, global::Godot.Variant.From<float>(___fieldSingle_default_value)); + double ___fieldDouble_default_value = 10; + values.Add(PropertyName._fieldDouble, global::Godot.Variant.From<double>(___fieldDouble_default_value)); + string ___fieldString_default_value = "foo"; + values.Add(PropertyName._fieldString, global::Godot.Variant.From<string>(___fieldString_default_value)); + global::Godot.Vector2 ___fieldVector2_default_value = new(10f, 10f); + values.Add(PropertyName._fieldVector2, global::Godot.Variant.From<global::Godot.Vector2>(___fieldVector2_default_value)); + global::Godot.Vector2I ___fieldVector2I_default_value = global::Godot.Vector2I.Up; + values.Add(PropertyName._fieldVector2I, global::Godot.Variant.From<global::Godot.Vector2I>(___fieldVector2I_default_value)); + global::Godot.Rect2 ___fieldRect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); + values.Add(PropertyName._fieldRect2, global::Godot.Variant.From<global::Godot.Rect2>(___fieldRect2_default_value)); + global::Godot.Rect2I ___fieldRect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); + values.Add(PropertyName._fieldRect2I, global::Godot.Variant.From<global::Godot.Rect2I>(___fieldRect2I_default_value)); + global::Godot.Transform2D ___fieldTransform2D_default_value = global::Godot.Transform2D.Identity; + values.Add(PropertyName._fieldTransform2D, global::Godot.Variant.From<global::Godot.Transform2D>(___fieldTransform2D_default_value)); + global::Godot.Vector3 ___fieldVector3_default_value = new(10f, 10f, 10f); + values.Add(PropertyName._fieldVector3, global::Godot.Variant.From<global::Godot.Vector3>(___fieldVector3_default_value)); + global::Godot.Vector3I ___fieldVector3I_default_value = global::Godot.Vector3I.Back; + values.Add(PropertyName._fieldVector3I, global::Godot.Variant.From<global::Godot.Vector3I>(___fieldVector3I_default_value)); + global::Godot.Basis ___fieldBasis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); + values.Add(PropertyName._fieldBasis, global::Godot.Variant.From<global::Godot.Basis>(___fieldBasis_default_value)); + global::Godot.Quaternion ___fieldQuaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); + values.Add(PropertyName._fieldQuaternion, global::Godot.Variant.From<global::Godot.Quaternion>(___fieldQuaternion_default_value)); + global::Godot.Transform3D ___fieldTransform3D_default_value = global::Godot.Transform3D.Identity; + values.Add(PropertyName._fieldTransform3D, global::Godot.Variant.From<global::Godot.Transform3D>(___fieldTransform3D_default_value)); + global::Godot.Vector4 ___fieldVector4_default_value = new(10f, 10f, 10f, 10f); + values.Add(PropertyName._fieldVector4, global::Godot.Variant.From<global::Godot.Vector4>(___fieldVector4_default_value)); + global::Godot.Vector4I ___fieldVector4I_default_value = global::Godot.Vector4I.One; + values.Add(PropertyName._fieldVector4I, global::Godot.Variant.From<global::Godot.Vector4I>(___fieldVector4I_default_value)); + global::Godot.Projection ___fieldProjection_default_value = global::Godot.Projection.Identity; + values.Add(PropertyName._fieldProjection, global::Godot.Variant.From<global::Godot.Projection>(___fieldProjection_default_value)); + global::Godot.Aabb ___fieldAabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); + values.Add(PropertyName._fieldAabb, global::Godot.Variant.From<global::Godot.Aabb>(___fieldAabb_default_value)); + global::Godot.Color ___fieldColor_default_value = global::Godot.Colors.Aquamarine; + values.Add(PropertyName._fieldColor, global::Godot.Variant.From<global::Godot.Color>(___fieldColor_default_value)); + global::Godot.Plane ___fieldPlane_default_value = global::Godot.Plane.PlaneXZ; + values.Add(PropertyName._fieldPlane, global::Godot.Variant.From<global::Godot.Plane>(___fieldPlane_default_value)); + global::Godot.Callable ___fieldCallable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); + values.Add(PropertyName._fieldCallable, global::Godot.Variant.From<global::Godot.Callable>(___fieldCallable_default_value)); + global::Godot.Signal ___fieldSignal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "property_list_changed"); + values.Add(PropertyName._fieldSignal, global::Godot.Variant.From<global::Godot.Signal>(___fieldSignal_default_value)); + global::ExportedFields.MyEnum ___fieldEnum_default_value = global::ExportedFields.MyEnum.C; + values.Add(PropertyName._fieldEnum, global::Godot.Variant.From<global::ExportedFields.MyEnum>(___fieldEnum_default_value)); + global::ExportedFields.MyFlagsEnum ___fieldFlagsEnum_default_value = global::ExportedFields.MyFlagsEnum.C; + values.Add(PropertyName._fieldFlagsEnum, global::Godot.Variant.From<global::ExportedFields.MyFlagsEnum>(___fieldFlagsEnum_default_value)); + byte[] ___fieldByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName._fieldByteArray, global::Godot.Variant.From<byte[]>(___fieldByteArray_default_value)); + int[] ___fieldInt32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName._fieldInt32Array, global::Godot.Variant.From<int[]>(___fieldInt32Array_default_value)); + long[] ___fieldInt64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName._fieldInt64Array, global::Godot.Variant.From<long[]>(___fieldInt64Array_default_value)); + float[] ___fieldSingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + values.Add(PropertyName._fieldSingleArray, global::Godot.Variant.From<float[]>(___fieldSingleArray_default_value)); + double[] ___fieldDoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + values.Add(PropertyName._fieldDoubleArray, global::Godot.Variant.From<double[]>(___fieldDoubleArray_default_value)); + string[] ___fieldStringArray_default_value = { "foo", "bar" }; + values.Add(PropertyName._fieldStringArray, global::Godot.Variant.From<string[]>(___fieldStringArray_default_value)); + string[] ___fieldStringArrayEnum_default_value = { "foo", "bar" }; + values.Add(PropertyName._fieldStringArrayEnum, global::Godot.Variant.From<string[]>(___fieldStringArrayEnum_default_value)); + global::Godot.Vector2[] ___fieldVector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; + values.Add(PropertyName._fieldVector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(___fieldVector2Array_default_value)); + global::Godot.Vector3[] ___fieldVector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; + values.Add(PropertyName._fieldVector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(___fieldVector3Array_default_value)); + global::Godot.Color[] ___fieldColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; + values.Add(PropertyName._fieldColorArray, global::Godot.Variant.From<global::Godot.Color[]>(___fieldColorArray_default_value)); + global::Godot.GodotObject[] ___fieldGodotObjectOrDerivedArray_default_value = { null }; + values.Add(PropertyName._fieldGodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(___fieldGodotObjectOrDerivedArray_default_value)); + global::Godot.StringName[] ___fieldStringNameArray_default_value = { "foo", "bar" }; + values.Add(PropertyName._fieldStringNameArray, global::Godot.Variant.From<global::Godot.StringName[]>(___fieldStringNameArray_default_value)); + global::Godot.NodePath[] ___fieldNodePathArray_default_value = { "foo", "bar" }; + values.Add(PropertyName._fieldNodePathArray, global::Godot.Variant.From<global::Godot.NodePath[]>(___fieldNodePathArray_default_value)); + global::Godot.Rid[] ___fieldRidArray_default_value = { default, default, default }; + values.Add(PropertyName._fieldRidArray, global::Godot.Variant.From<global::Godot.Rid[]>(___fieldRidArray_default_value)); + int[] ___fieldEmptyInt32Array_default_value = global::System.Array.Empty<int>(); + values.Add(PropertyName._fieldEmptyInt32Array, global::Godot.Variant.From<int[]>(___fieldEmptyInt32Array_default_value)); + int[] ___fieldArrayFromList_default_value = new global::System.Collections.Generic.List<int>(global::System.Array.Empty<int>()).ToArray(); + values.Add(PropertyName._fieldArrayFromList, global::Godot.Variant.From<int[]>(___fieldArrayFromList_default_value)); + global::Godot.Variant ___fieldVariant_default_value = "foo"; + values.Add(PropertyName._fieldVariant, global::Godot.Variant.From<global::Godot.Variant>(___fieldVariant_default_value)); + global::Godot.GodotObject ___fieldGodotObjectOrDerived_default_value = default; + values.Add(PropertyName._fieldGodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(___fieldGodotObjectOrDerived_default_value)); + global::Godot.Texture ___fieldGodotResourceTexture_default_value = default; + values.Add(PropertyName._fieldGodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(___fieldGodotResourceTexture_default_value)); + global::Godot.StringName ___fieldStringName_default_value = new global::Godot.StringName("foo"); + values.Add(PropertyName._fieldStringName, global::Godot.Variant.From<global::Godot.StringName>(___fieldStringName_default_value)); + global::Godot.NodePath ___fieldNodePath_default_value = new global::Godot.NodePath("foo"); + values.Add(PropertyName._fieldNodePath, global::Godot.Variant.From<global::Godot.NodePath>(___fieldNodePath_default_value)); + global::Godot.Rid ___fieldRid_default_value = default; + values.Add(PropertyName._fieldRid, global::Godot.Variant.From<global::Godot.Rid>(___fieldRid_default_value)); + global::Godot.Collections.Dictionary ___fieldGodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; + values.Add(PropertyName._fieldGodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(___fieldGodotDictionary_default_value)); + global::Godot.Collections.Array ___fieldGodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; + values.Add(PropertyName._fieldGodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(___fieldGodotArray_default_value)); + global::Godot.Collections.Dictionary<string, bool> ___fieldGodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; + values.Add(PropertyName._fieldGodotGenericDictionary, global::Godot.Variant.CreateFrom(___fieldGodotGenericDictionary_default_value)); + global::Godot.Collections.Array<int> ___fieldGodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName._fieldGodotGenericArray, global::Godot.Variant.CreateFrom(___fieldGodotGenericArray_default_value)); + long[] ___fieldEmptyInt64Array_default_value = global::System.Array.Empty<long>(); + values.Add(PropertyName._fieldEmptyInt64Array, global::Godot.Variant.From<long[]>(___fieldEmptyInt64Array_default_value)); return values; } #endif // TOOLS diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs index b5ec9b5b49..6e0e9fffbe 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptProperties.generated.cs @@ -9,209 +9,209 @@ partial class ExportedProperties /// </summary> public new class PropertyName : global::Godot.GodotObject.PropertyName { /// <summary> - /// Cached name for the 'NotGenerate_Complex_Lamda_Property' property. + /// Cached name for the 'NotGenerateComplexLamdaProperty' property. /// </summary> - public new static readonly global::Godot.StringName NotGenerate_Complex_Lamda_Property = "NotGenerate_Complex_Lamda_Property"; + public new static readonly global::Godot.StringName NotGenerateComplexLamdaProperty = "NotGenerateComplexLamdaProperty"; /// <summary> - /// Cached name for the 'NotGenerate_Lamda_NoField_Property' property. + /// Cached name for the 'NotGenerateLamdaNoFieldProperty' property. /// </summary> - public new static readonly global::Godot.StringName NotGenerate_Lamda_NoField_Property = "NotGenerate_Lamda_NoField_Property"; + public new static readonly global::Godot.StringName NotGenerateLamdaNoFieldProperty = "NotGenerateLamdaNoFieldProperty"; /// <summary> - /// Cached name for the 'NotGenerate_Complex_Return_Property' property. + /// Cached name for the 'NotGenerateComplexReturnProperty' property. /// </summary> - public new static readonly global::Godot.StringName NotGenerate_Complex_Return_Property = "NotGenerate_Complex_Return_Property"; + public new static readonly global::Godot.StringName NotGenerateComplexReturnProperty = "NotGenerateComplexReturnProperty"; /// <summary> - /// Cached name for the 'NotGenerate_Returns_Property' property. + /// Cached name for the 'NotGenerateReturnsProperty' property. /// </summary> - public new static readonly global::Godot.StringName NotGenerate_Returns_Property = "NotGenerate_Returns_Property"; + public new static readonly global::Godot.StringName NotGenerateReturnsProperty = "NotGenerateReturnsProperty"; /// <summary> - /// Cached name for the 'FullProperty_String' property. + /// Cached name for the 'FullPropertyString' property. /// </summary> - public new static readonly global::Godot.StringName FullProperty_String = "FullProperty_String"; + public new static readonly global::Godot.StringName FullPropertyString = "FullPropertyString"; /// <summary> - /// Cached name for the 'FullProperty_String_Complex' property. + /// Cached name for the 'FullPropertyString_Complex' property. /// </summary> - public new static readonly global::Godot.StringName FullProperty_String_Complex = "FullProperty_String_Complex"; + public new static readonly global::Godot.StringName FullPropertyString_Complex = "FullPropertyString_Complex"; /// <summary> - /// Cached name for the 'LamdaProperty_String' property. + /// Cached name for the 'LamdaPropertyString' property. /// </summary> - public new static readonly global::Godot.StringName LamdaProperty_String = "LamdaProperty_String"; + public new static readonly global::Godot.StringName LamdaPropertyString = "LamdaPropertyString"; /// <summary> - /// Cached name for the 'property_Boolean' property. + /// Cached name for the 'PropertyBoolean' property. /// </summary> - public new static readonly global::Godot.StringName property_Boolean = "property_Boolean"; + public new static readonly global::Godot.StringName PropertyBoolean = "PropertyBoolean"; /// <summary> - /// Cached name for the 'property_Char' property. + /// Cached name for the 'PropertyChar' property. /// </summary> - public new static readonly global::Godot.StringName property_Char = "property_Char"; + public new static readonly global::Godot.StringName PropertyChar = "PropertyChar"; /// <summary> - /// Cached name for the 'property_SByte' property. + /// Cached name for the 'PropertySByte' property. /// </summary> - public new static readonly global::Godot.StringName property_SByte = "property_SByte"; + public new static readonly global::Godot.StringName PropertySByte = "PropertySByte"; /// <summary> - /// Cached name for the 'property_Int16' property. + /// Cached name for the 'PropertyInt16' property. /// </summary> - public new static readonly global::Godot.StringName property_Int16 = "property_Int16"; + public new static readonly global::Godot.StringName PropertyInt16 = "PropertyInt16"; /// <summary> - /// Cached name for the 'property_Int32' property. + /// Cached name for the 'PropertyInt32' property. /// </summary> - public new static readonly global::Godot.StringName property_Int32 = "property_Int32"; + public new static readonly global::Godot.StringName PropertyInt32 = "PropertyInt32"; /// <summary> - /// Cached name for the 'property_Int64' property. + /// Cached name for the 'PropertyInt64' property. /// </summary> - public new static readonly global::Godot.StringName property_Int64 = "property_Int64"; + public new static readonly global::Godot.StringName PropertyInt64 = "PropertyInt64"; /// <summary> - /// Cached name for the 'property_Byte' property. + /// Cached name for the 'PropertyByte' property. /// </summary> - public new static readonly global::Godot.StringName property_Byte = "property_Byte"; + public new static readonly global::Godot.StringName PropertyByte = "PropertyByte"; /// <summary> - /// Cached name for the 'property_UInt16' property. + /// Cached name for the 'PropertyUInt16' property. /// </summary> - public new static readonly global::Godot.StringName property_UInt16 = "property_UInt16"; + public new static readonly global::Godot.StringName PropertyUInt16 = "PropertyUInt16"; /// <summary> - /// Cached name for the 'property_UInt32' property. + /// Cached name for the 'PropertyUInt32' property. /// </summary> - public new static readonly global::Godot.StringName property_UInt32 = "property_UInt32"; + public new static readonly global::Godot.StringName PropertyUInt32 = "PropertyUInt32"; /// <summary> - /// Cached name for the 'property_UInt64' property. + /// Cached name for the 'PropertyUInt64' property. /// </summary> - public new static readonly global::Godot.StringName property_UInt64 = "property_UInt64"; + public new static readonly global::Godot.StringName PropertyUInt64 = "PropertyUInt64"; /// <summary> - /// Cached name for the 'property_Single' property. + /// Cached name for the 'PropertySingle' property. /// </summary> - public new static readonly global::Godot.StringName property_Single = "property_Single"; + public new static readonly global::Godot.StringName PropertySingle = "PropertySingle"; /// <summary> - /// Cached name for the 'property_Double' property. + /// Cached name for the 'PropertyDouble' property. /// </summary> - public new static readonly global::Godot.StringName property_Double = "property_Double"; + public new static readonly global::Godot.StringName PropertyDouble = "PropertyDouble"; /// <summary> - /// Cached name for the 'property_String' property. + /// Cached name for the 'PropertyString' property. /// </summary> - public new static readonly global::Godot.StringName property_String = "property_String"; + public new static readonly global::Godot.StringName PropertyString = "PropertyString"; /// <summary> - /// Cached name for the 'property_Vector2' property. + /// Cached name for the 'PropertyVector2' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector2 = "property_Vector2"; + public new static readonly global::Godot.StringName PropertyVector2 = "PropertyVector2"; /// <summary> - /// Cached name for the 'property_Vector2I' property. + /// Cached name for the 'PropertyVector2I' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector2I = "property_Vector2I"; + public new static readonly global::Godot.StringName PropertyVector2I = "PropertyVector2I"; /// <summary> - /// Cached name for the 'property_Rect2' property. + /// Cached name for the 'PropertyRect2' property. /// </summary> - public new static readonly global::Godot.StringName property_Rect2 = "property_Rect2"; + public new static readonly global::Godot.StringName PropertyRect2 = "PropertyRect2"; /// <summary> - /// Cached name for the 'property_Rect2I' property. + /// Cached name for the 'PropertyRect2I' property. /// </summary> - public new static readonly global::Godot.StringName property_Rect2I = "property_Rect2I"; + public new static readonly global::Godot.StringName PropertyRect2I = "PropertyRect2I"; /// <summary> - /// Cached name for the 'property_Transform2D' property. + /// Cached name for the 'PropertyTransform2D' property. /// </summary> - public new static readonly global::Godot.StringName property_Transform2D = "property_Transform2D"; + public new static readonly global::Godot.StringName PropertyTransform2D = "PropertyTransform2D"; /// <summary> - /// Cached name for the 'property_Vector3' property. + /// Cached name for the 'PropertyVector3' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector3 = "property_Vector3"; + public new static readonly global::Godot.StringName PropertyVector3 = "PropertyVector3"; /// <summary> - /// Cached name for the 'property_Vector3I' property. + /// Cached name for the 'PropertyVector3I' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector3I = "property_Vector3I"; + public new static readonly global::Godot.StringName PropertyVector3I = "PropertyVector3I"; /// <summary> - /// Cached name for the 'property_Basis' property. + /// Cached name for the 'PropertyBasis' property. /// </summary> - public new static readonly global::Godot.StringName property_Basis = "property_Basis"; + public new static readonly global::Godot.StringName PropertyBasis = "PropertyBasis"; /// <summary> - /// Cached name for the 'property_Quaternion' property. + /// Cached name for the 'PropertyQuaternion' property. /// </summary> - public new static readonly global::Godot.StringName property_Quaternion = "property_Quaternion"; + public new static readonly global::Godot.StringName PropertyQuaternion = "PropertyQuaternion"; /// <summary> - /// Cached name for the 'property_Transform3D' property. + /// Cached name for the 'PropertyTransform3D' property. /// </summary> - public new static readonly global::Godot.StringName property_Transform3D = "property_Transform3D"; + public new static readonly global::Godot.StringName PropertyTransform3D = "PropertyTransform3D"; /// <summary> - /// Cached name for the 'property_Vector4' property. + /// Cached name for the 'PropertyVector4' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector4 = "property_Vector4"; + public new static readonly global::Godot.StringName PropertyVector4 = "PropertyVector4"; /// <summary> - /// Cached name for the 'property_Vector4I' property. + /// Cached name for the 'PropertyVector4I' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector4I = "property_Vector4I"; + public new static readonly global::Godot.StringName PropertyVector4I = "PropertyVector4I"; /// <summary> - /// Cached name for the 'property_Projection' property. + /// Cached name for the 'PropertyProjection' property. /// </summary> - public new static readonly global::Godot.StringName property_Projection = "property_Projection"; + public new static readonly global::Godot.StringName PropertyProjection = "PropertyProjection"; /// <summary> - /// Cached name for the 'property_Aabb' property. + /// Cached name for the 'PropertyAabb' property. /// </summary> - public new static readonly global::Godot.StringName property_Aabb = "property_Aabb"; + public new static readonly global::Godot.StringName PropertyAabb = "PropertyAabb"; /// <summary> - /// Cached name for the 'property_Color' property. + /// Cached name for the 'PropertyColor' property. /// </summary> - public new static readonly global::Godot.StringName property_Color = "property_Color"; + public new static readonly global::Godot.StringName PropertyColor = "PropertyColor"; /// <summary> - /// Cached name for the 'property_Plane' property. + /// Cached name for the 'PropertyPlane' property. /// </summary> - public new static readonly global::Godot.StringName property_Plane = "property_Plane"; + public new static readonly global::Godot.StringName PropertyPlane = "PropertyPlane"; /// <summary> - /// Cached name for the 'property_Callable' property. + /// Cached name for the 'PropertyCallable' property. /// </summary> - public new static readonly global::Godot.StringName property_Callable = "property_Callable"; + public new static readonly global::Godot.StringName PropertyCallable = "PropertyCallable"; /// <summary> - /// Cached name for the 'property_Signal' property. + /// Cached name for the 'PropertySignal' property. /// </summary> - public new static readonly global::Godot.StringName property_Signal = "property_Signal"; + public new static readonly global::Godot.StringName PropertySignal = "PropertySignal"; /// <summary> - /// Cached name for the 'property_Enum' property. + /// Cached name for the 'PropertyEnum' property. /// </summary> - public new static readonly global::Godot.StringName property_Enum = "property_Enum"; + public new static readonly global::Godot.StringName PropertyEnum = "PropertyEnum"; /// <summary> - /// Cached name for the 'property_FlagsEnum' property. + /// Cached name for the 'PropertyFlagsEnum' property. /// </summary> - public new static readonly global::Godot.StringName property_FlagsEnum = "property_FlagsEnum"; + public new static readonly global::Godot.StringName PropertyFlagsEnum = "PropertyFlagsEnum"; /// <summary> - /// Cached name for the 'property_ByteArray' property. + /// Cached name for the 'PropertyByteArray' property. /// </summary> - public new static readonly global::Godot.StringName property_ByteArray = "property_ByteArray"; + public new static readonly global::Godot.StringName PropertyByteArray = "PropertyByteArray"; /// <summary> - /// Cached name for the 'property_Int32Array' property. + /// Cached name for the 'PropertyInt32Array' property. /// </summary> - public new static readonly global::Godot.StringName property_Int32Array = "property_Int32Array"; + public new static readonly global::Godot.StringName PropertyInt32Array = "PropertyInt32Array"; /// <summary> - /// Cached name for the 'property_Int64Array' property. + /// Cached name for the 'PropertyInt64Array' property. /// </summary> - public new static readonly global::Godot.StringName property_Int64Array = "property_Int64Array"; + public new static readonly global::Godot.StringName PropertyInt64Array = "PropertyInt64Array"; /// <summary> - /// Cached name for the 'property_SingleArray' property. + /// Cached name for the 'PropertySingleArray' property. /// </summary> - public new static readonly global::Godot.StringName property_SingleArray = "property_SingleArray"; + public new static readonly global::Godot.StringName PropertySingleArray = "PropertySingleArray"; /// <summary> - /// Cached name for the 'property_DoubleArray' property. + /// Cached name for the 'PropertyDoubleArray' property. /// </summary> - public new static readonly global::Godot.StringName property_DoubleArray = "property_DoubleArray"; + public new static readonly global::Godot.StringName PropertyDoubleArray = "PropertyDoubleArray"; /// <summary> - /// Cached name for the 'property_StringArray' property. + /// Cached name for the 'PropertyStringArray' property. /// </summary> - public new static readonly global::Godot.StringName property_StringArray = "property_StringArray"; + public new static readonly global::Godot.StringName PropertyStringArray = "PropertyStringArray"; /// <summary> - /// Cached name for the 'property_StringArrayEnum' property. + /// Cached name for the 'PropertyStringArrayEnum' property. /// </summary> - public new static readonly global::Godot.StringName property_StringArrayEnum = "property_StringArrayEnum"; + public new static readonly global::Godot.StringName PropertyStringArrayEnum = "PropertyStringArrayEnum"; /// <summary> - /// Cached name for the 'property_Vector2Array' property. + /// Cached name for the 'PropertyVector2Array' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector2Array = "property_Vector2Array"; + public new static readonly global::Godot.StringName PropertyVector2Array = "PropertyVector2Array"; /// <summary> - /// Cached name for the 'property_Vector3Array' property. + /// Cached name for the 'PropertyVector3Array' property. /// </summary> - public new static readonly global::Godot.StringName property_Vector3Array = "property_Vector3Array"; + public new static readonly global::Godot.StringName PropertyVector3Array = "PropertyVector3Array"; /// <summary> - /// Cached name for the 'property_ColorArray' property. + /// Cached name for the 'PropertyColorArray' property. /// </summary> - public new static readonly global::Godot.StringName property_ColorArray = "property_ColorArray"; + public new static readonly global::Godot.StringName PropertyColorArray = "PropertyColorArray"; /// <summary> - /// Cached name for the 'property_GodotObjectOrDerivedArray' property. + /// Cached name for the 'PropertyGodotObjectOrDerivedArray' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotObjectOrDerivedArray = "property_GodotObjectOrDerivedArray"; + public new static readonly global::Godot.StringName PropertyGodotObjectOrDerivedArray = "PropertyGodotObjectOrDerivedArray"; /// <summary> /// Cached name for the 'field_StringNameArray' property. /// </summary> @@ -225,272 +225,272 @@ partial class ExportedProperties /// </summary> public new static readonly global::Godot.StringName field_RidArray = "field_RidArray"; /// <summary> - /// Cached name for the 'property_Variant' property. + /// Cached name for the 'PropertyVariant' property. /// </summary> - public new static readonly global::Godot.StringName property_Variant = "property_Variant"; + public new static readonly global::Godot.StringName PropertyVariant = "PropertyVariant"; /// <summary> - /// Cached name for the 'property_GodotObjectOrDerived' property. + /// Cached name for the 'PropertyGodotObjectOrDerived' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotObjectOrDerived = "property_GodotObjectOrDerived"; + public new static readonly global::Godot.StringName PropertyGodotObjectOrDerived = "PropertyGodotObjectOrDerived"; /// <summary> - /// Cached name for the 'property_GodotResourceTexture' property. + /// Cached name for the 'PropertyGodotResourceTexture' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotResourceTexture = "property_GodotResourceTexture"; + public new static readonly global::Godot.StringName PropertyGodotResourceTexture = "PropertyGodotResourceTexture"; /// <summary> - /// Cached name for the 'property_StringName' property. + /// Cached name for the 'PropertyStringName' property. /// </summary> - public new static readonly global::Godot.StringName property_StringName = "property_StringName"; + public new static readonly global::Godot.StringName PropertyStringName = "PropertyStringName"; /// <summary> - /// Cached name for the 'property_NodePath' property. + /// Cached name for the 'PropertyNodePath' property. /// </summary> - public new static readonly global::Godot.StringName property_NodePath = "property_NodePath"; + public new static readonly global::Godot.StringName PropertyNodePath = "PropertyNodePath"; /// <summary> - /// Cached name for the 'property_Rid' property. + /// Cached name for the 'PropertyRid' property. /// </summary> - public new static readonly global::Godot.StringName property_Rid = "property_Rid"; + public new static readonly global::Godot.StringName PropertyRid = "PropertyRid"; /// <summary> - /// Cached name for the 'property_GodotDictionary' property. + /// Cached name for the 'PropertyGodotDictionary' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotDictionary = "property_GodotDictionary"; + public new static readonly global::Godot.StringName PropertyGodotDictionary = "PropertyGodotDictionary"; /// <summary> - /// Cached name for the 'property_GodotArray' property. + /// Cached name for the 'PropertyGodotArray' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotArray = "property_GodotArray"; + public new static readonly global::Godot.StringName PropertyGodotArray = "PropertyGodotArray"; /// <summary> - /// Cached name for the 'property_GodotGenericDictionary' property. + /// Cached name for the 'PropertyGodotGenericDictionary' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotGenericDictionary = "property_GodotGenericDictionary"; + public new static readonly global::Godot.StringName PropertyGodotGenericDictionary = "PropertyGodotGenericDictionary"; /// <summary> - /// Cached name for the 'property_GodotGenericArray' property. + /// Cached name for the 'PropertyGodotGenericArray' property. /// </summary> - public new static readonly global::Godot.StringName property_GodotGenericArray = "property_GodotGenericArray"; + public new static readonly global::Godot.StringName PropertyGodotGenericArray = "PropertyGodotGenericArray"; /// <summary> - /// Cached name for the '_notGenerate_Property_String' field. + /// Cached name for the '_notGeneratePropertyString' field. /// </summary> - public new static readonly global::Godot.StringName _notGenerate_Property_String = "_notGenerate_Property_String"; + public new static readonly global::Godot.StringName _notGeneratePropertyString = "_notGeneratePropertyString"; /// <summary> - /// Cached name for the '_notGenerate_Property_Int' field. + /// Cached name for the '_notGeneratePropertyInt' field. /// </summary> - public new static readonly global::Godot.StringName _notGenerate_Property_Int = "_notGenerate_Property_Int"; + public new static readonly global::Godot.StringName _notGeneratePropertyInt = "_notGeneratePropertyInt"; /// <summary> - /// Cached name for the '_fullProperty_String' field. + /// Cached name for the '_fullPropertyString' field. /// </summary> - public new static readonly global::Godot.StringName _fullProperty_String = "_fullProperty_String"; + public new static readonly global::Godot.StringName _fullPropertyString = "_fullPropertyString"; /// <summary> - /// Cached name for the '_fullProperty_String_Complex' field. + /// Cached name for the '_fullPropertyStringComplex' field. /// </summary> - public new static readonly global::Godot.StringName _fullProperty_String_Complex = "_fullProperty_String_Complex"; + public new static readonly global::Godot.StringName _fullPropertyStringComplex = "_fullPropertyStringComplex"; /// <summary> - /// Cached name for the '_lamdaProperty_String' field. + /// Cached name for the '_lamdaPropertyString' field. /// </summary> - public new static readonly global::Godot.StringName _lamdaProperty_String = "_lamdaProperty_String"; + public new static readonly global::Godot.StringName _lamdaPropertyString = "_lamdaPropertyString"; } /// <inheritdoc/> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) { - if (name == PropertyName.NotGenerate_Complex_Lamda_Property) { - this.NotGenerate_Complex_Lamda_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + if (name == PropertyName.NotGenerateComplexLamdaProperty) { + this.NotGenerateComplexLamdaProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerate_Lamda_NoField_Property) { - this.NotGenerate_Lamda_NoField_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { + this.NotGenerateLamdaNoFieldProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerate_Complex_Return_Property) { - this.NotGenerate_Complex_Return_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.NotGenerateComplexReturnProperty) { + this.NotGenerateComplexReturnProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.NotGenerate_Returns_Property) { - this.NotGenerate_Returns_Property = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.NotGenerateReturnsProperty) { + this.NotGenerateReturnsProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.FullProperty_String) { - this.FullProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.FullPropertyString) { + this.FullPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.FullProperty_String_Complex) { - this.FullProperty_String_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.FullPropertyString_Complex) { + this.FullPropertyString_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.LamdaProperty_String) { - this.LamdaProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.LamdaPropertyString) { + this.LamdaPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.property_Boolean) { - this.property_Boolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + else if (name == PropertyName.PropertyBoolean) { + this.PropertyBoolean = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName.property_Char) { - this.property_Char = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); + else if (name == PropertyName.PropertyChar) { + this.PropertyChar = global::Godot.NativeInterop.VariantUtils.ConvertTo<char>(value); return true; } - else if (name == PropertyName.property_SByte) { - this.property_SByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); + else if (name == PropertyName.PropertySByte) { + this.PropertySByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<sbyte>(value); return true; } - else if (name == PropertyName.property_Int16) { - this.property_Int16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); + else if (name == PropertyName.PropertyInt16) { + this.PropertyInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<short>(value); return true; } - else if (name == PropertyName.property_Int32) { - this.property_Int32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + else if (name == PropertyName.PropertyInt32) { + this.PropertyInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName.property_Int64) { - this.property_Int64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); + else if (name == PropertyName.PropertyInt64) { + this.PropertyInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<long>(value); return true; } - else if (name == PropertyName.property_Byte) { - this.property_Byte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); + else if (name == PropertyName.PropertyByte) { + this.PropertyByte = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte>(value); return true; } - else if (name == PropertyName.property_UInt16) { - this.property_UInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); + else if (name == PropertyName.PropertyUInt16) { + this.PropertyUInt16 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ushort>(value); return true; } - else if (name == PropertyName.property_UInt32) { - this.property_UInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); + else if (name == PropertyName.PropertyUInt32) { + this.PropertyUInt32 = global::Godot.NativeInterop.VariantUtils.ConvertTo<uint>(value); return true; } - else if (name == PropertyName.property_UInt64) { - this.property_UInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); + else if (name == PropertyName.PropertyUInt64) { + this.PropertyUInt64 = global::Godot.NativeInterop.VariantUtils.ConvertTo<ulong>(value); return true; } - else if (name == PropertyName.property_Single) { - this.property_Single = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); + else if (name == PropertyName.PropertySingle) { + this.PropertySingle = global::Godot.NativeInterop.VariantUtils.ConvertTo<float>(value); return true; } - else if (name == PropertyName.property_Double) { - this.property_Double = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); + else if (name == PropertyName.PropertyDouble) { + this.PropertyDouble = global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(value); return true; } - else if (name == PropertyName.property_String) { - this.property_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName.PropertyString) { + this.PropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName.property_Vector2) { - this.property_Vector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); + else if (name == PropertyName.PropertyVector2) { + this.PropertyVector2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2>(value); return true; } - else if (name == PropertyName.property_Vector2I) { - this.property_Vector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); + else if (name == PropertyName.PropertyVector2I) { + this.PropertyVector2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2I>(value); return true; } - else if (name == PropertyName.property_Rect2) { - this.property_Rect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); + else if (name == PropertyName.PropertyRect2) { + this.PropertyRect2 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2>(value); return true; } - else if (name == PropertyName.property_Rect2I) { - this.property_Rect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); + else if (name == PropertyName.PropertyRect2I) { + this.PropertyRect2I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rect2I>(value); return true; } - else if (name == PropertyName.property_Transform2D) { - this.property_Transform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); + else if (name == PropertyName.PropertyTransform2D) { + this.PropertyTransform2D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform2D>(value); return true; } - else if (name == PropertyName.property_Vector3) { - this.property_Vector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); + else if (name == PropertyName.PropertyVector3) { + this.PropertyVector3 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3>(value); return true; } - else if (name == PropertyName.property_Vector3I) { - this.property_Vector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); + else if (name == PropertyName.PropertyVector3I) { + this.PropertyVector3I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3I>(value); return true; } - else if (name == PropertyName.property_Basis) { - this.property_Basis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); + else if (name == PropertyName.PropertyBasis) { + this.PropertyBasis = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Basis>(value); return true; } - else if (name == PropertyName.property_Quaternion) { - this.property_Quaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); + else if (name == PropertyName.PropertyQuaternion) { + this.PropertyQuaternion = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Quaternion>(value); return true; } - else if (name == PropertyName.property_Transform3D) { - this.property_Transform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); + else if (name == PropertyName.PropertyTransform3D) { + this.PropertyTransform3D = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Transform3D>(value); return true; } - else if (name == PropertyName.property_Vector4) { - this.property_Vector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); + else if (name == PropertyName.PropertyVector4) { + this.PropertyVector4 = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4>(value); return true; } - else if (name == PropertyName.property_Vector4I) { - this.property_Vector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); + else if (name == PropertyName.PropertyVector4I) { + this.PropertyVector4I = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector4I>(value); return true; } - else if (name == PropertyName.property_Projection) { - this.property_Projection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); + else if (name == PropertyName.PropertyProjection) { + this.PropertyProjection = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Projection>(value); return true; } - else if (name == PropertyName.property_Aabb) { - this.property_Aabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); + else if (name == PropertyName.PropertyAabb) { + this.PropertyAabb = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Aabb>(value); return true; } - else if (name == PropertyName.property_Color) { - this.property_Color = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); + else if (name == PropertyName.PropertyColor) { + this.PropertyColor = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color>(value); return true; } - else if (name == PropertyName.property_Plane) { - this.property_Plane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); + else if (name == PropertyName.PropertyPlane) { + this.PropertyPlane = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Plane>(value); return true; } - else if (name == PropertyName.property_Callable) { - this.property_Callable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); + else if (name == PropertyName.PropertyCallable) { + this.PropertyCallable = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value); return true; } - else if (name == PropertyName.property_Signal) { - this.property_Signal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); + else if (name == PropertyName.PropertySignal) { + this.PropertySignal = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Signal>(value); return true; } - else if (name == PropertyName.property_Enum) { - this.property_Enum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyEnum>(value); + else if (name == PropertyName.PropertyEnum) { + this.PropertyEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyEnum>(value); return true; } - else if (name == PropertyName.property_FlagsEnum) { - this.property_FlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyFlagsEnum>(value); + else if (name == PropertyName.PropertyFlagsEnum) { + this.PropertyFlagsEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::ExportedProperties.MyFlagsEnum>(value); return true; } - else if (name == PropertyName.property_ByteArray) { - this.property_ByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); + else if (name == PropertyName.PropertyByteArray) { + this.PropertyByteArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<byte[]>(value); return true; } - else if (name == PropertyName.property_Int32Array) { - this.property_Int32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); + else if (name == PropertyName.PropertyInt32Array) { + this.PropertyInt32Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<int[]>(value); return true; } - else if (name == PropertyName.property_Int64Array) { - this.property_Int64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); + else if (name == PropertyName.PropertyInt64Array) { + this.PropertyInt64Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<long[]>(value); return true; } - else if (name == PropertyName.property_SingleArray) { - this.property_SingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); + else if (name == PropertyName.PropertySingleArray) { + this.PropertySingleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<float[]>(value); return true; } - else if (name == PropertyName.property_DoubleArray) { - this.property_DoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); + else if (name == PropertyName.PropertyDoubleArray) { + this.PropertyDoubleArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<double[]>(value); return true; } - else if (name == PropertyName.property_StringArray) { - this.property_StringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + else if (name == PropertyName.PropertyStringArray) { + this.PropertyStringArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.property_StringArrayEnum) { - this.property_StringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); + else if (name == PropertyName.PropertyStringArrayEnum) { + this.PropertyStringArrayEnum = global::Godot.NativeInterop.VariantUtils.ConvertTo<string[]>(value); return true; } - else if (name == PropertyName.property_Vector2Array) { - this.property_Vector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); + else if (name == PropertyName.PropertyVector2Array) { + this.PropertyVector2Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector2[]>(value); return true; } - else if (name == PropertyName.property_Vector3Array) { - this.property_Vector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); + else if (name == PropertyName.PropertyVector3Array) { + this.PropertyVector3Array = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Vector3[]>(value); return true; } - else if (name == PropertyName.property_ColorArray) { - this.property_ColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); + else if (name == PropertyName.PropertyColorArray) { + this.PropertyColorArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Color[]>(value); return true; } - else if (name == PropertyName.property_GodotObjectOrDerivedArray) { - this.property_GodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); + else if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { + this.PropertyGodotObjectOrDerivedArray = global::Godot.NativeInterop.VariantUtils.ConvertToSystemArrayOfGodotObject<global::Godot.GodotObject>(value); return true; } else if (name == PropertyName.field_StringNameArray) { @@ -505,64 +505,64 @@ partial class ExportedProperties this.field_RidArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid[]>(value); return true; } - else if (name == PropertyName.property_Variant) { - this.property_Variant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); + else if (name == PropertyName.PropertyVariant) { + this.PropertyVariant = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Variant>(value); return true; } - else if (name == PropertyName.property_GodotObjectOrDerived) { - this.property_GodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); + else if (name == PropertyName.PropertyGodotObjectOrDerived) { + this.PropertyGodotObjectOrDerived = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.GodotObject>(value); return true; } - else if (name == PropertyName.property_GodotResourceTexture) { - this.property_GodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); + else if (name == PropertyName.PropertyGodotResourceTexture) { + this.PropertyGodotResourceTexture = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Texture>(value); return true; } - else if (name == PropertyName.property_StringName) { - this.property_StringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); + else if (name == PropertyName.PropertyStringName) { + this.PropertyStringName = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(value); return true; } - else if (name == PropertyName.property_NodePath) { - this.property_NodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); + else if (name == PropertyName.PropertyNodePath) { + this.PropertyNodePath = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.NodePath>(value); return true; } - else if (name == PropertyName.property_Rid) { - this.property_Rid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); + else if (name == PropertyName.PropertyRid) { + this.PropertyRid = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Rid>(value); return true; } - else if (name == PropertyName.property_GodotDictionary) { - this.property_GodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); + else if (name == PropertyName.PropertyGodotDictionary) { + this.PropertyGodotDictionary = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Dictionary>(value); return true; } - else if (name == PropertyName.property_GodotArray) { - this.property_GodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); + else if (name == PropertyName.PropertyGodotArray) { + this.PropertyGodotArray = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Collections.Array>(value); return true; } - else if (name == PropertyName.property_GodotGenericDictionary) { - this.property_GodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); + else if (name == PropertyName.PropertyGodotGenericDictionary) { + this.PropertyGodotGenericDictionary = global::Godot.NativeInterop.VariantUtils.ConvertToDictionary<string, bool>(value); return true; } - else if (name == PropertyName.property_GodotGenericArray) { - this.property_GodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); + else if (name == PropertyName.PropertyGodotGenericArray) { + this.PropertyGodotGenericArray = global::Godot.NativeInterop.VariantUtils.ConvertToArray<int>(value); return true; } - else if (name == PropertyName._notGenerate_Property_String) { - this._notGenerate_Property_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName._notGeneratePropertyString) { + this._notGeneratePropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._notGenerate_Property_Int) { - this._notGenerate_Property_Int = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); + else if (name == PropertyName._notGeneratePropertyInt) { + this._notGeneratePropertyInt = global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(value); return true; } - else if (name == PropertyName._fullProperty_String) { - this._fullProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName._fullPropertyString) { + this._fullPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._fullProperty_String_Complex) { - this._fullProperty_String_Complex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName._fullPropertyStringComplex) { + this._fullPropertyStringComplex = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } - else if (name == PropertyName._lamdaProperty_String) { - this._lamdaProperty_String = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); + else if (name == PropertyName._lamdaPropertyString) { + this._lamdaPropertyString = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value); return true; } return base.SetGodotClassPropertyValue(name, value); @@ -571,208 +571,208 @@ partial class ExportedProperties [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) { - if (name == PropertyName.NotGenerate_Complex_Lamda_Property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Complex_Lamda_Property); + if (name == PropertyName.NotGenerateComplexLamdaProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateComplexLamdaProperty); return true; } - else if (name == PropertyName.NotGenerate_Lamda_NoField_Property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Lamda_NoField_Property); + else if (name == PropertyName.NotGenerateLamdaNoFieldProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateLamdaNoFieldProperty); return true; } - else if (name == PropertyName.NotGenerate_Complex_Return_Property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Complex_Return_Property); + else if (name == PropertyName.NotGenerateComplexReturnProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateComplexReturnProperty); return true; } - else if (name == PropertyName.NotGenerate_Returns_Property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerate_Returns_Property); + else if (name == PropertyName.NotGenerateReturnsProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.NotGenerateReturnsProperty); return true; } - else if (name == PropertyName.FullProperty_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullProperty_String); + else if (name == PropertyName.FullPropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullPropertyString); return true; } - else if (name == PropertyName.FullProperty_String_Complex) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullProperty_String_Complex); + else if (name == PropertyName.FullPropertyString_Complex) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.FullPropertyString_Complex); return true; } - else if (name == PropertyName.LamdaProperty_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.LamdaProperty_String); + else if (name == PropertyName.LamdaPropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.LamdaPropertyString); return true; } - else if (name == PropertyName.property_Boolean) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.property_Boolean); + else if (name == PropertyName.PropertyBoolean) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.PropertyBoolean); return true; } - else if (name == PropertyName.property_Char) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.property_Char); + else if (name == PropertyName.PropertyChar) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<char>(this.PropertyChar); return true; } - else if (name == PropertyName.property_SByte) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.property_SByte); + else if (name == PropertyName.PropertySByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<sbyte>(this.PropertySByte); return true; } - else if (name == PropertyName.property_Int16) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.property_Int16); + else if (name == PropertyName.PropertyInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<short>(this.PropertyInt16); return true; } - else if (name == PropertyName.property_Int32) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.property_Int32); + else if (name == PropertyName.PropertyInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this.PropertyInt32); return true; } - else if (name == PropertyName.property_Int64) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.property_Int64); + else if (name == PropertyName.PropertyInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long>(this.PropertyInt64); return true; } - else if (name == PropertyName.property_Byte) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.property_Byte); + else if (name == PropertyName.PropertyByte) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte>(this.PropertyByte); return true; } - else if (name == PropertyName.property_UInt16) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.property_UInt16); + else if (name == PropertyName.PropertyUInt16) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ushort>(this.PropertyUInt16); return true; } - else if (name == PropertyName.property_UInt32) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.property_UInt32); + else if (name == PropertyName.PropertyUInt32) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<uint>(this.PropertyUInt32); return true; } - else if (name == PropertyName.property_UInt64) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.property_UInt64); + else if (name == PropertyName.PropertyUInt64) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<ulong>(this.PropertyUInt64); return true; } - else if (name == PropertyName.property_Single) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.property_Single); + else if (name == PropertyName.PropertySingle) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float>(this.PropertySingle); return true; } - else if (name == PropertyName.property_Double) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.property_Double); + else if (name == PropertyName.PropertyDouble) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double>(this.PropertyDouble); return true; } - else if (name == PropertyName.property_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.property_String); + else if (name == PropertyName.PropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.PropertyString); return true; } - else if (name == PropertyName.property_Vector2) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.property_Vector2); + else if (name == PropertyName.PropertyVector2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2>(this.PropertyVector2); return true; } - else if (name == PropertyName.property_Vector2I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.property_Vector2I); + else if (name == PropertyName.PropertyVector2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2I>(this.PropertyVector2I); return true; } - else if (name == PropertyName.property_Rect2) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.property_Rect2); + else if (name == PropertyName.PropertyRect2) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2>(this.PropertyRect2); return true; } - else if (name == PropertyName.property_Rect2I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.property_Rect2I); + else if (name == PropertyName.PropertyRect2I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rect2I>(this.PropertyRect2I); return true; } - else if (name == PropertyName.property_Transform2D) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.property_Transform2D); + else if (name == PropertyName.PropertyTransform2D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform2D>(this.PropertyTransform2D); return true; } - else if (name == PropertyName.property_Vector3) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.property_Vector3); + else if (name == PropertyName.PropertyVector3) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3>(this.PropertyVector3); return true; } - else if (name == PropertyName.property_Vector3I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.property_Vector3I); + else if (name == PropertyName.PropertyVector3I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3I>(this.PropertyVector3I); return true; } - else if (name == PropertyName.property_Basis) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.property_Basis); + else if (name == PropertyName.PropertyBasis) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Basis>(this.PropertyBasis); return true; } - else if (name == PropertyName.property_Quaternion) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.property_Quaternion); + else if (name == PropertyName.PropertyQuaternion) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Quaternion>(this.PropertyQuaternion); return true; } - else if (name == PropertyName.property_Transform3D) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.property_Transform3D); + else if (name == PropertyName.PropertyTransform3D) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Transform3D>(this.PropertyTransform3D); return true; } - else if (name == PropertyName.property_Vector4) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.property_Vector4); + else if (name == PropertyName.PropertyVector4) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4>(this.PropertyVector4); return true; } - else if (name == PropertyName.property_Vector4I) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.property_Vector4I); + else if (name == PropertyName.PropertyVector4I) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector4I>(this.PropertyVector4I); return true; } - else if (name == PropertyName.property_Projection) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.property_Projection); + else if (name == PropertyName.PropertyProjection) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Projection>(this.PropertyProjection); return true; } - else if (name == PropertyName.property_Aabb) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.property_Aabb); + else if (name == PropertyName.PropertyAabb) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Aabb>(this.PropertyAabb); return true; } - else if (name == PropertyName.property_Color) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.property_Color); + else if (name == PropertyName.PropertyColor) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color>(this.PropertyColor); return true; } - else if (name == PropertyName.property_Plane) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.property_Plane); + else if (name == PropertyName.PropertyPlane) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Plane>(this.PropertyPlane); return true; } - else if (name == PropertyName.property_Callable) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.property_Callable); + else if (name == PropertyName.PropertyCallable) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.PropertyCallable); return true; } - else if (name == PropertyName.property_Signal) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.property_Signal); + else if (name == PropertyName.PropertySignal) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Signal>(this.PropertySignal); return true; } - else if (name == PropertyName.property_Enum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyEnum>(this.property_Enum); + else if (name == PropertyName.PropertyEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyEnum>(this.PropertyEnum); return true; } - else if (name == PropertyName.property_FlagsEnum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyFlagsEnum>(this.property_FlagsEnum); + else if (name == PropertyName.PropertyFlagsEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::ExportedProperties.MyFlagsEnum>(this.PropertyFlagsEnum); return true; } - else if (name == PropertyName.property_ByteArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.property_ByteArray); + else if (name == PropertyName.PropertyByteArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<byte[]>(this.PropertyByteArray); return true; } - else if (name == PropertyName.property_Int32Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.property_Int32Array); + else if (name == PropertyName.PropertyInt32Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int[]>(this.PropertyInt32Array); return true; } - else if (name == PropertyName.property_Int64Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.property_Int64Array); + else if (name == PropertyName.PropertyInt64Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<long[]>(this.PropertyInt64Array); return true; } - else if (name == PropertyName.property_SingleArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.property_SingleArray); + else if (name == PropertyName.PropertySingleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<float[]>(this.PropertySingleArray); return true; } - else if (name == PropertyName.property_DoubleArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.property_DoubleArray); + else if (name == PropertyName.PropertyDoubleArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<double[]>(this.PropertyDoubleArray); return true; } - else if (name == PropertyName.property_StringArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.property_StringArray); + else if (name == PropertyName.PropertyStringArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.PropertyStringArray); return true; } - else if (name == PropertyName.property_StringArrayEnum) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.property_StringArrayEnum); + else if (name == PropertyName.PropertyStringArrayEnum) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string[]>(this.PropertyStringArrayEnum); return true; } - else if (name == PropertyName.property_Vector2Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.property_Vector2Array); + else if (name == PropertyName.PropertyVector2Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector2[]>(this.PropertyVector2Array); return true; } - else if (name == PropertyName.property_Vector3Array) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.property_Vector3Array); + else if (name == PropertyName.PropertyVector3Array) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Vector3[]>(this.PropertyVector3Array); return true; } - else if (name == PropertyName.property_ColorArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.property_ColorArray); + else if (name == PropertyName.PropertyColorArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Color[]>(this.PropertyColorArray); return true; } - else if (name == PropertyName.property_GodotObjectOrDerivedArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.property_GodotObjectOrDerivedArray); + else if (name == PropertyName.PropertyGodotObjectOrDerivedArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromSystemArrayOfGodotObject(this.PropertyGodotObjectOrDerivedArray); return true; } else if (name == PropertyName.field_StringNameArray) { @@ -787,64 +787,64 @@ partial class ExportedProperties value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid[]>(this.field_RidArray); return true; } - else if (name == PropertyName.property_Variant) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.property_Variant); + else if (name == PropertyName.PropertyVariant) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(this.PropertyVariant); return true; } - else if (name == PropertyName.property_GodotObjectOrDerived) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.property_GodotObjectOrDerived); + else if (name == PropertyName.PropertyGodotObjectOrDerived) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.GodotObject>(this.PropertyGodotObjectOrDerived); return true; } - else if (name == PropertyName.property_GodotResourceTexture) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.property_GodotResourceTexture); + else if (name == PropertyName.PropertyGodotResourceTexture) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Texture>(this.PropertyGodotResourceTexture); return true; } - else if (name == PropertyName.property_StringName) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.property_StringName); + else if (name == PropertyName.PropertyStringName) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.StringName>(this.PropertyStringName); return true; } - else if (name == PropertyName.property_NodePath) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.property_NodePath); + else if (name == PropertyName.PropertyNodePath) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.NodePath>(this.PropertyNodePath); return true; } - else if (name == PropertyName.property_Rid) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.property_Rid); + else if (name == PropertyName.PropertyRid) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Rid>(this.PropertyRid); return true; } - else if (name == PropertyName.property_GodotDictionary) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.property_GodotDictionary); + else if (name == PropertyName.PropertyGodotDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Dictionary>(this.PropertyGodotDictionary); return true; } - else if (name == PropertyName.property_GodotArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.property_GodotArray); + else if (name == PropertyName.PropertyGodotArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Collections.Array>(this.PropertyGodotArray); return true; } - else if (name == PropertyName.property_GodotGenericDictionary) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.property_GodotGenericDictionary); + else if (name == PropertyName.PropertyGodotGenericDictionary) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromDictionary(this.PropertyGodotGenericDictionary); return true; } - else if (name == PropertyName.property_GodotGenericArray) { - value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.property_GodotGenericArray); + else if (name == PropertyName.PropertyGodotGenericArray) { + value = global::Godot.NativeInterop.VariantUtils.CreateFromArray(this.PropertyGodotGenericArray); return true; } - else if (name == PropertyName._notGenerate_Property_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._notGenerate_Property_String); + else if (name == PropertyName._notGeneratePropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._notGeneratePropertyString); return true; } - else if (name == PropertyName._notGenerate_Property_Int) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._notGenerate_Property_Int); + else if (name == PropertyName._notGeneratePropertyInt) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(this._notGeneratePropertyInt); return true; } - else if (name == PropertyName._fullProperty_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullProperty_String); + else if (name == PropertyName._fullPropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullPropertyString); return true; } - else if (name == PropertyName._fullProperty_String_Complex) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullProperty_String_Complex); + else if (name == PropertyName._fullPropertyStringComplex) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._fullPropertyStringComplex); return true; } - else if (name == PropertyName._lamdaProperty_String) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._lamdaProperty_String); + else if (name == PropertyName._lamdaPropertyString) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this._lamdaPropertyString); return true; } return base.GetGodotClassPropertyValue(name, out value); @@ -858,75 +858,75 @@ partial class ExportedProperties internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() { var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._notGenerate_Property_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Complex_Lamda_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Lamda_NoField_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Complex_Return_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._notGenerate_Property_Int, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerate_Returns_Property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullProperty_String_Complex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullProperty_String_Complex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._lamdaProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.LamdaProperty_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.property_Boolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Char, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_SByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Int64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Byte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_UInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.property_Single, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.property_Double, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.property_String, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName.property_Vector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName.property_Vector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName.property_Rect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName.property_Rect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName.property_Transform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName.property_Vector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName.property_Vector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName.property_Basis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName.property_Quaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName.property_Transform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName.property_Vector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName.property_Vector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName.property_Projection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName.property_Aabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName.property_Color, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName.property_Plane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.property_Callable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName.property_Signal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_Enum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.property_FlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName.property_ByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.property_Int32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.property_Int64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName.property_SingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName.property_DoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.property_StringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.property_StringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName.property_Vector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName.property_Vector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName.property_ColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._notGeneratePropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerateComplexLamdaProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerateLamdaNoFieldProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerateComplexReturnProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName._notGeneratePropertyInt, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.NotGenerateReturnsProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullPropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullPropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._fullPropertyStringComplex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.FullPropertyString_Complex, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName._lamdaPropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.LamdaPropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.PropertyBoolean, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyChar, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertySByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyByte, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyUInt16, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyUInt32, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyUInt64, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.PropertySingle, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)3, name: PropertyName.PropertyDouble, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.PropertyString, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)5, name: PropertyName.PropertyVector2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)6, name: PropertyName.PropertyVector2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)7, name: PropertyName.PropertyRect2, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)8, name: PropertyName.PropertyRect2I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)11, name: PropertyName.PropertyTransform2D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)9, name: PropertyName.PropertyVector3, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)10, name: PropertyName.PropertyVector3I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)17, name: PropertyName.PropertyBasis, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)15, name: PropertyName.PropertyQuaternion, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)18, name: PropertyName.PropertyTransform3D, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)12, name: PropertyName.PropertyVector4, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)13, name: PropertyName.PropertyVector4I, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)19, name: PropertyName.PropertyProjection, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)16, name: PropertyName.PropertyAabb, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)20, name: PropertyName.PropertyColor, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)14, name: PropertyName.PropertyPlane, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.PropertyCallable, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)26, name: PropertyName.PropertySignal, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyEnum, hint: (global::Godot.PropertyHint)2, hintString: "A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)2, name: PropertyName.PropertyFlagsEnum, hint: (global::Godot.PropertyHint)6, hintString: "A:0,B:1,C:2", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)29, name: PropertyName.PropertyByteArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)30, name: PropertyName.PropertyInt32Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)31, name: PropertyName.PropertyInt64Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)32, name: PropertyName.PropertySingleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)33, name: PropertyName.PropertyDoubleArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.PropertyStringArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)34, name: PropertyName.PropertyStringArrayEnum, hint: (global::Godot.PropertyHint)23, hintString: "4/2:A,B,C", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)35, name: PropertyName.PropertyVector2Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)36, name: PropertyName.PropertyVector3Array, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)37, name: PropertyName.PropertyColorArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.PropertyGodotObjectOrDerivedArray, hint: (global::Godot.PropertyHint)23, hintString: "24/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_StringNameArray, hint: (global::Godot.PropertyHint)23, hintString: "21/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_NodePathArray, hint: (global::Godot.PropertyHint)23, hintString: "22/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.field_RidArray, hint: (global::Godot.PropertyHint)23, hintString: "23/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName.property_Variant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.property_GodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.property_GodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName.property_StringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName.property_NodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.property_Rid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.property_GodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.property_GodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); - properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.property_GodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)0, name: PropertyName.PropertyVariant, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)135174, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.PropertyGodotObjectOrDerived, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)24, name: PropertyName.PropertyGodotResourceTexture, hint: (global::Godot.PropertyHint)17, hintString: "Texture", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)21, name: PropertyName.PropertyStringName, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)22, name: PropertyName.PropertyNodePath, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)23, name: PropertyName.PropertyRid, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.PropertyGodotDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.PropertyGodotArray, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)27, name: PropertyName.PropertyGodotGenericDictionary, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); + properties.Add(new(type: (global::Godot.Variant.Type)28, name: PropertyName.PropertyGodotGenericArray, hint: (global::Godot.PropertyHint)23, hintString: "2/0:", usage: (global::Godot.PropertyUsageFlags)4102, exported: true)); return properties; } #pragma warning restore CS0109 diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs index a4cd10d080..a1b01aed4f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedProperties_ScriptPropertyDefVal.generated.cs @@ -12,134 +12,134 @@ partial class ExportedProperties internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues() { var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(64); - string __NotGenerate_Complex_Lamda_Property_default_value = default; - values.Add(PropertyName.NotGenerate_Complex_Lamda_Property, global::Godot.Variant.From<string>(__NotGenerate_Complex_Lamda_Property_default_value)); - string __NotGenerate_Lamda_NoField_Property_default_value = default; - values.Add(PropertyName.NotGenerate_Lamda_NoField_Property, global::Godot.Variant.From<string>(__NotGenerate_Lamda_NoField_Property_default_value)); - string __NotGenerate_Complex_Return_Property_default_value = default; - values.Add(PropertyName.NotGenerate_Complex_Return_Property, global::Godot.Variant.From<string>(__NotGenerate_Complex_Return_Property_default_value)); - string __NotGenerate_Returns_Property_default_value = default; - values.Add(PropertyName.NotGenerate_Returns_Property, global::Godot.Variant.From<string>(__NotGenerate_Returns_Property_default_value)); - string __FullProperty_String_default_value = "FullProperty_String"; - values.Add(PropertyName.FullProperty_String, global::Godot.Variant.From<string>(__FullProperty_String_default_value)); - string __FullProperty_String_Complex_default_value = new string("FullProperty_String_Complex") + global::System.Convert.ToInt32("1"); - values.Add(PropertyName.FullProperty_String_Complex, global::Godot.Variant.From<string>(__FullProperty_String_Complex_default_value)); - string __LamdaProperty_String_default_value = "LamdaProperty_String"; - values.Add(PropertyName.LamdaProperty_String, global::Godot.Variant.From<string>(__LamdaProperty_String_default_value)); - bool __property_Boolean_default_value = true; - values.Add(PropertyName.property_Boolean, global::Godot.Variant.From<bool>(__property_Boolean_default_value)); - char __property_Char_default_value = 'f'; - values.Add(PropertyName.property_Char, global::Godot.Variant.From<char>(__property_Char_default_value)); - sbyte __property_SByte_default_value = 10; - values.Add(PropertyName.property_SByte, global::Godot.Variant.From<sbyte>(__property_SByte_default_value)); - short __property_Int16_default_value = 10; - values.Add(PropertyName.property_Int16, global::Godot.Variant.From<short>(__property_Int16_default_value)); - int __property_Int32_default_value = 10; - values.Add(PropertyName.property_Int32, global::Godot.Variant.From<int>(__property_Int32_default_value)); - long __property_Int64_default_value = 10; - values.Add(PropertyName.property_Int64, global::Godot.Variant.From<long>(__property_Int64_default_value)); - byte __property_Byte_default_value = 10; - values.Add(PropertyName.property_Byte, global::Godot.Variant.From<byte>(__property_Byte_default_value)); - ushort __property_UInt16_default_value = 10; - values.Add(PropertyName.property_UInt16, global::Godot.Variant.From<ushort>(__property_UInt16_default_value)); - uint __property_UInt32_default_value = 10; - values.Add(PropertyName.property_UInt32, global::Godot.Variant.From<uint>(__property_UInt32_default_value)); - ulong __property_UInt64_default_value = 10; - values.Add(PropertyName.property_UInt64, global::Godot.Variant.From<ulong>(__property_UInt64_default_value)); - float __property_Single_default_value = 10; - values.Add(PropertyName.property_Single, global::Godot.Variant.From<float>(__property_Single_default_value)); - double __property_Double_default_value = 10; - values.Add(PropertyName.property_Double, global::Godot.Variant.From<double>(__property_Double_default_value)); - string __property_String_default_value = "foo"; - values.Add(PropertyName.property_String, global::Godot.Variant.From<string>(__property_String_default_value)); - global::Godot.Vector2 __property_Vector2_default_value = new(10f, 10f); - values.Add(PropertyName.property_Vector2, global::Godot.Variant.From<global::Godot.Vector2>(__property_Vector2_default_value)); - global::Godot.Vector2I __property_Vector2I_default_value = global::Godot.Vector2I.Up; - values.Add(PropertyName.property_Vector2I, global::Godot.Variant.From<global::Godot.Vector2I>(__property_Vector2I_default_value)); - global::Godot.Rect2 __property_Rect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); - values.Add(PropertyName.property_Rect2, global::Godot.Variant.From<global::Godot.Rect2>(__property_Rect2_default_value)); - global::Godot.Rect2I __property_Rect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); - values.Add(PropertyName.property_Rect2I, global::Godot.Variant.From<global::Godot.Rect2I>(__property_Rect2I_default_value)); - global::Godot.Transform2D __property_Transform2D_default_value = global::Godot.Transform2D.Identity; - values.Add(PropertyName.property_Transform2D, global::Godot.Variant.From<global::Godot.Transform2D>(__property_Transform2D_default_value)); - global::Godot.Vector3 __property_Vector3_default_value = new(10f, 10f, 10f); - values.Add(PropertyName.property_Vector3, global::Godot.Variant.From<global::Godot.Vector3>(__property_Vector3_default_value)); - global::Godot.Vector3I __property_Vector3I_default_value = global::Godot.Vector3I.Back; - values.Add(PropertyName.property_Vector3I, global::Godot.Variant.From<global::Godot.Vector3I>(__property_Vector3I_default_value)); - global::Godot.Basis __property_Basis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); - values.Add(PropertyName.property_Basis, global::Godot.Variant.From<global::Godot.Basis>(__property_Basis_default_value)); - global::Godot.Quaternion __property_Quaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); - values.Add(PropertyName.property_Quaternion, global::Godot.Variant.From<global::Godot.Quaternion>(__property_Quaternion_default_value)); - global::Godot.Transform3D __property_Transform3D_default_value = global::Godot.Transform3D.Identity; - values.Add(PropertyName.property_Transform3D, global::Godot.Variant.From<global::Godot.Transform3D>(__property_Transform3D_default_value)); - global::Godot.Vector4 __property_Vector4_default_value = new(10f, 10f, 10f, 10f); - values.Add(PropertyName.property_Vector4, global::Godot.Variant.From<global::Godot.Vector4>(__property_Vector4_default_value)); - global::Godot.Vector4I __property_Vector4I_default_value = global::Godot.Vector4I.One; - values.Add(PropertyName.property_Vector4I, global::Godot.Variant.From<global::Godot.Vector4I>(__property_Vector4I_default_value)); - global::Godot.Projection __property_Projection_default_value = global::Godot.Projection.Identity; - values.Add(PropertyName.property_Projection, global::Godot.Variant.From<global::Godot.Projection>(__property_Projection_default_value)); - global::Godot.Aabb __property_Aabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); - values.Add(PropertyName.property_Aabb, global::Godot.Variant.From<global::Godot.Aabb>(__property_Aabb_default_value)); - global::Godot.Color __property_Color_default_value = global::Godot.Colors.Aquamarine; - values.Add(PropertyName.property_Color, global::Godot.Variant.From<global::Godot.Color>(__property_Color_default_value)); - global::Godot.Plane __property_Plane_default_value = global::Godot.Plane.PlaneXZ; - values.Add(PropertyName.property_Plane, global::Godot.Variant.From<global::Godot.Plane>(__property_Plane_default_value)); - global::Godot.Callable __property_Callable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); - values.Add(PropertyName.property_Callable, global::Godot.Variant.From<global::Godot.Callable>(__property_Callable_default_value)); - global::Godot.Signal __property_Signal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "property_list_changed"); - values.Add(PropertyName.property_Signal, global::Godot.Variant.From<global::Godot.Signal>(__property_Signal_default_value)); - global::ExportedProperties.MyEnum __property_Enum_default_value = global::ExportedProperties.MyEnum.C; - values.Add(PropertyName.property_Enum, global::Godot.Variant.From<global::ExportedProperties.MyEnum>(__property_Enum_default_value)); - global::ExportedProperties.MyFlagsEnum __property_FlagsEnum_default_value = global::ExportedProperties.MyFlagsEnum.C; - values.Add(PropertyName.property_FlagsEnum, global::Godot.Variant.From<global::ExportedProperties.MyFlagsEnum>(__property_FlagsEnum_default_value)); - byte[] __property_ByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.property_ByteArray, global::Godot.Variant.From<byte[]>(__property_ByteArray_default_value)); - int[] __property_Int32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.property_Int32Array, global::Godot.Variant.From<int[]>(__property_Int32Array_default_value)); - long[] __property_Int64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.property_Int64Array, global::Godot.Variant.From<long[]>(__property_Int64Array_default_value)); - float[] __property_SingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - values.Add(PropertyName.property_SingleArray, global::Godot.Variant.From<float[]>(__property_SingleArray_default_value)); - double[] __property_DoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - values.Add(PropertyName.property_DoubleArray, global::Godot.Variant.From<double[]>(__property_DoubleArray_default_value)); - string[] __property_StringArray_default_value = { "foo", "bar" }; - values.Add(PropertyName.property_StringArray, global::Godot.Variant.From<string[]>(__property_StringArray_default_value)); - string[] __property_StringArrayEnum_default_value = { "foo", "bar" }; - values.Add(PropertyName.property_StringArrayEnum, global::Godot.Variant.From<string[]>(__property_StringArrayEnum_default_value)); - global::Godot.Vector2[] __property_Vector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; - values.Add(PropertyName.property_Vector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(__property_Vector2Array_default_value)); - global::Godot.Vector3[] __property_Vector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; - values.Add(PropertyName.property_Vector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(__property_Vector3Array_default_value)); - global::Godot.Color[] __property_ColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; - values.Add(PropertyName.property_ColorArray, global::Godot.Variant.From<global::Godot.Color[]>(__property_ColorArray_default_value)); - global::Godot.GodotObject[] __property_GodotObjectOrDerivedArray_default_value = { null }; - values.Add(PropertyName.property_GodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(__property_GodotObjectOrDerivedArray_default_value)); + string __NotGenerateComplexLamdaProperty_default_value = default; + values.Add(PropertyName.NotGenerateComplexLamdaProperty, global::Godot.Variant.From<string>(__NotGenerateComplexLamdaProperty_default_value)); + string __NotGenerateLamdaNoFieldProperty_default_value = default; + values.Add(PropertyName.NotGenerateLamdaNoFieldProperty, global::Godot.Variant.From<string>(__NotGenerateLamdaNoFieldProperty_default_value)); + string __NotGenerateComplexReturnProperty_default_value = default; + values.Add(PropertyName.NotGenerateComplexReturnProperty, global::Godot.Variant.From<string>(__NotGenerateComplexReturnProperty_default_value)); + string __NotGenerateReturnsProperty_default_value = default; + values.Add(PropertyName.NotGenerateReturnsProperty, global::Godot.Variant.From<string>(__NotGenerateReturnsProperty_default_value)); + string __FullPropertyString_default_value = "FullPropertyString"; + values.Add(PropertyName.FullPropertyString, global::Godot.Variant.From<string>(__FullPropertyString_default_value)); + string __FullPropertyString_Complex_default_value = new string("FullPropertyString_Complex") + global::System.Convert.ToInt32("1"); + values.Add(PropertyName.FullPropertyString_Complex, global::Godot.Variant.From<string>(__FullPropertyString_Complex_default_value)); + string __LamdaPropertyString_default_value = "LamdaPropertyString"; + values.Add(PropertyName.LamdaPropertyString, global::Godot.Variant.From<string>(__LamdaPropertyString_default_value)); + bool __PropertyBoolean_default_value = true; + values.Add(PropertyName.PropertyBoolean, global::Godot.Variant.From<bool>(__PropertyBoolean_default_value)); + char __PropertyChar_default_value = 'f'; + values.Add(PropertyName.PropertyChar, global::Godot.Variant.From<char>(__PropertyChar_default_value)); + sbyte __PropertySByte_default_value = 10; + values.Add(PropertyName.PropertySByte, global::Godot.Variant.From<sbyte>(__PropertySByte_default_value)); + short __PropertyInt16_default_value = 10; + values.Add(PropertyName.PropertyInt16, global::Godot.Variant.From<short>(__PropertyInt16_default_value)); + int __PropertyInt32_default_value = 10; + values.Add(PropertyName.PropertyInt32, global::Godot.Variant.From<int>(__PropertyInt32_default_value)); + long __PropertyInt64_default_value = 10; + values.Add(PropertyName.PropertyInt64, global::Godot.Variant.From<long>(__PropertyInt64_default_value)); + byte __PropertyByte_default_value = 10; + values.Add(PropertyName.PropertyByte, global::Godot.Variant.From<byte>(__PropertyByte_default_value)); + ushort __PropertyUInt16_default_value = 10; + values.Add(PropertyName.PropertyUInt16, global::Godot.Variant.From<ushort>(__PropertyUInt16_default_value)); + uint __PropertyUInt32_default_value = 10; + values.Add(PropertyName.PropertyUInt32, global::Godot.Variant.From<uint>(__PropertyUInt32_default_value)); + ulong __PropertyUInt64_default_value = 10; + values.Add(PropertyName.PropertyUInt64, global::Godot.Variant.From<ulong>(__PropertyUInt64_default_value)); + float __PropertySingle_default_value = 10; + values.Add(PropertyName.PropertySingle, global::Godot.Variant.From<float>(__PropertySingle_default_value)); + double __PropertyDouble_default_value = 10; + values.Add(PropertyName.PropertyDouble, global::Godot.Variant.From<double>(__PropertyDouble_default_value)); + string __PropertyString_default_value = "foo"; + values.Add(PropertyName.PropertyString, global::Godot.Variant.From<string>(__PropertyString_default_value)); + global::Godot.Vector2 __PropertyVector2_default_value = new(10f, 10f); + values.Add(PropertyName.PropertyVector2, global::Godot.Variant.From<global::Godot.Vector2>(__PropertyVector2_default_value)); + global::Godot.Vector2I __PropertyVector2I_default_value = global::Godot.Vector2I.Up; + values.Add(PropertyName.PropertyVector2I, global::Godot.Variant.From<global::Godot.Vector2I>(__PropertyVector2I_default_value)); + global::Godot.Rect2 __PropertyRect2_default_value = new(new global::Godot.Vector2(10f, 10f), new global::Godot.Vector2(10f, 10f)); + values.Add(PropertyName.PropertyRect2, global::Godot.Variant.From<global::Godot.Rect2>(__PropertyRect2_default_value)); + global::Godot.Rect2I __PropertyRect2I_default_value = new(new global::Godot.Vector2I(10, 10), new global::Godot.Vector2I(10, 10)); + values.Add(PropertyName.PropertyRect2I, global::Godot.Variant.From<global::Godot.Rect2I>(__PropertyRect2I_default_value)); + global::Godot.Transform2D __PropertyTransform2D_default_value = global::Godot.Transform2D.Identity; + values.Add(PropertyName.PropertyTransform2D, global::Godot.Variant.From<global::Godot.Transform2D>(__PropertyTransform2D_default_value)); + global::Godot.Vector3 __PropertyVector3_default_value = new(10f, 10f, 10f); + values.Add(PropertyName.PropertyVector3, global::Godot.Variant.From<global::Godot.Vector3>(__PropertyVector3_default_value)); + global::Godot.Vector3I __PropertyVector3I_default_value = global::Godot.Vector3I.Back; + values.Add(PropertyName.PropertyVector3I, global::Godot.Variant.From<global::Godot.Vector3I>(__PropertyVector3I_default_value)); + global::Godot.Basis __PropertyBasis_default_value = new global::Godot.Basis(global::Godot.Quaternion.Identity); + values.Add(PropertyName.PropertyBasis, global::Godot.Variant.From<global::Godot.Basis>(__PropertyBasis_default_value)); + global::Godot.Quaternion __PropertyQuaternion_default_value = new global::Godot.Quaternion(global::Godot.Basis.Identity); + values.Add(PropertyName.PropertyQuaternion, global::Godot.Variant.From<global::Godot.Quaternion>(__PropertyQuaternion_default_value)); + global::Godot.Transform3D __PropertyTransform3D_default_value = global::Godot.Transform3D.Identity; + values.Add(PropertyName.PropertyTransform3D, global::Godot.Variant.From<global::Godot.Transform3D>(__PropertyTransform3D_default_value)); + global::Godot.Vector4 __PropertyVector4_default_value = new(10f, 10f, 10f, 10f); + values.Add(PropertyName.PropertyVector4, global::Godot.Variant.From<global::Godot.Vector4>(__PropertyVector4_default_value)); + global::Godot.Vector4I __PropertyVector4I_default_value = global::Godot.Vector4I.One; + values.Add(PropertyName.PropertyVector4I, global::Godot.Variant.From<global::Godot.Vector4I>(__PropertyVector4I_default_value)); + global::Godot.Projection __PropertyProjection_default_value = global::Godot.Projection.Identity; + values.Add(PropertyName.PropertyProjection, global::Godot.Variant.From<global::Godot.Projection>(__PropertyProjection_default_value)); + global::Godot.Aabb __PropertyAabb_default_value = new global::Godot.Aabb(10f, 10f, 10f, new global::Godot.Vector3(1f, 1f, 1f)); + values.Add(PropertyName.PropertyAabb, global::Godot.Variant.From<global::Godot.Aabb>(__PropertyAabb_default_value)); + global::Godot.Color __PropertyColor_default_value = global::Godot.Colors.Aquamarine; + values.Add(PropertyName.PropertyColor, global::Godot.Variant.From<global::Godot.Color>(__PropertyColor_default_value)); + global::Godot.Plane __PropertyPlane_default_value = global::Godot.Plane.PlaneXZ; + values.Add(PropertyName.PropertyPlane, global::Godot.Variant.From<global::Godot.Plane>(__PropertyPlane_default_value)); + global::Godot.Callable __PropertyCallable_default_value = new global::Godot.Callable(global::Godot.Engine.GetMainLoop(), "_process"); + values.Add(PropertyName.PropertyCallable, global::Godot.Variant.From<global::Godot.Callable>(__PropertyCallable_default_value)); + global::Godot.Signal __PropertySignal_default_value = new global::Godot.Signal(global::Godot.Engine.GetMainLoop(), "Propertylist_changed"); + values.Add(PropertyName.PropertySignal, global::Godot.Variant.From<global::Godot.Signal>(__PropertySignal_default_value)); + global::ExportedProperties.MyEnum __PropertyEnum_default_value = global::ExportedProperties.MyEnum.C; + values.Add(PropertyName.PropertyEnum, global::Godot.Variant.From<global::ExportedProperties.MyEnum>(__PropertyEnum_default_value)); + global::ExportedProperties.MyFlagsEnum __PropertyFlagsEnum_default_value = global::ExportedProperties.MyFlagsEnum.C; + values.Add(PropertyName.PropertyFlagsEnum, global::Godot.Variant.From<global::ExportedProperties.MyFlagsEnum>(__PropertyFlagsEnum_default_value)); + byte[] __PropertyByteArray_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.PropertyByteArray, global::Godot.Variant.From<byte[]>(__PropertyByteArray_default_value)); + int[] __PropertyInt32Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.PropertyInt32Array, global::Godot.Variant.From<int[]>(__PropertyInt32Array_default_value)); + long[] __PropertyInt64Array_default_value = { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.PropertyInt64Array, global::Godot.Variant.From<long[]>(__PropertyInt64Array_default_value)); + float[] __PropertySingleArray_default_value = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + values.Add(PropertyName.PropertySingleArray, global::Godot.Variant.From<float[]>(__PropertySingleArray_default_value)); + double[] __PropertyDoubleArray_default_value = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + values.Add(PropertyName.PropertyDoubleArray, global::Godot.Variant.From<double[]>(__PropertyDoubleArray_default_value)); + string[] __PropertyStringArray_default_value = { "foo", "bar" }; + values.Add(PropertyName.PropertyStringArray, global::Godot.Variant.From<string[]>(__PropertyStringArray_default_value)); + string[] __PropertyStringArrayEnum_default_value = { "foo", "bar" }; + values.Add(PropertyName.PropertyStringArrayEnum, global::Godot.Variant.From<string[]>(__PropertyStringArrayEnum_default_value)); + global::Godot.Vector2[] __PropertyVector2Array_default_value = { global::Godot.Vector2.Up, global::Godot.Vector2.Down, global::Godot.Vector2.Left, global::Godot.Vector2.Right }; + values.Add(PropertyName.PropertyVector2Array, global::Godot.Variant.From<global::Godot.Vector2[]>(__PropertyVector2Array_default_value)); + global::Godot.Vector3[] __PropertyVector3Array_default_value = { global::Godot.Vector3.Up, global::Godot.Vector3.Down, global::Godot.Vector3.Left, global::Godot.Vector3.Right }; + values.Add(PropertyName.PropertyVector3Array, global::Godot.Variant.From<global::Godot.Vector3[]>(__PropertyVector3Array_default_value)); + global::Godot.Color[] __PropertyColorArray_default_value = { global::Godot.Colors.Aqua, global::Godot.Colors.Aquamarine, global::Godot.Colors.Azure, global::Godot.Colors.Beige }; + values.Add(PropertyName.PropertyColorArray, global::Godot.Variant.From<global::Godot.Color[]>(__PropertyColorArray_default_value)); + global::Godot.GodotObject[] __PropertyGodotObjectOrDerivedArray_default_value = { null }; + values.Add(PropertyName.PropertyGodotObjectOrDerivedArray, global::Godot.Variant.CreateFrom(__PropertyGodotObjectOrDerivedArray_default_value)); global::Godot.StringName[] __field_StringNameArray_default_value = { "foo", "bar" }; values.Add(PropertyName.field_StringNameArray, global::Godot.Variant.From<global::Godot.StringName[]>(__field_StringNameArray_default_value)); global::Godot.NodePath[] __field_NodePathArray_default_value = { "foo", "bar" }; values.Add(PropertyName.field_NodePathArray, global::Godot.Variant.From<global::Godot.NodePath[]>(__field_NodePathArray_default_value)); global::Godot.Rid[] __field_RidArray_default_value = { default, default, default }; values.Add(PropertyName.field_RidArray, global::Godot.Variant.From<global::Godot.Rid[]>(__field_RidArray_default_value)); - global::Godot.Variant __property_Variant_default_value = "foo"; - values.Add(PropertyName.property_Variant, global::Godot.Variant.From<global::Godot.Variant>(__property_Variant_default_value)); - global::Godot.GodotObject __property_GodotObjectOrDerived_default_value = default; - values.Add(PropertyName.property_GodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(__property_GodotObjectOrDerived_default_value)); - global::Godot.Texture __property_GodotResourceTexture_default_value = default; - values.Add(PropertyName.property_GodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(__property_GodotResourceTexture_default_value)); - global::Godot.StringName __property_StringName_default_value = new global::Godot.StringName("foo"); - values.Add(PropertyName.property_StringName, global::Godot.Variant.From<global::Godot.StringName>(__property_StringName_default_value)); - global::Godot.NodePath __property_NodePath_default_value = new global::Godot.NodePath("foo"); - values.Add(PropertyName.property_NodePath, global::Godot.Variant.From<global::Godot.NodePath>(__property_NodePath_default_value)); - global::Godot.Rid __property_Rid_default_value = default; - values.Add(PropertyName.property_Rid, global::Godot.Variant.From<global::Godot.Rid>(__property_Rid_default_value)); - global::Godot.Collections.Dictionary __property_GodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; - values.Add(PropertyName.property_GodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(__property_GodotDictionary_default_value)); - global::Godot.Collections.Array __property_GodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; - values.Add(PropertyName.property_GodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(__property_GodotArray_default_value)); - global::Godot.Collections.Dictionary<string, bool> __property_GodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; - values.Add(PropertyName.property_GodotGenericDictionary, global::Godot.Variant.CreateFrom(__property_GodotGenericDictionary_default_value)); - global::Godot.Collections.Array<int> __property_GodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; - values.Add(PropertyName.property_GodotGenericArray, global::Godot.Variant.CreateFrom(__property_GodotGenericArray_default_value)); + global::Godot.Variant __PropertyVariant_default_value = "foo"; + values.Add(PropertyName.PropertyVariant, global::Godot.Variant.From<global::Godot.Variant>(__PropertyVariant_default_value)); + global::Godot.GodotObject __PropertyGodotObjectOrDerived_default_value = default; + values.Add(PropertyName.PropertyGodotObjectOrDerived, global::Godot.Variant.From<global::Godot.GodotObject>(__PropertyGodotObjectOrDerived_default_value)); + global::Godot.Texture __PropertyGodotResourceTexture_default_value = default; + values.Add(PropertyName.PropertyGodotResourceTexture, global::Godot.Variant.From<global::Godot.Texture>(__PropertyGodotResourceTexture_default_value)); + global::Godot.StringName __PropertyStringName_default_value = new global::Godot.StringName("foo"); + values.Add(PropertyName.PropertyStringName, global::Godot.Variant.From<global::Godot.StringName>(__PropertyStringName_default_value)); + global::Godot.NodePath __PropertyNodePath_default_value = new global::Godot.NodePath("foo"); + values.Add(PropertyName.PropertyNodePath, global::Godot.Variant.From<global::Godot.NodePath>(__PropertyNodePath_default_value)); + global::Godot.Rid __PropertyRid_default_value = default; + values.Add(PropertyName.PropertyRid, global::Godot.Variant.From<global::Godot.Rid>(__PropertyRid_default_value)); + global::Godot.Collections.Dictionary __PropertyGodotDictionary_default_value = new() { { "foo", 10 }, { global::Godot.Vector2.Up, global::Godot.Colors.Chocolate } }; + values.Add(PropertyName.PropertyGodotDictionary, global::Godot.Variant.From<global::Godot.Collections.Dictionary>(__PropertyGodotDictionary_default_value)); + global::Godot.Collections.Array __PropertyGodotArray_default_value = new() { "foo", 10, global::Godot.Vector2.Up, global::Godot.Colors.Chocolate }; + values.Add(PropertyName.PropertyGodotArray, global::Godot.Variant.From<global::Godot.Collections.Array>(__PropertyGodotArray_default_value)); + global::Godot.Collections.Dictionary<string, bool> __PropertyGodotGenericDictionary_default_value = new() { { "foo", true }, { "bar", false } }; + values.Add(PropertyName.PropertyGodotGenericDictionary, global::Godot.Variant.CreateFrom(__PropertyGodotGenericDictionary_default_value)); + global::Godot.Collections.Array<int> __PropertyGodotGenericArray_default_value = new() { 0, 1, 2, 3, 4, 5, 6 }; + values.Add(PropertyName.PropertyGodotGenericArray, global::Godot.Variant.CreateFrom(__PropertyGodotGenericArray_default_value)); return values; } #endif // TOOLS diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs index f812457aa5..91f808f55e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/MixedReadOnlyWriteOnly_ScriptProperties.generated.cs @@ -9,40 +9,40 @@ partial class MixedReadOnlyWriteOnly /// </summary> public new class PropertyName : global::Godot.GodotObject.PropertyName { /// <summary> - /// Cached name for the 'readonly_auto_property' property. + /// Cached name for the 'ReadOnlyAutoProperty' property. /// </summary> - public new static readonly global::Godot.StringName readonly_auto_property = "readonly_auto_property"; + public new static readonly global::Godot.StringName ReadOnlyAutoProperty = "ReadOnlyAutoProperty"; /// <summary> - /// Cached name for the 'readonly_property' property. + /// Cached name for the 'ReadOnlyProperty' property. /// </summary> - public new static readonly global::Godot.StringName readonly_property = "readonly_property"; + public new static readonly global::Godot.StringName ReadOnlyProperty = "ReadOnlyProperty"; /// <summary> - /// Cached name for the 'initonly_auto_property' property. + /// Cached name for the 'InitOnlyAutoProperty' property. /// </summary> - public new static readonly global::Godot.StringName initonly_auto_property = "initonly_auto_property"; + public new static readonly global::Godot.StringName InitOnlyAutoProperty = "InitOnlyAutoProperty"; /// <summary> - /// Cached name for the 'writeonly_property' property. + /// Cached name for the 'WriteOnlyProperty' property. /// </summary> - public new static readonly global::Godot.StringName writeonly_property = "writeonly_property"; + public new static readonly global::Godot.StringName WriteOnlyProperty = "WriteOnlyProperty"; /// <summary> - /// Cached name for the 'readonly_field' field. + /// Cached name for the 'ReadOnlyField' field. /// </summary> - public new static readonly global::Godot.StringName readonly_field = "readonly_field"; + public new static readonly global::Godot.StringName ReadOnlyField = "ReadOnlyField"; /// <summary> - /// Cached name for the 'writeonly_backing_field' field. + /// Cached name for the '_writeOnlyBackingField' field. /// </summary> - public new static readonly global::Godot.StringName writeonly_backing_field = "writeonly_backing_field"; + public new static readonly global::Godot.StringName _writeOnlyBackingField = "_writeOnlyBackingField"; } /// <inheritdoc/> [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value) { - if (name == PropertyName.writeonly_property) { - this.writeonly_property = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + if (name == PropertyName.WriteOnlyProperty) { + this.WriteOnlyProperty = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } - else if (name == PropertyName.writeonly_backing_field) { - this.writeonly_backing_field = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); + else if (name == PropertyName._writeOnlyBackingField) { + this._writeOnlyBackingField = global::Godot.NativeInterop.VariantUtils.ConvertTo<bool>(value); return true; } return base.SetGodotClassPropertyValue(name, value); @@ -51,24 +51,24 @@ partial class MixedReadOnlyWriteOnly [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value) { - if (name == PropertyName.readonly_auto_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_auto_property); + if (name == PropertyName.ReadOnlyAutoProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyAutoProperty); return true; } - else if (name == PropertyName.readonly_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_property); + else if (name == PropertyName.ReadOnlyProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyProperty); return true; } - else if (name == PropertyName.initonly_auto_property) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.initonly_auto_property); + else if (name == PropertyName.InitOnlyAutoProperty) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.InitOnlyAutoProperty); return true; } - else if (name == PropertyName.readonly_field) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.readonly_field); + else if (name == PropertyName.ReadOnlyField) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.ReadOnlyField); return true; } - else if (name == PropertyName.writeonly_backing_field) { - value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this.writeonly_backing_field); + else if (name == PropertyName._writeOnlyBackingField) { + value = global::Godot.NativeInterop.VariantUtils.CreateFrom<bool>(this._writeOnlyBackingField); return true; } return base.GetGodotClassPropertyValue(name, out value); @@ -82,12 +82,12 @@ partial class MixedReadOnlyWriteOnly internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList() { var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>(); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.readonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.initonly_auto_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_backing_field, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); - properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.writeonly_property, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyField, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyAutoProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.ReadOnlyProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)4, name: PropertyName.InitOnlyAutoProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName._writeOnlyBackingField, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); + properties.Add(new(type: (global::Godot.Variant.Type)1, name: PropertyName.WriteOnlyProperty, hint: (global::Godot.PropertyHint)0, hintString: "", usage: (global::Godot.PropertyUsageFlags)4096, exported: false)); return properties; } #pragma warning restore CS0109 diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs index 94c2bda363..2586db1137 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllReadOnly.cs @@ -2,8 +2,8 @@ using Godot; public partial class AllReadOnly : GodotObject { - public readonly string readonly_field = "foo"; - public string readonly_auto_property { get; } = "foo"; - public string readonly_property { get => "foo"; } - public string initonly_auto_property { get; init; } + public readonly string ReadOnlyField = "foo"; + public string ReadOnlyAutoProperty { get; } = "foo"; + public string ReadOnlyProperty { get => "foo"; } + public string InitOnlyAutoProperty { get; init; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs index 156d6bb6a5..e2ebff4876 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/AllWriteOnly.cs @@ -2,6 +2,6 @@ using Godot; public partial class AllWriteOnly : GodotObject { - bool writeonly_backing_field = false; - public bool writeonly_property { set => writeonly_backing_field = value; } + private bool _writeOnlyBackingField = false; + public bool WriteOnlyProperty { set => _writeOnlyBackingField = value; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs index dfe2217c26..d364e40bf0 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Bar.cs @@ -1,14 +1,14 @@ using Godot; -partial class Bar : GodotObject +public partial class Bar : GodotObject { } // Foo in another file -partial class Foo +public partial class Foo { } -partial class NotSameNameAsFile : GodotObject +public partial class NotSameNameAsFile : GodotObject { } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs index 09d654ffcb..0938d10afe 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedFields.cs @@ -4,99 +4,99 @@ using System.Collections.Generic; public partial class ExportedFields : GodotObject { - [Export] private Boolean field_Boolean = true; - [Export] private Char field_Char = 'f'; - [Export] private SByte field_SByte = 10; - [Export] private Int16 field_Int16 = 10; - [Export] private Int32 field_Int32 = 10; - [Export] private Int64 field_Int64 = 10; - [Export] private Byte field_Byte = 10; - [Export] private UInt16 field_UInt16 = 10; - [Export] private UInt32 field_UInt32 = 10; - [Export] private UInt64 field_UInt64 = 10; - [Export] private Single field_Single = 10; - [Export] private Double field_Double = 10; - [Export] private String field_String = "foo"; + [Export] private Boolean _fieldBoolean = true; + [Export] private Char _fieldChar = 'f'; + [Export] private SByte _fieldSByte = 10; + [Export] private Int16 _fieldInt16 = 10; + [Export] private Int32 _fieldInt32 = 10; + [Export] private Int64 _fieldInt64 = 10; + [Export] private Byte _fieldByte = 10; + [Export] private UInt16 _fieldUInt16 = 10; + [Export] private UInt32 _fieldUInt32 = 10; + [Export] private UInt64 _fieldUInt64 = 10; + [Export] private Single _fieldSingle = 10; + [Export] private Double _fieldDouble = 10; + [Export] private String _fieldString = "foo"; // Godot structs - [Export] private Vector2 field_Vector2 = new(10f, 10f); - [Export] private Vector2I field_Vector2I = Vector2I.Up; - [Export] private Rect2 field_Rect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); - [Export] private Rect2I field_Rect2I = new(new Vector2I(10, 10), new Vector2I(10, 10)); - [Export] private Transform2D field_Transform2D = Transform2D.Identity; - [Export] private Vector3 field_Vector3 = new(10f, 10f, 10f); - [Export] private Vector3I field_Vector3I = Vector3I.Back; - [Export] private Basis field_Basis = new Basis(Quaternion.Identity); - [Export] private Quaternion field_Quaternion = new Quaternion(Basis.Identity); - [Export] private Transform3D field_Transform3D = Transform3D.Identity; - [Export] private Vector4 field_Vector4 = new(10f, 10f, 10f, 10f); - [Export] private Vector4I field_Vector4I = Vector4I.One; - [Export] private Projection field_Projection = Projection.Identity; - [Export] private Aabb field_Aabb = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); - [Export] private Color field_Color = Colors.Aquamarine; - [Export] private Plane field_Plane = Plane.PlaneXZ; - [Export] private Callable field_Callable = new Callable(Engine.GetMainLoop(), "_process"); - [Export] private Signal field_Signal = new Signal(Engine.GetMainLoop(), "property_list_changed"); + [Export] private Vector2 _fieldVector2 = new(10f, 10f); + [Export] private Vector2I _fieldVector2I = Vector2I.Up; + [Export] private Rect2 _fieldRect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I _fieldRect2I = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D _fieldTransform2D = Transform2D.Identity; + [Export] private Vector3 _fieldVector3 = new(10f, 10f, 10f); + [Export] private Vector3I _fieldVector3I = Vector3I.Back; + [Export] private Basis _fieldBasis = new Basis(Quaternion.Identity); + [Export] private Quaternion _fieldQuaternion = new Quaternion(Basis.Identity); + [Export] private Transform3D _fieldTransform3D = Transform3D.Identity; + [Export] private Vector4 _fieldVector4 = new(10f, 10f, 10f, 10f); + [Export] private Vector4I _fieldVector4I = Vector4I.One; + [Export] private Projection _fieldProjection = Projection.Identity; + [Export] private Aabb _fieldAabb = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color _fieldColor = Colors.Aquamarine; + [Export] private Plane _fieldPlane = Plane.PlaneXZ; + [Export] private Callable _fieldCallable = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal _fieldSignal = new Signal(Engine.GetMainLoop(), "property_list_changed"); // Enums - enum MyEnum + public enum MyEnum { A, B, C } - [Export] private MyEnum field_Enum = MyEnum.C; + [Export] private MyEnum _fieldEnum = MyEnum.C; [Flags] - enum MyFlagsEnum + public enum MyFlagsEnum { A, B, C } - [Export] private MyFlagsEnum field_FlagsEnum = MyFlagsEnum.C; + [Export] private MyFlagsEnum _fieldFlagsEnum = MyFlagsEnum.C; // Arrays - [Export] private Byte[] field_ByteArray = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int32[] field_Int32Array = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int64[] field_Int64Array = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Single[] field_SingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - [Export] private Double[] field_DoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - [Export] private String[] field_StringArray = { "foo", "bar" }; - [Export(PropertyHint.Enum, "A,B,C")] private String[] field_StringArrayEnum = { "foo", "bar" }; - [Export] private Vector2[] field_Vector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; - [Export] private Vector3[] field_Vector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; - [Export] private Color[] field_ColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; - [Export] private GodotObject[] field_GodotObjectOrDerivedArray = { null }; - [Export] private StringName[] field_StringNameArray = { "foo", "bar" }; - [Export] private NodePath[] field_NodePathArray = { "foo", "bar" }; - [Export] private Rid[] field_RidArray = { default, default, default }; + [Export] private Byte[] _fieldByteArray = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] _fieldInt32Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] _fieldInt64Array = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] _fieldSingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] _fieldDoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] _fieldStringArray = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] _fieldStringArrayEnum = { "foo", "bar" }; + [Export] private Vector2[] _fieldVector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] _fieldVector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] _fieldColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] _fieldGodotObjectOrDerivedArray = { null }; + [Export] private StringName[] _fieldStringNameArray = { "foo", "bar" }; + [Export] private NodePath[] _fieldNodePathArray = { "foo", "bar" }; + [Export] private Rid[] _fieldRidArray = { default, default, default }; // Note we use Array and not System.Array. This tests the generated namespace qualification. - [Export] private Int32[] field_empty_Int32Array = Array.Empty<Int32>(); + [Export] private Int32[] _fieldEmptyInt32Array = Array.Empty<Int32>(); // Note we use List and not System.Collections.Generic. - [Export] private int[] field_array_from_list = new List<int>(Array.Empty<int>()).ToArray(); + [Export] private int[] _fieldArrayFromList = new List<int>(Array.Empty<int>()).ToArray(); // Variant - [Export] private Variant field_Variant = "foo"; + [Export] private Variant _fieldVariant = "foo"; // Classes - [Export] private GodotObject field_GodotObjectOrDerived; - [Export] private Godot.Texture field_GodotResourceTexture; - [Export] private StringName field_StringName = new StringName("foo"); - [Export] private NodePath field_NodePath = new NodePath("foo"); - [Export] private Rid field_Rid; + [Export] private GodotObject _fieldGodotObjectOrDerived; + [Export] private Godot.Texture _fieldGodotResourceTexture; + [Export] private StringName _fieldStringName = new StringName("foo"); + [Export] private NodePath _fieldNodePath = new NodePath("foo"); + [Export] private Rid _fieldRid; [Export] - private Godot.Collections.Dictionary field_GodotDictionary = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; + private Godot.Collections.Dictionary _fieldGodotDictionary = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; [Export] - private Godot.Collections.Array field_GodotArray = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; + private Godot.Collections.Array _fieldGodotArray = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; [Export] - private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary = new() { { "foo", true }, { "bar", false } }; + private Godot.Collections.Dictionary<string, bool> _fieldGodotGenericDictionary = new() { { "foo", true }, { "bar", false } }; [Export] - private Godot.Collections.Array<int> field_GodotGenericArray = new() { 0, 1, 2, 3, 4, 5, 6 }; + private Godot.Collections.Array<int> _fieldGodotGenericArray = new() { 0, 1, 2, 3, 4, 5, 6 }; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs index 3783838dae..9ae23066fc 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedProperties.cs @@ -4,41 +4,41 @@ using System; public partial class ExportedProperties : GodotObject { // Do not generate default value - private String _notGenerate_Property_String = new string("not generate"); + private String _notGeneratePropertyString = new string("not generate"); [Export] - public String NotGenerate_Complex_Lamda_Property + public String NotGenerateComplexLamdaProperty { - get => _notGenerate_Property_String + Convert.ToInt32("1"); - set => _notGenerate_Property_String = value; + get => _notGeneratePropertyString + Convert.ToInt32("1"); + set => _notGeneratePropertyString = value; } [Export] - public String NotGenerate_Lamda_NoField_Property + public String NotGenerateLamdaNoFieldProperty { get => new string("not generate"); - set => _notGenerate_Property_String = value; + set => _notGeneratePropertyString = value; } [Export] - public String NotGenerate_Complex_Return_Property + public String NotGenerateComplexReturnProperty { get { - return _notGenerate_Property_String + Convert.ToInt32("1"); + return _notGeneratePropertyString + Convert.ToInt32("1"); } set { - _notGenerate_Property_String = value; + _notGeneratePropertyString = value; } } - private int _notGenerate_Property_Int = 1; + private int _notGeneratePropertyInt = 1; [Export] - public string NotGenerate_Returns_Property + public string NotGenerateReturnsProperty { get { - if (_notGenerate_Property_Int == 1) + if (_notGeneratePropertyInt == 1) { return "a"; } @@ -49,138 +49,138 @@ public partial class ExportedProperties : GodotObject } set { - _notGenerate_Property_Int = value == "a" ? 1 : 2; + _notGeneratePropertyInt = value == "a" ? 1 : 2; } } // Full Property - private String _fullProperty_String = "FullProperty_String"; + private String _fullPropertyString = "FullPropertyString"; [Export] - public String FullProperty_String + public String FullPropertyString { get { - return _fullProperty_String; + return _fullPropertyString; } set { - _fullProperty_String = value; + _fullPropertyString = value; } } - private String _fullProperty_String_Complex = new string("FullProperty_String_Complex") + Convert.ToInt32("1"); + private String _fullPropertyStringComplex = new string("FullPropertyString_Complex") + Convert.ToInt32("1"); [Export] - public String FullProperty_String_Complex + public String FullPropertyString_Complex { get { - return _fullProperty_String_Complex; + return _fullPropertyStringComplex; } set { - _fullProperty_String_Complex = value; + _fullPropertyStringComplex = value; } } // Lambda Property - private String _lamdaProperty_String = "LamdaProperty_String"; + private String _lamdaPropertyString = "LamdaPropertyString"; [Export] - public String LamdaProperty_String + public String LamdaPropertyString { - get => _lamdaProperty_String; - set => _lamdaProperty_String = value; + get => _lamdaPropertyString; + set => _lamdaPropertyString = value; } // Auto Property - [Export] private Boolean property_Boolean { get; set; } = true; - [Export] private Char property_Char { get; set; } = 'f'; - [Export] private SByte property_SByte { get; set; } = 10; - [Export] private Int16 property_Int16 { get; set; } = 10; - [Export] private Int32 property_Int32 { get; set; } = 10; - [Export] private Int64 property_Int64 { get; set; } = 10; - [Export] private Byte property_Byte { get; set; } = 10; - [Export] private UInt16 property_UInt16 { get; set; } = 10; - [Export] private UInt32 property_UInt32 { get; set; } = 10; - [Export] private UInt64 property_UInt64 { get; set; } = 10; - [Export] private Single property_Single { get; set; } = 10; - [Export] private Double property_Double { get; set; } = 10; - [Export] private String property_String { get; set; } = "foo"; + [Export] private Boolean PropertyBoolean { get; set; } = true; + [Export] private Char PropertyChar { get; set; } = 'f'; + [Export] private SByte PropertySByte { get; set; } = 10; + [Export] private Int16 PropertyInt16 { get; set; } = 10; + [Export] private Int32 PropertyInt32 { get; set; } = 10; + [Export] private Int64 PropertyInt64 { get; set; } = 10; + [Export] private Byte PropertyByte { get; set; } = 10; + [Export] private UInt16 PropertyUInt16 { get; set; } = 10; + [Export] private UInt32 PropertyUInt32 { get; set; } = 10; + [Export] private UInt64 PropertyUInt64 { get; set; } = 10; + [Export] private Single PropertySingle { get; set; } = 10; + [Export] private Double PropertyDouble { get; set; } = 10; + [Export] private String PropertyString { get; set; } = "foo"; // Godot structs - [Export] private Vector2 property_Vector2 { get; set; } = new(10f, 10f); - [Export] private Vector2I property_Vector2I { get; set; } = Vector2I.Up; - [Export] private Rect2 property_Rect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); - [Export] private Rect2I property_Rect2I { get; set; } = new(new Vector2I(10, 10), new Vector2I(10, 10)); - [Export] private Transform2D property_Transform2D { get; set; } = Transform2D.Identity; - [Export] private Vector3 property_Vector3 { get; set; } = new(10f, 10f, 10f); - [Export] private Vector3I property_Vector3I { get; set; } = Vector3I.Back; - [Export] private Basis property_Basis { get; set; } = new Basis(Quaternion.Identity); - [Export] private Quaternion property_Quaternion { get; set; } = new Quaternion(Basis.Identity); - [Export] private Transform3D property_Transform3D { get; set; } = Transform3D.Identity; - [Export] private Vector4 property_Vector4 { get; set; } = new(10f, 10f, 10f, 10f); - [Export] private Vector4I property_Vector4I { get; set; } = Vector4I.One; - [Export] private Projection property_Projection { get; set; } = Projection.Identity; - [Export] private Aabb property_Aabb { get; set; } = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); - [Export] private Color property_Color { get; set; } = Colors.Aquamarine; - [Export] private Plane property_Plane { get; set; } = Plane.PlaneXZ; - [Export] private Callable property_Callable { get; set; } = new Callable(Engine.GetMainLoop(), "_process"); - [Export] private Signal property_Signal { get; set; } = new Signal(Engine.GetMainLoop(), "property_list_changed"); + [Export] private Vector2 PropertyVector2 { get; set; } = new(10f, 10f); + [Export] private Vector2I PropertyVector2I { get; set; } = Vector2I.Up; + [Export] private Rect2 PropertyRect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f)); + [Export] private Rect2I PropertyRect2I { get; set; } = new(new Vector2I(10, 10), new Vector2I(10, 10)); + [Export] private Transform2D PropertyTransform2D { get; set; } = Transform2D.Identity; + [Export] private Vector3 PropertyVector3 { get; set; } = new(10f, 10f, 10f); + [Export] private Vector3I PropertyVector3I { get; set; } = Vector3I.Back; + [Export] private Basis PropertyBasis { get; set; } = new Basis(Quaternion.Identity); + [Export] private Quaternion PropertyQuaternion { get; set; } = new Quaternion(Basis.Identity); + [Export] private Transform3D PropertyTransform3D { get; set; } = Transform3D.Identity; + [Export] private Vector4 PropertyVector4 { get; set; } = new(10f, 10f, 10f, 10f); + [Export] private Vector4I PropertyVector4I { get; set; } = Vector4I.One; + [Export] private Projection PropertyProjection { get; set; } = Projection.Identity; + [Export] private Aabb PropertyAabb { get; set; } = new Aabb(10f, 10f, 10f, new Vector3(1f, 1f, 1f)); + [Export] private Color PropertyColor { get; set; } = Colors.Aquamarine; + [Export] private Plane PropertyPlane { get; set; } = Plane.PlaneXZ; + [Export] private Callable PropertyCallable { get; set; } = new Callable(Engine.GetMainLoop(), "_process"); + [Export] private Signal PropertySignal { get; set; } = new Signal(Engine.GetMainLoop(), "Propertylist_changed"); // Enums - enum MyEnum + public enum MyEnum { A, B, C } - [Export] private MyEnum property_Enum { get; set; } = MyEnum.C; + [Export] private MyEnum PropertyEnum { get; set; } = MyEnum.C; [Flags] - enum MyFlagsEnum + public enum MyFlagsEnum { A, B, C } - [Export] private MyFlagsEnum property_FlagsEnum { get; set; } = MyFlagsEnum.C; + [Export] private MyFlagsEnum PropertyFlagsEnum { get; set; } = MyFlagsEnum.C; // Arrays - [Export] private Byte[] property_ByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int32[] property_Int32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Int64[] property_Int64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; - [Export] private Single[] property_SingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; - [Export] private Double[] property_DoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; - [Export] private String[] property_StringArray { get; set; } = { "foo", "bar" }; - [Export(PropertyHint.Enum, "A,B,C")] private String[] property_StringArrayEnum { get; set; } = { "foo", "bar" }; - [Export] private Vector2[] property_Vector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; - [Export] private Vector3[] property_Vector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; - [Export] private Color[] property_ColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; - [Export] private GodotObject[] property_GodotObjectOrDerivedArray { get; set; } = { null }; + [Export] private Byte[] PropertyByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int32[] PropertyInt32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Int64[] PropertyInt64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 }; + [Export] private Single[] PropertySingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f }; + [Export] private Double[] PropertyDoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d }; + [Export] private String[] PropertyStringArray { get; set; } = { "foo", "bar" }; + [Export(PropertyHint.Enum, "A,B,C")] private String[] PropertyStringArrayEnum { get; set; } = { "foo", "bar" }; + [Export] private Vector2[] PropertyVector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right }; + [Export] private Vector3[] PropertyVector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right }; + [Export] private Color[] PropertyColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige }; + [Export] private GodotObject[] PropertyGodotObjectOrDerivedArray { get; set; } = { null }; [Export] private StringName[] field_StringNameArray { get; set; } = { "foo", "bar" }; [Export] private NodePath[] field_NodePathArray { get; set; } = { "foo", "bar" }; [Export] private Rid[] field_RidArray { get; set; } = { default, default, default }; // Variant - [Export] private Variant property_Variant { get; set; } = "foo"; + [Export] private Variant PropertyVariant { get; set; } = "foo"; // Classes - [Export] private GodotObject property_GodotObjectOrDerived { get; set; } - [Export] private Godot.Texture property_GodotResourceTexture { get; set; } - [Export] private StringName property_StringName { get; set; } = new StringName("foo"); - [Export] private NodePath property_NodePath { get; set; } = new NodePath("foo"); - [Export] private Rid property_Rid { get; set; } + [Export] private GodotObject PropertyGodotObjectOrDerived { get; set; } + [Export] private Godot.Texture PropertyGodotResourceTexture { get; set; } + [Export] private StringName PropertyStringName { get; set; } = new StringName("foo"); + [Export] private NodePath PropertyNodePath { get; set; } = new NodePath("foo"); + [Export] private Rid PropertyRid { get; set; } [Export] - private Godot.Collections.Dictionary property_GodotDictionary { get; set; } = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; + private Godot.Collections.Dictionary PropertyGodotDictionary { get; set; } = new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } }; [Export] - private Godot.Collections.Array property_GodotArray { get; set; } = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; + private Godot.Collections.Array PropertyGodotArray { get; set; } = new() { "foo", 10, Vector2.Up, Colors.Chocolate }; [Export] - private Godot.Collections.Dictionary<string, bool> property_GodotGenericDictionary { get; set; } = new() { { "foo", true }, { "bar", false } }; + private Godot.Collections.Dictionary<string, bool> PropertyGodotGenericDictionary { get; set; } = new() { { "foo", true }, { "bar", false } }; [Export] - private Godot.Collections.Array<int> property_GodotGenericArray { get; set; } = new() { 0, 1, 2, 3, 4, 5, 6 }; + private Godot.Collections.Array<int> PropertyGodotGenericArray { get; set; } = new() { 0, 1, 2, 3, 4, 5, 6 }; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs index 26853553c7..53801990d3 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Foo.cs @@ -1,10 +1,10 @@ using Godot; -partial class Foo : GodotObject +public partial class Foo : GodotObject { } // Foo again in the same file -partial class Foo +public partial class Foo { } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs index 15c1e03801..83e9094a25 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs @@ -1,18 +1,18 @@ using Godot; -partial class Generic<T> : GodotObject +public partial class Generic<T> : GodotObject { private int _field; } // Generic again but different generic parameters -partial class {|GD0003:Generic|}<T, R> : GodotObject +public partial class {|GD0003:Generic|}<T, R> : GodotObject { private int _field; } // Generic again but without generic parameters -partial class {|GD0003:Generic|} : GodotObject +public partial class {|GD0003:Generic|} : GodotObject { private int _field; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs index 5a83e21e96..ce8a7fe218 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs @@ -1,6 +1,6 @@ using Godot; -partial class Generic<T> : GodotObject +public partial class Generic<T> : GodotObject { private int _field; } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs index 61a48cefc9..190a3fb256 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MixedReadOnlyWriteOnly.cs @@ -2,11 +2,11 @@ using Godot; public partial class MixedReadOnlyWriteOnly : GodotObject { - public readonly string readonly_field = "foo"; - public string readonly_auto_property { get; } = "foo"; - public string readonly_property { get => "foo"; } - public string initonly_auto_property { get; init; } + public readonly string ReadOnlyField = "foo"; + public string ReadOnlyAutoProperty { get; } = "foo"; + public string ReadOnlyProperty { get => "foo"; } + public string InitOnlyAutoProperty { get; init; } - bool writeonly_backing_field = false; - public bool writeonly_property { set => writeonly_backing_field = value; } + bool _writeOnlyBackingField = false; + public bool WriteOnlyProperty { set => _writeOnlyBackingField = value; } } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs index 47063a9cdf..0cf462f799 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MoreExportedFields.cs @@ -4,5 +4,5 @@ using System; public partial class ExportedFields : GodotObject { // Note we use Array and not System.Array. This tests the generated namespace qualification. - [Export] private Int64[] field_empty_Int64Array = Array.Empty<Int64>(); + [Export] private Int64[] _fieldEmptyInt64Array = Array.Empty<Int64>(); } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs index 5506465b92..b431522e7c 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ScriptBoilerplate.cs @@ -24,7 +24,7 @@ public partial class ScriptBoilerplate : Node } } -partial struct OuterClass +public partial struct OuterClass { public partial class NestedClass : RefCounted { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs index 35db0d6f10..9784bd0b78 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Godot.SourceGenerators { - static class ExtensionMethods + internal static class ExtensionMethods { public static bool TryGetGlobalAnalyzerProperty( this GeneratorExecutionContext context, string property, out string? value diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs index 77530ea049..22af25b9c4 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GlobalClassAnalyzer.cs @@ -1,9 +1,7 @@ using System.Collections.Immutable; using System.Linq; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace Godot.SourceGenerators @@ -23,10 +21,8 @@ namespace Godot.SourceGenerators context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration); } - private void AnalyzeNode(SyntaxNodeAnalysisContext context) + private static void AnalyzeNode(SyntaxNodeAnalysisContext context) { - var typeClassDecl = (ClassDeclarationSyntax)context.Node; - // Return if not a type symbol or the type is not a global class. if (context.ContainingSymbol is not INamedTypeSymbol typeSymbol || !typeSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotGlobalClassAttribute() ?? false)) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index f837dcd810..f314f7dada 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -171,7 +171,7 @@ namespace Godot.SourceGenerators if (godotClassMethods.Length > 0) { - const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>"; + const string ListType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>"; source.Append(" /// <summary>\n") .Append(" /// Get the method information for all the methods declared in this class.\n") @@ -182,11 +182,11 @@ namespace Godot.SourceGenerators source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); source.Append(" internal new static ") - .Append(listType) + .Append(ListType) .Append(" GetGodotMethodList()\n {\n"); source.Append(" var methods = new ") - .Append(listType) + .Append(ListType) .Append("(") .Append(godotClassMethods.Length) .Append(");\n"); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index ecd208e38e..a0e410e31a 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -246,7 +246,7 @@ namespace Godot.SourceGenerators } // Generate GetGodotPropertyList - const string dictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>"; + const string DictionaryType = "global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>"; source.Append(" /// <summary>\n") .Append(" /// Get the property information for all the properties declared in this class.\n") @@ -257,11 +257,11 @@ namespace Godot.SourceGenerators source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); source.Append(" internal new static ") - .Append(dictionaryType) + .Append(DictionaryType) .Append(" GetGodotPropertyList()\n {\n"); source.Append(" var properties = new ") - .Append(dictionaryType) + .Append(DictionaryType) .Append("();\n"); // To retain the definition order (and display categories correctly), we want to diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index 0ec0a0827c..d13a828875 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -351,7 +351,7 @@ namespace Godot.SourceGenerators { source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n"); - const string dictionaryType = + const string DictionaryType = "global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>"; source.Append("#if TOOLS\n"); @@ -366,11 +366,11 @@ namespace Godot.SourceGenerators source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); source.Append(" internal new static "); - source.Append(dictionaryType); + source.Append(DictionaryType); source.Append(" GetGodotPropertyDefaultValues()\n {\n"); source.Append(" var values = new "); - source.Append(dictionaryType); + source.Append(DictionaryType); source.Append("("); source.Append(exportedMembers.Count); source.Append(");\n"); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index ff8422ea09..107bd93faa 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -225,7 +225,7 @@ namespace Godot.SourceGenerators if (godotSignalDelegates.Count > 0) { - const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>"; + const string ListType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>"; source.Append(" /// <summary>\n") .Append(" /// Get the signal information for all the signals declared in this class.\n") @@ -236,11 +236,11 @@ namespace Godot.SourceGenerators source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); source.Append(" internal new static ") - .Append(listType) + .Append(ListType) .Append(" GetGodotSignalList()\n {\n"); source.Append(" var signals = new ") - .Append(listType) + .Append(ListType) .Append("(") .Append(godotSignalDelegates.Count) .Append(");\n"); diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs index 3072ca2857..5bf07f626b 100644 --- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs +++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs @@ -210,7 +210,7 @@ namespace GodotTools.OpenVisualStudio return null; } - static string NormalizePath(string path) + private static string NormalizePath(string path) { return new Uri(Path.GetFullPath(path)).LocalPath .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index b4adc94c64..bf6cab11c7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -511,6 +511,7 @@ namespace GodotTools FocusMode = Control.FocusModeEnum.None, Shortcut = EditorDefShortcut("mono/build_solution", "Build Project".TTR(), (Key)KeyModifierMask.MaskAlt | Key.B), ShortcutInTooltip = true, + ThemeTypeVariation = "RunBarButton", }; EditorShortcutOverride("mono/build_solution", "macos", (Key)KeyModifierMask.MaskMeta | (Key)KeyModifierMask.MaskCtrl | Key.B); diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index 90c443ebb8..175bb78051 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -1,3 +1,6 @@ +#pragma warning disable IDE1006 // Naming rule violation +// ReSharper disable InconsistentNaming + using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -8,7 +11,6 @@ using GodotTools.IdeMessaging.Requests; namespace GodotTools.Internals { - [SuppressMessage("ReSharper", "InconsistentNaming")] [GenerateUnmanagedCallbacks(typeof(InternalUnmanagedCallbacks))] internal static partial class Internal { diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 7960a1ad5b..0a9162bd28 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1538,7 +1538,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n"); - p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n{"); + p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" OPEN_BLOCK); for (const ConstantInterface &iconstant : global_constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { @@ -1589,50 +1589,48 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { _log("Declaring global enum '%s' inside struct '%s'\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data()); - p_output.append("\npublic partial struct "); - p_output.append(enum_class_name); - p_output.append("\n" OPEN_BLOCK); + p_output << "\npublic partial struct " << enum_class_name << "\n" OPEN_BLOCK; } + const String maybe_indent = !enum_in_static_class ? "" : INDENT1; + if (ienum.is_flags) { - p_output.append("\n[System.Flags]"); + p_output << "\n" + << maybe_indent << "[System.Flags]"; } - p_output.append("\npublic enum "); - p_output.append(enum_proxy_name); - p_output.append(" : long"); - p_output.append("\n" OPEN_BLOCK); + p_output << "\n" + << maybe_indent << "public enum " << enum_proxy_name << " : long" + << "\n" + << maybe_indent << OPEN_BLOCK; - const ConstantInterface &last = ienum.constants.back()->get(); for (const ConstantInterface &iconstant : ienum.constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), nullptr); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); if (summary_lines.size()) { - p_output.append(INDENT1 "/// <summary>\n"); + p_output << maybe_indent << INDENT1 "/// <summary>\n"; for (int i = 0; i < summary_lines.size(); i++) { - p_output.append(INDENT1 "/// "); - p_output.append(summary_lines[i]); - p_output.append("\n"); + p_output << maybe_indent << INDENT1 "/// " << summary_lines[i] << "\n"; } - p_output.append(INDENT1 "/// </summary>\n"); + p_output << maybe_indent << INDENT1 "/// </summary>\n"; } } - p_output.append(INDENT1); - p_output.append(iconstant.proxy_name); - p_output.append(" = "); - p_output.append(itos(iconstant.value)); - p_output.append(&iconstant != &last ? ",\n" : "\n"); + p_output << maybe_indent << INDENT1 + << iconstant.proxy_name + << " = " + << itos(iconstant.value) + << ",\n"; } - p_output.append(CLOSE_BLOCK); + p_output << maybe_indent << CLOSE_BLOCK; if (enum_in_static_class) { - p_output.append(CLOSE_BLOCK); + p_output << CLOSE_BLOCK; } } } @@ -2162,7 +2160,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << MEMBER_BEGIN "public " << itype.proxy_name << "() : this(" << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1 << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK - << INDENT3 "_ConstructAndInitialize(" CS_STATIC_FIELD_NATIVE_CTOR ", " + << INDENT3 "ConstructAndInitialize(" CS_STATIC_FIELD_NATIVE_CTOR ", " << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " << (itype.is_ref_counted ? "true" : "false") << ");\n" << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; @@ -2171,7 +2169,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << MEMBER_BEGIN "internal " << itype.proxy_name << "() : this(" << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1 << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK - << INDENT3 "_ConstructAndInitialize(null, " + << INDENT3 "ConstructAndInitialize(null, " << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: " << (itype.is_ref_counted ? "true" : "false") << ");\n" << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1; @@ -2180,7 +2178,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add.. em.. trick constructor. Sort of. output.append(MEMBER_BEGIN "internal "); output.append(itype.proxy_name); - output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ") {}\n"); + output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ") { }\n"); } } @@ -2241,6 +2239,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str << INDENT1 "/// <param name=\"args\">Arguments to use with the invoked method.</param>\n" << INDENT1 "/// <param name=\"ret\">Value returned by the invoked method.</param>\n"; + // Avoid raising diagnostics because of calls to obsolete methods. + output << "#pragma warning disable CS0618 // Member is obsolete\n"; + output << INDENT1 "protected internal " << (is_derived_type ? "override" : "virtual") << " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, " << "NativeVariantPtrArgs args, out godot_variant ret)\n" @@ -2319,6 +2320,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output << INDENT1 "}\n"; + output << "#pragma warning restore CS0618\n"; + // Generate HasGodotClassMethod output << MEMBER_BEGIN "/// <summary>\n" @@ -2969,7 +2972,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found if (idx != 0) { - p_output << ","; + p_output << ", "; } p_output << sformat(arg_type->cs_variant_to_managed, @@ -3568,7 +3571,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.is_deprecated = itype.class_doc->is_deprecated; itype.deprecation_message = itype.class_doc->deprecated_message; - if (itype.deprecation_message.is_empty()) { + if (itype.is_deprecated && itype.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Type: '" + itype.proxy_name + "'."); itype.deprecation_message = "This class is deprecated."; } @@ -3652,7 +3655,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { iprop.is_deprecated = iprop.prop_doc->is_deprecated; iprop.deprecation_message = iprop.prop_doc->deprecated_message; - if (iprop.deprecation_message.is_empty()) { + if (iprop.is_deprecated && iprop.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Property: '" + itype.proxy_name + "." + iprop.proxy_name + "'."); iprop.deprecation_message = "This property is deprecated."; } @@ -3841,7 +3844,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.is_deprecated = imethod.method_doc->is_deprecated; imethod.deprecation_message = imethod.method_doc->deprecated_message; - if (imethod.deprecation_message.is_empty()) { + if (imethod.is_deprecated && imethod.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Method: '" + itype.proxy_name + "." + imethod.proxy_name + "'."); imethod.deprecation_message = "This method is deprecated."; } @@ -3957,7 +3960,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { isignal.is_deprecated = isignal.method_doc->is_deprecated; isignal.deprecation_message = isignal.method_doc->deprecated_message; - if (isignal.deprecation_message.is_empty()) { + if (isignal.is_deprecated && isignal.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + itype.proxy_name + "." + isignal.proxy_name + "'."); isignal.deprecation_message = "This signal is deprecated."; } @@ -4007,7 +4010,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { iconstant.is_deprecated = iconstant.const_doc->is_deprecated; iconstant.deprecation_message = iconstant.const_doc->deprecated_message; - if (iconstant.deprecation_message.is_empty()) { + if (iconstant.is_deprecated && iconstant.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Enum member: '" + itype.proxy_name + "." + ienum.proxy_name + "." + iconstant.proxy_name + "'."); iconstant.deprecation_message = "This enum member is deprecated."; } @@ -4059,7 +4062,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { iconstant.is_deprecated = iconstant.const_doc->is_deprecated; iconstant.deprecation_message = iconstant.const_doc->deprecated_message; - if (iconstant.deprecation_message.is_empty()) { + if (iconstant.is_deprecated && iconstant.deprecation_message.is_empty()) { WARN_PRINT("An empty deprecation message is discouraged. Constant: '" + itype.proxy_name + "." + iconstant.proxy_name + "'."); iconstant.deprecation_message = "This constant is deprecated."; } diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig index 987e6c543b..0d9a88ecb8 100644 --- a/modules/mono/glue/GodotSharp/.editorconfig +++ b/modules/mono/glue/GodotSharp/.editorconfig @@ -1,18 +1,37 @@ +# This file should only contain severity override to diagnostics, in order to make generated and +# interop code compilation readable. We want to limit the scope of suppression as much as possible. + [**/Generated/**.cs] +# IDE1006: Naming rule violation +dotnet_diagnostic.IDE1006.severity = none # CA1062: Validate parameter is non-null before using it # Useful for generated code, as it disables nullable dotnet_diagnostic.CA1062.severity = error # CA1069: Enums should not have duplicate values dotnet_diagnostic.CA1069.severity = none +# CA1707: Identifiers should not contain underscores +dotnet_diagnostic.CA1707.severity = none # CA1708: Identifiers should differ by more than case dotnet_diagnostic.CA1708.severity = none +# CA1711: Identifiers should not have incorrect suffix +# Disable warning for suffixes like EventHandler, Flags, Enum, etc. +dotnet_diagnostic.CA1711.severity = none # CA1716: Identifiers should not match keywords # This is suppressed, because it will report `@event` as well as `event` dotnet_diagnostic.CA1716.severity = none +# CA1720: Identifiers should not contain type names +dotnet_diagnostic.CA1720.severity = none # CS1591: Missing XML comment for publicly visible type or member dotnet_diagnostic.CS1591.severity = none # CS1573: Parameter has no matching param tag in the XML comment dotnet_diagnostic.CS1573.severity = none +# TODO: Temporary change to not pollute the warnings, but this denotes with ou doc generation +# CS1734: XML comment on '' has a paramref tag for '', but there is no parameter by that name +dotnet_diagnostic.CS1734.severity = none + +[GodotSharp/Core/NativeInterop/**.cs] +# CA1720: Identifiers should not contain type names +dotnet_diagnostic.CA1720.severity = none [GodotSharp/Core/**.cs] # CS1591: Missing XML comment for publicly visible type or member diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs index 750e11777d..f3f6759e1d 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs @@ -387,7 +387,7 @@ using Godot.NativeInterop; } private static bool IsGodotInteropStruct(ITypeSymbol type) => - GodotInteropStructs.Contains(type.FullQualifiedNameOmitGlobal()); + _godotInteropStructs.Contains(type.FullQualifiedNameOmitGlobal()); private static bool IsByRefParameter(IParameterSymbol parameter) => parameter.RefKind is RefKind.In or RefKind.Out or RefKind.Ref; @@ -448,7 +448,7 @@ using Godot.NativeInterop; source.Append(";\n"); } - private static readonly string[] GodotInteropStructs = + private static readonly string[] _godotInteropStructs = { "Godot.NativeInterop.godot_ref", "Godot.NativeInterop.godot_variant_call_error", diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs index daaf4730fd..4e80afc4a5 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs @@ -8,6 +8,8 @@ using System.ComponentModel; namespace Godot; #pragma warning disable CS1734 // XML comment on 'X' has a paramref tag for 'Y', but there is no parameter by that name. +// TODO: This is currently disabled because of https://github.com/dotnet/roslyn/issues/52904 +#pragma warning disable IDE0040 // Add accessibility modifiers. partial class AnimationNode { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index fa74d5e101..9b5aec7031 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -151,7 +151,6 @@ namespace Godot.Collections // from derived types (e.g.: Node[]). Implicit conversion from Derived[] to Base[] are // fine as long as the array is not mutated. However, Span does this type checking at // instantiation, so it's not possible to use it even when not mutating anything. - // ReSharper disable once RedundantNameQualifier /// <summary> /// Constructs a new <see cref="Array"/> from the given ReadOnlySpan's elements. /// </summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs index 6a73d6f70c..c53e964156 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RpcAttribute.cs @@ -19,7 +19,7 @@ namespace Godot /// <summary> /// If the method will also be called locally; otherwise, it is only called remotely. /// </summary> - public bool CallLocal { get; init; } = false; + public bool CallLocal { get; init; } /// <summary> /// Transfer mode for the annotated method. @@ -29,7 +29,7 @@ namespace Godot /// <summary> /// Transfer channel for the annotated mode. /// </summary> - public int TransferChannel { get; init; } = 0; + public int TransferChannel { get; init; } /// <summary> /// Constructs a <see cref="RpcAttribute"/> instance. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs index ac2e2fae3c..af1f4860cd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs @@ -2,7 +2,7 @@ namespace Godot.Bridge; public static class AlcReloadCfg { - private static bool _configured = false; + private static bool _configured; public static void Configure(bool alcReloadEnabled) { @@ -14,5 +14,5 @@ public static class AlcReloadCfg IsAlcReloadingEnabled = alcReloadEnabled; } - internal static bool IsAlcReloadingEnabled = false; + internal static bool IsAlcReloadingEnabled; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 0f271d6547..1b23276bbd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -30,7 +30,8 @@ namespace Godot.Bridge foreach (var type in typesInAlc.Keys) { if (_scriptTypeBiMap.RemoveByScriptType(type, out IntPtr scriptPtr) && - (!_pathTypeBiMap.TryGetScriptPath(type, out string? scriptPath) || scriptPath.StartsWith("csharp://"))) + (!_pathTypeBiMap.TryGetScriptPath(type, out string? scriptPath) || + scriptPath.StartsWith("csharp://", StringComparison.Ordinal))) { // For scripts without a path, we need to keep the class qualified name for reloading _scriptDataForReload.TryAdd(scriptPtr, @@ -584,7 +585,7 @@ namespace Godot.Bridge // (every Resource must have a unique path). So we create a unique "virtual" path // for each type. - if (!scriptPath.StartsWith("res://")) + if (!scriptPath.StartsWith("res://", StringComparison.Ordinal)) { throw new ArgumentException("Script path must start with 'res://'.", nameof(scriptPath)); } @@ -597,7 +598,7 @@ namespace Godot.Bridge { // This path is slower, but it's only executed for the first instantiation of the type - if (scriptType.IsConstructedGenericType && !scriptPath.StartsWith("csharp://")) + if (scriptType.IsConstructedGenericType && !scriptPath.StartsWith("csharp://", StringComparison.Ordinal)) { // If the script type is generic it can't be loaded using the real script path. // Construct a virtual path unique to this constructed generic type and add it @@ -700,7 +701,6 @@ namespace Godot.Bridge return godot_bool.False; } - // ReSharper disable once RedundantNameQualifier if (!typeof(GodotObject).IsAssignableFrom(scriptType)) { // The class no longer inherits GodotObject, can't reload @@ -1007,8 +1007,9 @@ namespace Godot.Bridge return (List<MethodInfo>?)getGodotMethodListMethod.Invoke(null, null); } +#pragma warning disable IDE1006 // Naming rule violation // ReSharper disable once InconsistentNaming - [SuppressMessage("ReSharper", "NotAccessedField.Local")] + // ReSharper disable once NotAccessedField.Local [StructLayout(LayoutKind.Sequential)] private ref struct godotsharp_property_info { @@ -1025,6 +1026,7 @@ namespace Godot.Bridge HintString.Dispose(); } } +#pragma warning restore IDE1006 [UnmanagedCallersOnly] internal static unsafe void GetPropertyInfoList(IntPtr scriptPtr, @@ -1063,9 +1065,9 @@ namespace Godot.Bridge int length = properties.Count; // There's no recursion here, so it's ok to go with a big enough number for most cases - // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_info) - const int stackMaxLength = 32; - bool useStack = length < stackMaxLength; + // StackMaxSize = StackMaxLength * sizeof(godotsharp_property_info) + const int StackMaxLength = 32; + bool useStack = length < StackMaxLength; godotsharp_property_info* interopProperties; @@ -1073,7 +1075,7 @@ namespace Godot.Bridge { // Weird limitation, hence the need for aux: // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable." - var aux = stackalloc godotsharp_property_info[stackMaxLength]; + var aux = stackalloc godotsharp_property_info[StackMaxLength]; interopProperties = aux; } else @@ -1124,8 +1126,9 @@ namespace Godot.Bridge } } +#pragma warning disable IDE1006 // Naming rule violation // ReSharper disable once InconsistentNaming - [SuppressMessage("ReSharper", "NotAccessedField.Local")] + // ReSharper disable once NotAccessedField.Local [StructLayout(LayoutKind.Sequential)] private ref struct godotsharp_property_def_val_pair { @@ -1133,6 +1136,7 @@ namespace Godot.Bridge public godot_string_name Name; // Not owned public godot_variant Value; // Not owned } +#pragma warning restore IDE1006 private delegate bool InvokeGodotClassStaticMethodDelegate(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret); @@ -1252,9 +1256,9 @@ namespace Godot.Bridge int length = defaultValues.Count; // There's no recursion here, so it's ok to go with a big enough number for most cases - // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_def_val_pair) - const int stackMaxLength = 32; - bool useStack = length < stackMaxLength; + // StackMaxSize = StackMaxLength * sizeof(godotsharp_property_def_val_pair) + const int StackMaxLength = 32; + bool useStack = length < StackMaxLength; godotsharp_property_def_val_pair* interopDefaultValues; @@ -1262,7 +1266,7 @@ namespace Godot.Bridge { // Weird limitation, hence the need for aux: // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable." - var aux = stackalloc godotsharp_property_def_val_pair[stackMaxLength]; + var aux = stackalloc godotsharp_property_def_val_pair[StackMaxLength]; interopDefaultValues = aux; } else diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index c29a0f2bd8..72a3fe3ed0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -38,7 +38,9 @@ namespace Godot public float B; /// <summary> - /// The color's alpha (transparency) component, typically on the range of 0 to 1. + /// The color's alpha component, typically on the range of 0 to 1. + /// A value of 0 means that the color is fully transparent. + /// A value of 1 means that the color is fully opaque. /// </summary> public float A; @@ -534,7 +536,11 @@ namespace Godot /// <param name="r">The color's red component, typically on the range of 0 to 1.</param> /// <param name="g">The color's green component, typically on the range of 0 to 1.</param> /// <param name="b">The color's blue component, typically on the range of 0 to 1.</param> - /// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param> + /// <param name="a"> + /// The color's alpha value, typically on the range of 0 to 1. + /// A value of 0 means that the color is fully transparent. + /// A value of 1 means that the color is fully opaque. + /// </param> public Color(float r, float g, float b, float a = 1.0f) { R = r; @@ -547,7 +553,11 @@ namespace Godot /// Constructs a <see cref="Color"/> from an existing color and an alpha value. /// </summary> /// <param name="c">The color to construct from. Only its RGB values are used.</param> - /// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param> + /// <param name="a"> + /// The color's alpha value, typically on the range of 0 to 1. + /// A value of 0 means that the color is fully transparent. + /// A value of 1 means that the color is fully opaque. + /// </param> public Color(Color c, float a = 1.0f) { R = c.R; @@ -784,7 +794,7 @@ namespace Godot name = name.Replace(".", string.Empty, StringComparison.Ordinal); name = name.ToUpperInvariant(); - return Colors.namedColors.TryGetValue(name, out color); + return Colors.NamedColors.TryGetValue(name, out color); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs index 44b1c2554c..5cb16fc385 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs @@ -9,7 +9,7 @@ namespace Godot public static class Colors { // Color names and values are derived from core/math/color_names.inc - internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> { + internal static readonly Dictionary<string, Color> NamedColors = new Dictionary<string, Color> { { "ALICEBLUE", Colors.AliceBlue }, { "ANTIQUEWHITE", Colors.AntiqueWhite }, { "AQUA", Colors.Aqua }, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs index 42f19ace1a..28a4e1bc76 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs @@ -26,7 +26,6 @@ public static class CustomGCHandle [MethodImpl(MethodImplOptions.NoInlining)] public static bool IsAlcBeingUnloaded(AssemblyLoadContext alc) => _alcsBeingUnloaded.TryGetValue(alc, out _); - // ReSharper disable once RedundantNameQualifier private static ConcurrentDictionary< AssemblyLoadContext, ConcurrentDictionary<GCHandle, object> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs index 57b292793a..0d96a9a5c1 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs @@ -62,8 +62,9 @@ namespace Godot Trace.Listeners.Add(new GodotTraceListener()); } - [StructLayout(LayoutKind.Sequential)] +#pragma warning disable IDE1006 // Naming rule violation // ReSharper disable once InconsistentNaming + [StructLayout(LayoutKind.Sequential)] internal ref struct godot_stack_info { public godot_string File; @@ -71,8 +72,8 @@ namespace Godot public int Line; } - [StructLayout(LayoutKind.Sequential)] // ReSharper disable once InconsistentNaming + [StructLayout(LayoutKind.Sequential)] internal ref struct godot_stack_info_vector { private IntPtr _writeProxy; @@ -101,6 +102,7 @@ namespace Godot _ptr = null; } } +#pragma warning restore IDE1006 internal static unsafe StackFrame? GetCurrentStackFrame(int skipFrames = 0) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index fc6e7a3ebe..c680142638 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -141,7 +141,6 @@ namespace Godot return true; } } - // ReSharper disable once RedundantNameQualifier case GodotObject godotObject: { using (var stream = new MemoryStream()) @@ -414,7 +413,6 @@ namespace Godot case TargetKind.GodotObject: { ulong objectId = reader.ReadUInt64(); - // ReSharper disable once RedundantNameQualifier GodotObject? godotObject = GodotObject.InstanceFromId(objectId); if (godotObject == null) return false; @@ -495,7 +493,7 @@ namespace Godot string methodName = reader.ReadString(); - int flags = reader.ReadInt32(); + BindingFlags flags = (BindingFlags)reader.ReadInt32(); bool hasReturn = reader.ReadBoolean(); Type? returnType = hasReturn ? DeserializeType(reader) : typeof(void); @@ -511,7 +509,11 @@ namespace Godot parameterTypes[i] = parameterType; } - methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags, null, parameterTypes, null); +#pragma warning disable REFL045 // These flags are insufficient to match any members + // TODO: Suppressing invalid warning, remove when issue is fixed + // https://github.com/DotNetAnalyzers/ReflectionAnalyzers/issues/209 + methodInfo = declaringType.GetMethod(methodName, flags, null, parameterTypes, null); +#pragma warning restore REFL045 return methodInfo != null && methodInfo.ReturnType == returnType; } @@ -588,7 +590,6 @@ namespace Godot internal static class RuntimeTypeConversionHelper { - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static godot_variant ConvertToVariant(object? obj) { if (obj == null) @@ -713,10 +714,8 @@ namespace Godot private delegate object? ConvertToSystemObjectFunc(in godot_variant managed); - [SuppressMessage("ReSharper", "RedundantNameQualifier")] - // ReSharper disable once RedundantNameQualifier private static readonly System.Collections.Generic.Dictionary<Type, ConvertToSystemObjectFunc> - ToSystemObjectFuncByType = new() + _toSystemObjectFuncByType = new() { [typeof(bool)] = (in godot_variant variant) => VariantUtils.ConvertTo<bool>(variant), [typeof(char)] = (in godot_variant variant) => VariantUtils.ConvertTo<char>(variant), @@ -771,10 +770,9 @@ namespace Godot [typeof(Variant)] = (in godot_variant variant) => VariantUtils.ConvertTo<Variant>(variant), }; - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static object? ConvertToObjectOfType(in godot_variant variant, Type type) { - if (ToSystemObjectFuncByType.TryGetValue(type, out var func)) + if (_toSystemObjectFuncByType.TryGetValue(type, out var func)) return func(variant); if (typeof(GodotObject).IsAssignableFrom(type)) @@ -838,8 +836,7 @@ namespace Godot if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>)) { - var ctor = type.GetConstructor(BindingFlags.Default, - new[] { typeof(Godot.Collections.Dictionary) }); + var ctor = type.GetConstructor(new[] { typeof(Godot.Collections.Dictionary) }); if (ctor == null) throw new InvalidOperationException("Dictionary constructor not found"); @@ -852,8 +849,7 @@ namespace Godot if (genericTypeDef == typeof(Godot.Collections.Array<>)) { - var ctor = type.GetConstructor(BindingFlags.Default, - new[] { typeof(Godot.Collections.Array) }); + var ctor = type.GetConstructor(new[] { typeof(Godot.Collections.Array) }); if (ctor == null) throw new InvalidOperationException("Array constructor not found"); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs index 53292e10cf..0ae3e1e130 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs @@ -59,7 +59,6 @@ namespace Godot GD.Print("Unloading: Finished disposing tracked instances."); } - // ReSharper disable once RedundantNameQualifier private static ConcurrentDictionary<WeakReference<GodotObject>, byte> GodotObjectInstances { get; } = new(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs index 84b2a04276..0be9cdc953 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotObject.base.cs @@ -10,8 +10,8 @@ namespace Godot { public partial class GodotObject : IDisposable { - private bool _disposed = false; - private static readonly Type CachedType = typeof(GodotObject); + private bool _disposed; + private static readonly Type _cachedType = typeof(GodotObject); internal IntPtr NativePtr; private bool _memoryOwn; @@ -25,11 +25,11 @@ namespace Godot { unsafe { - _ConstructAndInitialize(NativeCtor, NativeName, CachedType, refCounted: false); + ConstructAndInitialize(NativeCtor, NativeName, _cachedType, refCounted: false); } } - internal unsafe void _ConstructAndInitialize( + internal unsafe void ConstructAndInitialize( delegate* unmanaged<IntPtr> nativeCtor, StringName nativeName, Type cachedType, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 09269508b7..16d4616fcd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -36,11 +36,11 @@ namespace Godot public const real_t NaN = real_t.NaN; // 0.0174532924f and 0.0174532925199433 - private const float _degToRadConstF = (float)0.0174532925199432957692369077M; - private const double _degToRadConstD = (double)0.0174532925199432957692369077M; + private const float DegToRadConstF = (float)0.0174532925199432957692369077M; + private const double DegToRadConstD = (double)0.0174532925199432957692369077M; // 57.29578f and 57.2957795130823 - private const float _radToDegConstF = (float)57.295779513082320876798154814M; - private const double _radToDegConstD = (double)57.295779513082320876798154814M; + private const float RadToDegConstF = (float)57.295779513082320876798154814M; + private const double RadToDegConstD = (double)57.295779513082320876798154814M; /// <summary> /// Returns the absolute value of <paramref name="s"/> (i.e. positive value). @@ -760,7 +760,7 @@ namespace Godot /// <returns>The same angle expressed in radians.</returns> public static float DegToRad(float deg) { - return deg * _degToRadConstF; + return deg * DegToRadConstF; } /// <summary> @@ -770,7 +770,7 @@ namespace Godot /// <returns>The same angle expressed in radians.</returns> public static double DegToRad(double deg) { - return deg * _degToRadConstD; + return deg * DegToRadConstD; } /// <summary> @@ -957,10 +957,10 @@ namespace Godot return true; } // Then check for approximate equality. - float tolerance = _epsilonF * Math.Abs(a); - if (tolerance < _epsilonF) + float tolerance = EpsilonF * Math.Abs(a); + if (tolerance < EpsilonF) { - tolerance = _epsilonF; + tolerance = EpsilonF; } return Math.Abs(a - b) < tolerance; } @@ -981,10 +981,10 @@ namespace Godot return true; } // Then check for approximate equality. - double tolerance = _epsilonD * Math.Abs(a); - if (tolerance < _epsilonD) + double tolerance = EpsilonD * Math.Abs(a); + if (tolerance < EpsilonD) { - tolerance = _epsilonD; + tolerance = EpsilonD; } return Math.Abs(a - b) < tolerance; } @@ -1069,7 +1069,7 @@ namespace Godot [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsZeroApprox(float s) { - return Math.Abs(s) < _epsilonF; + return Math.Abs(s) < EpsilonF; } /// <summary> @@ -1084,7 +1084,7 @@ namespace Godot [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsZeroApprox(double s) { - return Math.Abs(s) < _epsilonD; + return Math.Abs(s) < EpsilonD; } /// <summary> @@ -1412,7 +1412,7 @@ namespace Godot [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float RadToDeg(float rad) { - return rad * _radToDegConstF; + return rad * RadToDegConstF; } /// <summary> @@ -1423,7 +1423,7 @@ namespace Godot [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double RadToDeg(double rad) { - return rad * _radToDegConstD; + return rad * RadToDegConstD; } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index cc2d61f58d..9020602cb4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs @@ -21,8 +21,8 @@ namespace Godot public const real_t Sqrt2 = (real_t)1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 // Epsilon size should depend on the precision used. - private const float _epsilonF = 1e-06f; - private const double _epsilonD = 1e-14; + private const float EpsilonF = 1e-06f; + private const double EpsilonD = 1e-14; /// <summary> /// A very small number used for float comparison with error tolerance. @@ -31,7 +31,7 @@ namespace Godot #if REAL_T_IS_DOUBLE public const real_t Epsilon = _epsilonD; #else - public const real_t Epsilon = _epsilonF; + public const real_t Epsilon = EpsilonF; #endif /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs index a8642a916c..a019dd3513 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs @@ -1,3 +1,7 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores +#pragma warning disable IDE1006 // Naming rule violation +// ReSharper disable InconsistentNaming + using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; @@ -24,7 +28,6 @@ namespace Godot.NativeInterop } // Apparently a struct with a byte is not blittable? It crashes when calling a UnmanagedCallersOnly function ptr. - // ReSharper disable once InconsistentNaming public enum godot_bool : byte { True = 1, @@ -32,7 +35,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_ref { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -62,7 +64,6 @@ namespace Godot.NativeInterop } } - [SuppressMessage("ReSharper", "InconsistentNaming")] public enum godot_variant_call_error_error { GODOT_CALL_ERROR_CALL_OK = 0, @@ -75,7 +76,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_variant_call_error { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -106,7 +106,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_csharp_type_info { private godot_string _className; @@ -161,7 +160,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential, Pack = 8)] - // ReSharper disable once InconsistentNaming public ref struct godot_variant { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -176,7 +174,6 @@ namespace Godot.NativeInterop private godot_variant_data _data; [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming private unsafe ref struct godot_variant_data { [FieldOffset(0)] public godot_bool _bool; @@ -212,7 +209,6 @@ namespace Godot.NativeInterop [FieldOffset(0)] public godot_array _m_array; [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public struct godot_variant_obj_data { public ulong id; @@ -220,7 +216,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public struct godot_variant_data_mem { #pragma warning disable 169 @@ -480,7 +475,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming internal struct movable { // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits. @@ -502,7 +496,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_string { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -534,7 +527,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_string_name { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -590,7 +582,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming internal struct movable { private IntPtr _data; @@ -607,7 +598,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_node_path { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -638,7 +628,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming internal struct movable { private IntPtr _data; @@ -655,7 +644,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming public ref struct godot_signal { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -698,7 +686,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming public ref struct godot_callable { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -736,7 +723,6 @@ namespace Godot.NativeInterop // Don't pass a C# default constructed `godot_array` to native code, unless it's going to // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming public ref struct godot_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -817,7 +803,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming internal struct movable { private unsafe ArrayPrivate* _p; @@ -838,7 +823,6 @@ namespace Godot.NativeInterop // Don't pass a C# default constructed `godot_dictionary` to native code, unless it's going to // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine). [StructLayout(LayoutKind.Explicit)] - // ReSharper disable once InconsistentNaming public ref struct godot_dictionary { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -886,7 +870,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming internal struct movable { private unsafe DictionaryPrivate* _p; @@ -903,7 +886,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_byte_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -935,7 +917,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_int32_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -967,7 +948,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_int64_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -999,7 +979,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_float32_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1031,7 +1010,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_float64_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1063,7 +1041,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_string_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1095,7 +1072,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_vector2_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1127,7 +1103,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_vector3_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1159,7 +1134,6 @@ namespace Godot.NativeInterop } [StructLayout(LayoutKind.Sequential)] - // ReSharper disable once InconsistentNaming public ref struct godot_packed_color_array { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1190,7 +1164,6 @@ namespace Godot.NativeInterop } } - [SuppressMessage("ReSharper", "InconsistentNaming")] public enum godot_error_handler_type { ERR_HANDLER_ERROR = 0, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs index 0cc89d78af..9f7fa53e24 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores + using System; using System.Runtime.InteropServices; using Godot.Collections; @@ -213,13 +215,13 @@ namespace Godot.NativeInterop if (p_string.Buffer == IntPtr.Zero) return string.Empty; - const int sizeOfChar32 = 4; + const int SizeOfChar32 = 4; byte* bytes = (byte*)p_string.Buffer; int size = p_string.Size; if (size == 0) return string.Empty; size -= 1; // zero at the end - int sizeInBytes = size * sizeOfChar32; + int sizeInBytes = size * SizeOfChar32; return System.Text.Encoding.UTF32.GetString(bytes, sizeInBytes); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index d181bf2c0f..fef21fae46 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -1,9 +1,11 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores +#pragma warning disable IDE1006 // Naming rule violation +// ReSharper disable InconsistentNaming + using System; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Godot.SourceGenerators.Internal; -// ReSharper disable InconsistentNaming namespace Godot.NativeInterop { @@ -16,7 +18,7 @@ namespace Godot.NativeInterop [GenerateUnmanagedCallbacks(typeof(UnmanagedCallbacks))] public static unsafe partial class NativeFuncs { - private static bool initialized = false; + private static bool initialized; // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global public static void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs index 44ec16dca9..9f237e4d00 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs @@ -1,3 +1,5 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores +#pragma warning disable IDE1006 // Naming rule violation // ReSharper disable InconsistentNaming namespace Godot.NativeInterop diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index e6bcd9393d..464b517428 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -1,8 +1,11 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores +#pragma warning disable IDE1006 // Naming rule violation +// ReSharper disable InconsistentNaming + using System; using System.Runtime.CompilerServices; using Godot.Collections; -// ReSharper disable InconsistentNaming #nullable enable @@ -240,7 +243,6 @@ namespace Godot.NativeInterop public static godot_variant CreateFromSystemArrayOfRid(Span<Rid> from) => CreateFromArray(new Collections.Array(from)); - // ReSharper disable once RedundantNameQualifier public static godot_variant CreateFromSystemArrayOfGodotObject(GodotObject[]? from) { if (from == null) @@ -306,7 +308,6 @@ namespace Godot.NativeInterop } [MethodImpl(MethodImplOptions.AggressiveInlining)] - // ReSharper disable once RedundantNameQualifier public static godot_variant CreateFromGodotObject(GodotObject? from) => from != null ? CreateFromGodotObjectPtr(GodotObject.GetPtr(from)) : default; @@ -459,7 +460,6 @@ namespace Godot.NativeInterop => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero; [MethodImpl(MethodImplOptions.AggressiveInlining)] - // ReSharper disable once RedundantNameQualifier public static GodotObject ConvertToGodotObject(in godot_variant p_var) => InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var)); @@ -615,7 +615,6 @@ namespace Godot.NativeInterop } public static T[] ConvertToSystemArrayOfGodotObject<T>(in godot_variant p_var) - // ReSharper disable once RedundantNameQualifier where T : GodotObject { using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs index 12b0a47079..d8f7214c2f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.generic.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Godot.NativeInterop; @@ -25,7 +24,6 @@ public partial class VariantUtils // ReSharper disable once StaticMemberInGenericType internal static unsafe delegate*<in godot_variant, T> FromVariantCb; - [SuppressMessage("ReSharper", "RedundantNameQualifier")] static GenericConversion() { RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); @@ -33,7 +31,6 @@ public partial class VariantUtils } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static godot_variant CreateFrom<[MustBeVariant] T>(in T from) { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -224,7 +221,6 @@ public partial class VariantUtils } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] - [SuppressMessage("ReSharper", "RedundantNameQualifier")] public static T ConvertTo<[MustBeVariant] T>(in godot_variant variant) { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index 2aac23d799..c0889fb0e8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -251,10 +251,10 @@ namespace Godot /// <param name="right">The right clipping distance.</param> /// <param name="bottom">The bottom clipping distance.</param> /// <param name="top">The top clipping distance.</param> - /// <param name="near">The near clipping distance.</param> - /// <param name="far">The far clipping distance.</param> + /// <param name="depthNear">The near clipping distance.</param> + /// <param name="depthFar">The far clipping distance.</param> /// <returns>The created projection.</returns> - public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t depth_near, real_t depth_far) + public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t depthNear, real_t depthFar) { if (right <= left) { @@ -264,18 +264,18 @@ namespace Godot { throw new ArgumentException("top is less or equal to bottom."); } - if (depth_far <= depth_near) + if (depthFar <= depthNear) { throw new ArgumentException("far is less or equal to near."); } - real_t x = 2 * depth_near / (right - left); - real_t y = 2 * depth_near / (top - bottom); + real_t x = 2 * depthNear / (right - left); + real_t y = 2 * depthNear / (top - bottom); real_t a = (right + left) / (right - left); real_t b = (top + bottom) / (top - bottom); - real_t c = -(depth_far + depth_near) / (depth_far - depth_near); - real_t d = -2 * depth_far * depth_near / (depth_far - depth_near); + real_t c = -(depthFar + depthNear) / (depthFar - depthNear); + real_t d = -2 * depthFar * depthNear / (depthFar - depthNear); return new Projection( new Vector4(x, 0, 0, 0), @@ -293,17 +293,17 @@ namespace Godot /// <param name="size">The frustum size.</param> /// <param name="aspect">The aspect ratio.</param> /// <param name="offset">The offset to apply.</param> - /// <param name="near">The near clipping distance.</param> - /// <param name="far">The far clipping distance.</param> + /// <param name="depthNear">The near clipping distance.</param> + /// <param name="depthFar">The far clipping distance.</param> /// <param name="flipFov">If the field of view is flipped over the projection's diagonal.</param> /// <returns>The created projection.</returns> - public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t depth_near, real_t depth_far, bool flipFov) + public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t depthNear, real_t depthFar, bool flipFov) { if (!flipFov) { size *= aspect; } - return CreateFrustum(-size / 2 + offset.X, +size / 2 + offset.X, -size / aspect / 2 + offset.Y, +size / aspect / 2 + offset.Y, depth_near, depth_far); + return CreateFrustum(-size / 2 + offset.X, +size / 2 + offset.X, -size / aspect / 2 + offset.Y, +size / aspect / 2 + offset.Y, depthNear, depthFar); } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index f249bac69c..9cd5498fa8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1836,8 +1836,8 @@ namespace Godot return Uri.EscapeDataString(instance); } - private const string _uniqueNodePrefix = "%"; - private static readonly string[] _invalidNodeNameCharacters = { ".", ":", "@", "/", "\"", _uniqueNodePrefix }; + private const string UniqueNodePrefix = "%"; + private static readonly string[] _invalidNodeNameCharacters = { ".", ":", "@", "/", "\"", UniqueNodePrefix }; /// <summary> /// Removes any characters from the string that are prohibited in diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs index 9aad965ad0..036a26328a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Variant.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Godot.NativeInterop; @@ -7,7 +6,6 @@ namespace Godot; #nullable enable -[SuppressMessage("ReSharper", "RedundantNameQualifier")] public partial struct Variant : IDisposable { internal godot_variant.movable NativeVar; diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs index 7a3bb0df7e..d1289ee6ba 100644 --- a/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/Compat.cs @@ -7,6 +7,9 @@ using System.ComponentModel; namespace Godot; +// TODO: This is currently disabled because of https://github.com/dotnet/roslyn/issues/52904 +#pragma warning disable IDE0040 // Add accessibility modifiers. + partial class EditorUndoRedoManager { /// <inheritdoc cref="CreateAction(string, UndoRedo.MergeMode, GodotObject, bool)"/> diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp index 9fdfb20842..d1ac784103 100644 --- a/modules/navigation/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp @@ -35,7 +35,7 @@ #include "core/config/project_settings.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/multimesh_instance_2d.h" -#include "scene/2d/physics_body_2d.h" +#include "scene/2d/physics/static_body_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/2d/tile_map.h" #include "scene/resources/2d/capsule_shape_2d.h" diff --git a/modules/navigation/3d/nav_mesh_generator_3d.cpp b/modules/navigation/3d/nav_mesh_generator_3d.cpp index 4cd4f60edc..e1ed9c51aa 100644 --- a/modules/navigation/3d/nav_mesh_generator_3d.cpp +++ b/modules/navigation/3d/nav_mesh_generator_3d.cpp @@ -37,7 +37,7 @@ #include "core/os/thread.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/static_body_3d.h" #include "scene/resources/3d/box_shape_3d.h" #include "scene/resources/3d/capsule_shape_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" diff --git a/modules/navigation/nav_agent.h b/modules/navigation/nav_agent.h index 00b5bc13ab..18997803f2 100644 --- a/modules/navigation/nav_agent.h +++ b/modules/navigation/nav_agent.h @@ -31,7 +31,6 @@ #ifndef NAV_AGENT_H #define NAV_AGENT_H -#include "nav_agent.h" #include "nav_rid.h" #include "core/object/class_db.h" diff --git a/modules/noise/noise_texture_3d.cpp b/modules/noise/noise_texture_3d.cpp index f2e01b0612..1e929e6f63 100644 --- a/modules/noise/noise_texture_3d.cpp +++ b/modules/noise/noise_texture_3d.cpp @@ -142,6 +142,8 @@ TypedArray<Image> NoiseTexture3D::_generate_texture() { return TypedArray<Image>(); } + ERR_FAIL_COND_V_MSG((int64_t)width * height * depth > Image::MAX_PIXELS, TypedArray<Image>(), "The NoiseTexture3D is too big, consider lowering its width, height, or depth."); + Vector<Ref<Image>> images; if (seamless) { diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 471fda74bf..53182b8e2d 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -416,7 +416,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } - if (EDITOR_GET("export/android/shutdown_adb_on_exit")) { + if (ea->has_runnable_preset.is_set() && EDITOR_GET("export/android/shutdown_adb_on_exit")) { String adb = get_adb_path(); if (!FileAccess::exists(adb)) { return; //adb not configured diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index d8e546f571..b2014f2849 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -4905,7 +4905,7 @@ DisplayServerMacOS::~DisplayServerMacOS() { } // Destroy all status indicators. - for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E;) { + for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E; ++E) { [[NSStatusBar systemStatusBar] removeStatusItem:E->value.item]; } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 6f3f6189e5..4bb6d2f3f5 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -5539,7 +5539,7 @@ DisplayServerWindows::~DisplayServerWindows() { cursors_cache.clear(); // Destroy all status indicators. - for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E;) { + for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E; ++E) { NOTIFYICONDATAW ndat; ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW)); ndat.cbSize = sizeof(NOTIFYICONDATAW); diff --git a/scene/2d/SCsub b/scene/2d/SCsub index fc61250247..94e1ab6c96 100644 --- a/scene/2d/SCsub +++ b/scene/2d/SCsub @@ -3,3 +3,6 @@ Import("env") env.add_source_files(env.scene_sources, "*.cpp") + +# Chain load SCsubs +SConscript("physics/SCsub") diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 4762ae28f8..cbd3c244d9 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -32,8 +32,8 @@ #include "audio_stream_player_2d.compat.inc" #include "core/config/project_settings.h" -#include "scene/2d/area_2d.h" #include "scene/2d/audio_listener_2d.h" +#include "scene/2d/physics/area_2d.h" #include "scene/audio/audio_stream_player_internal.h" #include "scene/main/viewport.h" #include "scene/resources/world_2d.h" diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp deleted file mode 100644 index 41b121a482..0000000000 --- a/scene/2d/joint_2d.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/**************************************************************************/ -/* joint_2d.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#include "joint_2d.h" - -#include "physics_body_2d.h" -#include "scene/scene_string_names.h" - -void Joint2D::_disconnect_signals() { - Node *node_a = get_node_or_null(a); - PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); - if (body_a) { - body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); - } - - Node *node_b = get_node_or_null(b); - PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); - if (body_b) { - body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); - } -} - -void Joint2D::_body_exit_tree() { - _disconnect_signals(); - _update_joint(true); - update_configuration_warnings(); -} - -void Joint2D::_update_joint(bool p_only_free) { - if (ba.is_valid() && bb.is_valid() && exclude_from_collision) { - PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false); - } - - ba = RID(); - bb = RID(); - configured = false; - - if (p_only_free || !is_inside_tree()) { - PhysicsServer2D::get_singleton()->joint_clear(joint); - warning = String(); - return; - } - - Node *node_a = get_node_or_null(a); - Node *node_b = get_node_or_null(b); - - PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); - PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); - - bool valid = false; - - if (node_a && !body_a && node_b && !body_b) { - warning = RTR("Node A and Node B must be PhysicsBody2Ds"); - } else if (node_a && !body_a) { - warning = RTR("Node A must be a PhysicsBody2D"); - } else if (node_b && !body_b) { - warning = RTR("Node B must be a PhysicsBody2D"); - } else if (!body_a || !body_b) { - warning = RTR("Joint is not connected to two PhysicsBody2Ds"); - } else if (body_a == body_b) { - warning = RTR("Node A and Node B must be different PhysicsBody2Ds"); - } else { - warning = String(); - valid = true; - } - - update_configuration_warnings(); - - if (!valid) { - PhysicsServer2D::get_singleton()->joint_clear(joint); - return; - } - - if (body_a) { - body_a->force_update_transform(); - } - - if (body_b) { - body_b->force_update_transform(); - } - - configured = true; - - _configure_joint(joint, body_a, body_b); - - ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint."); - - PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); - - ba = body_a->get_rid(); - bb = body_b->get_rid(); - - body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); - body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); - - PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); -} - -void Joint2D::set_node_a(const NodePath &p_node_a) { - if (a == p_node_a) { - return; - } - - if (is_configured()) { - _disconnect_signals(); - } - - a = p_node_a; - if (Engine::get_singleton()->is_editor_hint()) { - // When in editor, the setter may be called as a result of node rename. - // It happens before the node actually changes its name, which triggers false warning. - callable_mp(this, &Joint2D::_update_joint).call_deferred(); - } else { - _update_joint(); - } -} - -NodePath Joint2D::get_node_a() const { - return a; -} - -void Joint2D::set_node_b(const NodePath &p_node_b) { - if (b == p_node_b) { - return; - } - - if (is_configured()) { - _disconnect_signals(); - } - - b = p_node_b; - if (Engine::get_singleton()->is_editor_hint()) { - callable_mp(this, &Joint2D::_update_joint).call_deferred(); - } else { - _update_joint(); - } -} - -NodePath Joint2D::get_node_b() const { - return b; -} - -void Joint2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_POST_ENTER_TREE: { - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(); - } break; - - case NOTIFICATION_EXIT_TREE: { - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(true); - } break; - } -} - -void Joint2D::set_bias(real_t p_bias) { - bias = p_bias; - if (joint.is_valid()) { - PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); - } -} - -real_t Joint2D::get_bias() const { - return bias; -} - -void Joint2D::set_exclude_nodes_from_collision(bool p_enable) { - if (exclude_from_collision == p_enable) { - return; - } - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(true); - exclude_from_collision = p_enable; - _update_joint(); -} - -bool Joint2D::get_exclude_nodes_from_collision() const { - return exclude_from_collision; -} - -PackedStringArray Joint2D::get_configuration_warnings() const { - PackedStringArray warnings = Node2D::get_configuration_warnings(); - - if (!warning.is_empty()) { - warnings.push_back(warning); - } - - return warnings; -} - -void Joint2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint2D::set_node_a); - ClassDB::bind_method(D_METHOD("get_node_a"), &Joint2D::get_node_a); - - ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint2D::set_node_b); - ClassDB::bind_method(D_METHOD("get_node_b"), &Joint2D::get_node_b); - - ClassDB::bind_method(D_METHOD("set_bias", "bias"), &Joint2D::set_bias); - ClassDB::bind_method(D_METHOD("get_bias"), &Joint2D::get_bias); - - ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision); - ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision); - - ClassDB::bind_method(D_METHOD("get_rid"), &Joint2D::get_rid); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_b", "get_node_b"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), "set_bias", "get_bias"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); -} - -Joint2D::Joint2D() { - joint = PhysicsServer2D::get_singleton()->joint_create(); - set_hide_clip_children(true); -} - -Joint2D::~Joint2D() { - ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); - PhysicsServer2D::get_singleton()->free(joint); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -void PinJoint2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_DRAW: { - if (!is_inside_tree()) { - break; - } - - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { - break; - } - - draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(0, -10), Point2(0, +10), Color(0.7, 0.6, 0.0, 0.5), 3); - } break; - } -} - -void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { - PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_position(), body_a->get_rid(), body_b ? body_b->get_rid() : RID()); - PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness); - PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_LIMIT_UPPER, angular_limit_upper); - PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_LIMIT_LOWER, angular_limit_lower); - PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_MOTOR_TARGET_VELOCITY, motor_target_velocity); - PhysicsServer2D::get_singleton()->pin_joint_set_flag(p_joint, PhysicsServer2D::PIN_JOINT_FLAG_MOTOR_ENABLED, motor_enabled); - PhysicsServer2D::get_singleton()->pin_joint_set_flag(p_joint, PhysicsServer2D::PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED, angular_limit_enabled); -} - -void PinJoint2D::set_softness(real_t p_softness) { - if (softness == p_softness) { - return; - } - softness = p_softness; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness); - } -} - -real_t PinJoint2D::get_softness() const { - return softness; -} - -void PinJoint2D::set_angular_limit_lower(real_t p_angular_limit_lower) { - if (angular_limit_lower == p_angular_limit_lower) { - return; - } - angular_limit_lower = p_angular_limit_lower; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_LIMIT_LOWER, p_angular_limit_lower); - } -} - -real_t PinJoint2D::get_angular_limit_lower() const { - return angular_limit_lower; -} - -void PinJoint2D::set_angular_limit_upper(real_t p_angular_limit_upper) { - if (angular_limit_upper == p_angular_limit_upper) { - return; - } - angular_limit_upper = p_angular_limit_upper; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_LIMIT_UPPER, p_angular_limit_upper); - } -} - -real_t PinJoint2D::get_angular_limit_upper() const { - return angular_limit_upper; -} - -void PinJoint2D::set_motor_target_velocity(real_t p_motor_target_velocity) { - if (motor_target_velocity == p_motor_target_velocity) { - return; - } - motor_target_velocity = p_motor_target_velocity; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_MOTOR_TARGET_VELOCITY, motor_target_velocity); - } -} - -real_t PinJoint2D::get_motor_target_velocity() const { - return motor_target_velocity; -} - -void PinJoint2D::set_motor_enabled(bool p_motor_enabled) { - if (motor_enabled == p_motor_enabled) { - return; - } - motor_enabled = p_motor_enabled; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_flag(get_rid(), PhysicsServer2D::PIN_JOINT_FLAG_MOTOR_ENABLED, motor_enabled); - } -} - -bool PinJoint2D::is_motor_enabled() const { - return motor_enabled; -} - -void PinJoint2D::set_angular_limit_enabled(bool p_angular_limit_enabled) { - if (angular_limit_enabled == p_angular_limit_enabled) { - return; - } - angular_limit_enabled = p_angular_limit_enabled; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->pin_joint_set_flag(get_rid(), PhysicsServer2D::PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED, angular_limit_enabled); - } -} - -bool PinJoint2D::is_angular_limit_enabled() const { - return angular_limit_enabled; -} - -void PinJoint2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_softness", "softness"), &PinJoint2D::set_softness); - ClassDB::bind_method(D_METHOD("get_softness"), &PinJoint2D::get_softness); - ClassDB::bind_method(D_METHOD("set_angular_limit_lower", "angular_limit_lower"), &PinJoint2D::set_angular_limit_lower); - ClassDB::bind_method(D_METHOD("get_angular_limit_lower"), &PinJoint2D::get_angular_limit_lower); - ClassDB::bind_method(D_METHOD("set_angular_limit_upper", "angular_limit_upper"), &PinJoint2D::set_angular_limit_upper); - ClassDB::bind_method(D_METHOD("get_angular_limit_upper"), &PinJoint2D::get_angular_limit_upper); - ClassDB::bind_method(D_METHOD("set_motor_target_velocity", "motor_target_velocity"), &PinJoint2D::set_motor_target_velocity); - ClassDB::bind_method(D_METHOD("get_motor_target_velocity"), &PinJoint2D::get_motor_target_velocity); - ClassDB::bind_method(D_METHOD("set_motor_enabled", "enabled"), &PinJoint2D::set_motor_enabled); - ClassDB::bind_method(D_METHOD("is_motor_enabled"), &PinJoint2D::is_motor_enabled); - ClassDB::bind_method(D_METHOD("set_angular_limit_enabled", "enabled"), &PinJoint2D::set_angular_limit_enabled); - ClassDB::bind_method(D_METHOD("is_angular_limit_enabled"), &PinJoint2D::is_angular_limit_enabled); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_softness", "get_softness"); - ADD_GROUP("Angular Limit", "angular_limit_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "angular_limit_enabled"), "set_angular_limit_enabled", "is_angular_limit_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_angular_limit_lower", "get_angular_limit_lower"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_angular_limit_upper", "get_angular_limit_upper"); - ADD_GROUP("Motor", "motor_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motor_enabled"), "set_motor_enabled", "is_motor_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motor_target_velocity", PROPERTY_HINT_RANGE, U"-200,200,0.01,or_greater,or_less,radians_as_degrees,suffix:\u00B0/s"), "set_motor_target_velocity", "get_motor_target_velocity"); -} - -PinJoint2D::PinJoint2D() { -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -void GrooveJoint2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_DRAW: { - if (!is_inside_tree()) { - break; - } - - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { - break; - } - - draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(-10, initial_offset), Point2(+10, initial_offset), Color(0.8, 0.8, 0.9, 0.5), 5); - } break; - } -} - -void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { - Transform2D gt = get_global_transform(); - Vector2 groove_A1 = gt.get_origin(); - Vector2 groove_A2 = gt.xform(Vector2(0, length)); - Vector2 anchor_B = gt.xform(Vector2(0, initial_offset)); - - PhysicsServer2D::get_singleton()->joint_make_groove(p_joint, groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid()); -} - -void GrooveJoint2D::set_length(real_t p_length) { - length = p_length; - queue_redraw(); -} - -real_t GrooveJoint2D::get_length() const { - return length; -} - -void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) { - initial_offset = p_initial_offset; - queue_redraw(); -} - -real_t GrooveJoint2D::get_initial_offset() const { - return initial_offset; -} - -void GrooveJoint2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_length", "length"), &GrooveJoint2D::set_length); - ClassDB::bind_method(D_METHOD("get_length"), &GrooveJoint2D::get_length); - ClassDB::bind_method(D_METHOD("set_initial_offset", "offset"), &GrooveJoint2D::set_initial_offset); - ClassDB::bind_method(D_METHOD("get_initial_offset"), &GrooveJoint2D::get_initial_offset); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_initial_offset", "get_initial_offset"); -} - -GrooveJoint2D::GrooveJoint2D() { -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -void DampedSpringJoint2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_DRAW: { - if (!is_inside_tree()) { - break; - } - - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { - break; - } - - draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3); - draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3); - } break; - } -} - -void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { - Transform2D gt = get_global_transform(); - Vector2 anchor_A = gt.get_origin(); - Vector2 anchor_B = gt.xform(Vector2(0, length)); - - PhysicsServer2D::get_singleton()->joint_make_damped_spring(p_joint, anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid()); - if (rest_length) { - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length); - } - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness); - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping); -} - -void DampedSpringJoint2D::set_length(real_t p_length) { - length = p_length; - queue_redraw(); -} - -real_t DampedSpringJoint2D::get_length() const { - return length; -} - -void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) { - rest_length = p_rest_length; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length); - } -} - -real_t DampedSpringJoint2D::get_rest_length() const { - return rest_length; -} - -void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) { - stiffness = p_stiffness; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness); - } -} - -real_t DampedSpringJoint2D::get_stiffness() const { - return stiffness; -} - -void DampedSpringJoint2D::set_damping(real_t p_damping) { - damping = p_damping; - queue_redraw(); - if (is_configured()) { - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping); - } -} - -real_t DampedSpringJoint2D::get_damping() const { - return damping; -} - -void DampedSpringJoint2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_length", "length"), &DampedSpringJoint2D::set_length); - ClassDB::bind_method(D_METHOD("get_length"), &DampedSpringJoint2D::get_length); - ClassDB::bind_method(D_METHOD("set_rest_length", "rest_length"), &DampedSpringJoint2D::set_rest_length); - ClassDB::bind_method(D_METHOD("get_rest_length"), &DampedSpringJoint2D::get_rest_length); - ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &DampedSpringJoint2D::set_stiffness); - ClassDB::bind_method(D_METHOD("get_stiffness"), &DampedSpringJoint2D::get_stiffness); - ClassDB::bind_method(D_METHOD("set_damping", "damping"), &DampedSpringJoint2D::set_damping); - ClassDB::bind_method(D_METHOD("get_damping"), &DampedSpringJoint2D::get_damping); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_RANGE, "0,65535,1,exp,suffix:px"), "set_rest_length", "get_rest_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness", PROPERTY_HINT_RANGE, "0.1,64,0.1,exp"), "set_stiffness", "get_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0.01,16,0.01,exp"), "set_damping", "get_damping"); -} - -DampedSpringJoint2D::DampedSpringJoint2D() { -} diff --git a/scene/2d/joint_2d.h b/scene/2d/joint_2d.h deleted file mode 100644 index 5ff75a77a1..0000000000 --- a/scene/2d/joint_2d.h +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************/ -/* joint_2d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#ifndef JOINT_2D_H -#define JOINT_2D_H - -#include "node_2d.h" - -class PhysicsBody2D; - -class Joint2D : public Node2D { - GDCLASS(Joint2D, Node2D); - - RID joint; - RID ba, bb; - - NodePath a; - NodePath b; - real_t bias = 0.0; - - bool exclude_from_collision = true; - bool configured = false; - String warning; - -protected: - void _disconnect_signals(); - void _body_exit_tree(); - void _update_joint(bool p_only_free = false); - - void _notification(int p_what); - virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0; - - static void _bind_methods(); - - _FORCE_INLINE_ bool is_configured() const { return configured; } - -public: - virtual PackedStringArray get_configuration_warnings() const override; - - void set_node_a(const NodePath &p_node_a); - NodePath get_node_a() const; - - void set_node_b(const NodePath &p_node_b); - NodePath get_node_b() const; - - void set_bias(real_t p_bias); - real_t get_bias() const; - - void set_exclude_nodes_from_collision(bool p_enable); - bool get_exclude_nodes_from_collision() const; - - RID get_rid() const { return joint; } - Joint2D(); - ~Joint2D(); -}; - -class PinJoint2D : public Joint2D { - GDCLASS(PinJoint2D, Joint2D); - - real_t softness = 0.0; - real_t angular_limit_lower = 0.0; - real_t angular_limit_upper = 0.0; - real_t motor_target_velocity = 0.0; - bool motor_enabled = false; - bool angular_limit_enabled = false; - -protected: - void _notification(int p_what); - virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; - static void _bind_methods(); - -public: - void set_softness(real_t p_softness); - real_t get_softness() const; - void set_angular_limit_lower(real_t p_angular_limit_lower); - real_t get_angular_limit_lower() const; - void set_angular_limit_upper(real_t p_angular_limit_upper); - real_t get_angular_limit_upper() const; - void set_motor_target_velocity(real_t p_motor_target_velocity); - real_t get_motor_target_velocity() const; - - void set_motor_enabled(bool p_motor_enabled); - bool is_motor_enabled() const; - void set_angular_limit_enabled(bool p_angular_limit_enabled); - bool is_angular_limit_enabled() const; - - PinJoint2D(); -}; - -class GrooveJoint2D : public Joint2D { - GDCLASS(GrooveJoint2D, Joint2D); - - real_t length = 50.0; - real_t initial_offset = 25.0; - -protected: - void _notification(int p_what); - virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; - static void _bind_methods(); - -public: - void set_length(real_t p_length); - real_t get_length() const; - - void set_initial_offset(real_t p_initial_offset); - real_t get_initial_offset() const; - - GrooveJoint2D(); -}; - -class DampedSpringJoint2D : public Joint2D { - GDCLASS(DampedSpringJoint2D, Joint2D); - - real_t stiffness = 20.0; - real_t damping = 1.0; - real_t rest_length = 0.0; - real_t length = 50.0; - -protected: - void _notification(int p_what); - virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; - static void _bind_methods(); - -public: - void set_length(real_t p_length); - real_t get_length() const; - - void set_rest_length(real_t p_rest_length); - real_t get_rest_length() const; - - void set_damping(real_t p_damping); - real_t get_damping() const; - - void set_stiffness(real_t p_stiffness); - real_t get_stiffness() const; - - DampedSpringJoint2D(); -}; - -#endif // JOINT_2D_H diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 60fb64a8e2..07a3910720 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -81,11 +81,17 @@ void NavigationObstacle2D::_notification(int p_what) { NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); _update_position(get_global_position()); set_physics_process_internal(true); +#ifdef DEBUG_ENABLED + RS::get_singleton()->canvas_item_set_parent(debug_canvas_item, get_world_2d()->get_canvas()); +#endif // DEBUG_ENABLED } break; case NOTIFICATION_EXIT_TREE: { set_physics_process_internal(false); _update_map(RID()); +#ifdef DEBUG_ENABLED + RS::get_singleton()->canvas_item_set_parent(debug_canvas_item, RID()); +#endif // DEBUG_ENABLED } break; case NOTIFICATION_PAUSED: { @@ -110,6 +116,12 @@ void NavigationObstacle2D::_notification(int p_what) { NavigationServer2D::get_singleton()->obstacle_set_paused(obstacle, !can_process()); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { +#ifdef DEBUG_ENABLED + RS::get_singleton()->canvas_item_set_visible(debug_canvas_item, is_visible_in_tree()); +#endif // DEBUG_ENABLED + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (is_inside_tree()) { _update_position(get_global_position()); @@ -136,6 +148,9 @@ void NavigationObstacle2D::_notification(int p_what) { } if (is_debug_enabled) { + RS::get_singleton()->canvas_item_clear(debug_canvas_item); + Transform2D debug_transform = Transform2D(0.0, get_global_position()); + RS::get_singleton()->canvas_item_set_transform(debug_canvas_item, debug_transform); _update_fake_agent_radius_debug(); _update_static_obstacle_debug(); } @@ -152,6 +167,10 @@ NavigationObstacle2D::NavigationObstacle2D() { NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, vertices); NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers); NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); + +#ifdef DEBUG_ENABLED + debug_canvas_item = RenderingServer::get_singleton()->canvas_item_create(); +#endif // DEBUG_ENABLED } NavigationObstacle2D::~NavigationObstacle2D() { @@ -159,6 +178,13 @@ NavigationObstacle2D::~NavigationObstacle2D() { NavigationServer2D::get_singleton()->free(obstacle); obstacle = RID(); + +#ifdef DEBUG_ENABLED + if (debug_canvas_item.is_valid()) { + RenderingServer::get_singleton()->free(debug_canvas_item); + debug_canvas_item = RID(); + } +#endif // DEBUG_ENABLED } void NavigationObstacle2D::set_vertices(const Vector<Vector2> &p_vertices) { @@ -267,7 +293,8 @@ void NavigationObstacle2D::_update_position(const Vector2 p_position) { void NavigationObstacle2D::_update_fake_agent_radius_debug() { if (radius > 0.0 && NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius()) { Color debug_radius_color = NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_obstacles_radius_color(); - RS::get_singleton()->canvas_item_add_circle(get_canvas_item(), Vector2(), radius, debug_radius_color); + + RS::get_singleton()->canvas_item_add_circle(debug_canvas_item, Vector2(), radius, debug_radius_color); } } #endif // DEBUG_ENABLED @@ -291,7 +318,7 @@ void NavigationObstacle2D::_update_static_obstacle_debug() { debug_obstacle_polygon_colors.resize(debug_obstacle_polygon_vertices.size()); debug_obstacle_polygon_colors.fill(debug_static_obstacle_face_color); - RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_obstacle_polygon_vertices, debug_obstacle_polygon_colors); + RS::get_singleton()->canvas_item_add_polygon(debug_canvas_item, debug_obstacle_polygon_vertices, debug_obstacle_polygon_colors); Color debug_static_obstacle_edge_color; @@ -309,7 +336,7 @@ void NavigationObstacle2D::_update_static_obstacle_debug() { debug_obstacle_line_colors.resize(debug_obstacle_line_vertices.size()); debug_obstacle_line_colors.fill(debug_static_obstacle_edge_color); - RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_obstacle_line_vertices, debug_obstacle_line_colors, 4.0); + RS::get_singleton()->canvas_item_add_polyline(debug_canvas_item, debug_obstacle_line_vertices, debug_obstacle_line_colors, 4.0); } } #endif // DEBUG_ENABLED diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index 8e8f6c1146..f9d0e27714 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -56,6 +56,7 @@ class NavigationObstacle2D : public Node2D { #ifdef DEBUG_ENABLED private: + RID debug_canvas_item; void _update_fake_agent_radius_debug(); void _update_static_obstacle_debug(); #endif // DEBUG_ENABLED diff --git a/scene/2d/physics/SCsub b/scene/2d/physics/SCsub new file mode 100644 index 0000000000..e7fd3fe643 --- /dev/null +++ b/scene/2d/physics/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") + +# Chain load SCsubs +SConscript("joints/SCsub") diff --git a/scene/2d/physics/animatable_body_2d.cpp b/scene/2d/physics/animatable_body_2d.cpp new file mode 100644 index 0000000000..10e90e708b --- /dev/null +++ b/scene/2d/physics/animatable_body_2d.cpp @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* animatable_body_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "animatable_body_2d.h" + +void AnimatableBody2D::set_sync_to_physics(bool p_enable) { + if (sync_to_physics == p_enable) { + return; + } + + sync_to_physics = p_enable; + + _update_kinematic_motion(); +} + +bool AnimatableBody2D::is_sync_to_physics_enabled() const { + return sync_to_physics; +} + +void AnimatableBody2D::_update_kinematic_motion() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + if (sync_to_physics) { + PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody2D::_body_state_changed)); + set_only_update_transform_changes(true); + set_notify_local_transform(true); + } else { + PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable()); + set_only_update_transform_changes(false); + set_notify_local_transform(false); + } +} + +void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { + if (!sync_to_physics) { + return; + } + + last_valid_transform = p_state->get_transform(); + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); +} + +void AnimatableBody2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + last_valid_transform = get_global_transform(); + _update_kinematic_motion(); + } break; + + case NOTIFICATION_EXIT_TREE: { + set_only_update_transform_changes(false); + set_notify_local_transform(false); + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + // Used by sync to physics, send the new transform to the physics... + Transform2D new_transform = get_global_transform(); + + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); + + // ... but then revert changes. + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + } break; + } +} + +void AnimatableBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody2D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody2D::is_sync_to_physics_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); +} + +AnimatableBody2D::AnimatableBody2D() : + StaticBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { +} diff --git a/scene/2d/physics/animatable_body_2d.h b/scene/2d/physics/animatable_body_2d.h new file mode 100644 index 0000000000..e510d5cc9c --- /dev/null +++ b/scene/2d/physics/animatable_body_2d.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* animatable_body_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef ANIMATABLE_BODY_2D_H +#define ANIMATABLE_BODY_2D_H + +#include "scene/2d/physics/static_body_2d.h" + +class AnimatableBody2D : public StaticBody2D { + GDCLASS(AnimatableBody2D, StaticBody2D); + +private: + bool sync_to_physics = true; + + Transform2D last_valid_transform; + + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); + void _body_state_changed(PhysicsDirectBodyState2D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + AnimatableBody2D(); + +private: + void _update_kinematic_motion(); + + void set_sync_to_physics(bool p_enable); + bool is_sync_to_physics_enabled() const; +}; + +#endif // ANIMATABLE_BODY_2D_H diff --git a/scene/2d/area_2d.cpp b/scene/2d/physics/area_2d.cpp index b1ff94dda4..b1ff94dda4 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/physics/area_2d.cpp diff --git a/scene/2d/area_2d.h b/scene/2d/physics/area_2d.h index 9d6e04b706..7c59d76e00 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/physics/area_2d.h @@ -32,7 +32,7 @@ #define AREA_2D_H #include "core/templates/vset.h" -#include "scene/2d/collision_object_2d.h" +#include "scene/2d/physics/collision_object_2d.h" class Area2D : public CollisionObject2D { GDCLASS(Area2D, CollisionObject2D); diff --git a/scene/2d/physics/character_body_2d.cpp b/scene/2d/physics/character_body_2d.cpp new file mode 100644 index 0000000000..e5d575a159 --- /dev/null +++ b/scene/2d/physics/character_body_2d.cpp @@ -0,0 +1,755 @@ +/**************************************************************************/ +/* character_body_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "character_body_2d.h" + +// So, if you pass 45 as limit, avoid numerical precision errors when angle is 45. +#define FLOOR_ANGLE_THRESHOLD 0.01 + +bool CharacterBody2D::move_and_slide() { + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + Vector2 current_platform_velocity = platform_velocity; + Transform2D gt = get_global_transform(); + previous_position = gt.columns[2]; + + if ((on_floor || on_wall) && platform_rid.is_valid()) { + bool excluded = false; + if (on_floor) { + excluded = (platform_floor_layers & platform_layer) == 0; + } else if (on_wall) { + excluded = (platform_wall_layers & platform_layer) == 0; + } + if (!excluded) { + //this approach makes sure there is less delay between the actual body velocity and the one we saved + PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid); + if (bs) { + Vector2 local_position = gt.columns[2] - bs->get_transform().columns[2]; + current_platform_velocity = bs->get_velocity_at_local_position(local_position); + } else { + // Body is removed or destroyed, invalidate floor. + current_platform_velocity = Vector2(); + platform_rid = RID(); + } + } else { + current_platform_velocity = Vector2(); + } + } + + motion_results.clear(); + last_motion = Vector2(); + + bool was_on_floor = on_floor; + on_floor = false; + on_ceiling = false; + on_wall = false; + + if (!current_platform_velocity.is_zero_approx()) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.exclude_bodies.insert(platform_rid); + if (platform_object_id.is_valid()) { + parameters.exclude_objects.insert(platform_object_id); + } + + PhysicsServer2D::MotionResult floor_result; + if (move_and_collide(parameters, floor_result, false, false)) { + motion_results.push_back(floor_result); + _set_collision_direction(floor_result); + } + } + + if (motion_mode == MOTION_MODE_GROUNDED) { + _move_and_slide_grounded(delta, was_on_floor); + } else { + _move_and_slide_floating(delta); + } + + // Compute real velocity. + real_velocity = get_position_delta() / delta; + + if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { + // Add last platform velocity when just left a moving platform. + if (!on_floor && !on_wall) { + if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { + current_platform_velocity = current_platform_velocity.slide(up_direction); + } + velocity += current_platform_velocity; + } + } + + return motion_results.size() > 0; +} + +void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { + Vector2 motion = velocity * p_delta; + Vector2 motion_slide_up = motion.slide(up_direction); + + Vector2 prev_floor_normal = floor_normal; + + platform_rid = RID(); + platform_object_id = ObjectID(); + floor_normal = Vector2(); + platform_velocity = Vector2(); + + // No sliding on first attempt to keep floor motion stable when possible, + // When stop on slope is enabled or when there is no up direction. + bool sliding_enabled = !floor_stop_on_slope; + // Constant speed can be applied only the first time sliding is enabled. + bool can_apply_constant_speed = sliding_enabled; + // If the platform's ceiling push down the body. + bool apply_ceiling_velocity = false; + bool first_slide = true; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; + Vector2 last_travel; + + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + + Vector2 prev_position = parameters.from.columns[2]; + + PhysicsServer2D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, !sliding_enabled); + + last_motion = result.travel; + + if (collided) { + motion_results.push_back(result); + _set_collision_direction(result); + + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. + if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { + // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. + if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { + apply_ceiling_velocity = true; + Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); + Vector2 motion_vertical_velocity = up_direction * up_direction.dot(velocity); + if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); + } + } + } + + if (on_floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { + Transform2D gt = get_global_transform(); + if (result.travel.length() <= margin + CMP_EPSILON) { + gt.columns[2] -= result.travel; + } + set_global_transform(gt); + velocity = Vector2(); + last_motion = Vector2(); + motion = Vector2(); + break; + } + + if (result.remainder.is_zero_approx()) { + motion = Vector2(); + break; + } + + // Move on floor only checks. + if (floor_block_on_wall && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) { + // Avoid to move forward on a wall if floor_block_on_wall is true. + if (p_was_on_floor && !on_floor && !vel_dir_facing_up) { + // If the movement is large the body can be prevented from reaching the walls. + if (result.travel.length() <= margin + CMP_EPSILON) { + // Cancels the motion. + Transform2D gt = get_global_transform(); + gt.columns[2] -= result.travel; + set_global_transform(gt); + } + // Determines if you are on the ground. + _snap_on_floor(true, false, true); + velocity = Vector2(); + last_motion = Vector2(); + motion = Vector2(); + break; + } + // Prevents the body from being able to climb a slope when it moves forward against the wall. + else if (!on_floor) { + motion = up_direction * up_direction.dot(result.remainder); + motion = motion.slide(result.collision_normal); + } else { + motion = result.remainder; + } + } + // Constant Speed when the slope is upward. + else if (floor_constant_speed && is_on_floor_only() && can_apply_constant_speed && p_was_on_floor && motion.dot(result.collision_normal) < 0) { + can_apply_constant_speed = false; + Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); + motion = motion_slide_norm * (motion_slide_up.length() - result.travel.slide(up_direction).length() - last_travel.slide(up_direction).length()); + } + // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. + else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { + Vector2 slide_motion = result.remainder.slide(result.collision_normal); + if (slide_motion.dot(velocity) > 0.0) { + motion = slide_motion; + } else { + motion = Vector2(); + } + if (slide_on_ceiling && on_ceiling) { + // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. + if (vel_dir_facing_up) { + velocity = velocity.slide(result.collision_normal); + } else { + // Avoid acceleration in slope when falling. + velocity = up_direction * up_direction.dot(velocity); + } + } + } + // No sliding on first attempt to keep floor motion stable when possible. + else { + motion = result.remainder; + if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { + velocity = velocity.slide(up_direction); + motion = motion.slide(up_direction); + } + } + + last_travel = result.travel; + } + // When you move forward in a downward slope you don’t collide because you will be in the air. + // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied. + else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) { + can_apply_constant_speed = false; + sliding_enabled = true; + Transform2D gt = get_global_transform(); + gt.columns[2] = prev_position; + set_global_transform(gt); + + Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized(); + motion = motion_slide_norm * (motion_slide_up.length()); + collided = true; + } + + can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled; + sliding_enabled = true; + first_slide = false; + + if (!collided || motion.is_zero_approx()) { + break; + } + } + + _snap_on_floor(p_was_on_floor, vel_dir_facing_up); + + // Scales the horizontal velocity according to the wall slope. + if (is_on_wall_only() && motion_slide_up.dot(motion_results.get(0).collision_normal) < 0) { + Vector2 slide_motion = velocity.slide(motion_results.get(0).collision_normal); + if (motion_slide_up.dot(slide_motion) < 0) { + velocity = up_direction * up_direction.dot(velocity); + } else { + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); + } + } + + // Reset the gravity accumulation when touching the ground. + if (on_floor && !vel_dir_facing_up) { + velocity = velocity.slide(up_direction); + } +} + +void CharacterBody2D::_move_and_slide_floating(double p_delta) { + Vector2 motion = velocity * p_delta; + + platform_rid = RID(); + platform_object_id = ObjectID(); + floor_normal = Vector2(); + platform_velocity = Vector2(); + + bool first_slide = true; + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + + PhysicsServer2D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, false); + + last_motion = result.travel; + + if (collided) { + motion_results.push_back(result); + _set_collision_direction(result); + + if (result.remainder.is_zero_approx()) { + motion = Vector2(); + break; + } + + if (wall_min_slide_angle != 0 && result.get_angle(-velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + motion = Vector2(); + } else if (first_slide) { + Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); + motion = motion_slide_norm * (motion.length() - result.travel.length()); + } else { + motion = result.remainder.slide(result.collision_normal); + } + + if (motion.dot(velocity) <= 0.0) { + motion = Vector2(); + } + } + + if (!collided || motion.is_zero_approx()) { + break; + } + + first_slide = false; + } +} +void CharacterBody2D::apply_floor_snap() { + _apply_floor_snap(); +} + +// Method that avoids the p_wall_as_floor parameter for the public method. +void CharacterBody2D::_apply_floor_snap(bool p_wall_as_floor) { + if (on_floor) { + return; + } + + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + + PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.collide_separation_ray = true; + + PhysicsServer2D::MotionResult result; + if (move_and_collide(parameters, result, true, false)) { + if ((result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) || + (p_wall_as_floor && result.get_angle(-up_direction) > floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { + on_floor = true; + floor_normal = result.collision_normal; + _set_platform_data(result); + + if (floor_stop_on_slope) { + // move and collide may stray the object a bit because of pre un-stucking, + // so only ensure that motion happens on floor direction in this case. + if (result.travel.length() > margin) { + result.travel = up_direction * up_direction.dot(result.travel); + } else { + result.travel = Vector2(); + } + } + + parameters.from.columns[2] += result.travel; + set_global_transform(parameters.from); + } + } +} + +void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor) { + if (on_floor || !p_was_on_floor || p_vel_dir_facing_up) { + return; + } + + _apply_floor_snap(p_wall_as_floor); +} + +bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) { + if (up_direction == Vector2() || on_floor || !p_was_on_floor || p_vel_dir_facing_up) { + return false; + } + + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + + PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.collide_separation_ray = true; + + PhysicsServer2D::MotionResult result; + if (move_and_collide(parameters, result, true, false)) { + if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + return true; + } + } + + return false; +} + +void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) { + if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + on_floor = true; + floor_normal = p_result.collision_normal; + _set_platform_data(p_result); + } else if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + on_ceiling = true; + } else { + on_wall = true; + wall_normal = p_result.collision_normal; + // Don't apply wall velocity when the collider is a CharacterBody2D. + if (Object::cast_to<CharacterBody2D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) { + _set_platform_data(p_result); + } + } +} + +void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) { + platform_rid = p_result.collider; + platform_object_id = p_result.collider_id; + platform_velocity = p_result.collider_velocity; + platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); +} + +const Vector2 &CharacterBody2D::get_velocity() const { + return velocity; +} + +void CharacterBody2D::set_velocity(const Vector2 &p_velocity) { + velocity = p_velocity; +} + +bool CharacterBody2D::is_on_floor() const { + return on_floor; +} + +bool CharacterBody2D::is_on_floor_only() const { + return on_floor && !on_wall && !on_ceiling; +} + +bool CharacterBody2D::is_on_wall() const { + return on_wall; +} + +bool CharacterBody2D::is_on_wall_only() const { + return on_wall && !on_floor && !on_ceiling; +} + +bool CharacterBody2D::is_on_ceiling() const { + return on_ceiling; +} + +bool CharacterBody2D::is_on_ceiling_only() const { + return on_ceiling && !on_floor && !on_wall; +} + +const Vector2 &CharacterBody2D::get_floor_normal() const { + return floor_normal; +} + +const Vector2 &CharacterBody2D::get_wall_normal() const { + return wall_normal; +} + +const Vector2 &CharacterBody2D::get_last_motion() const { + return last_motion; +} + +Vector2 CharacterBody2D::get_position_delta() const { + return get_global_transform().columns[2] - previous_position; +} + +const Vector2 &CharacterBody2D::get_real_velocity() const { + return real_velocity; +} + +real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); + return Math::acos(floor_normal.dot(p_up_direction)); +} + +const Vector2 &CharacterBody2D::get_platform_velocity() const { + return platform_velocity; +} + +int CharacterBody2D::get_slide_collision_count() const { + return motion_results.size(); +} + +PhysicsServer2D::MotionResult CharacterBody2D::get_slide_collision(int p_bounce) const { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer2D::MotionResult()); + return motion_results[p_bounce]; +} + +Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision2D>()); + if (p_bounce >= slide_colliders.size()) { + slide_colliders.resize(p_bounce + 1); + } + + // Create a new instance when the cached reference is invalid or still in use in script. + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { + slide_colliders.write[p_bounce].instantiate(); + slide_colliders.write[p_bounce]->owner = this; + } + + slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; + return slide_colliders[p_bounce]; +} + +Ref<KinematicCollision2D> CharacterBody2D::_get_last_slide_collision() { + if (motion_results.size() == 0) { + return Ref<KinematicCollision2D>(); + } + return _get_slide_collision(motion_results.size() - 1); +} + +void CharacterBody2D::set_safe_margin(real_t p_margin) { + margin = p_margin; +} + +real_t CharacterBody2D::get_safe_margin() const { + return margin; +} + +bool CharacterBody2D::is_floor_stop_on_slope_enabled() const { + return floor_stop_on_slope; +} + +void CharacterBody2D::set_floor_stop_on_slope_enabled(bool p_enabled) { + floor_stop_on_slope = p_enabled; +} + +bool CharacterBody2D::is_floor_constant_speed_enabled() const { + return floor_constant_speed; +} + +void CharacterBody2D::set_floor_constant_speed_enabled(bool p_enabled) { + floor_constant_speed = p_enabled; +} + +bool CharacterBody2D::is_floor_block_on_wall_enabled() const { + return floor_block_on_wall; +} + +void CharacterBody2D::set_floor_block_on_wall_enabled(bool p_enabled) { + floor_block_on_wall = p_enabled; +} + +bool CharacterBody2D::is_slide_on_ceiling_enabled() const { + return slide_on_ceiling; +} + +void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) { + slide_on_ceiling = p_enabled; +} + +uint32_t CharacterBody2D::get_platform_floor_layers() const { + return platform_floor_layers; +} + +void CharacterBody2D::set_platform_floor_layers(uint32_t p_exclude_layers) { + platform_floor_layers = p_exclude_layers; +} + +uint32_t CharacterBody2D::get_platform_wall_layers() const { + return platform_wall_layers; +} + +void CharacterBody2D::set_platform_wall_layers(uint32_t p_exclude_layers) { + platform_wall_layers = p_exclude_layers; +} + +void CharacterBody2D::set_motion_mode(MotionMode p_mode) { + motion_mode = p_mode; +} + +CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const { + return motion_mode; +} + +void CharacterBody2D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { + platform_on_leave = p_on_leave_apply_velocity; +} + +CharacterBody2D::PlatformOnLeave CharacterBody2D::get_platform_on_leave() const { + return platform_on_leave; +} + +int CharacterBody2D::get_max_slides() const { + return max_slides; +} + +void CharacterBody2D::set_max_slides(int p_max_slides) { + ERR_FAIL_COND(p_max_slides < 1); + max_slides = p_max_slides; +} + +real_t CharacterBody2D::get_floor_max_angle() const { + return floor_max_angle; +} + +void CharacterBody2D::set_floor_max_angle(real_t p_radians) { + floor_max_angle = p_radians; +} + +real_t CharacterBody2D::get_floor_snap_length() { + return floor_snap_length; +} + +void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) { + ERR_FAIL_COND(p_floor_snap_length < 0); + floor_snap_length = p_floor_snap_length; +} + +real_t CharacterBody2D::get_wall_min_slide_angle() const { + return wall_min_slide_angle; +} + +void CharacterBody2D::set_wall_min_slide_angle(real_t p_radians) { + wall_min_slide_angle = p_radians; +} + +const Vector2 &CharacterBody2D::get_up_direction() const { + return up_direction; +} + +void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { + ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Floating motion mode instead."); + up_direction = p_up_direction.normalized(); +} + +void CharacterBody2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + // Reset move_and_slide() data. + on_floor = false; + platform_rid = RID(); + platform_object_id = ObjectID(); + on_ceiling = false; + on_wall = false; + motion_results.clear(); + platform_velocity = Vector2(); + } break; + } +} + +void CharacterBody2D::_validate_property(PropertyInfo &p_property) const { + if (motion_mode == MOTION_MODE_FLOATING) { + if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } else { + if (p_property.name == "wall_min_slide_angle") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } +} + +void CharacterBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); + ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody2D::apply_floor_snap); + + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); + + ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody2D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); + ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody2D::set_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody2D::is_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody2D::set_floor_block_on_wall_enabled); + ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody2D::is_floor_block_on_wall_enabled); + ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled); + ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled); + + ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_platform_floor_layers); + ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody2D::get_platform_floor_layers); + ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_platform_wall_layers); + ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody2D::get_platform_wall_layers); + + ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides); + ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides); + ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle); + ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); + ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length); + ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length); + ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody2D::get_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody2D::set_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); + ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); + ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); + ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode); + ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_platform_on_leave); + ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody2D::get_platform_on_leave); + + ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody2D::is_on_ceiling_only); + ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall); + ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody2D::is_on_wall_only); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody2D::get_wall_normal); + ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody2D::get_last_motion); + ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody2D::get_position_delta); + ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody2D::get_real_velocity); + ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody2D::get_floor_angle, DEFVAL(Vector2(0.0, -1.0))); + ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody2D::get_platform_velocity); + ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count); + ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); + ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); + + ADD_GROUP("Floor", "floor_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees"), "set_floor_max_angle", "get_floor_max_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length"); + + ADD_GROUP("Moving Platform", "platform_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); + + ADD_GROUP("Collision", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin"); + + BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); + BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); + + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); +} + +CharacterBody2D::CharacterBody2D() : + PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { +} + +CharacterBody2D::~CharacterBody2D() { + for (int i = 0; i < slide_colliders.size(); i++) { + if (slide_colliders[i].is_valid()) { + slide_colliders.write[i]->owner = nullptr; + } + } +} diff --git a/scene/2d/physics/character_body_2d.h b/scene/2d/physics/character_body_2d.h new file mode 100644 index 0000000000..395438a1f1 --- /dev/null +++ b/scene/2d/physics/character_body_2d.h @@ -0,0 +1,173 @@ +/**************************************************************************/ +/* character_body_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef CHARACTER_BODY_2D_H +#define CHARACTER_BODY_2D_H + +#include "scene/2d/physics/kinematic_collision_2d.h" +#include "scene/2d/physics/physics_body_2d.h" + +class CharacterBody2D : public PhysicsBody2D { + GDCLASS(CharacterBody2D, PhysicsBody2D); + +public: + enum MotionMode { + MOTION_MODE_GROUNDED, + MOTION_MODE_FLOATING, + }; + enum PlatformOnLeave { + PLATFORM_ON_LEAVE_ADD_VELOCITY, + PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, + PLATFORM_ON_LEAVE_DO_NOTHING, + }; + bool move_and_slide(); + void apply_floor_snap(); + + const Vector2 &get_velocity() const; + void set_velocity(const Vector2 &p_velocity); + + bool is_on_floor() const; + bool is_on_floor_only() const; + bool is_on_wall() const; + bool is_on_wall_only() const; + bool is_on_ceiling() const; + bool is_on_ceiling_only() const; + const Vector2 &get_last_motion() const; + Vector2 get_position_delta() const; + const Vector2 &get_floor_normal() const; + const Vector2 &get_wall_normal() const; + const Vector2 &get_real_velocity() const; + + real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; + const Vector2 &get_platform_velocity() const; + + int get_slide_collision_count() const; + PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const; + + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; + + bool is_floor_stop_on_slope_enabled() const; + void set_floor_stop_on_slope_enabled(bool p_enabled); + + bool is_floor_constant_speed_enabled() const; + void set_floor_constant_speed_enabled(bool p_enabled); + + bool is_floor_block_on_wall_enabled() const; + void set_floor_block_on_wall_enabled(bool p_enabled); + + bool is_slide_on_ceiling_enabled() const; + void set_slide_on_ceiling_enabled(bool p_enabled); + + int get_max_slides() const; + void set_max_slides(int p_max_slides); + + real_t get_floor_max_angle() const; + void set_floor_max_angle(real_t p_radians); + + real_t get_floor_snap_length(); + void set_floor_snap_length(real_t p_floor_snap_length); + + real_t get_wall_min_slide_angle() const; + void set_wall_min_slide_angle(real_t p_radians); + + uint32_t get_platform_floor_layers() const; + void set_platform_floor_layers(const uint32_t p_exclude_layer); + + uint32_t get_platform_wall_layers() const; + void set_platform_wall_layers(const uint32_t p_exclude_layer); + + void set_motion_mode(MotionMode p_mode); + MotionMode get_motion_mode() const; + + void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); + PlatformOnLeave get_platform_on_leave() const; + + CharacterBody2D(); + ~CharacterBody2D(); + +private: + real_t margin = 0.08; + MotionMode motion_mode = MOTION_MODE_GROUNDED; + PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; + + bool floor_constant_speed = false; + bool floor_stop_on_slope = true; + bool floor_block_on_wall = true; + bool slide_on_ceiling = true; + int max_slides = 4; + int platform_layer = 0; + real_t floor_max_angle = Math::deg_to_rad((real_t)45.0); + real_t floor_snap_length = 1; + real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0); + Vector2 up_direction = Vector2(0.0, -1.0); + uint32_t platform_floor_layers = UINT32_MAX; + uint32_t platform_wall_layers = 0; + Vector2 velocity; + + Vector2 floor_normal; + Vector2 platform_velocity; + Vector2 wall_normal; + Vector2 last_motion; + Vector2 previous_position; + Vector2 real_velocity; + + RID platform_rid; + ObjectID platform_object_id; + bool on_floor = false; + bool on_ceiling = false; + bool on_wall = false; + + Vector<PhysicsServer2D::MotionResult> motion_results; + Vector<Ref<KinematicCollision2D>> slide_colliders; + + void _move_and_slide_floating(double p_delta); + void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); + + Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); + Ref<KinematicCollision2D> _get_last_slide_collision(); + const Vector2 &get_up_direction() const; + bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up); + void set_up_direction(const Vector2 &p_up_direction); + void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result); + void _set_platform_data(const PhysicsServer2D::MotionResult &p_result); + void _apply_floor_snap(bool p_wall_as_floor = false); + void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor = false); + +protected: + void _notification(int p_what); + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; +}; + +VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); +VARIANT_ENUM_CAST(CharacterBody2D::PlatformOnLeave); + +#endif // CHARACTER_BODY_2D_H diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/physics/collision_object_2d.cpp index 4e5852984b..4e5852984b 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/physics/collision_object_2d.cpp diff --git a/scene/2d/collision_object_2d.h b/scene/2d/physics/collision_object_2d.h index 2c8534665c..2c8534665c 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/physics/collision_object_2d.h diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/physics/collision_polygon_2d.cpp index 3bc5bce8f0..96ef346d23 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/physics/collision_polygon_2d.cpp @@ -30,9 +30,9 @@ #include "collision_polygon_2d.h" -#include "collision_object_2d.h" #include "core/math/geometry_2d.h" -#include "scene/2d/area_2d.h" +#include "scene/2d/physics/area_2d.h" +#include "scene/2d/physics/collision_object_2d.h" #include "scene/resources/2d/concave_polygon_shape_2d.h" #include "scene/resources/2d/convex_polygon_shape_2d.h" diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/physics/collision_polygon_2d.h index f1ee30babe..f1ee30babe 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/physics/collision_polygon_2d.h diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/physics/collision_shape_2d.cpp index 5539e49135..6fc29ffe63 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/physics/collision_shape_2d.cpp @@ -30,8 +30,8 @@ #include "collision_shape_2d.h" -#include "collision_object_2d.h" -#include "scene/2d/area_2d.h" +#include "scene/2d/physics/area_2d.h" +#include "scene/2d/physics/collision_object_2d.h" #include "scene/resources/2d/concave_polygon_shape_2d.h" #include "scene/resources/2d/convex_polygon_shape_2d.h" diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/physics/collision_shape_2d.h index 65436f1539..65436f1539 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/physics/collision_shape_2d.h diff --git a/scene/2d/physics/joints/SCsub b/scene/2d/physics/joints/SCsub new file mode 100644 index 0000000000..fc61250247 --- /dev/null +++ b/scene/2d/physics/joints/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/2d/physics/joints/damped_spring_joint_2d.cpp b/scene/2d/physics/joints/damped_spring_joint_2d.cpp new file mode 100644 index 0000000000..4b210ec0c7 --- /dev/null +++ b/scene/2d/physics/joints/damped_spring_joint_2d.cpp @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* damped_spring_joint_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "damped_spring_joint_2d.h" + +#include "scene/2d/physics/physics_body_2d.h" + +void DampedSpringJoint2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + if (!is_inside_tree()) { + break; + } + + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { + break; + } + + draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3); + } break; + } +} + +void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { + Transform2D gt = get_global_transform(); + Vector2 anchor_A = gt.get_origin(); + Vector2 anchor_B = gt.xform(Vector2(0, length)); + + PhysicsServer2D::get_singleton()->joint_make_damped_spring(p_joint, anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid()); + if (rest_length) { + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length); + } + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness); + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping); +} + +void DampedSpringJoint2D::set_length(real_t p_length) { + length = p_length; + queue_redraw(); +} + +real_t DampedSpringJoint2D::get_length() const { + return length; +} + +void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) { + rest_length = p_rest_length; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length); + } +} + +real_t DampedSpringJoint2D::get_rest_length() const { + return rest_length; +} + +void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) { + stiffness = p_stiffness; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness); + } +} + +real_t DampedSpringJoint2D::get_stiffness() const { + return stiffness; +} + +void DampedSpringJoint2D::set_damping(real_t p_damping) { + damping = p_damping; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping); + } +} + +real_t DampedSpringJoint2D::get_damping() const { + return damping; +} + +void DampedSpringJoint2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_length", "length"), &DampedSpringJoint2D::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &DampedSpringJoint2D::get_length); + ClassDB::bind_method(D_METHOD("set_rest_length", "rest_length"), &DampedSpringJoint2D::set_rest_length); + ClassDB::bind_method(D_METHOD("get_rest_length"), &DampedSpringJoint2D::get_rest_length); + ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &DampedSpringJoint2D::set_stiffness); + ClassDB::bind_method(D_METHOD("get_stiffness"), &DampedSpringJoint2D::get_stiffness); + ClassDB::bind_method(D_METHOD("set_damping", "damping"), &DampedSpringJoint2D::set_damping); + ClassDB::bind_method(D_METHOD("get_damping"), &DampedSpringJoint2D::get_damping); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_RANGE, "0,65535,1,exp,suffix:px"), "set_rest_length", "get_rest_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness", PROPERTY_HINT_RANGE, "0.1,64,0.1,exp"), "set_stiffness", "get_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0.01,16,0.01,exp"), "set_damping", "get_damping"); +} + +DampedSpringJoint2D::DampedSpringJoint2D() { +} diff --git a/scene/2d/physics/joints/damped_spring_joint_2d.h b/scene/2d/physics/joints/damped_spring_joint_2d.h new file mode 100644 index 0000000000..de9fda80b9 --- /dev/null +++ b/scene/2d/physics/joints/damped_spring_joint_2d.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* damped_spring_joint_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef DAMPED_SPRING_JOINT_2D_H +#define DAMPED_SPRING_JOINT_2D_H + +#include "scene/2d/physics/joints/joint_2d.h" + +class PhysicsBody2D; + +class DampedSpringJoint2D : public Joint2D { + GDCLASS(DampedSpringJoint2D, Joint2D); + + real_t stiffness = 20.0; + real_t damping = 1.0; + real_t rest_length = 0.0; + real_t length = 50.0; + +protected: + void _notification(int p_what); + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + static void _bind_methods(); + +public: + void set_length(real_t p_length); + real_t get_length() const; + + void set_rest_length(real_t p_rest_length); + real_t get_rest_length() const; + + void set_damping(real_t p_damping); + real_t get_damping() const; + + void set_stiffness(real_t p_stiffness); + real_t get_stiffness() const; + + DampedSpringJoint2D(); +}; + +#endif // DAMPED_SPRING_JOINT_2D_H diff --git a/scene/2d/physics/joints/groove_joint_2d.cpp b/scene/2d/physics/joints/groove_joint_2d.cpp new file mode 100644 index 0000000000..415a49d8bd --- /dev/null +++ b/scene/2d/physics/joints/groove_joint_2d.cpp @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* groove_joint_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "groove_joint_2d.h" + +#include "scene/2d/physics/physics_body_2d.h" + +void GrooveJoint2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + if (!is_inside_tree()) { + break; + } + + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { + break; + } + + draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(-10, length), Point2(+10, length), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(0, 0), Point2(0, length), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(-10, initial_offset), Point2(+10, initial_offset), Color(0.8, 0.8, 0.9, 0.5), 5); + } break; + } +} + +void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { + Transform2D gt = get_global_transform(); + Vector2 groove_A1 = gt.get_origin(); + Vector2 groove_A2 = gt.xform(Vector2(0, length)); + Vector2 anchor_B = gt.xform(Vector2(0, initial_offset)); + + PhysicsServer2D::get_singleton()->joint_make_groove(p_joint, groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid()); +} + +void GrooveJoint2D::set_length(real_t p_length) { + length = p_length; + queue_redraw(); +} + +real_t GrooveJoint2D::get_length() const { + return length; +} + +void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) { + initial_offset = p_initial_offset; + queue_redraw(); +} + +real_t GrooveJoint2D::get_initial_offset() const { + return initial_offset; +} + +void GrooveJoint2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_length", "length"), &GrooveJoint2D::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &GrooveJoint2D::get_length); + ClassDB::bind_method(D_METHOD("set_initial_offset", "offset"), &GrooveJoint2D::set_initial_offset); + ClassDB::bind_method(D_METHOD("get_initial_offset"), &GrooveJoint2D::get_initial_offset); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_initial_offset", "get_initial_offset"); +} + +GrooveJoint2D::GrooveJoint2D() { +} diff --git a/scene/2d/physics/joints/groove_joint_2d.h b/scene/2d/physics/joints/groove_joint_2d.h new file mode 100644 index 0000000000..b04692fbff --- /dev/null +++ b/scene/2d/physics/joints/groove_joint_2d.h @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* groove_joint_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef GROOVE_JOINT_2D_H +#define GROOVE_JOINT_2D_H + +#include "scene/2d/physics/joints/joint_2d.h" + +class PhysicsBody2D; + +class GrooveJoint2D : public Joint2D { + GDCLASS(GrooveJoint2D, Joint2D); + + real_t length = 50.0; + real_t initial_offset = 25.0; + +protected: + void _notification(int p_what); + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + static void _bind_methods(); + +public: + void set_length(real_t p_length); + real_t get_length() const; + + void set_initial_offset(real_t p_initial_offset); + real_t get_initial_offset() const; + + GrooveJoint2D(); +}; + +#endif // GROOVE_JOINT_2D_H diff --git a/scene/2d/physics/joints/joint_2d.cpp b/scene/2d/physics/joints/joint_2d.cpp new file mode 100644 index 0000000000..dd1697a29c --- /dev/null +++ b/scene/2d/physics/joints/joint_2d.cpp @@ -0,0 +1,254 @@ +/**************************************************************************/ +/* joint_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "joint_2d.h" + +#include "scene/2d/physics/physics_body_2d.h" +#include "scene/scene_string_names.h" + +void Joint2D::_disconnect_signals() { + Node *node_a = get_node_or_null(a); + PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); + if (body_a) { + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + } + + Node *node_b = get_node_or_null(b); + PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); + if (body_b) { + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + } +} + +void Joint2D::_body_exit_tree() { + _disconnect_signals(); + _update_joint(true); + update_configuration_warnings(); +} + +void Joint2D::_update_joint(bool p_only_free) { + if (ba.is_valid() && bb.is_valid() && exclude_from_collision) { + PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false); + } + + ba = RID(); + bb = RID(); + configured = false; + + if (p_only_free || !is_inside_tree()) { + PhysicsServer2D::get_singleton()->joint_clear(joint); + warning = String(); + return; + } + + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); + + PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); + PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); + + bool valid = false; + + if (node_a && !body_a && node_b && !body_b) { + warning = RTR("Node A and Node B must be PhysicsBody2Ds"); + } else if (node_a && !body_a) { + warning = RTR("Node A must be a PhysicsBody2D"); + } else if (node_b && !body_b) { + warning = RTR("Node B must be a PhysicsBody2D"); + } else if (!body_a || !body_b) { + warning = RTR("Joint is not connected to two PhysicsBody2Ds"); + } else if (body_a == body_b) { + warning = RTR("Node A and Node B must be different PhysicsBody2Ds"); + } else { + warning = String(); + valid = true; + } + + update_configuration_warnings(); + + if (!valid) { + PhysicsServer2D::get_singleton()->joint_clear(joint); + return; + } + + if (body_a) { + body_a->force_update_transform(); + } + + if (body_b) { + body_b->force_update_transform(); + } + + configured = true; + + _configure_joint(joint, body_a, body_b); + + ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint."); + + PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); + + ba = body_a->get_rid(); + bb = body_b->get_rid(); + + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + + PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); +} + +void Joint2D::set_node_a(const NodePath &p_node_a) { + if (a == p_node_a) { + return; + } + + if (is_configured()) { + _disconnect_signals(); + } + + a = p_node_a; + if (Engine::get_singleton()->is_editor_hint()) { + // When in editor, the setter may be called as a result of node rename. + // It happens before the node actually changes its name, which triggers false warning. + callable_mp(this, &Joint2D::_update_joint).call_deferred(); + } else { + _update_joint(); + } +} + +NodePath Joint2D::get_node_a() const { + return a; +} + +void Joint2D::set_node_b(const NodePath &p_node_b) { + if (b == p_node_b) { + return; + } + + if (is_configured()) { + _disconnect_signals(); + } + + b = p_node_b; + if (Engine::get_singleton()->is_editor_hint()) { + callable_mp(this, &Joint2D::_update_joint).call_deferred(); + } else { + _update_joint(); + } +} + +NodePath Joint2D::get_node_b() const { + return b; +} + +void Joint2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POST_ENTER_TREE: { + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(); + } break; + + case NOTIFICATION_EXIT_TREE: { + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(true); + } break; + } +} + +void Joint2D::set_bias(real_t p_bias) { + bias = p_bias; + if (joint.is_valid()) { + PhysicsServer2D::get_singleton()->joint_set_param(joint, PhysicsServer2D::JOINT_PARAM_BIAS, bias); + } +} + +real_t Joint2D::get_bias() const { + return bias; +} + +void Joint2D::set_exclude_nodes_from_collision(bool p_enable) { + if (exclude_from_collision == p_enable) { + return; + } + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(true); + exclude_from_collision = p_enable; + _update_joint(); +} + +bool Joint2D::get_exclude_nodes_from_collision() const { + return exclude_from_collision; +} + +PackedStringArray Joint2D::get_configuration_warnings() const { + PackedStringArray warnings = Node2D::get_configuration_warnings(); + + if (!warning.is_empty()) { + warnings.push_back(warning); + } + + return warnings; +} + +void Joint2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint2D::set_node_a); + ClassDB::bind_method(D_METHOD("get_node_a"), &Joint2D::get_node_a); + + ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint2D::set_node_b); + ClassDB::bind_method(D_METHOD("get_node_b"), &Joint2D::get_node_b); + + ClassDB::bind_method(D_METHOD("set_bias", "bias"), &Joint2D::set_bias); + ClassDB::bind_method(D_METHOD("get_bias"), &Joint2D::get_bias); + + ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision); + ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision); + + ClassDB::bind_method(D_METHOD("get_rid"), &Joint2D::get_rid); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), "set_bias", "get_bias"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); +} + +Joint2D::Joint2D() { + joint = PhysicsServer2D::get_singleton()->joint_create(); + set_hide_clip_children(true); +} + +Joint2D::~Joint2D() { + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); + PhysicsServer2D::get_singleton()->free(joint); +} diff --git a/scene/2d/physics/joints/joint_2d.h b/scene/2d/physics/joints/joint_2d.h new file mode 100644 index 0000000000..bdd2730bfa --- /dev/null +++ b/scene/2d/physics/joints/joint_2d.h @@ -0,0 +1,84 @@ +/**************************************************************************/ +/* joint_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef JOINT_2D_H +#define JOINT_2D_H + +#include "scene/2d/node_2d.h" + +class PhysicsBody2D; + +class Joint2D : public Node2D { + GDCLASS(Joint2D, Node2D); + + RID joint; + RID ba, bb; + + NodePath a; + NodePath b; + real_t bias = 0.0; + + bool exclude_from_collision = true; + bool configured = false; + String warning; + +protected: + void _disconnect_signals(); + void _body_exit_tree(); + void _update_joint(bool p_only_free = false); + + void _notification(int p_what); + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0; + + static void _bind_methods(); + + _FORCE_INLINE_ bool is_configured() const { return configured; } + +public: + virtual PackedStringArray get_configuration_warnings() const override; + + void set_node_a(const NodePath &p_node_a); + NodePath get_node_a() const; + + void set_node_b(const NodePath &p_node_b); + NodePath get_node_b() const; + + void set_bias(real_t p_bias); + real_t get_bias() const; + + void set_exclude_nodes_from_collision(bool p_enable); + bool get_exclude_nodes_from_collision() const; + + RID get_rid() const { return joint; } + Joint2D(); + ~Joint2D(); +}; + +#endif // JOINT_2D_H diff --git a/scene/2d/physics/joints/pin_joint_2d.cpp b/scene/2d/physics/joints/pin_joint_2d.cpp new file mode 100644 index 0000000000..6ff0c485f5 --- /dev/null +++ b/scene/2d/physics/joints/pin_joint_2d.cpp @@ -0,0 +1,177 @@ +/**************************************************************************/ +/* pin_joint_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "pin_joint_2d.h" + +#include "scene/2d/physics/physics_body_2d.h" + +void PinJoint2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + if (!is_inside_tree()) { + break; + } + + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { + break; + } + + draw_line(Point2(-10, 0), Point2(+10, 0), Color(0.7, 0.6, 0.0, 0.5), 3); + draw_line(Point2(0, -10), Point2(0, +10), Color(0.7, 0.6, 0.0, 0.5), 3); + } break; + } +} + +void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { + PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_position(), body_a->get_rid(), body_b ? body_b->get_rid() : RID()); + PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness); + PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_LIMIT_UPPER, angular_limit_upper); + PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_LIMIT_LOWER, angular_limit_lower); + PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_MOTOR_TARGET_VELOCITY, motor_target_velocity); + PhysicsServer2D::get_singleton()->pin_joint_set_flag(p_joint, PhysicsServer2D::PIN_JOINT_FLAG_MOTOR_ENABLED, motor_enabled); + PhysicsServer2D::get_singleton()->pin_joint_set_flag(p_joint, PhysicsServer2D::PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED, angular_limit_enabled); +} + +void PinJoint2D::set_softness(real_t p_softness) { + if (softness == p_softness) { + return; + } + softness = p_softness; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness); + } +} + +real_t PinJoint2D::get_softness() const { + return softness; +} + +void PinJoint2D::set_angular_limit_lower(real_t p_angular_limit_lower) { + if (angular_limit_lower == p_angular_limit_lower) { + return; + } + angular_limit_lower = p_angular_limit_lower; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_LIMIT_LOWER, p_angular_limit_lower); + } +} + +real_t PinJoint2D::get_angular_limit_lower() const { + return angular_limit_lower; +} + +void PinJoint2D::set_angular_limit_upper(real_t p_angular_limit_upper) { + if (angular_limit_upper == p_angular_limit_upper) { + return; + } + angular_limit_upper = p_angular_limit_upper; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_LIMIT_UPPER, p_angular_limit_upper); + } +} + +real_t PinJoint2D::get_angular_limit_upper() const { + return angular_limit_upper; +} + +void PinJoint2D::set_motor_target_velocity(real_t p_motor_target_velocity) { + if (motor_target_velocity == p_motor_target_velocity) { + return; + } + motor_target_velocity = p_motor_target_velocity; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_MOTOR_TARGET_VELOCITY, motor_target_velocity); + } +} + +real_t PinJoint2D::get_motor_target_velocity() const { + return motor_target_velocity; +} + +void PinJoint2D::set_motor_enabled(bool p_motor_enabled) { + if (motor_enabled == p_motor_enabled) { + return; + } + motor_enabled = p_motor_enabled; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_flag(get_rid(), PhysicsServer2D::PIN_JOINT_FLAG_MOTOR_ENABLED, motor_enabled); + } +} + +bool PinJoint2D::is_motor_enabled() const { + return motor_enabled; +} + +void PinJoint2D::set_angular_limit_enabled(bool p_angular_limit_enabled) { + if (angular_limit_enabled == p_angular_limit_enabled) { + return; + } + angular_limit_enabled = p_angular_limit_enabled; + queue_redraw(); + if (is_configured()) { + PhysicsServer2D::get_singleton()->pin_joint_set_flag(get_rid(), PhysicsServer2D::PIN_JOINT_FLAG_ANGULAR_LIMIT_ENABLED, angular_limit_enabled); + } +} + +bool PinJoint2D::is_angular_limit_enabled() const { + return angular_limit_enabled; +} + +void PinJoint2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_softness", "softness"), &PinJoint2D::set_softness); + ClassDB::bind_method(D_METHOD("get_softness"), &PinJoint2D::get_softness); + ClassDB::bind_method(D_METHOD("set_angular_limit_lower", "angular_limit_lower"), &PinJoint2D::set_angular_limit_lower); + ClassDB::bind_method(D_METHOD("get_angular_limit_lower"), &PinJoint2D::get_angular_limit_lower); + ClassDB::bind_method(D_METHOD("set_angular_limit_upper", "angular_limit_upper"), &PinJoint2D::set_angular_limit_upper); + ClassDB::bind_method(D_METHOD("get_angular_limit_upper"), &PinJoint2D::get_angular_limit_upper); + ClassDB::bind_method(D_METHOD("set_motor_target_velocity", "motor_target_velocity"), &PinJoint2D::set_motor_target_velocity); + ClassDB::bind_method(D_METHOD("get_motor_target_velocity"), &PinJoint2D::get_motor_target_velocity); + ClassDB::bind_method(D_METHOD("set_motor_enabled", "enabled"), &PinJoint2D::set_motor_enabled); + ClassDB::bind_method(D_METHOD("is_motor_enabled"), &PinJoint2D::is_motor_enabled); + ClassDB::bind_method(D_METHOD("set_angular_limit_enabled", "enabled"), &PinJoint2D::set_angular_limit_enabled); + ClassDB::bind_method(D_METHOD("is_angular_limit_enabled"), &PinJoint2D::is_angular_limit_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_softness", "get_softness"); + ADD_GROUP("Angular Limit", "angular_limit_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "angular_limit_enabled"), "set_angular_limit_enabled", "is_angular_limit_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_angular_limit_lower", "get_angular_limit_lower"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_angular_limit_upper", "get_angular_limit_upper"); + ADD_GROUP("Motor", "motor_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motor_enabled"), "set_motor_enabled", "is_motor_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motor_target_velocity", PROPERTY_HINT_RANGE, U"-200,200,0.01,or_greater,or_less,radians_as_degrees,suffix:\u00B0/s"), "set_motor_target_velocity", "get_motor_target_velocity"); +} + +PinJoint2D::PinJoint2D() { +} diff --git a/scene/2d/physics/joints/pin_joint_2d.h b/scene/2d/physics/joints/pin_joint_2d.h new file mode 100644 index 0000000000..c2d78ba324 --- /dev/null +++ b/scene/2d/physics/joints/pin_joint_2d.h @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* pin_joint_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PIN_JOINT_2D_H +#define PIN_JOINT_2D_H + +#include "scene/2d/physics/joints/joint_2d.h" + +class PhysicsBody2D; + +class PinJoint2D : public Joint2D { + GDCLASS(PinJoint2D, Joint2D); + + real_t softness = 0.0; + real_t angular_limit_lower = 0.0; + real_t angular_limit_upper = 0.0; + real_t motor_target_velocity = 0.0; + bool motor_enabled = false; + bool angular_limit_enabled = false; + +protected: + void _notification(int p_what); + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + static void _bind_methods(); + +public: + void set_softness(real_t p_softness); + real_t get_softness() const; + void set_angular_limit_lower(real_t p_angular_limit_lower); + real_t get_angular_limit_lower() const; + void set_angular_limit_upper(real_t p_angular_limit_upper); + real_t get_angular_limit_upper() const; + void set_motor_target_velocity(real_t p_motor_target_velocity); + real_t get_motor_target_velocity() const; + + void set_motor_enabled(bool p_motor_enabled); + bool is_motor_enabled() const; + void set_angular_limit_enabled(bool p_angular_limit_enabled); + bool is_angular_limit_enabled() const; + + PinJoint2D(); +}; + +#endif // PIN_JOINT_2D_H diff --git a/scene/2d/physics/kinematic_collision_2d.cpp b/scene/2d/physics/kinematic_collision_2d.cpp new file mode 100644 index 0000000000..7e7c33b259 --- /dev/null +++ b/scene/2d/physics/kinematic_collision_2d.cpp @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* kinematic_collision_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "kinematic_collision_2d.h" + +#include "scene/2d/physics/character_body_2d.h" +#include "scene/2d/physics/physics_body_2d.h" + +Vector2 KinematicCollision2D::get_position() const { + return result.collision_point; +} + +Vector2 KinematicCollision2D::get_normal() const { + return result.collision_normal; +} + +Vector2 KinematicCollision2D::get_travel() const { + return result.travel; +} + +Vector2 KinematicCollision2D::get_remainder() const { + return result.remainder; +} + +real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); + return result.get_angle(p_up_direction); +} + +real_t KinematicCollision2D::get_depth() const { + return result.collision_depth; +} + +Object *KinematicCollision2D::get_local_shape() const { + if (!owner) { + return nullptr; + } + uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape); + return owner->shape_owner_get_owner(ownerid); +} + +Object *KinematicCollision2D::get_collider() const { + if (result.collider_id.is_valid()) { + return ObjectDB::get_instance(result.collider_id); + } + + return nullptr; +} + +ObjectID KinematicCollision2D::get_collider_id() const { + return result.collider_id; +} + +RID KinematicCollision2D::get_collider_rid() const { + return result.collider; +} + +Object *KinematicCollision2D::get_collider_shape() const { + Object *collider = get_collider(); + if (collider) { + CollisionObject2D *obj2d = Object::cast_to<CollisionObject2D>(collider); + if (obj2d) { + uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape); + return obj2d->shape_owner_get_owner(ownerid); + } + } + + return nullptr; +} + +int KinematicCollision2D::get_collider_shape_index() const { + return result.collider_shape; +} + +Vector2 KinematicCollision2D::get_collider_velocity() const { + return result.collider_velocity; +} + +void KinematicCollision2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision2D::get_position); + ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision2D::get_normal); + ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel); + ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder); + ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0))); + ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision2D::get_depth); + ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape); + ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider); + ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision2D::get_collider_rid); + ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape); + ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index); + ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity); +} diff --git a/scene/2d/physics/kinematic_collision_2d.h b/scene/2d/physics/kinematic_collision_2d.h new file mode 100644 index 0000000000..0d187b87a5 --- /dev/null +++ b/scene/2d/physics/kinematic_collision_2d.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* kinematic_collision_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef KINEMATIC_COLLISION_2D_H +#define KINEMATIC_COLLISION_2D_H + +#include "core/object/ref_counted.h" +#include "servers/physics_server_2d.h" + +class CharacterBody2D; +class PhysicsBody2D; + +class KinematicCollision2D : public RefCounted { + GDCLASS(KinematicCollision2D, RefCounted); + + PhysicsBody2D *owner = nullptr; + friend class PhysicsBody2D; + friend class CharacterBody2D; + PhysicsServer2D::MotionResult result; + +protected: + static void _bind_methods(); + +public: + Vector2 get_position() const; + Vector2 get_normal() const; + Vector2 get_travel() const; + Vector2 get_remainder() const; + real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; + real_t get_depth() const; + Object *get_local_shape() const; + Object *get_collider() const; + ObjectID get_collider_id() const; + RID get_collider_rid() const; + Object *get_collider_shape() const; + int get_collider_shape_index() const; + Vector2 get_collider_velocity() const; +}; + +#endif // KINEMATIC_COLLISION_2D_H diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physics/physical_bone_2d.cpp index 64cf56fa85..77bb8c24b8 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physics/physical_bone_2d.cpp @@ -30,7 +30,7 @@ #include "physical_bone_2d.h" -#include "scene/2d/joint_2d.h" +#include "scene/2d/physics/joints/joint_2d.h" void PhysicalBone2D::_notification(int p_what) { switch (p_what) { diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physics/physical_bone_2d.h index e585f2c0ed..0547469b5e 100644 --- a/scene/2d/physical_bone_2d.h +++ b/scene/2d/physics/physical_bone_2d.h @@ -31,7 +31,7 @@ #ifndef PHYSICAL_BONE_2D_H #define PHYSICAL_BONE_2D_H -#include "scene/2d/physics_body_2d.h" +#include "scene/2d/physics/rigid_body_2d.h" #include "scene/2d/skeleton_2d.h" class Joint2D; diff --git a/scene/2d/physics/physics_body_2d.cpp b/scene/2d/physics/physics_body_2d.cpp new file mode 100644 index 0000000000..81120d0b01 --- /dev/null +++ b/scene/2d/physics/physics_body_2d.cpp @@ -0,0 +1,180 @@ +/**************************************************************************/ +/* physics_body_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "physics_body_2d.h" + +#include "scene/scene_string_names.h" + +void PhysicsBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody2D::get_gravity); + + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with); +} + +PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) : + CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) { + set_body_mode(p_mode); + set_pickable(false); +} + +PhysicsBody2D::~PhysicsBody2D() { + if (motion_cache.is_valid()) { + motion_cache->owner = nullptr; + } +} + +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); + parameters.recovery_as_collision = p_recovery_as_collision; + + PhysicsServer2D::MotionResult result; + + if (move_and_collide(parameters, result, p_test_only)) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { + motion_cache.instantiate(); + motion_cache->owner = this; + } + + motion_cache->result = result; + return motion_cache; + } + + return Ref<KinematicCollision2D>(); +} + +bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) { + if (is_only_update_transform_changes_enabled()) { + ERR_PRINT("Move functions do not work together with 'sync to physics' option. See the documentation for details."); + } + + bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result); + + // Restore direction of motion to be along original motion, + // in order to avoid sliding due to recovery, + // but only if collision depth is low enough to avoid tunneling. + if (p_cancel_sliding) { + real_t motion_length = p_parameters.motion.length(); + real_t precision = 0.001; + + if (colliding) { + // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, + // so even in normal resting cases the depth can be a bit more than the margin. + precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); + + if (r_result.collision_depth > p_parameters.margin + precision) { + p_cancel_sliding = false; + } + } + + if (p_cancel_sliding) { + // When motion is null, recovery is the resulting motion. + Vector2 motion_normal; + if (motion_length > CMP_EPSILON) { + motion_normal = p_parameters.motion / motion_length; + } + + // Check depth of recovery. + real_t projected_length = r_result.travel.dot(motion_normal); + Vector2 recovery = r_result.travel - motion_normal * projected_length; + real_t recovery_length = recovery.length(); + // Fixes cases where canceling slide causes the motion to go too deep into the ground, + // because we're only taking rest information into account and not general recovery. + if (recovery_length < p_parameters.margin + precision) { + // Apply adjustment to motion. + r_result.travel = motion_normal * projected_length; + r_result.remainder = p_parameters.motion - r_result.travel; + } + } + } + + if (!p_test_only) { + Transform2D gt = p_parameters.from; + gt.columns[2] += r_result.travel; + set_global_transform(gt); + } + + return colliding; +} + +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) { + ERR_FAIL_COND_V(!is_inside_tree(), false); + + PhysicsServer2D::MotionResult *r = nullptr; + PhysicsServer2D::MotionResult temp_result; + if (r_collision.is_valid()) { + // Needs const_cast because method bindings don't support non-const Ref. + r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result); + } else { + r = &temp_result; + } + + PhysicsServer2D::MotionParameters parameters(p_from, p_motion, p_margin); + parameters.recovery_as_collision = p_recovery_as_collision; + + return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); +} + +Vector2 PhysicsBody2D::get_gravity() const { + PhysicsDirectBodyState2D *state = PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(state, Vector2()); + return state->get_total_gravity(); +} + +TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { + List<RID> exceptions; + PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); + Array ret; + for (const RID &body : exceptions) { + ObjectID instance_id = PhysicsServer2D::get_singleton()->body_get_object_instance_id(body); + Object *obj = ObjectDB::get_instance(instance_id); + PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(obj); + ret.append(physics_body); + } + return ret; +} + +void PhysicsBody2D::add_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); + ERR_FAIL_NULL_MSG(physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); + PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid()); +} + +void PhysicsBody2D::remove_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); + ERR_FAIL_NULL_MSG(physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); + PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid()); +} diff --git a/scene/2d/physics/physics_body_2d.h b/scene/2d/physics/physics_body_2d.h new file mode 100644 index 0000000000..43bc479881 --- /dev/null +++ b/scene/2d/physics/physics_body_2d.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* physics_body_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PHYSICS_BODY_2D_H +#define PHYSICS_BODY_2D_H + +#include "core/templates/vset.h" +#include "scene/2d/physics/collision_object_2d.h" +#include "scene/2d/physics/kinematic_collision_2d.h" +#include "scene/resources/physics_material.h" +#include "servers/physics_server_2d.h" + +class PhysicsBody2D : public CollisionObject2D { + GDCLASS(PhysicsBody2D, CollisionObject2D); + +protected: + static void _bind_methods(); + PhysicsBody2D(PhysicsServer2D::BodyMode p_mode); + + Ref<KinematicCollision2D> motion_cache; + + Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false); + +public: + bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); + bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); + Vector2 get_gravity() const; + + TypedArray<PhysicsBody2D> get_collision_exceptions(); + void add_collision_exception_with(Node *p_node); //must be physicsbody + void remove_collision_exception_with(Node *p_node); + + virtual ~PhysicsBody2D(); +}; + +#endif // PHYSICS_BODY_2D_H diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/physics/ray_cast_2d.cpp index f27ac169b6..cb9497c14e 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/physics/ray_cast_2d.cpp @@ -30,7 +30,7 @@ #include "ray_cast_2d.h" -#include "collision_object_2d.h" +#include "scene/2d/physics/collision_object_2d.h" #include "scene/resources/world_2d.h" void RayCast2D::set_target_position(const Vector2 &p_point) { diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/physics/ray_cast_2d.h index 0a856635da..0a856635da 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/physics/ray_cast_2d.h diff --git a/scene/2d/physics/rigid_body_2d.cpp b/scene/2d/physics/rigid_body_2d.cpp new file mode 100644 index 0000000000..12112510a8 --- /dev/null +++ b/scene/2d/physics/rigid_body_2d.cpp @@ -0,0 +1,817 @@ +/**************************************************************************/ +/* rigid_body_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "rigid_body_2d.h" + +#include "scene/scene_string_names.h" + +void RigidBody2D::_body_enter_tree(ObjectID p_id) { + Object *obj = ObjectDB::get_instance(p_id); + Node *node = Object::cast_to<Node>(obj); + ERR_FAIL_NULL(node); + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->value.in_scene); + + contact_monitor->locked = true; + + E->value.in_scene = true; + emit_signal(SceneStringNames::get_singleton()->body_entered, node); + + for (int i = 0; i < E->value.shapes.size(); i++) { + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); + } + + contact_monitor->locked = false; +} + +void RigidBody2D::_body_exit_tree(ObjectID p_id) { + Object *obj = ObjectDB::get_instance(p_id); + Node *node = Object::cast_to<Node>(obj); + ERR_FAIL_NULL(node); + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->value.in_scene); + E->value.in_scene = false; + + contact_monitor->locked = true; + + emit_signal(SceneStringNames::get_singleton()->body_exited, node); + + for (int i = 0; i < E->value.shapes.size(); i++) { + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); + } + + contact_monitor->locked = false; +} + +void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) { + bool body_in = p_status == 1; + ObjectID objid = p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = Object::cast_to<Node>(obj); + + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + E = contact_monitor->body_map.insert(objid, BodyState()); + E->value.rid = p_body; + //E->value.rc=0; + E->value.in_scene = node && node->is_inside_tree(); + if (node) { + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree).bind(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree).bind(objid)); + if (E->value.in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_entered, node); + } + } + + //E->value.rc++; + } + + if (node) { + E->value.shapes.insert(ShapePair(p_body_shape, p_local_shape)); + } + + if (E->value.in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape); + } + + } else { + //E->value.rc--; + + if (node) { + E->value.shapes.erase(ShapePair(p_body_shape, p_local_shape)); + } + + bool in_scene = E->value.in_scene; + + if (E->value.shapes.is_empty()) { + if (node) { + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree)); + if (in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_exited, node); + } + } + + contact_monitor->body_map.remove(E); + } + if (node && in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, node, p_body_shape, p_local_shape); + } + } +} + +struct _RigidBody2DInOut { + RID rid; + ObjectID id; + int shape = 0; + int local_shape = 0; +}; + +void RigidBody2D::_sync_body_state(PhysicsDirectBodyState2D *p_state) { + if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) { + set_block_transform_notify(true); + set_global_transform(p_state->get_transform()); + set_block_transform_notify(false); + } + + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + contact_count = p_state->get_contact_count(); + + if (sleeping != p_state->is_sleeping()) { + sleeping = p_state->is_sleeping(); + emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); + } +} + +void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { + lock_callback(); + + if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { + _sync_body_state(p_state); + + Transform2D old_transform = get_global_transform(); + GDVIRTUAL_CALL(_integrate_forces, p_state); + Transform2D new_transform = get_global_transform(); + + if (new_transform != old_transform) { + // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); + } + } + + _sync_body_state(p_state); + + if (contact_monitor) { + contact_monitor->locked = true; + + //untag all + int rc = 0; + for (KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + for (int i = 0; i < E.value.shapes.size(); i++) { + E.value.shapes[i].tagged = false; + rc++; + } + } + + _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut)); + int toadd_count = 0; //state->get_contact_count(); + RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction)); + int toremove_count = 0; + + //put the ones to add + + for (int i = 0; i < p_state->get_contact_count(); i++) { + RID col_rid = p_state->get_contact_collider(i); + ObjectID col_obj = p_state->get_contact_collider_id(i); + int local_shape = p_state->get_contact_local_shape(i); + int col_shape = p_state->get_contact_collider_shape(i); + + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj); + if (!E) { + toadd[toadd_count].rid = col_rid; + toadd[toadd_count].local_shape = local_shape; + toadd[toadd_count].id = col_obj; + toadd[toadd_count].shape = col_shape; + toadd_count++; + continue; + } + + ShapePair sp(col_shape, local_shape); + int idx = E->value.shapes.find(sp); + if (idx == -1) { + toadd[toadd_count].rid = col_rid; + toadd[toadd_count].local_shape = local_shape; + toadd[toadd_count].id = col_obj; + toadd[toadd_count].shape = col_shape; + toadd_count++; + continue; + } + + E->value.shapes[idx].tagged = true; + } + + //put the ones to remove + + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + for (int i = 0; i < E.value.shapes.size(); i++) { + if (!E.value.shapes[i].tagged) { + toremove[toremove_count].rid = E.value.rid; + toremove[toremove_count].body_id = E.key; + toremove[toremove_count].pair = E.value.shapes[i]; + toremove_count++; + } + } + } + + //process removals + + for (int i = 0; i < toremove_count; i++) { + _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); + } + + //process additions + + for (int i = 0; i < toadd_count; i++) { + _body_inout(1, toadd[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape); + } + + contact_monitor->locked = false; + } + + unlock_callback(); +} + +void RigidBody2D::_apply_body_mode() { + if (freeze) { + switch (freeze_mode) { + case FREEZE_MODE_STATIC: { + set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); + } break; + case FREEZE_MODE_KINEMATIC: { + set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); + } break; + } + } else if (lock_rotation) { + set_body_mode(PhysicsServer2D::BODY_MODE_RIGID_LINEAR); + } else { + set_body_mode(PhysicsServer2D::BODY_MODE_RIGID); + } +} + +void RigidBody2D::set_lock_rotation_enabled(bool p_lock_rotation) { + if (p_lock_rotation == lock_rotation) { + return; + } + + lock_rotation = p_lock_rotation; + _apply_body_mode(); +} + +bool RigidBody2D::is_lock_rotation_enabled() const { + return lock_rotation; +} + +void RigidBody2D::set_freeze_enabled(bool p_freeze) { + if (p_freeze == freeze) { + return; + } + + freeze = p_freeze; + _apply_body_mode(); +} + +bool RigidBody2D::is_freeze_enabled() const { + return freeze; +} + +void RigidBody2D::set_freeze_mode(FreezeMode p_freeze_mode) { + if (p_freeze_mode == freeze_mode) { + return; + } + + freeze_mode = p_freeze_mode; + _apply_body_mode(); +} + +RigidBody2D::FreezeMode RigidBody2D::get_freeze_mode() const { + return freeze_mode; +} + +void RigidBody2D::set_mass(real_t p_mass) { + ERR_FAIL_COND(p_mass <= 0); + mass = p_mass; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_MASS, mass); +} + +real_t RigidBody2D::get_mass() const { + return mass; +} + +void RigidBody2D::set_inertia(real_t p_inertia) { + ERR_FAIL_COND(p_inertia < 0); + inertia = p_inertia; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); +} + +real_t RigidBody2D::get_inertia() const { + return inertia; +} + +void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) { + if (center_of_mass_mode == p_mode) { + return; + } + + center_of_mass_mode = p_mode; + + switch (center_of_mass_mode) { + case CENTER_OF_MASS_MODE_AUTO: { + center_of_mass = Vector2(); + PhysicsServer2D::get_singleton()->body_reset_mass_properties(get_rid()); + if (inertia != 0.0) { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); + } + } break; + + case CENTER_OF_MASS_MODE_CUSTOM: { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); + } break; + } +} + +RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const { + return center_of_mass_mode; +} + +void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) { + if (center_of_mass == p_center_of_mass) { + return; + } + + ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); + center_of_mass = p_center_of_mass; + + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); +} + +const Vector2 &RigidBody2D::get_center_of_mass() const { + return center_of_mass; +} + +void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics)); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics)); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const { + return physics_material_override; +} + +void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) { + gravity_scale = p_gravity_scale; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); +} + +real_t RigidBody2D::get_gravity_scale() const { + return gravity_scale; +} + +void RigidBody2D::set_linear_damp_mode(DampMode p_mode) { + linear_damp_mode = p_mode; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); +} + +RigidBody2D::DampMode RigidBody2D::get_linear_damp_mode() const { + return linear_damp_mode; +} + +void RigidBody2D::set_angular_damp_mode(DampMode p_mode) { + angular_damp_mode = p_mode; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); +} + +RigidBody2D::DampMode RigidBody2D::get_angular_damp_mode() const { + return angular_damp_mode; +} + +void RigidBody2D::set_linear_damp(real_t p_linear_damp) { + ERR_FAIL_COND(p_linear_damp < -1); + linear_damp = p_linear_damp; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP, linear_damp); +} + +real_t RigidBody2D::get_linear_damp() const { + return linear_damp; +} + +void RigidBody2D::set_angular_damp(real_t p_angular_damp) { + ERR_FAIL_COND(p_angular_damp < -1); + angular_damp = p_angular_damp; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP, angular_damp); +} + +real_t RigidBody2D::get_angular_damp() const { + return angular_damp; +} + +void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) { + Vector2 axis = p_axis.normalized(); + linear_velocity -= axis * axis.dot(linear_velocity); + linear_velocity += p_axis; + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) { + linear_velocity = p_velocity; + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +Vector2 RigidBody2D::get_linear_velocity() const { + return linear_velocity; +} + +void RigidBody2D::set_angular_velocity(real_t p_velocity) { + angular_velocity = p_velocity; + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); +} + +real_t RigidBody2D::get_angular_velocity() const { + return angular_velocity; +} + +void RigidBody2D::set_use_custom_integrator(bool p_enable) { + if (custom_integrator == p_enable) { + return; + } + + custom_integrator = p_enable; + PhysicsServer2D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); +} + +bool RigidBody2D::is_using_custom_integrator() { + return custom_integrator; +} + +void RigidBody2D::set_sleeping(bool p_sleeping) { + sleeping = p_sleeping; + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_SLEEPING, sleeping); +} + +void RigidBody2D::set_can_sleep(bool p_active) { + can_sleep = p_active; + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_CAN_SLEEP, p_active); +} + +bool RigidBody2D::is_able_to_sleep() const { + return can_sleep; +} + +bool RigidBody2D::is_sleeping() const { + return sleeping; +} + +void RigidBody2D::set_max_contacts_reported(int p_amount) { + max_contacts_reported = p_amount; + PhysicsServer2D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount); +} + +int RigidBody2D::get_max_contacts_reported() const { + return max_contacts_reported; +} + +int RigidBody2D::get_contact_count() const { + return contact_count; +} + +void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) { + PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + +void RigidBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) { + PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); +} + +void RigidBody2D::apply_torque_impulse(real_t p_torque) { + PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque); +} + +void RigidBody2D::apply_central_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_apply_central_force(get_rid(), p_force); +} + +void RigidBody2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) { + PhysicsServer2D::get_singleton()->body_apply_force(get_rid(), p_force, p_position); +} + +void RigidBody2D::apply_torque(real_t p_torque) { + PhysicsServer2D::get_singleton()->body_apply_torque(get_rid(), p_torque); +} + +void RigidBody2D::add_constant_central_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_add_constant_central_force(get_rid(), p_force); +} + +void RigidBody2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) { + PhysicsServer2D::get_singleton()->body_add_constant_force(get_rid(), p_force, p_position); +} + +void RigidBody2D::add_constant_torque(const real_t p_torque) { + PhysicsServer2D::get_singleton()->body_add_constant_torque(get_rid(), p_torque); +} + +void RigidBody2D::set_constant_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_set_constant_force(get_rid(), p_force); +} + +Vector2 RigidBody2D::get_constant_force() const { + return PhysicsServer2D::get_singleton()->body_get_constant_force(get_rid()); +} + +void RigidBody2D::set_constant_torque(real_t p_torque) { + PhysicsServer2D::get_singleton()->body_set_constant_torque(get_rid(), p_torque); +} + +real_t RigidBody2D::get_constant_torque() const { + return PhysicsServer2D::get_singleton()->body_get_constant_torque(get_rid()); +} + +void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) { + ccd_mode = p_mode; + PhysicsServer2D::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), PhysicsServer2D::CCDMode(p_mode)); +} + +RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() const { + return ccd_mode; +} + +TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const { + ERR_FAIL_NULL_V(contact_monitor, TypedArray<Node2D>()); + + TypedArray<Node2D> ret; + ret.resize(contact_monitor->body_map.size()); + int idx = 0; + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + Object *obj = ObjectDB::get_instance(E.key); + if (!obj) { + ret.resize(ret.size() - 1); //ops + } else { + ret[idx++] = obj; + } + } + + return ret; +} + +void RigidBody2D::set_contact_monitor(bool p_enabled) { + if (p_enabled == is_contact_monitor_enabled()) { + return; + } + + if (!p_enabled) { + ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead."); + + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + //clean up mess + Object *obj = ObjectDB::get_instance(E.key); + Node *node = Object::cast_to<Node>(obj); + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree)); + } + } + + memdelete(contact_monitor); + contact_monitor = nullptr; + } else { + contact_monitor = memnew(ContactMonitor); + contact_monitor->locked = false; + } +} + +bool RigidBody2D::is_contact_monitor_enabled() const { + return contact_monitor != nullptr; +} + +void RigidBody2D::_notification(int p_what) { +#ifdef TOOLS_ENABLED + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); // Used for warnings and only in editor. + } + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + update_configuration_warnings(); + } break; + } +#endif +} + +PackedStringArray RigidBody2D::get_configuration_warnings() const { + Transform2D t = get_transform(); + + PackedStringArray warnings = CollisionObject2D::get_configuration_warnings(); + + if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) { + warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + } + + return warnings; +} + +void RigidBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody2D::set_mass); + ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody2D::get_mass); + + ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia); + ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia); + + ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode); + ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode); + + ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass); + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale); + ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale); + + ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody2D::set_linear_damp_mode); + ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody2D::get_linear_damp_mode); + + ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody2D::set_angular_damp_mode); + ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody2D::get_angular_damp_mode); + + ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody2D::set_linear_damp); + ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody2D::get_linear_damp); + + ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody2D::set_angular_damp); + ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody2D::get_angular_damp); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody2D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody2D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody2D::set_angular_velocity); + ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody2D::get_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody2D::set_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody2D::get_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody2D::get_contact_count); + + ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody2D::set_use_custom_integrator); + ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody2D::is_using_custom_integrator); + + ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody2D::set_contact_monitor); + ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody2D::is_contact_monitor_enabled); + + ClassDB::bind_method(D_METHOD("set_continuous_collision_detection_mode", "mode"), &RigidBody2D::set_continuous_collision_detection_mode); + ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode); + + ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse, Vector2()); + ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody2D::apply_impulse, Vector2()); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse); + + ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody2D::apply_central_force); + ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody2D::apply_force, Vector2()); + ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody2D::apply_torque); + + ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody2D::add_constant_central_force); + ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody2D::add_constant_force, Vector2()); + ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody2D::add_constant_torque); + + ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody2D::set_constant_force); + ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody2D::get_constant_force); + + ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody2D::set_constant_torque); + ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody2D::get_constant_torque); + + ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping); + ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping); + + ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep); + ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep); + + ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody2D::set_lock_rotation_enabled); + ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody2D::is_lock_rotation_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody2D::set_freeze_enabled); + ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody2D::is_freeze_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody2D::set_freeze_mode); + ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody2D::get_freeze_mode); + + ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies); + + GDVIRTUAL_BIND(_integrate_forces, "state"); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); + ADD_GROUP("Mass Distribution", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass"); + ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia"); + ADD_GROUP("Deactivation", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); + ADD_GROUP("Solver", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); + ADD_GROUP("Linear", "linear_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_GROUP("Angular", "angular_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_GROUP("Constant Forces", "constant_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px/s\u00B2"), "set_constant_force", "get_constant_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque"); + + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("sleeping_state_changed")); + + BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); + + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); + + BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); + BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); + + BIND_ENUM_CONSTANT(CCD_MODE_DISABLED); + BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY); + BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE); +} + +void RigidBody2D::_validate_property(PropertyInfo &p_property) const { + if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { + if (p_property.name == "center_of_mass") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } +} + +RigidBody2D::RigidBody2D() : + PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) { + PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody2D::_body_state_changed)); +} + +RigidBody2D::~RigidBody2D() { + if (contact_monitor) { + memdelete(contact_monitor); + } +} + +void RigidBody2D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } +} diff --git a/scene/2d/physics/rigid_body_2d.h b/scene/2d/physics/rigid_body_2d.h new file mode 100644 index 0000000000..40af66f28d --- /dev/null +++ b/scene/2d/physics/rigid_body_2d.h @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* rigid_body_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef RIGID_BODY_2D_H +#define RIGID_BODY_2D_H + +#include "scene/2d/physics/static_body_2d.h" + +class RigidBody2D : public PhysicsBody2D { + GDCLASS(RigidBody2D, PhysicsBody2D); + +public: + enum FreezeMode { + FREEZE_MODE_STATIC, + FREEZE_MODE_KINEMATIC, + }; + + enum CenterOfMassMode { + CENTER_OF_MASS_MODE_AUTO, + CENTER_OF_MASS_MODE_CUSTOM, + }; + + enum DampMode { + DAMP_MODE_COMBINE, + DAMP_MODE_REPLACE, + }; + + enum CCDMode { + CCD_MODE_DISABLED, + CCD_MODE_CAST_RAY, + CCD_MODE_CAST_SHAPE, + }; + +private: + bool can_sleep = true; + bool lock_rotation = false; + bool freeze = false; + FreezeMode freeze_mode = FREEZE_MODE_STATIC; + + real_t mass = 1.0; + real_t inertia = 0.0; + CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; + Vector2 center_of_mass; + + Ref<PhysicsMaterial> physics_material_override; + real_t gravity_scale = 1.0; + + DampMode linear_damp_mode = DAMP_MODE_COMBINE; + DampMode angular_damp_mode = DAMP_MODE_COMBINE; + + real_t linear_damp = 0.0; + real_t angular_damp = 0.0; + + Vector2 linear_velocity; + real_t angular_velocity = 0.0; + bool sleeping = false; + + int max_contacts_reported = 0; + int contact_count = 0; + + bool custom_integrator = false; + + CCDMode ccd_mode = CCD_MODE_DISABLED; + + struct ShapePair { + int body_shape = 0; + int local_shape = 0; + bool tagged = false; + bool operator<(const ShapePair &p_sp) const { + if (body_shape == p_sp.body_shape) { + return local_shape < p_sp.local_shape; + } + + return body_shape < p_sp.body_shape; + } + + ShapePair() {} + ShapePair(int p_bs, int p_ls) { + body_shape = p_bs; + local_shape = p_ls; + } + }; + struct RigidBody2D_RemoveAction { + RID rid; + ObjectID body_id; + ShapePair pair; + }; + struct BodyState { + RID rid; + //int rc; + bool in_scene = false; + VSet<ShapePair> shapes; + }; + + struct ContactMonitor { + bool locked = false; + HashMap<ObjectID, BodyState> body_map; + }; + + ContactMonitor *contact_monitor = nullptr; + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); + + void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); + + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); + void _body_state_changed(PhysicsDirectBodyState2D *p_state); + + void _sync_body_state(PhysicsDirectBodyState2D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + + void _validate_property(PropertyInfo &p_property) const; + + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) + + void _apply_body_mode(); + +public: + void set_lock_rotation_enabled(bool p_lock_rotation); + bool is_lock_rotation_enabled() const; + + void set_freeze_enabled(bool p_freeze); + bool is_freeze_enabled() const; + + void set_freeze_mode(FreezeMode p_freeze_mode); + FreezeMode get_freeze_mode() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_inertia(real_t p_inertia); + real_t get_inertia() const; + + void set_center_of_mass_mode(CenterOfMassMode p_mode); + CenterOfMassMode get_center_of_mass_mode() const; + + void set_center_of_mass(const Vector2 &p_center_of_mass); + const Vector2 &get_center_of_mass() const; + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; + + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + void set_linear_damp_mode(DampMode p_mode); + DampMode get_linear_damp_mode() const; + + void set_angular_damp_mode(DampMode p_mode); + DampMode get_angular_damp_mode() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; + + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_linear_velocity(const Vector2 &p_velocity); + Vector2 get_linear_velocity() const; + + void set_axis_velocity(const Vector2 &p_axis); + + void set_angular_velocity(real_t p_velocity); + real_t get_angular_velocity() const; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + + void set_sleeping(bool p_sleeping); + bool is_sleeping() const; + + void set_can_sleep(bool p_active); + bool is_able_to_sleep() const; + + void set_contact_monitor(bool p_enabled); + bool is_contact_monitor_enabled() const; + + void set_max_contacts_reported(int p_amount); + int get_max_contacts_reported() const; + int get_contact_count() const; + + void set_continuous_collision_detection_mode(CCDMode p_mode); + CCDMode get_continuous_collision_detection_mode() const; + + void apply_central_impulse(const Vector2 &p_impulse); + void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()); + void apply_torque_impulse(real_t p_torque); + + void apply_central_force(const Vector2 &p_force); + void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); + void apply_torque(real_t p_torque); + + void add_constant_central_force(const Vector2 &p_force); + void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); + void add_constant_torque(real_t p_torque); + + void set_constant_force(const Vector2 &p_force); + Vector2 get_constant_force() const; + + void set_constant_torque(real_t p_torque); + real_t get_constant_torque() const; + + TypedArray<Node2D> get_colliding_bodies() const; //function for script + + virtual PackedStringArray get_configuration_warnings() const override; + + RigidBody2D(); + ~RigidBody2D(); + +private: + void _reload_physics_characteristics(); +}; + +VARIANT_ENUM_CAST(RigidBody2D::FreezeMode); +VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode); +VARIANT_ENUM_CAST(RigidBody2D::DampMode); +VARIANT_ENUM_CAST(RigidBody2D::CCDMode); + +#endif // RIGID_BODY_2D_H diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/physics/shape_cast_2d.cpp index 38e3b3180b..00be84b622 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/physics/shape_cast_2d.cpp @@ -31,8 +31,8 @@ #include "shape_cast_2d.h" #include "core/config/engine.h" -#include "scene/2d/collision_object_2d.h" -#include "scene/2d/physics_body_2d.h" +#include "scene/2d/physics/collision_object_2d.h" +#include "scene/2d/physics/physics_body_2d.h" #include "scene/resources/2d/circle_shape_2d.h" #include "servers/physics_2d/godot_physics_server_2d.h" diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/physics/shape_cast_2d.h index 6b8fd5b798..6b8fd5b798 100644 --- a/scene/2d/shape_cast_2d.h +++ b/scene/2d/physics/shape_cast_2d.h diff --git a/scene/2d/physics/static_body_2d.cpp b/scene/2d/physics/static_body_2d.cpp new file mode 100644 index 0000000000..3c5af73c1e --- /dev/null +++ b/scene/2d/physics/static_body_2d.cpp @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* static_body_2d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "static_body_2d.h" + +void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) { + constant_linear_velocity = p_vel; + + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); +} + +void StaticBody2D::set_constant_angular_velocity(real_t p_vel) { + constant_angular_velocity = p_vel; + + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); +} + +Vector2 StaticBody2D::get_constant_linear_velocity() const { + return constant_linear_velocity; +} + +real_t StaticBody2D::get_constant_angular_velocity() const { + return constant_angular_velocity; +} + +void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics)); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics)); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const { + return physics_material_override; +} + +void StaticBody2D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } +} + +void StaticBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_constant_angular_velocity", "get_constant_angular_velocity"); +} + +StaticBody2D::StaticBody2D(PhysicsServer2D::BodyMode p_mode) : + PhysicsBody2D(p_mode) { +} diff --git a/scene/2d/physics/static_body_2d.h b/scene/2d/physics/static_body_2d.h new file mode 100644 index 0000000000..ce05596d94 --- /dev/null +++ b/scene/2d/physics/static_body_2d.h @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* static_body_2d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef STATIC_BODY_2D_H +#define STATIC_BODY_2D_H + +#include "scene/2d/physics/physics_body_2d.h" + +class StaticBody2D : public PhysicsBody2D { + GDCLASS(StaticBody2D, PhysicsBody2D); + +private: + Vector2 constant_linear_velocity; + real_t constant_angular_velocity = 0.0; + + Ref<PhysicsMaterial> physics_material_override; + +protected: + static void _bind_methods(); + +public: + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; + + void set_constant_linear_velocity(const Vector2 &p_vel); + void set_constant_angular_velocity(real_t p_vel); + + Vector2 get_constant_linear_velocity() const; + real_t get_constant_angular_velocity() const; + + StaticBody2D(PhysicsServer2D::BodyMode p_mode = PhysicsServer2D::BODY_MODE_STATIC); + +private: + void _reload_physics_characteristics(); +}; + +#endif // STATIC_BODY_2D_H diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp deleted file mode 100644 index 92af3fa3f0..0000000000 --- a/scene/2d/physics_body_2d.cpp +++ /dev/null @@ -1,1923 +0,0 @@ -/**************************************************************************/ -/* physics_body_2d.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#include "physics_body_2d.h" - -#include "scene/scene_string_names.h" - -void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody2D::get_gravity); - - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); - ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); - ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with); -} - -PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) : - CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) { - set_body_mode(p_mode); - set_pickable(false); -} - -PhysicsBody2D::~PhysicsBody2D() { - if (motion_cache.is_valid()) { - motion_cache->owner = nullptr; - } -} - -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) { - PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); - parameters.recovery_as_collision = p_recovery_as_collision; - - PhysicsServer2D::MotionResult result; - - if (move_and_collide(parameters, result, p_test_only)) { - // Create a new instance when the cached reference is invalid or still in use in script. - if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { - motion_cache.instantiate(); - motion_cache->owner = this; - } - - motion_cache->result = result; - return motion_cache; - } - - return Ref<KinematicCollision2D>(); -} - -bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) { - if (is_only_update_transform_changes_enabled()) { - ERR_PRINT("Move functions do not work together with 'sync to physics' option. See the documentation for details."); - } - - bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result); - - // Restore direction of motion to be along original motion, - // in order to avoid sliding due to recovery, - // but only if collision depth is low enough to avoid tunneling. - if (p_cancel_sliding) { - real_t motion_length = p_parameters.motion.length(); - real_t precision = 0.001; - - if (colliding) { - // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, - // so even in normal resting cases the depth can be a bit more than the margin. - precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); - - if (r_result.collision_depth > p_parameters.margin + precision) { - p_cancel_sliding = false; - } - } - - if (p_cancel_sliding) { - // When motion is null, recovery is the resulting motion. - Vector2 motion_normal; - if (motion_length > CMP_EPSILON) { - motion_normal = p_parameters.motion / motion_length; - } - - // Check depth of recovery. - real_t projected_length = r_result.travel.dot(motion_normal); - Vector2 recovery = r_result.travel - motion_normal * projected_length; - real_t recovery_length = recovery.length(); - // Fixes cases where canceling slide causes the motion to go too deep into the ground, - // because we're only taking rest information into account and not general recovery. - if (recovery_length < p_parameters.margin + precision) { - // Apply adjustment to motion. - r_result.travel = motion_normal * projected_length; - r_result.remainder = p_parameters.motion - r_result.travel; - } - } - } - - if (!p_test_only) { - Transform2D gt = p_parameters.from; - gt.columns[2] += r_result.travel; - set_global_transform(gt); - } - - return colliding; -} - -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) { - ERR_FAIL_COND_V(!is_inside_tree(), false); - - PhysicsServer2D::MotionResult *r = nullptr; - PhysicsServer2D::MotionResult temp_result; - if (r_collision.is_valid()) { - // Needs const_cast because method bindings don't support non-const Ref. - r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result); - } else { - r = &temp_result; - } - - PhysicsServer2D::MotionParameters parameters(p_from, p_motion, p_margin); - parameters.recovery_as_collision = p_recovery_as_collision; - - return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); -} - -Vector2 PhysicsBody2D::get_gravity() const { - PhysicsDirectBodyState2D *state = PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid()); - ERR_FAIL_NULL_V(state, Vector2()); - return state->get_total_gravity(); -} - -TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { - List<RID> exceptions; - PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); - Array ret; - for (const RID &body : exceptions) { - ObjectID instance_id = PhysicsServer2D::get_singleton()->body_get_object_instance_id(body); - Object *obj = ObjectDB::get_instance(instance_id); - PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(obj); - ret.append(physics_body); - } - return ret; -} - -void PhysicsBody2D::add_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); - PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); - ERR_FAIL_NULL_MSG(physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); - PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid()); -} - -void PhysicsBody2D::remove_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); - PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node); - ERR_FAIL_NULL_MSG(physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D."); - PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid()); -} - -void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) { - constant_linear_velocity = p_vel; - - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); -} - -void StaticBody2D::set_constant_angular_velocity(real_t p_vel) { - constant_angular_velocity = p_vel; - - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); -} - -Vector2 StaticBody2D::get_constant_linear_velocity() const { - return constant_linear_velocity; -} - -real_t StaticBody2D::get_constant_angular_velocity() const { - return constant_angular_velocity; -} - -void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { - if (physics_material_override.is_valid()) { - physics_material_override->disconnect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics)); - } - - physics_material_override = p_physics_material_override; - - if (physics_material_override.is_valid()) { - physics_material_override->connect_changed(callable_mp(this, &StaticBody2D::_reload_physics_characteristics)); - } - _reload_physics_characteristics(); -} - -Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const { - return physics_material_override; -} - -void StaticBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity); - ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_constant_linear_velocity", "get_constant_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_constant_angular_velocity", "get_constant_angular_velocity"); -} - -StaticBody2D::StaticBody2D(PhysicsServer2D::BodyMode p_mode) : - PhysicsBody2D(p_mode) { -} - -void StaticBody2D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -void AnimatableBody2D::set_sync_to_physics(bool p_enable) { - if (sync_to_physics == p_enable) { - return; - } - - sync_to_physics = p_enable; - - _update_kinematic_motion(); -} - -bool AnimatableBody2D::is_sync_to_physics_enabled() const { - return sync_to_physics; -} - -void AnimatableBody2D::_update_kinematic_motion() { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - - if (sync_to_physics) { - PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody2D::_body_state_changed)); - set_only_update_transform_changes(true); - set_notify_local_transform(true); - } else { - PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable()); - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } -} - -void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { - if (!sync_to_physics) { - return; - } - - last_valid_transform = p_state->get_transform(); - set_notify_local_transform(false); - set_global_transform(last_valid_transform); - set_notify_local_transform(true); -} - -void AnimatableBody2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - last_valid_transform = get_global_transform(); - _update_kinematic_motion(); - } break; - - case NOTIFICATION_EXIT_TREE: { - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } break; - - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - // Used by sync to physics, send the new transform to the physics... - Transform2D new_transform = get_global_transform(); - - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); - - // ... but then revert changes. - set_notify_local_transform(false); - set_global_transform(last_valid_transform); - set_notify_local_transform(true); - } break; - } -} - -void AnimatableBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody2D::set_sync_to_physics); - ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody2D::is_sync_to_physics_enabled); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); -} - -AnimatableBody2D::AnimatableBody2D() : - StaticBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { -} - -void RigidBody2D::_body_enter_tree(ObjectID p_id) { - Object *obj = ObjectDB::get_instance(p_id); - Node *node = Object::cast_to<Node>(obj); - ERR_FAIL_NULL(node); - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); - ERR_FAIL_COND(!E); - ERR_FAIL_COND(E->value.in_scene); - - contact_monitor->locked = true; - - E->value.in_scene = true; - emit_signal(SceneStringNames::get_singleton()->body_entered, node); - - for (int i = 0; i < E->value.shapes.size(); i++) { - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); - } - - contact_monitor->locked = false; -} - -void RigidBody2D::_body_exit_tree(ObjectID p_id) { - Object *obj = ObjectDB::get_instance(p_id); - Node *node = Object::cast_to<Node>(obj); - ERR_FAIL_NULL(node); - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); - ERR_FAIL_COND(!E); - ERR_FAIL_COND(!E->value.in_scene); - E->value.in_scene = false; - - contact_monitor->locked = true; - - emit_signal(SceneStringNames::get_singleton()->body_exited, node); - - for (int i = 0; i < E->value.shapes.size(); i++) { - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); - } - - contact_monitor->locked = false; -} - -void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) { - bool body_in = p_status == 1; - ObjectID objid = p_instance; - - Object *obj = ObjectDB::get_instance(objid); - Node *node = Object::cast_to<Node>(obj); - - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(objid); - - ERR_FAIL_COND(!body_in && !E); - - if (body_in) { - if (!E) { - E = contact_monitor->body_map.insert(objid, BodyState()); - E->value.rid = p_body; - //E->value.rc=0; - E->value.in_scene = node && node->is_inside_tree(); - if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree).bind(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree).bind(objid)); - if (E->value.in_scene) { - emit_signal(SceneStringNames::get_singleton()->body_entered, node); - } - } - - //E->value.rc++; - } - - if (node) { - E->value.shapes.insert(ShapePair(p_body_shape, p_local_shape)); - } - - if (E->value.in_scene) { - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape); - } - - } else { - //E->value.rc--; - - if (node) { - E->value.shapes.erase(ShapePair(p_body_shape, p_local_shape)); - } - - bool in_scene = E->value.in_scene; - - if (E->value.shapes.is_empty()) { - if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree)); - if (in_scene) { - emit_signal(SceneStringNames::get_singleton()->body_exited, node); - } - } - - contact_monitor->body_map.remove(E); - } - if (node && in_scene) { - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, node, p_body_shape, p_local_shape); - } - } -} - -struct _RigidBody2DInOut { - RID rid; - ObjectID id; - int shape = 0; - int local_shape = 0; -}; - -void RigidBody2D::_sync_body_state(PhysicsDirectBodyState2D *p_state) { - if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) { - set_block_transform_notify(true); - set_global_transform(p_state->get_transform()); - set_block_transform_notify(false); - } - - linear_velocity = p_state->get_linear_velocity(); - angular_velocity = p_state->get_angular_velocity(); - - contact_count = p_state->get_contact_count(); - - if (sleeping != p_state->is_sleeping()) { - sleeping = p_state->is_sleeping(); - emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); - } -} - -void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { - lock_callback(); - - if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { - _sync_body_state(p_state); - - Transform2D old_transform = get_global_transform(); - GDVIRTUAL_CALL(_integrate_forces, p_state); - Transform2D new_transform = get_global_transform(); - - if (new_transform != old_transform) { - // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); - } - } - - _sync_body_state(p_state); - - if (contact_monitor) { - contact_monitor->locked = true; - - //untag all - int rc = 0; - for (KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - for (int i = 0; i < E.value.shapes.size(); i++) { - E.value.shapes[i].tagged = false; - rc++; - } - } - - _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut)); - int toadd_count = 0; //state->get_contact_count(); - RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction)); - int toremove_count = 0; - - //put the ones to add - - for (int i = 0; i < p_state->get_contact_count(); i++) { - RID col_rid = p_state->get_contact_collider(i); - ObjectID col_obj = p_state->get_contact_collider_id(i); - int local_shape = p_state->get_contact_local_shape(i); - int col_shape = p_state->get_contact_collider_shape(i); - - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj); - if (!E) { - toadd[toadd_count].rid = col_rid; - toadd[toadd_count].local_shape = local_shape; - toadd[toadd_count].id = col_obj; - toadd[toadd_count].shape = col_shape; - toadd_count++; - continue; - } - - ShapePair sp(col_shape, local_shape); - int idx = E->value.shapes.find(sp); - if (idx == -1) { - toadd[toadd_count].rid = col_rid; - toadd[toadd_count].local_shape = local_shape; - toadd[toadd_count].id = col_obj; - toadd[toadd_count].shape = col_shape; - toadd_count++; - continue; - } - - E->value.shapes[idx].tagged = true; - } - - //put the ones to remove - - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - for (int i = 0; i < E.value.shapes.size(); i++) { - if (!E.value.shapes[i].tagged) { - toremove[toremove_count].rid = E.value.rid; - toremove[toremove_count].body_id = E.key; - toremove[toremove_count].pair = E.value.shapes[i]; - toremove_count++; - } - } - } - - //process removals - - for (int i = 0; i < toremove_count; i++) { - _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); - } - - //process additions - - for (int i = 0; i < toadd_count; i++) { - _body_inout(1, toadd[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape); - } - - contact_monitor->locked = false; - } - - unlock_callback(); -} - -void RigidBody2D::_apply_body_mode() { - if (freeze) { - switch (freeze_mode) { - case FREEZE_MODE_STATIC: { - set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); - } break; - case FREEZE_MODE_KINEMATIC: { - set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); - } break; - } - } else if (lock_rotation) { - set_body_mode(PhysicsServer2D::BODY_MODE_RIGID_LINEAR); - } else { - set_body_mode(PhysicsServer2D::BODY_MODE_RIGID); - } -} - -void RigidBody2D::set_lock_rotation_enabled(bool p_lock_rotation) { - if (p_lock_rotation == lock_rotation) { - return; - } - - lock_rotation = p_lock_rotation; - _apply_body_mode(); -} - -bool RigidBody2D::is_lock_rotation_enabled() const { - return lock_rotation; -} - -void RigidBody2D::set_freeze_enabled(bool p_freeze) { - if (p_freeze == freeze) { - return; - } - - freeze = p_freeze; - _apply_body_mode(); -} - -bool RigidBody2D::is_freeze_enabled() const { - return freeze; -} - -void RigidBody2D::set_freeze_mode(FreezeMode p_freeze_mode) { - if (p_freeze_mode == freeze_mode) { - return; - } - - freeze_mode = p_freeze_mode; - _apply_body_mode(); -} - -RigidBody2D::FreezeMode RigidBody2D::get_freeze_mode() const { - return freeze_mode; -} - -void RigidBody2D::set_mass(real_t p_mass) { - ERR_FAIL_COND(p_mass <= 0); - mass = p_mass; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_MASS, mass); -} - -real_t RigidBody2D::get_mass() const { - return mass; -} - -void RigidBody2D::set_inertia(real_t p_inertia) { - ERR_FAIL_COND(p_inertia < 0); - inertia = p_inertia; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); -} - -real_t RigidBody2D::get_inertia() const { - return inertia; -} - -void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) { - if (center_of_mass_mode == p_mode) { - return; - } - - center_of_mass_mode = p_mode; - - switch (center_of_mass_mode) { - case CENTER_OF_MASS_MODE_AUTO: { - center_of_mass = Vector2(); - PhysicsServer2D::get_singleton()->body_reset_mass_properties(get_rid()); - if (inertia != 0.0) { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); - } - } break; - - case CENTER_OF_MASS_MODE_CUSTOM: { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); - } break; - } -} - -RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const { - return center_of_mass_mode; -} - -void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) { - if (center_of_mass == p_center_of_mass) { - return; - } - - ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); - center_of_mass = p_center_of_mass; - - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); -} - -const Vector2 &RigidBody2D::get_center_of_mass() const { - return center_of_mass; -} - -void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { - if (physics_material_override.is_valid()) { - physics_material_override->disconnect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics)); - } - - physics_material_override = p_physics_material_override; - - if (physics_material_override.is_valid()) { - physics_material_override->connect_changed(callable_mp(this, &RigidBody2D::_reload_physics_characteristics)); - } - _reload_physics_characteristics(); -} - -Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const { - return physics_material_override; -} - -void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) { - gravity_scale = p_gravity_scale; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); -} - -real_t RigidBody2D::get_gravity_scale() const { - return gravity_scale; -} - -void RigidBody2D::set_linear_damp_mode(DampMode p_mode) { - linear_damp_mode = p_mode; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); -} - -RigidBody2D::DampMode RigidBody2D::get_linear_damp_mode() const { - return linear_damp_mode; -} - -void RigidBody2D::set_angular_damp_mode(DampMode p_mode) { - angular_damp_mode = p_mode; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); -} - -RigidBody2D::DampMode RigidBody2D::get_angular_damp_mode() const { - return angular_damp_mode; -} - -void RigidBody2D::set_linear_damp(real_t p_linear_damp) { - ERR_FAIL_COND(p_linear_damp < -1); - linear_damp = p_linear_damp; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP, linear_damp); -} - -real_t RigidBody2D::get_linear_damp() const { - return linear_damp; -} - -void RigidBody2D::set_angular_damp(real_t p_angular_damp) { - ERR_FAIL_COND(p_angular_damp < -1); - angular_damp = p_angular_damp; - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP, angular_damp); -} - -real_t RigidBody2D::get_angular_damp() const { - return angular_damp; -} - -void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) { - Vector2 axis = p_axis.normalized(); - linear_velocity -= axis * axis.dot(linear_velocity); - linear_velocity += p_axis; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); -} - -void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) { - linear_velocity = p_velocity; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); -} - -Vector2 RigidBody2D::get_linear_velocity() const { - return linear_velocity; -} - -void RigidBody2D::set_angular_velocity(real_t p_velocity) { - angular_velocity = p_velocity; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); -} - -real_t RigidBody2D::get_angular_velocity() const { - return angular_velocity; -} - -void RigidBody2D::set_use_custom_integrator(bool p_enable) { - if (custom_integrator == p_enable) { - return; - } - - custom_integrator = p_enable; - PhysicsServer2D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); -} - -bool RigidBody2D::is_using_custom_integrator() { - return custom_integrator; -} - -void RigidBody2D::set_sleeping(bool p_sleeping) { - sleeping = p_sleeping; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_SLEEPING, sleeping); -} - -void RigidBody2D::set_can_sleep(bool p_active) { - can_sleep = p_active; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_CAN_SLEEP, p_active); -} - -bool RigidBody2D::is_able_to_sleep() const { - return can_sleep; -} - -bool RigidBody2D::is_sleeping() const { - return sleeping; -} - -void RigidBody2D::set_max_contacts_reported(int p_amount) { - max_contacts_reported = p_amount; - PhysicsServer2D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount); -} - -int RigidBody2D::get_max_contacts_reported() const { - return max_contacts_reported; -} - -int RigidBody2D::get_contact_count() const { - return contact_count; -} - -void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) { - PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); -} - -void RigidBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) { - PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); -} - -void RigidBody2D::apply_torque_impulse(real_t p_torque) { - PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque); -} - -void RigidBody2D::apply_central_force(const Vector2 &p_force) { - PhysicsServer2D::get_singleton()->body_apply_central_force(get_rid(), p_force); -} - -void RigidBody2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) { - PhysicsServer2D::get_singleton()->body_apply_force(get_rid(), p_force, p_position); -} - -void RigidBody2D::apply_torque(real_t p_torque) { - PhysicsServer2D::get_singleton()->body_apply_torque(get_rid(), p_torque); -} - -void RigidBody2D::add_constant_central_force(const Vector2 &p_force) { - PhysicsServer2D::get_singleton()->body_add_constant_central_force(get_rid(), p_force); -} - -void RigidBody2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) { - PhysicsServer2D::get_singleton()->body_add_constant_force(get_rid(), p_force, p_position); -} - -void RigidBody2D::add_constant_torque(const real_t p_torque) { - PhysicsServer2D::get_singleton()->body_add_constant_torque(get_rid(), p_torque); -} - -void RigidBody2D::set_constant_force(const Vector2 &p_force) { - PhysicsServer2D::get_singleton()->body_set_constant_force(get_rid(), p_force); -} - -Vector2 RigidBody2D::get_constant_force() const { - return PhysicsServer2D::get_singleton()->body_get_constant_force(get_rid()); -} - -void RigidBody2D::set_constant_torque(real_t p_torque) { - PhysicsServer2D::get_singleton()->body_set_constant_torque(get_rid(), p_torque); -} - -real_t RigidBody2D::get_constant_torque() const { - return PhysicsServer2D::get_singleton()->body_get_constant_torque(get_rid()); -} - -void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) { - ccd_mode = p_mode; - PhysicsServer2D::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), PhysicsServer2D::CCDMode(p_mode)); -} - -RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() const { - return ccd_mode; -} - -TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const { - ERR_FAIL_NULL_V(contact_monitor, TypedArray<Node2D>()); - - TypedArray<Node2D> ret; - ret.resize(contact_monitor->body_map.size()); - int idx = 0; - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; - } - } - - return ret; -} - -void RigidBody2D::set_contact_monitor(bool p_enabled) { - if (p_enabled == is_contact_monitor_enabled()) { - return; - } - - if (!p_enabled) { - ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead."); - - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - //clean up mess - Object *obj = ObjectDB::get_instance(E.key); - Node *node = Object::cast_to<Node>(obj); - - if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree)); - } - } - - memdelete(contact_monitor); - contact_monitor = nullptr; - } else { - contact_monitor = memnew(ContactMonitor); - contact_monitor->locked = false; - } -} - -bool RigidBody2D::is_contact_monitor_enabled() const { - return contact_monitor != nullptr; -} - -void RigidBody2D::_notification(int p_what) { -#ifdef TOOLS_ENABLED - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); // Used for warnings and only in editor. - } - } break; - - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - update_configuration_warnings(); - } break; - } -#endif -} - -PackedStringArray RigidBody2D::get_configuration_warnings() const { - Transform2D t = get_transform(); - - PackedStringArray warnings = CollisionObject2D::get_configuration_warnings(); - - if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) { - warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); - } - - return warnings; -} - -void RigidBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody2D::set_mass); - ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody2D::get_mass); - - ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia); - ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia); - - ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode); - ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode); - - ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass); - ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override); - - ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale); - ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale); - - ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody2D::set_linear_damp_mode); - ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody2D::get_linear_damp_mode); - - ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody2D::set_angular_damp_mode); - ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody2D::get_angular_damp_mode); - - ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody2D::set_linear_damp); - ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody2D::get_linear_damp); - - ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody2D::set_angular_damp); - ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody2D::get_angular_damp); - - ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody2D::set_linear_velocity); - ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody2D::get_linear_velocity); - - ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody2D::set_angular_velocity); - ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody2D::get_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody2D::set_max_contacts_reported); - ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody2D::get_max_contacts_reported); - ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody2D::get_contact_count); - - ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody2D::set_use_custom_integrator); - ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody2D::is_using_custom_integrator); - - ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody2D::set_contact_monitor); - ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody2D::is_contact_monitor_enabled); - - ClassDB::bind_method(D_METHOD("set_continuous_collision_detection_mode", "mode"), &RigidBody2D::set_continuous_collision_detection_mode); - ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode); - - ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity); - ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse, Vector2()); - ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody2D::apply_impulse, Vector2()); - ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse); - - ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody2D::apply_central_force); - ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody2D::apply_force, Vector2()); - ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody2D::apply_torque); - - ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody2D::add_constant_central_force); - ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody2D::add_constant_force, Vector2()); - ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody2D::add_constant_torque); - - ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody2D::set_constant_force); - ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody2D::get_constant_force); - - ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody2D::set_constant_torque); - ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody2D::get_constant_torque); - - ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping); - ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping); - - ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep); - ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep); - - ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody2D::set_lock_rotation_enabled); - ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody2D::is_lock_rotation_enabled); - - ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody2D::set_freeze_enabled); - ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody2D::is_freeze_enabled); - - ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody2D::set_freeze_mode); - ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody2D::get_freeze_mode); - - ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies); - - GDVIRTUAL_BIND(_integrate_forces, "state"); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); - ADD_GROUP("Mass Distribution", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass"); - ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia"); - ADD_GROUP("Deactivation", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); - ADD_GROUP("Solver", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); - ADD_GROUP("Linear", "linear_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_linear_velocity", "get_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); - ADD_GROUP("Angular", "angular_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); - ADD_GROUP("Constant Forces", "constant_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px/s\u00B2"), "set_constant_force", "get_constant_force"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque"); - - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - - BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); - BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); - - BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); - BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); - - BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); - BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); - - BIND_ENUM_CONSTANT(CCD_MODE_DISABLED); - BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY); - BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE); -} - -void RigidBody2D::_validate_property(PropertyInfo &p_property) const { - if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { - if (p_property.name == "center_of_mass") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } -} - -RigidBody2D::RigidBody2D() : - PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) { - PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody2D::_body_state_changed)); -} - -RigidBody2D::~RigidBody2D() { - if (contact_monitor) { - memdelete(contact_monitor); - } -} - -void RigidBody2D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -////////////////////////// - -// So, if you pass 45 as limit, avoid numerical precision errors when angle is 45. -#define FLOOR_ANGLE_THRESHOLD 0.01 - -bool CharacterBody2D::move_and_slide() { - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - Vector2 current_platform_velocity = platform_velocity; - Transform2D gt = get_global_transform(); - previous_position = gt.columns[2]; - - if ((on_floor || on_wall) && platform_rid.is_valid()) { - bool excluded = false; - if (on_floor) { - excluded = (platform_floor_layers & platform_layer) == 0; - } else if (on_wall) { - excluded = (platform_wall_layers & platform_layer) == 0; - } - if (!excluded) { - //this approach makes sure there is less delay between the actual body velocity and the one we saved - PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid); - if (bs) { - Vector2 local_position = gt.columns[2] - bs->get_transform().columns[2]; - current_platform_velocity = bs->get_velocity_at_local_position(local_position); - } else { - // Body is removed or destroyed, invalidate floor. - current_platform_velocity = Vector2(); - platform_rid = RID(); - } - } else { - current_platform_velocity = Vector2(); - } - } - - motion_results.clear(); - last_motion = Vector2(); - - bool was_on_floor = on_floor; - on_floor = false; - on_ceiling = false; - on_wall = false; - - if (!current_platform_velocity.is_zero_approx()) { - PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - parameters.exclude_bodies.insert(platform_rid); - if (platform_object_id.is_valid()) { - parameters.exclude_objects.insert(platform_object_id); - } - - PhysicsServer2D::MotionResult floor_result; - if (move_and_collide(parameters, floor_result, false, false)) { - motion_results.push_back(floor_result); - _set_collision_direction(floor_result); - } - } - - if (motion_mode == MOTION_MODE_GROUNDED) { - _move_and_slide_grounded(delta, was_on_floor); - } else { - _move_and_slide_floating(delta); - } - - // Compute real velocity. - real_velocity = get_position_delta() / delta; - - if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { - // Add last platform velocity when just left a moving platform. - if (!on_floor && !on_wall) { - if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { - current_platform_velocity = current_platform_velocity.slide(up_direction); - } - velocity += current_platform_velocity; - } - } - - return motion_results.size() > 0; -} - -void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector2 motion = velocity * p_delta; - Vector2 motion_slide_up = motion.slide(up_direction); - - Vector2 prev_floor_normal = floor_normal; - - platform_rid = RID(); - platform_object_id = ObjectID(); - floor_normal = Vector2(); - platform_velocity = Vector2(); - - // No sliding on first attempt to keep floor motion stable when possible, - // When stop on slope is enabled or when there is no up direction. - bool sliding_enabled = !floor_stop_on_slope; - // Constant speed can be applied only the first time sliding is enabled. - bool can_apply_constant_speed = sliding_enabled; - // If the platform's ceiling push down the body. - bool apply_ceiling_velocity = false; - bool first_slide = true; - bool vel_dir_facing_up = velocity.dot(up_direction) > 0; - Vector2 last_travel; - - for (int iteration = 0; iteration < max_slides; ++iteration) { - PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - - Vector2 prev_position = parameters.from.columns[2]; - - PhysicsServer2D::MotionResult result; - bool collided = move_and_collide(parameters, result, false, !sliding_enabled); - - last_motion = result.travel; - - if (collided) { - motion_results.push_back(result); - _set_collision_direction(result); - - // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. - if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { - // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. - if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { - apply_ceiling_velocity = true; - Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); - Vector2 motion_vertical_velocity = up_direction * up_direction.dot(velocity); - if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - velocity = ceiling_vertical_velocity + velocity.slide(up_direction); - } - } - } - - if (on_floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { - Transform2D gt = get_global_transform(); - if (result.travel.length() <= margin + CMP_EPSILON) { - gt.columns[2] -= result.travel; - } - set_global_transform(gt); - velocity = Vector2(); - last_motion = Vector2(); - motion = Vector2(); - break; - } - - if (result.remainder.is_zero_approx()) { - motion = Vector2(); - break; - } - - // Move on floor only checks. - if (floor_block_on_wall && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) { - // Avoid to move forward on a wall if floor_block_on_wall is true. - if (p_was_on_floor && !on_floor && !vel_dir_facing_up) { - // If the movement is large the body can be prevented from reaching the walls. - if (result.travel.length() <= margin + CMP_EPSILON) { - // Cancels the motion. - Transform2D gt = get_global_transform(); - gt.columns[2] -= result.travel; - set_global_transform(gt); - } - // Determines if you are on the ground. - _snap_on_floor(true, false, true); - velocity = Vector2(); - last_motion = Vector2(); - motion = Vector2(); - break; - } - // Prevents the body from being able to climb a slope when it moves forward against the wall. - else if (!on_floor) { - motion = up_direction * up_direction.dot(result.remainder); - motion = motion.slide(result.collision_normal); - } else { - motion = result.remainder; - } - } - // Constant Speed when the slope is upward. - else if (floor_constant_speed && is_on_floor_only() && can_apply_constant_speed && p_was_on_floor && motion.dot(result.collision_normal) < 0) { - can_apply_constant_speed = false; - Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); - motion = motion_slide_norm * (motion_slide_up.length() - result.travel.slide(up_direction).length() - last_travel.slide(up_direction).length()); - } - // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. - else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { - Vector2 slide_motion = result.remainder.slide(result.collision_normal); - if (slide_motion.dot(velocity) > 0.0) { - motion = slide_motion; - } else { - motion = Vector2(); - } - if (slide_on_ceiling && on_ceiling) { - // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. - if (vel_dir_facing_up) { - velocity = velocity.slide(result.collision_normal); - } else { - // Avoid acceleration in slope when falling. - velocity = up_direction * up_direction.dot(velocity); - } - } - } - // No sliding on first attempt to keep floor motion stable when possible. - else { - motion = result.remainder; - if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { - velocity = velocity.slide(up_direction); - motion = motion.slide(up_direction); - } - } - - last_travel = result.travel; - } - // When you move forward in a downward slope you don’t collide because you will be in the air. - // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied. - else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) { - can_apply_constant_speed = false; - sliding_enabled = true; - Transform2D gt = get_global_transform(); - gt.columns[2] = prev_position; - set_global_transform(gt); - - Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized(); - motion = motion_slide_norm * (motion_slide_up.length()); - collided = true; - } - - can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled; - sliding_enabled = true; - first_slide = false; - - if (!collided || motion.is_zero_approx()) { - break; - } - } - - _snap_on_floor(p_was_on_floor, vel_dir_facing_up); - - // Scales the horizontal velocity according to the wall slope. - if (is_on_wall_only() && motion_slide_up.dot(motion_results.get(0).collision_normal) < 0) { - Vector2 slide_motion = velocity.slide(motion_results.get(0).collision_normal); - if (motion_slide_up.dot(slide_motion) < 0) { - velocity = up_direction * up_direction.dot(velocity); - } else { - // Keeps the vertical motion from velocity and add the horizontal motion of the projection. - velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); - } - } - - // Reset the gravity accumulation when touching the ground. - if (on_floor && !vel_dir_facing_up) { - velocity = velocity.slide(up_direction); - } -} - -void CharacterBody2D::_move_and_slide_floating(double p_delta) { - Vector2 motion = velocity * p_delta; - - platform_rid = RID(); - platform_object_id = ObjectID(); - floor_normal = Vector2(); - platform_velocity = Vector2(); - - bool first_slide = true; - for (int iteration = 0; iteration < max_slides; ++iteration) { - PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - - PhysicsServer2D::MotionResult result; - bool collided = move_and_collide(parameters, result, false, false); - - last_motion = result.travel; - - if (collided) { - motion_results.push_back(result); - _set_collision_direction(result); - - if (result.remainder.is_zero_approx()) { - motion = Vector2(); - break; - } - - if (wall_min_slide_angle != 0 && result.get_angle(-velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { - motion = Vector2(); - } else if (first_slide) { - Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); - motion = motion_slide_norm * (motion.length() - result.travel.length()); - } else { - motion = result.remainder.slide(result.collision_normal); - } - - if (motion.dot(velocity) <= 0.0) { - motion = Vector2(); - } - } - - if (!collided || motion.is_zero_approx()) { - break; - } - - first_slide = false; - } -} -void CharacterBody2D::apply_floor_snap() { - _apply_floor_snap(); -} - -// Method that avoids the p_wall_as_floor parameter for the public method. -void CharacterBody2D::_apply_floor_snap(bool p_wall_as_floor) { - if (on_floor) { - return; - } - - // Snap by at least collision margin to keep floor state consistent. - real_t length = MAX(floor_snap_length, margin); - - PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - parameters.collide_separation_ray = true; - - PhysicsServer2D::MotionResult result; - if (move_and_collide(parameters, result, true, false)) { - if ((result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) || - (p_wall_as_floor && result.get_angle(-up_direction) > floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { - on_floor = true; - floor_normal = result.collision_normal; - _set_platform_data(result); - - if (floor_stop_on_slope) { - // move and collide may stray the object a bit because of pre un-stucking, - // so only ensure that motion happens on floor direction in this case. - if (result.travel.length() > margin) { - result.travel = up_direction * up_direction.dot(result.travel); - } else { - result.travel = Vector2(); - } - } - - parameters.from.columns[2] += result.travel; - set_global_transform(parameters.from); - } - } -} - -void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor) { - if (on_floor || !p_was_on_floor || p_vel_dir_facing_up) { - return; - } - - _apply_floor_snap(p_wall_as_floor); -} - -bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) { - if (up_direction == Vector2() || on_floor || !p_was_on_floor || p_vel_dir_facing_up) { - return false; - } - - // Snap by at least collision margin to keep floor state consistent. - real_t length = MAX(floor_snap_length, margin); - - PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - parameters.collide_separation_ray = true; - - PhysicsServer2D::MotionResult result; - if (move_and_collide(parameters, result, true, false)) { - if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { - return true; - } - } - - return false; -} - -void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) { - if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor - on_floor = true; - floor_normal = p_result.collision_normal; - _set_platform_data(p_result); - } else if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling - on_ceiling = true; - } else { - on_wall = true; - wall_normal = p_result.collision_normal; - // Don't apply wall velocity when the collider is a CharacterBody2D. - if (Object::cast_to<CharacterBody2D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) { - _set_platform_data(p_result); - } - } -} - -void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) { - platform_rid = p_result.collider; - platform_object_id = p_result.collider_id; - platform_velocity = p_result.collider_velocity; - platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); -} - -const Vector2 &CharacterBody2D::get_velocity() const { - return velocity; -} - -void CharacterBody2D::set_velocity(const Vector2 &p_velocity) { - velocity = p_velocity; -} - -bool CharacterBody2D::is_on_floor() const { - return on_floor; -} - -bool CharacterBody2D::is_on_floor_only() const { - return on_floor && !on_wall && !on_ceiling; -} - -bool CharacterBody2D::is_on_wall() const { - return on_wall; -} - -bool CharacterBody2D::is_on_wall_only() const { - return on_wall && !on_floor && !on_ceiling; -} - -bool CharacterBody2D::is_on_ceiling() const { - return on_ceiling; -} - -bool CharacterBody2D::is_on_ceiling_only() const { - return on_ceiling && !on_floor && !on_wall; -} - -const Vector2 &CharacterBody2D::get_floor_normal() const { - return floor_normal; -} - -const Vector2 &CharacterBody2D::get_wall_normal() const { - return wall_normal; -} - -const Vector2 &CharacterBody2D::get_last_motion() const { - return last_motion; -} - -Vector2 CharacterBody2D::get_position_delta() const { - return get_global_transform().columns[2] - previous_position; -} - -const Vector2 &CharacterBody2D::get_real_velocity() const { - return real_velocity; -} - -real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const { - ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); - return Math::acos(floor_normal.dot(p_up_direction)); -} - -const Vector2 &CharacterBody2D::get_platform_velocity() const { - return platform_velocity; -} - -int CharacterBody2D::get_slide_collision_count() const { - return motion_results.size(); -} - -PhysicsServer2D::MotionResult CharacterBody2D::get_slide_collision(int p_bounce) const { - ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer2D::MotionResult()); - return motion_results[p_bounce]; -} - -Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { - ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision2D>()); - if (p_bounce >= slide_colliders.size()) { - slide_colliders.resize(p_bounce + 1); - } - - // Create a new instance when the cached reference is invalid or still in use in script. - if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { - slide_colliders.write[p_bounce].instantiate(); - slide_colliders.write[p_bounce]->owner = this; - } - - slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; - return slide_colliders[p_bounce]; -} - -Ref<KinematicCollision2D> CharacterBody2D::_get_last_slide_collision() { - if (motion_results.size() == 0) { - return Ref<KinematicCollision2D>(); - } - return _get_slide_collision(motion_results.size() - 1); -} - -void CharacterBody2D::set_safe_margin(real_t p_margin) { - margin = p_margin; -} - -real_t CharacterBody2D::get_safe_margin() const { - return margin; -} - -bool CharacterBody2D::is_floor_stop_on_slope_enabled() const { - return floor_stop_on_slope; -} - -void CharacterBody2D::set_floor_stop_on_slope_enabled(bool p_enabled) { - floor_stop_on_slope = p_enabled; -} - -bool CharacterBody2D::is_floor_constant_speed_enabled() const { - return floor_constant_speed; -} - -void CharacterBody2D::set_floor_constant_speed_enabled(bool p_enabled) { - floor_constant_speed = p_enabled; -} - -bool CharacterBody2D::is_floor_block_on_wall_enabled() const { - return floor_block_on_wall; -} - -void CharacterBody2D::set_floor_block_on_wall_enabled(bool p_enabled) { - floor_block_on_wall = p_enabled; -} - -bool CharacterBody2D::is_slide_on_ceiling_enabled() const { - return slide_on_ceiling; -} - -void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) { - slide_on_ceiling = p_enabled; -} - -uint32_t CharacterBody2D::get_platform_floor_layers() const { - return platform_floor_layers; -} - -void CharacterBody2D::set_platform_floor_layers(uint32_t p_exclude_layers) { - platform_floor_layers = p_exclude_layers; -} - -uint32_t CharacterBody2D::get_platform_wall_layers() const { - return platform_wall_layers; -} - -void CharacterBody2D::set_platform_wall_layers(uint32_t p_exclude_layers) { - platform_wall_layers = p_exclude_layers; -} - -void CharacterBody2D::set_motion_mode(MotionMode p_mode) { - motion_mode = p_mode; -} - -CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const { - return motion_mode; -} - -void CharacterBody2D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { - platform_on_leave = p_on_leave_apply_velocity; -} - -CharacterBody2D::PlatformOnLeave CharacterBody2D::get_platform_on_leave() const { - return platform_on_leave; -} - -int CharacterBody2D::get_max_slides() const { - return max_slides; -} - -void CharacterBody2D::set_max_slides(int p_max_slides) { - ERR_FAIL_COND(p_max_slides < 1); - max_slides = p_max_slides; -} - -real_t CharacterBody2D::get_floor_max_angle() const { - return floor_max_angle; -} - -void CharacterBody2D::set_floor_max_angle(real_t p_radians) { - floor_max_angle = p_radians; -} - -real_t CharacterBody2D::get_floor_snap_length() { - return floor_snap_length; -} - -void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) { - ERR_FAIL_COND(p_floor_snap_length < 0); - floor_snap_length = p_floor_snap_length; -} - -real_t CharacterBody2D::get_wall_min_slide_angle() const { - return wall_min_slide_angle; -} - -void CharacterBody2D::set_wall_min_slide_angle(real_t p_radians) { - wall_min_slide_angle = p_radians; -} - -const Vector2 &CharacterBody2D::get_up_direction() const { - return up_direction; -} - -void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { - ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Floating motion mode instead."); - up_direction = p_up_direction.normalized(); -} - -void CharacterBody2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - // Reset move_and_slide() data. - on_floor = false; - platform_rid = RID(); - platform_object_id = ObjectID(); - on_ceiling = false; - on_wall = false; - motion_results.clear(); - platform_velocity = Vector2(); - } break; - } -} - -void CharacterBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); - ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody2D::apply_floor_snap); - - ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); - ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); - - ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody2D::set_safe_margin); - ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); - ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody2D::set_floor_constant_speed_enabled); - ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody2D::is_floor_constant_speed_enabled); - ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody2D::set_floor_block_on_wall_enabled); - ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody2D::is_floor_block_on_wall_enabled); - ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled); - ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled); - - ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_platform_floor_layers); - ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody2D::get_platform_floor_layers); - ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_platform_wall_layers); - ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody2D::get_platform_wall_layers); - - ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides); - ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides); - ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle); - ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); - ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length); - ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length); - ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody2D::get_wall_min_slide_angle); - ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody2D::set_wall_min_slide_angle); - ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); - ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); - ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); - ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode); - ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_platform_on_leave); - ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody2D::get_platform_on_leave); - - ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); - ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only); - ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling); - ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody2D::is_on_ceiling_only); - ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall); - ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody2D::is_on_wall_only); - ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal); - ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody2D::get_wall_normal); - ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody2D::get_last_motion); - ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody2D::get_position_delta); - ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody2D::get_real_velocity); - ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody2D::get_floor_angle, DEFVAL(Vector2(0.0, -1.0))); - ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody2D::get_platform_velocity); - ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count); - ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); - ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); - - ADD_GROUP("Floor", "floor_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees"), "set_floor_max_angle", "get_floor_max_angle"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length"); - - ADD_GROUP("Moving Platform", "platform_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); - - ADD_GROUP("Collision", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin"); - - BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); - BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); - - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); -} - -void CharacterBody2D::_validate_property(PropertyInfo &p_property) const { - if (motion_mode == MOTION_MODE_FLOATING) { - if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } else { - if (p_property.name == "wall_min_slide_angle") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } -} - -CharacterBody2D::CharacterBody2D() : - PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { -} - -CharacterBody2D::~CharacterBody2D() { - for (int i = 0; i < slide_colliders.size(); i++) { - if (slide_colliders[i].is_valid()) { - slide_colliders.write[i]->owner = nullptr; - } - } -} - -//////////////////////// - -Vector2 KinematicCollision2D::get_position() const { - return result.collision_point; -} - -Vector2 KinematicCollision2D::get_normal() const { - return result.collision_normal; -} - -Vector2 KinematicCollision2D::get_travel() const { - return result.travel; -} - -Vector2 KinematicCollision2D::get_remainder() const { - return result.remainder; -} - -real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const { - ERR_FAIL_COND_V(p_up_direction == Vector2(), 0); - return result.get_angle(p_up_direction); -} - -real_t KinematicCollision2D::get_depth() const { - return result.collision_depth; -} - -Object *KinematicCollision2D::get_local_shape() const { - if (!owner) { - return nullptr; - } - uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape); - return owner->shape_owner_get_owner(ownerid); -} - -Object *KinematicCollision2D::get_collider() const { - if (result.collider_id.is_valid()) { - return ObjectDB::get_instance(result.collider_id); - } - - return nullptr; -} - -ObjectID KinematicCollision2D::get_collider_id() const { - return result.collider_id; -} - -RID KinematicCollision2D::get_collider_rid() const { - return result.collider; -} - -Object *KinematicCollision2D::get_collider_shape() const { - Object *collider = get_collider(); - if (collider) { - CollisionObject2D *obj2d = Object::cast_to<CollisionObject2D>(collider); - if (obj2d) { - uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape); - return obj2d->shape_owner_get_owner(ownerid); - } - } - - return nullptr; -} - -int KinematicCollision2D::get_collider_shape_index() const { - return result.collider_shape; -} - -Vector2 KinematicCollision2D::get_collider_velocity() const { - return result.collider_velocity; -} - -void KinematicCollision2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_position"), &KinematicCollision2D::get_position); - ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision2D::get_normal); - ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel); - ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder); - ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0))); - ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision2D::get_depth); - ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape); - ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider); - ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id); - ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision2D::get_collider_rid); - ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape); - ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index); - ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity); -} diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h deleted file mode 100644 index 88161e284a..0000000000 --- a/scene/2d/physics_body_2d.h +++ /dev/null @@ -1,493 +0,0 @@ -/**************************************************************************/ -/* physics_body_2d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#ifndef PHYSICS_BODY_2D_H -#define PHYSICS_BODY_2D_H - -#include "core/templates/vset.h" -#include "scene/2d/collision_object_2d.h" -#include "scene/resources/physics_material.h" -#include "servers/physics_server_2d.h" - -class KinematicCollision2D; - -class PhysicsBody2D : public CollisionObject2D { - GDCLASS(PhysicsBody2D, CollisionObject2D); - -protected: - static void _bind_methods(); - PhysicsBody2D(PhysicsServer2D::BodyMode p_mode); - - Ref<KinematicCollision2D> motion_cache; - - Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false); - -public: - bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false); - Vector2 get_gravity() const; - - TypedArray<PhysicsBody2D> get_collision_exceptions(); - void add_collision_exception_with(Node *p_node); //must be physicsbody - void remove_collision_exception_with(Node *p_node); - - virtual ~PhysicsBody2D(); -}; - -class StaticBody2D : public PhysicsBody2D { - GDCLASS(StaticBody2D, PhysicsBody2D); - -private: - Vector2 constant_linear_velocity; - real_t constant_angular_velocity = 0.0; - - Ref<PhysicsMaterial> physics_material_override; - -protected: - static void _bind_methods(); - -public: - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); - Ref<PhysicsMaterial> get_physics_material_override() const; - - void set_constant_linear_velocity(const Vector2 &p_vel); - void set_constant_angular_velocity(real_t p_vel); - - Vector2 get_constant_linear_velocity() const; - real_t get_constant_angular_velocity() const; - - StaticBody2D(PhysicsServer2D::BodyMode p_mode = PhysicsServer2D::BODY_MODE_STATIC); - -private: - void _reload_physics_characteristics(); -}; - -class AnimatableBody2D : public StaticBody2D { - GDCLASS(AnimatableBody2D, StaticBody2D); - -private: - bool sync_to_physics = true; - - Transform2D last_valid_transform; - - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); - void _body_state_changed(PhysicsDirectBodyState2D *p_state); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - AnimatableBody2D(); - -private: - void _update_kinematic_motion(); - - void set_sync_to_physics(bool p_enable); - bool is_sync_to_physics_enabled() const; -}; - -class RigidBody2D : public PhysicsBody2D { - GDCLASS(RigidBody2D, PhysicsBody2D); - -public: - enum FreezeMode { - FREEZE_MODE_STATIC, - FREEZE_MODE_KINEMATIC, - }; - - enum CenterOfMassMode { - CENTER_OF_MASS_MODE_AUTO, - CENTER_OF_MASS_MODE_CUSTOM, - }; - - enum DampMode { - DAMP_MODE_COMBINE, - DAMP_MODE_REPLACE, - }; - - enum CCDMode { - CCD_MODE_DISABLED, - CCD_MODE_CAST_RAY, - CCD_MODE_CAST_SHAPE, - }; - -private: - bool can_sleep = true; - bool lock_rotation = false; - bool freeze = false; - FreezeMode freeze_mode = FREEZE_MODE_STATIC; - - real_t mass = 1.0; - real_t inertia = 0.0; - CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; - Vector2 center_of_mass; - - Ref<PhysicsMaterial> physics_material_override; - real_t gravity_scale = 1.0; - - DampMode linear_damp_mode = DAMP_MODE_COMBINE; - DampMode angular_damp_mode = DAMP_MODE_COMBINE; - - real_t linear_damp = 0.0; - real_t angular_damp = 0.0; - - Vector2 linear_velocity; - real_t angular_velocity = 0.0; - bool sleeping = false; - - int max_contacts_reported = 0; - int contact_count = 0; - - bool custom_integrator = false; - - CCDMode ccd_mode = CCD_MODE_DISABLED; - - struct ShapePair { - int body_shape = 0; - int local_shape = 0; - bool tagged = false; - bool operator<(const ShapePair &p_sp) const { - if (body_shape == p_sp.body_shape) { - return local_shape < p_sp.local_shape; - } - - return body_shape < p_sp.body_shape; - } - - ShapePair() {} - ShapePair(int p_bs, int p_ls) { - body_shape = p_bs; - local_shape = p_ls; - } - }; - struct RigidBody2D_RemoveAction { - RID rid; - ObjectID body_id; - ShapePair pair; - }; - struct BodyState { - RID rid; - //int rc; - bool in_scene = false; - VSet<ShapePair> shapes; - }; - - struct ContactMonitor { - bool locked = false; - HashMap<ObjectID, BodyState> body_map; - }; - - ContactMonitor *contact_monitor = nullptr; - void _body_enter_tree(ObjectID p_id); - void _body_exit_tree(ObjectID p_id); - - void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); - - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); - void _body_state_changed(PhysicsDirectBodyState2D *p_state); - - void _sync_body_state(PhysicsDirectBodyState2D *p_state); - -protected: - void _notification(int p_what); - static void _bind_methods(); - - void _validate_property(PropertyInfo &p_property) const; - - GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) - - void _apply_body_mode(); - -public: - void set_lock_rotation_enabled(bool p_lock_rotation); - bool is_lock_rotation_enabled() const; - - void set_freeze_enabled(bool p_freeze); - bool is_freeze_enabled() const; - - void set_freeze_mode(FreezeMode p_freeze_mode); - FreezeMode get_freeze_mode() const; - - void set_mass(real_t p_mass); - real_t get_mass() const; - - void set_inertia(real_t p_inertia); - real_t get_inertia() const; - - void set_center_of_mass_mode(CenterOfMassMode p_mode); - CenterOfMassMode get_center_of_mass_mode() const; - - void set_center_of_mass(const Vector2 &p_center_of_mass); - const Vector2 &get_center_of_mass() const; - - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); - Ref<PhysicsMaterial> get_physics_material_override() const; - - void set_gravity_scale(real_t p_gravity_scale); - real_t get_gravity_scale() const; - - void set_linear_damp_mode(DampMode p_mode); - DampMode get_linear_damp_mode() const; - - void set_angular_damp_mode(DampMode p_mode); - DampMode get_angular_damp_mode() const; - - void set_linear_damp(real_t p_linear_damp); - real_t get_linear_damp() const; - - void set_angular_damp(real_t p_angular_damp); - real_t get_angular_damp() const; - - void set_linear_velocity(const Vector2 &p_velocity); - Vector2 get_linear_velocity() const; - - void set_axis_velocity(const Vector2 &p_axis); - - void set_angular_velocity(real_t p_velocity); - real_t get_angular_velocity() const; - - void set_use_custom_integrator(bool p_enable); - bool is_using_custom_integrator(); - - void set_sleeping(bool p_sleeping); - bool is_sleeping() const; - - void set_can_sleep(bool p_active); - bool is_able_to_sleep() const; - - void set_contact_monitor(bool p_enabled); - bool is_contact_monitor_enabled() const; - - void set_max_contacts_reported(int p_amount); - int get_max_contacts_reported() const; - int get_contact_count() const; - - void set_continuous_collision_detection_mode(CCDMode p_mode); - CCDMode get_continuous_collision_detection_mode() const; - - void apply_central_impulse(const Vector2 &p_impulse); - void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()); - void apply_torque_impulse(real_t p_torque); - - void apply_central_force(const Vector2 &p_force); - void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); - void apply_torque(real_t p_torque); - - void add_constant_central_force(const Vector2 &p_force); - void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); - void add_constant_torque(real_t p_torque); - - void set_constant_force(const Vector2 &p_force); - Vector2 get_constant_force() const; - - void set_constant_torque(real_t p_torque); - real_t get_constant_torque() const; - - TypedArray<Node2D> get_colliding_bodies() const; //function for script - - virtual PackedStringArray get_configuration_warnings() const override; - - RigidBody2D(); - ~RigidBody2D(); - -private: - void _reload_physics_characteristics(); -}; - -VARIANT_ENUM_CAST(RigidBody2D::FreezeMode); -VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode); -VARIANT_ENUM_CAST(RigidBody2D::DampMode); -VARIANT_ENUM_CAST(RigidBody2D::CCDMode); - -class CharacterBody2D : public PhysicsBody2D { - GDCLASS(CharacterBody2D, PhysicsBody2D); - -public: - enum MotionMode { - MOTION_MODE_GROUNDED, - MOTION_MODE_FLOATING, - }; - enum PlatformOnLeave { - PLATFORM_ON_LEAVE_ADD_VELOCITY, - PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, - PLATFORM_ON_LEAVE_DO_NOTHING, - }; - bool move_and_slide(); - void apply_floor_snap(); - - const Vector2 &get_velocity() const; - void set_velocity(const Vector2 &p_velocity); - - bool is_on_floor() const; - bool is_on_floor_only() const; - bool is_on_wall() const; - bool is_on_wall_only() const; - bool is_on_ceiling() const; - bool is_on_ceiling_only() const; - const Vector2 &get_last_motion() const; - Vector2 get_position_delta() const; - const Vector2 &get_floor_normal() const; - const Vector2 &get_wall_normal() const; - const Vector2 &get_real_velocity() const; - - real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; - const Vector2 &get_platform_velocity() const; - - int get_slide_collision_count() const; - PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const; - - void set_safe_margin(real_t p_margin); - real_t get_safe_margin() const; - - bool is_floor_stop_on_slope_enabled() const; - void set_floor_stop_on_slope_enabled(bool p_enabled); - - bool is_floor_constant_speed_enabled() const; - void set_floor_constant_speed_enabled(bool p_enabled); - - bool is_floor_block_on_wall_enabled() const; - void set_floor_block_on_wall_enabled(bool p_enabled); - - bool is_slide_on_ceiling_enabled() const; - void set_slide_on_ceiling_enabled(bool p_enabled); - - int get_max_slides() const; - void set_max_slides(int p_max_slides); - - real_t get_floor_max_angle() const; - void set_floor_max_angle(real_t p_radians); - - real_t get_floor_snap_length(); - void set_floor_snap_length(real_t p_floor_snap_length); - - real_t get_wall_min_slide_angle() const; - void set_wall_min_slide_angle(real_t p_radians); - - uint32_t get_platform_floor_layers() const; - void set_platform_floor_layers(const uint32_t p_exclude_layer); - - uint32_t get_platform_wall_layers() const; - void set_platform_wall_layers(const uint32_t p_exclude_layer); - - void set_motion_mode(MotionMode p_mode); - MotionMode get_motion_mode() const; - - void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); - PlatformOnLeave get_platform_on_leave() const; - - CharacterBody2D(); - ~CharacterBody2D(); - -private: - real_t margin = 0.08; - MotionMode motion_mode = MOTION_MODE_GROUNDED; - PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; - - bool floor_constant_speed = false; - bool floor_stop_on_slope = true; - bool floor_block_on_wall = true; - bool slide_on_ceiling = true; - int max_slides = 4; - int platform_layer = 0; - real_t floor_max_angle = Math::deg_to_rad((real_t)45.0); - real_t floor_snap_length = 1; - real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0); - Vector2 up_direction = Vector2(0.0, -1.0); - uint32_t platform_floor_layers = UINT32_MAX; - uint32_t platform_wall_layers = 0; - Vector2 velocity; - - Vector2 floor_normal; - Vector2 platform_velocity; - Vector2 wall_normal; - Vector2 last_motion; - Vector2 previous_position; - Vector2 real_velocity; - - RID platform_rid; - ObjectID platform_object_id; - bool on_floor = false; - bool on_ceiling = false; - bool on_wall = false; - - Vector<PhysicsServer2D::MotionResult> motion_results; - Vector<Ref<KinematicCollision2D>> slide_colliders; - - void _move_and_slide_floating(double p_delta); - void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); - - Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); - Ref<KinematicCollision2D> _get_last_slide_collision(); - const Vector2 &get_up_direction() const; - bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up); - void set_up_direction(const Vector2 &p_up_direction); - void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result); - void _set_platform_data(const PhysicsServer2D::MotionResult &p_result); - void _apply_floor_snap(bool p_wall_as_floor = false); - void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor = false); - -protected: - void _notification(int p_what); - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; -}; - -VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); -VARIANT_ENUM_CAST(CharacterBody2D::PlatformOnLeave); - -class KinematicCollision2D : public RefCounted { - GDCLASS(KinematicCollision2D, RefCounted); - - PhysicsBody2D *owner = nullptr; - friend class PhysicsBody2D; - friend class CharacterBody2D; - PhysicsServer2D::MotionResult result; - -protected: - static void _bind_methods(); - -public: - Vector2 get_position() const; - Vector2 get_normal() const; - Vector2 get_travel() const; - Vector2 get_remainder() const; - real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; - real_t get_depth() const; - Object *get_local_shape() const; - Object *get_collider() const; - ObjectID get_collider_id() const; - RID get_collider_rid() const; - Object *get_collider_shape() const; - int get_collider_shape_index() const; - Vector2 get_collider_velocity() const; -}; - -#endif // PHYSICS_BODY_2D_H diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index 2753fee7e9..c9431f53d8 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -1625,8 +1625,11 @@ void TileMapLayer::_queue_internal_update() { if (pending_update) { return; } - pending_update = true; - callable_mp(this, &TileMapLayer::_deferred_internal_update).call_deferred(); + // Don't update when outside the tree, it doesn't do anything useful, and causes threading problems. + if (is_inside_tree()) { + pending_update = true; + callable_mp(this, &TileMapLayer::_deferred_internal_update).call_deferred(); + } } void TileMapLayer::_deferred_internal_update() { @@ -1695,7 +1698,8 @@ void TileMapLayer::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] = true; - _queue_internal_update(); + // Update immediately on exiting. + update_internals(); } break; case TileMap::NOTIFICATION_ENTER_CANVAS: { @@ -1705,7 +1709,8 @@ void TileMapLayer::_notification(int p_what) { case TileMap::NOTIFICATION_EXIT_CANVAS: { dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true; - _queue_internal_update(); + // Update immediately on exiting. + update_internals(); } break; case TileMap::NOTIFICATION_VISIBILITY_CHANGED: { diff --git a/scene/3d/SCsub b/scene/3d/SCsub index fc61250247..94e1ab6c96 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -3,3 +3,6 @@ Import("env") env.add_source_files(env.scene_sources, "*.cpp") + +# Chain load SCsubs +SConscript("physics/SCsub") diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 2bb376c9ab..f1f9a04ea0 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -32,9 +32,9 @@ #include "audio_stream_player_3d.compat.inc" #include "core/config/project_settings.h" -#include "scene/3d/area_3d.h" #include "scene/3d/audio_listener_3d.h" #include "scene/3d/camera_3d.h" +#include "scene/3d/physics/area_3d.h" #include "scene/3d/velocity_tracker_3d.h" #include "scene/audio/audio_stream_player_internal.h" #include "scene/main/viewport.h" diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index a44aa54c17..e8bd498e1f 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -30,7 +30,6 @@ #include "camera_3d.h" -#include "collision_object_3d.h" #include "core/math/projection.h" #include "scene/main/viewport.h" diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h deleted file mode 100644 index 527aed4079..0000000000 --- a/scene/3d/joint_3d.h +++ /dev/null @@ -1,301 +0,0 @@ -/**************************************************************************/ -/* joint_3d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#ifndef JOINT_3D_H -#define JOINT_3D_H - -#include "scene/3d/node_3d.h" -#include "scene/3d/physics_body_3d.h" - -class Joint3D : public Node3D { - GDCLASS(Joint3D, Node3D); - - RID ba, bb; - - RID joint; - - NodePath a; - NodePath b; - - int solver_priority = 1; - bool exclude_from_collision = true; - String warning; - bool configured = false; - -protected: - void _disconnect_signals(); - void _body_exit_tree(); - void _update_joint(bool p_only_free = false); - - void _notification(int p_what); - - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0; - - static void _bind_methods(); - - _FORCE_INLINE_ bool is_configured() const { return configured; } - -public: - virtual PackedStringArray get_configuration_warnings() const override; - - void set_node_a(const NodePath &p_node_a); - NodePath get_node_a() const; - - void set_node_b(const NodePath &p_node_b); - NodePath get_node_b() const; - - void set_solver_priority(int p_priority); - int get_solver_priority() const; - - void set_exclude_nodes_from_collision(bool p_enable); - bool get_exclude_nodes_from_collision() const; - - RID get_rid() const { return joint; } - Joint3D(); - ~Joint3D(); -}; - -/////////////////////////////////////////// - -class PinJoint3D : public Joint3D { - GDCLASS(PinJoint3D, Joint3D); - -public: - enum Param { - PARAM_BIAS = PhysicsServer3D::PIN_JOINT_BIAS, - PARAM_DAMPING = PhysicsServer3D::PIN_JOINT_DAMPING, - PARAM_IMPULSE_CLAMP = PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP - }; - -protected: - real_t params[3]; - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; - static void _bind_methods(); - -public: - void set_param(Param p_param, real_t p_value); - real_t get_param(Param p_param) const; - - PinJoint3D(); -}; - -VARIANT_ENUM_CAST(PinJoint3D::Param); - -class HingeJoint3D : public Joint3D { - GDCLASS(HingeJoint3D, Joint3D); - -public: - enum Param { - PARAM_BIAS = PhysicsServer3D::HINGE_JOINT_BIAS, - PARAM_LIMIT_UPPER = PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, - PARAM_LIMIT_LOWER = PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, - PARAM_LIMIT_BIAS = PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, - PARAM_LIMIT_SOFTNESS = PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, - PARAM_LIMIT_RELAXATION = PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, - PARAM_MOTOR_TARGET_VELOCITY = PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY, - PARAM_MOTOR_MAX_IMPULSE = PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE, - PARAM_MAX = PhysicsServer3D::HINGE_JOINT_MAX - }; - - enum Flag { - FLAG_USE_LIMIT = PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, - FLAG_ENABLE_MOTOR = PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR, - FLAG_MAX = PhysicsServer3D::HINGE_JOINT_FLAG_MAX - }; - -protected: - real_t params[PARAM_MAX]; - bool flags[FLAG_MAX]; - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; - static void _bind_methods(); - -public: - void set_param(Param p_param, real_t p_value); - real_t get_param(Param p_param) const; - - void set_flag(Flag p_flag, bool p_value); - bool get_flag(Flag p_flag) const; - - HingeJoint3D(); -}; - -VARIANT_ENUM_CAST(HingeJoint3D::Param); -VARIANT_ENUM_CAST(HingeJoint3D::Flag); - -class SliderJoint3D : public Joint3D { - GDCLASS(SliderJoint3D, Joint3D); - -public: - enum Param { - PARAM_LINEAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, - PARAM_LINEAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, - PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, - PARAM_LINEAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, - PARAM_LINEAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, - PARAM_LINEAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS, - PARAM_LINEAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION, - PARAM_LINEAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING, - PARAM_LINEAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS, - PARAM_LINEAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION, - PARAM_LINEAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING, - - PARAM_ANGULAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, - PARAM_ANGULAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, - PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, - PARAM_ANGULAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION, - PARAM_ANGULAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, - PARAM_ANGULAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS, - PARAM_ANGULAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION, - PARAM_ANGULAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING, - PARAM_ANGULAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS, - PARAM_ANGULAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION, - PARAM_ANGULAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING, - PARAM_MAX = PhysicsServer3D::SLIDER_JOINT_MAX - - }; - -protected: - real_t params[PARAM_MAX]; - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; - static void _bind_methods(); - -public: - void set_param(Param p_param, real_t p_value); - real_t get_param(Param p_param) const; - - SliderJoint3D(); -}; - -VARIANT_ENUM_CAST(SliderJoint3D::Param); - -class ConeTwistJoint3D : public Joint3D { - GDCLASS(ConeTwistJoint3D, Joint3D); - -public: - enum Param { - PARAM_SWING_SPAN, - PARAM_TWIST_SPAN, - PARAM_BIAS, - PARAM_SOFTNESS, - PARAM_RELAXATION, - PARAM_MAX - }; - -protected: - real_t params[PARAM_MAX]; - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; - static void _bind_methods(); - -public: - void set_param(Param p_param, real_t p_value); - real_t get_param(Param p_param) const; - - ConeTwistJoint3D(); -}; - -VARIANT_ENUM_CAST(ConeTwistJoint3D::Param); - -class Generic6DOFJoint3D : public Joint3D { - GDCLASS(Generic6DOFJoint3D, Joint3D); - -public: - enum Param { - PARAM_LINEAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, - PARAM_LINEAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, - PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, - PARAM_LINEAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, - PARAM_LINEAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, - PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY, - PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT, - PARAM_LINEAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, - PARAM_LINEAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, - PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, - PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, - PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, - PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, - PARAM_ANGULAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, - PARAM_ANGULAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, - PARAM_ANGULAR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT, - PARAM_ANGULAR_ERP = PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, - PARAM_ANGULAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY, - PARAM_ANGULAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT, - PARAM_ANGULAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, - PARAM_ANGULAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, - PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, - PARAM_MAX = PhysicsServer3D::G6DOF_JOINT_MAX, - }; - - enum Flag { - FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, - FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, - FLAG_ENABLE_LINEAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, - FLAG_ENABLE_ANGULAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, - FLAG_ENABLE_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR, - FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR, - FLAG_MAX = PhysicsServer3D::G6DOF_JOINT_FLAG_MAX - }; - -protected: - real_t params_x[PARAM_MAX]; - bool flags_x[FLAG_MAX]; - real_t params_y[PARAM_MAX]; - bool flags_y[FLAG_MAX]; - real_t params_z[PARAM_MAX]; - bool flags_z[FLAG_MAX]; - - virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; - static void _bind_methods(); - -public: - void set_param_x(Param p_param, real_t p_value); - real_t get_param_x(Param p_param) const; - - void set_param_y(Param p_param, real_t p_value); - real_t get_param_y(Param p_param) const; - - void set_param_z(Param p_param, real_t p_value); - real_t get_param_z(Param p_param) const; - - void set_flag_x(Flag p_flag, bool p_enabled); - bool get_flag_x(Flag p_flag) const; - - void set_flag_y(Flag p_flag, bool p_enabled); - bool get_flag_y(Flag p_flag) const; - - void set_flag_z(Flag p_flag, bool p_enabled); - bool get_flag_z(Flag p_flag) const; - - Generic6DOFJoint3D(); -}; - -VARIANT_ENUM_CAST(Generic6DOFJoint3D::Param); -VARIANT_ENUM_CAST(Generic6DOFJoint3D::Flag); - -#endif // JOINT_3D_H diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index eeb41573f7..8635240655 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -30,8 +30,9 @@ #include "mesh_instance_3d.h" -#include "collision_shape_3d.h" -#include "physics_body_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/static_body_3d.h" +#include "scene/3d/skeleton_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" #include "scene/resources/3d/convex_polygon_shape_3d.h" diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index 98cd5efef2..82450927d3 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -31,8 +31,6 @@ #include "navigation_obstacle_3d.h" #include "core/math/geometry_2d.h" -#include "scene/3d/collision_shape_3d.h" -#include "scene/3d/physics_body_3d.h" #include "servers/navigation_server_3d.h" void NavigationObstacle3D::_bind_methods() { diff --git a/scene/3d/physics/SCsub b/scene/3d/physics/SCsub new file mode 100644 index 0000000000..e7fd3fe643 --- /dev/null +++ b/scene/3d/physics/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") + +# Chain load SCsubs +SConscript("joints/SCsub") diff --git a/scene/3d/physics/animatable_body_3d.cpp b/scene/3d/physics/animatable_body_3d.cpp new file mode 100644 index 0000000000..407e23a57e --- /dev/null +++ b/scene/3d/physics/animatable_body_3d.cpp @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* animatable_body_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "animatable_body_3d.h" + +Vector3 AnimatableBody3D::get_linear_velocity() const { + return linear_velocity; +} + +Vector3 AnimatableBody3D::get_angular_velocity() const { + return angular_velocity; +} + +void AnimatableBody3D::set_sync_to_physics(bool p_enable) { + if (sync_to_physics == p_enable) { + return; + } + + sync_to_physics = p_enable; + + _update_kinematic_motion(); +} + +bool AnimatableBody3D::is_sync_to_physics_enabled() const { + return sync_to_physics; +} + +void AnimatableBody3D::_update_kinematic_motion() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + if (sync_to_physics) { + set_only_update_transform_changes(true); + set_notify_local_transform(true); + } else { + set_only_update_transform_changes(false); + set_notify_local_transform(false); + } +} + +void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + if (!sync_to_physics) { + return; + } + + last_valid_transform = p_state->get_transform(); + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + _on_transform_changed(); +} + +void AnimatableBody3D::_notification(int p_what) { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + last_valid_transform = get_global_transform(); + _update_kinematic_motion(); + } break; + + case NOTIFICATION_EXIT_TREE: { + set_only_update_transform_changes(false); + set_notify_local_transform(false); + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + // Used by sync to physics, send the new transform to the physics... + Transform3D new_transform = get_global_transform(); + + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + + // ... but then revert changes. + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + _on_transform_changed(); + } break; + } +} + +void AnimatableBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody3D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody3D::is_sync_to_physics_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); +} + +AnimatableBody3D::AnimatableBody3D() : + StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody3D::_body_state_changed)); +} diff --git a/scene/3d/physics/animatable_body_3d.h b/scene/3d/physics/animatable_body_3d.h new file mode 100644 index 0000000000..715b6917c0 --- /dev/null +++ b/scene/3d/physics/animatable_body_3d.h @@ -0,0 +1,67 @@ +/**************************************************************************/ +/* animatable_body_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef ANIMATABLE_BODY_3D_H +#define ANIMATABLE_BODY_3D_H + +#include "scene/3d/physics/static_body_3d.h" + +class AnimatableBody3D : public StaticBody3D { + GDCLASS(AnimatableBody3D, StaticBody3D); + +private: + Vector3 linear_velocity; + Vector3 angular_velocity; + + bool sync_to_physics = true; + + Transform3D last_valid_transform; + + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); + void _body_state_changed(PhysicsDirectBodyState3D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + virtual Vector3 get_linear_velocity() const override; + virtual Vector3 get_angular_velocity() const override; + + AnimatableBody3D(); + +private: + void _update_kinematic_motion(); + + void set_sync_to_physics(bool p_enable); + bool is_sync_to_physics_enabled() const; +}; + +#endif // ANIMATABLE_BODY_3D_H diff --git a/scene/3d/area_3d.cpp b/scene/3d/physics/area_3d.cpp index 014c33cad0..014c33cad0 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/physics/area_3d.cpp diff --git a/scene/3d/area_3d.h b/scene/3d/physics/area_3d.h index 05c558e8f0..41382b6128 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/physics/area_3d.h @@ -32,7 +32,7 @@ #define AREA_3D_H #include "core/templates/vset.h" -#include "scene/3d/collision_object_3d.h" +#include "scene/3d/physics/collision_object_3d.h" #include "scene/scene_string_names.h" class Area3D : public CollisionObject3D { diff --git a/scene/3d/physics/character_body_3d.cpp b/scene/3d/physics/character_body_3d.cpp new file mode 100644 index 0000000000..b71b9519a9 --- /dev/null +++ b/scene/3d/physics/character_body_3d.cpp @@ -0,0 +1,939 @@ +/**************************************************************************/ +/* character_body_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "character_body_3d.h" + +//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. +#define FLOOR_ANGLE_THRESHOLD 0.01 + +bool CharacterBody3D::move_and_slide() { + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky + double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + velocity[i] = 0.0; + } + } + + Transform3D gt = get_global_transform(); + previous_position = gt.origin; + + Vector3 current_platform_velocity = platform_velocity; + + if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) { + bool excluded = false; + if (collision_state.floor) { + excluded = (platform_floor_layers & platform_layer) == 0; + } else if (collision_state.wall) { + excluded = (platform_wall_layers & platform_layer) == 0; + } + if (!excluded) { + //this approach makes sure there is less delay between the actual body velocity and the one we saved + PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid); + if (bs) { + Vector3 local_position = gt.origin - bs->get_transform().origin; + current_platform_velocity = bs->get_velocity_at_local_position(local_position); + } else { + // Body is removed or destroyed, invalidate floor. + current_platform_velocity = Vector3(); + platform_rid = RID(); + } + } else { + current_platform_velocity = Vector3(); + } + } + + motion_results.clear(); + + bool was_on_floor = collision_state.floor; + collision_state.state = 0; + + last_motion = Vector3(); + + if (!current_platform_velocity.is_zero_approx()) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + + parameters.exclude_bodies.insert(platform_rid); + if (platform_object_id.is_valid()) { + parameters.exclude_objects.insert(platform_object_id); + } + + PhysicsServer3D::MotionResult floor_result; + if (move_and_collide(parameters, floor_result, false, false)) { + motion_results.push_back(floor_result); + + CollisionState result_state; + _set_collision_direction(floor_result, result_state); + } + } + + if (motion_mode == MOTION_MODE_GROUNDED) { + _move_and_slide_grounded(delta, was_on_floor); + } else { + _move_and_slide_floating(delta); + } + + // Compute real velocity. + real_velocity = get_position_delta() / delta; + + if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { + // Add last platform velocity when just left a moving platform. + if (!collision_state.floor && !collision_state.wall) { + if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { + current_platform_velocity = current_platform_velocity.slide(up_direction); + } + velocity += current_platform_velocity; + } + } + + return motion_results.size() > 0; +} + +void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { + Vector3 motion = velocity * p_delta; + Vector3 motion_slide_up = motion.slide(up_direction); + Vector3 prev_floor_normal = floor_normal; + + platform_rid = RID(); + platform_object_id = ObjectID(); + platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); + platform_ceiling_velocity = Vector3(); + floor_normal = Vector3(); + wall_normal = Vector3(); + ceiling_normal = Vector3(); + + // No sliding on first attempt to keep floor motion stable when possible, + // When stop on slope is enabled or when there is no up direction. + bool sliding_enabled = !floor_stop_on_slope; + // Constant speed can be applied only the first time sliding is enabled. + bool can_apply_constant_speed = sliding_enabled; + // If the platform's ceiling push down the body. + bool apply_ceiling_velocity = false; + bool first_slide = true; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; + Vector3 total_travel; + + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); + parameters.max_collisions = 6; // There can be 4 collisions between 2 walls + 2 more for the floor. + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + + PhysicsServer3D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, !sliding_enabled); + + last_motion = result.travel; + + if (collided) { + motion_results.push_back(result); + + CollisionState previous_state = collision_state; + + CollisionState result_state; + _set_collision_direction(result, result_state); + + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. + if (collision_state.ceiling && platform_ceiling_velocity != Vector3() && platform_ceiling_velocity.dot(up_direction) < 0) { + // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. + if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (ceiling_normal + up_direction).length() < 0.01) { + apply_ceiling_velocity = true; + Vector3 ceiling_vertical_velocity = up_direction * up_direction.dot(platform_ceiling_velocity); + Vector3 motion_vertical_velocity = up_direction * up_direction.dot(velocity); + if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); + } + } + } + + if (collision_state.floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { + Transform3D gt = get_global_transform(); + if (result.travel.length() <= margin + CMP_EPSILON) { + gt.origin -= result.travel; + } + set_global_transform(gt); + velocity = Vector3(); + motion = Vector3(); + last_motion = Vector3(); + break; + } + + if (result.remainder.is_zero_approx()) { + motion = Vector3(); + break; + } + + // Apply regular sliding by default. + bool apply_default_sliding = true; + + // Wall collision checks. + if (result_state.wall && (motion_slide_up.dot(wall_normal) <= 0)) { + // Move on floor only checks. + if (floor_block_on_wall) { + // Needs horizontal motion from current motion instead of motion_slide_up + // to properly test the angle and avoid standing on slopes + Vector3 horizontal_motion = motion.slide(up_direction); + Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized(); + real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(horizontal_motion.normalized()))); + + // Avoid to move forward on a wall if floor_block_on_wall is true. + // Applies only when the motion angle is under 90 degrees, + // in order to avoid blocking lateral motion along a wall. + if (motion_angle < .5 * Math_PI) { + apply_default_sliding = false; + if (p_was_on_floor && !vel_dir_facing_up) { + // Cancel the motion. + Transform3D gt = get_global_transform(); + real_t travel_total = result.travel.length(); + real_t cancel_dist_max = MIN(0.1, margin * 20); + if (travel_total <= margin + CMP_EPSILON) { + gt.origin -= result.travel; + result.travel = Vector3(); // Cancel for constant speed computation. + } else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls. + gt.origin -= result.travel.slide(up_direction); + // Keep remaining motion in sync with amount canceled. + motion = motion.slide(up_direction); + result.travel = Vector3(); + } else { + // Travel is too high to be safely canceled, we take it into account. + result.travel = result.travel.slide(up_direction); + motion = motion.normalized() * result.travel.length(); + } + set_global_transform(gt); + // Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations. + _snap_on_floor(true, false); + } else { + // If the movement is not canceled we only keep the remaining. + motion = result.remainder; + } + + // Apply slide on forward in order to allow only lateral motion on next step. + Vector3 forward = wall_normal.slide(up_direction).normalized(); + motion = motion.slide(forward); + + // Scales the horizontal velocity according to the wall slope. + if (vel_dir_facing_up) { + Vector3 slide_motion = velocity.slide(result.collisions[0].normal); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); + } else { + velocity = velocity.slide(forward); + } + + // Allow only lateral motion along previous floor when already on floor. + // Fixes slowing down when moving in diagonal against an inclined wall. + if (p_was_on_floor && !vel_dir_facing_up && (motion.dot(up_direction) > 0.0)) { + // Slide along the corner between the wall and previous floor. + Vector3 floor_side = prev_floor_normal.cross(wall_normal); + if (floor_side != Vector3()) { + motion = floor_side * motion.dot(floor_side); + } + } + + // Stop all motion when a second wall is hit (unless sliding down or jumping), + // in order to avoid jittering in corner cases. + bool stop_all_motion = previous_state.wall && !vel_dir_facing_up; + + // Allow sliding when the body falls. + if (!collision_state.floor && motion.dot(up_direction) < 0) { + Vector3 slide_motion = motion.slide(wall_normal); + // Test again to allow sliding only if the result goes downwards. + // Fixes jittering issues at the bottom of inclined walls. + if (slide_motion.dot(up_direction) < 0) { + stop_all_motion = false; + motion = slide_motion; + } + } + + if (stop_all_motion) { + motion = Vector3(); + velocity = Vector3(); + } + } + } + + // Stop horizontal motion when under wall slide threshold. + if (p_was_on_floor && (wall_min_slide_angle > 0.0) && result_state.wall) { + Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized(); + real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized()))); + if (motion_angle < wall_min_slide_angle) { + motion = up_direction * motion.dot(up_direction); + velocity = up_direction * velocity.dot(up_direction); + + apply_default_sliding = false; + } + } + } + + if (apply_default_sliding) { + // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. + if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { + const PhysicsServer3D::MotionCollision &collision = result.collisions[0]; + + Vector3 slide_motion = result.remainder.slide(collision.normal); + if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_zero_approx()) { + // Slide using the intersection between the motion plane and the floor plane, + // in order to keep the direction intact. + real_t motion_length = slide_motion.length(); + slide_motion = up_direction.cross(result.remainder).cross(floor_normal); + + // Keep the length from default slide to change speed in slopes by default, + // when constant speed is not enabled. + slide_motion.normalize(); + slide_motion *= motion_length; + } + + if (slide_motion.dot(velocity) > 0.0) { + motion = slide_motion; + } else { + motion = Vector3(); + } + + if (slide_on_ceiling && result_state.ceiling) { + // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. + if (vel_dir_facing_up) { + velocity = velocity.slide(collision.normal); + } else { + // Avoid acceleration in slope when falling. + velocity = up_direction * up_direction.dot(velocity); + } + } + } + // No sliding on first attempt to keep floor motion stable when possible. + else { + motion = result.remainder; + if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) { + velocity = velocity.slide(up_direction); + motion = motion.slide(up_direction); + } + } + } + + total_travel += result.travel; + + // Apply Constant Speed. + if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_zero_approx()) { + Vector3 travel_slide_up = total_travel.slide(up_direction); + motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length())); + } + } + // When you move forward in a downward slope you don’t collide because you will be in the air. + // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied. + else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) { + can_apply_constant_speed = false; + sliding_enabled = true; + Transform3D gt = get_global_transform(); + gt.origin = gt.origin - result.travel; + set_global_transform(gt); + + // Slide using the intersection between the motion plane and the floor plane, + // in order to keep the direction intact. + Vector3 motion_slide_norm = up_direction.cross(motion).cross(prev_floor_normal); + motion_slide_norm.normalize(); + + motion = motion_slide_norm * (motion_slide_up.length()); + collided = true; + } + + if (!collided || motion.is_zero_approx()) { + break; + } + + can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled; + sliding_enabled = true; + first_slide = false; + } + + _snap_on_floor(p_was_on_floor, vel_dir_facing_up); + + // Reset the gravity accumulation when touching the ground. + if (collision_state.floor && !vel_dir_facing_up) { + velocity = velocity.slide(up_direction); + } +} + +void CharacterBody3D::_move_and_slide_floating(double p_delta) { + Vector3 motion = velocity * p_delta; + + platform_rid = RID(); + platform_object_id = ObjectID(); + floor_normal = Vector3(); + platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); + + bool first_slide = true; + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + + PhysicsServer3D::MotionResult result; + bool collided = move_and_collide(parameters, result, false, false); + + last_motion = result.travel; + + if (collided) { + motion_results.push_back(result); + + CollisionState result_state; + _set_collision_direction(result, result_state); + + if (result.remainder.is_zero_approx()) { + motion = Vector3(); + break; + } + + if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + motion = Vector3(); + if (result.travel.length() < margin + CMP_EPSILON) { + Transform3D gt = get_global_transform(); + gt.origin -= result.travel; + set_global_transform(gt); + } + } else if (first_slide) { + Vector3 motion_slide_norm = result.remainder.slide(wall_normal).normalized(); + motion = motion_slide_norm * (motion.length() - result.travel.length()); + } else { + motion = result.remainder.slide(wall_normal); + } + + if (motion.dot(velocity) <= 0.0) { + motion = Vector3(); + } + } + + if (!collided || motion.is_zero_approx()) { + break; + } + + first_slide = false; + } +} + +void CharacterBody3D::apply_floor_snap() { + if (collision_state.floor) { + return; + } + + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + + PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.max_collisions = 4; + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.collide_separation_ray = true; + + PhysicsServer3D::MotionResult result; + if (move_and_collide(parameters, result, true, false)) { + CollisionState result_state; + // Apply direction for floor only. + _set_collision_direction(result, result_state, CollisionState(true, false, false)); + + if (result_state.floor) { + if (floor_stop_on_slope) { + // move and collide may stray the object a bit because of pre un-stucking, + // so only ensure that motion happens on floor direction in this case. + if (result.travel.length() > margin) { + result.travel = up_direction * up_direction.dot(result.travel); + } else { + result.travel = Vector3(); + } + } + + parameters.from.origin += result.travel; + set_global_transform(parameters.from); + } + } +} + +void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up) { + if (collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) { + return; + } + + apply_floor_snap(); +} + +bool CharacterBody3D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) { + if (up_direction == Vector3() || collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) { + return false; + } + + // Snap by at least collision margin to keep floor state consistent. + real_t length = MAX(floor_snap_length, margin); + + PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); + parameters.max_collisions = 4; + parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. + parameters.collide_separation_ray = true; + + PhysicsServer3D::MotionResult result; + if (move_and_collide(parameters, result, true, false)) { + CollisionState result_state; + // Don't apply direction for any type. + _set_collision_direction(result, result_state, CollisionState()); + + return result_state.floor; + } + + return false; +} + +void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state) { + r_state.state = 0; + + real_t wall_depth = -1.0; + real_t floor_depth = -1.0; + + bool was_on_wall = collision_state.wall; + Vector3 prev_wall_normal = wall_normal; + int wall_collision_count = 0; + Vector3 combined_wall_normal; + Vector3 tmp_wall_col; // Avoid duplicate on average calculation. + + for (int i = p_result.collision_count - 1; i >= 0; i--) { + const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i]; + + if (motion_mode == MOTION_MODE_GROUNDED) { + // Check if any collision is floor. + real_t floor_angle = collision.get_angle(up_direction); + if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + r_state.floor = true; + if (p_apply_state.floor && collision.depth > floor_depth) { + collision_state.floor = true; + floor_normal = collision.normal; + floor_depth = collision.depth; + _set_platform_data(collision); + } + continue; + } + + // Check if any collision is ceiling. + real_t ceiling_angle = collision.get_angle(-up_direction); + if (ceiling_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + r_state.ceiling = true; + if (p_apply_state.ceiling) { + platform_ceiling_velocity = collision.collider_velocity; + ceiling_normal = collision.normal; + collision_state.ceiling = true; + } + continue; + } + } + + // Collision is wall by default. + r_state.wall = true; + + if (p_apply_state.wall && collision.depth > wall_depth) { + collision_state.wall = true; + wall_depth = collision.depth; + wall_normal = collision.normal; + + // Don't apply wall velocity when the collider is a CharacterBody3D. + if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(collision.collider_id)) == nullptr) { + _set_platform_data(collision); + } + } + + // Collect normal for calculating average. + if (!collision.normal.is_equal_approx(tmp_wall_col)) { + tmp_wall_col = collision.normal; + combined_wall_normal += collision.normal; + wall_collision_count++; + } + } + + if (r_state.wall) { + if (wall_collision_count > 1 && !r_state.floor) { + // Check if wall normals cancel out to floor support. + if (!r_state.floor && motion_mode == MOTION_MODE_GROUNDED) { + combined_wall_normal.normalize(); + real_t floor_angle = Math::acos(combined_wall_normal.dot(up_direction)); + if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + r_state.floor = true; + r_state.wall = false; + if (p_apply_state.floor) { + collision_state.floor = true; + floor_normal = combined_wall_normal; + } + if (p_apply_state.wall) { + collision_state.wall = was_on_wall; + wall_normal = prev_wall_normal; + } + return; + } + } + } + } +} + +void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision &p_collision) { + platform_rid = p_collision.collider; + platform_object_id = p_collision.collider_id; + platform_velocity = p_collision.collider_velocity; + platform_angular_velocity = p_collision.collider_angular_velocity; + platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid); +} + +void CharacterBody3D::set_safe_margin(real_t p_margin) { + margin = p_margin; +} + +real_t CharacterBody3D::get_safe_margin() const { + return margin; +} + +const Vector3 &CharacterBody3D::get_velocity() const { + return velocity; +} + +void CharacterBody3D::set_velocity(const Vector3 &p_velocity) { + velocity = p_velocity; +} + +bool CharacterBody3D::is_on_floor() const { + return collision_state.floor; +} + +bool CharacterBody3D::is_on_floor_only() const { + return collision_state.floor && !collision_state.wall && !collision_state.ceiling; +} + +bool CharacterBody3D::is_on_wall() const { + return collision_state.wall; +} + +bool CharacterBody3D::is_on_wall_only() const { + return collision_state.wall && !collision_state.floor && !collision_state.ceiling; +} + +bool CharacterBody3D::is_on_ceiling() const { + return collision_state.ceiling; +} + +bool CharacterBody3D::is_on_ceiling_only() const { + return collision_state.ceiling && !collision_state.floor && !collision_state.wall; +} + +const Vector3 &CharacterBody3D::get_floor_normal() const { + return floor_normal; +} + +const Vector3 &CharacterBody3D::get_wall_normal() const { + return wall_normal; +} + +const Vector3 &CharacterBody3D::get_last_motion() const { + return last_motion; +} + +Vector3 CharacterBody3D::get_position_delta() const { + return get_global_transform().origin - previous_position; +} + +const Vector3 &CharacterBody3D::get_real_velocity() const { + return real_velocity; +} + +real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const { + ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); + return Math::acos(floor_normal.dot(p_up_direction)); +} + +const Vector3 &CharacterBody3D::get_platform_velocity() const { + return platform_velocity; +} + +const Vector3 &CharacterBody3D::get_platform_angular_velocity() const { + return platform_angular_velocity; +} + +Vector3 CharacterBody3D::get_linear_velocity() const { + return get_real_velocity(); +} + +int CharacterBody3D::get_slide_collision_count() const { + return motion_results.size(); +} + +PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult()); + return motion_results[p_bounce]; +} + +Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>()); + if (p_bounce >= slide_colliders.size()) { + slide_colliders.resize(p_bounce + 1); + } + + // Create a new instance when the cached reference is invalid or still in use in script. + if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { + slide_colliders.write[p_bounce].instantiate(); + slide_colliders.write[p_bounce]->owner = this; + } + + slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; + return slide_colliders[p_bounce]; +} + +Ref<KinematicCollision3D> CharacterBody3D::_get_last_slide_collision() { + if (motion_results.size() == 0) { + return Ref<KinematicCollision3D>(); + } + return _get_slide_collision(motion_results.size() - 1); +} + +bool CharacterBody3D::is_floor_stop_on_slope_enabled() const { + return floor_stop_on_slope; +} + +void CharacterBody3D::set_floor_stop_on_slope_enabled(bool p_enabled) { + floor_stop_on_slope = p_enabled; +} + +bool CharacterBody3D::is_floor_constant_speed_enabled() const { + return floor_constant_speed; +} + +void CharacterBody3D::set_floor_constant_speed_enabled(bool p_enabled) { + floor_constant_speed = p_enabled; +} + +bool CharacterBody3D::is_floor_block_on_wall_enabled() const { + return floor_block_on_wall; +} + +void CharacterBody3D::set_floor_block_on_wall_enabled(bool p_enabled) { + floor_block_on_wall = p_enabled; +} + +bool CharacterBody3D::is_slide_on_ceiling_enabled() const { + return slide_on_ceiling; +} + +void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) { + slide_on_ceiling = p_enabled; +} + +uint32_t CharacterBody3D::get_platform_floor_layers() const { + return platform_floor_layers; +} + +void CharacterBody3D::set_platform_floor_layers(uint32_t p_exclude_layers) { + platform_floor_layers = p_exclude_layers; +} + +uint32_t CharacterBody3D::get_platform_wall_layers() const { + return platform_wall_layers; +} + +void CharacterBody3D::set_platform_wall_layers(uint32_t p_exclude_layers) { + platform_wall_layers = p_exclude_layers; +} + +void CharacterBody3D::set_motion_mode(MotionMode p_mode) { + motion_mode = p_mode; +} + +CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const { + return motion_mode; +} + +void CharacterBody3D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { + platform_on_leave = p_on_leave_apply_velocity; +} + +CharacterBody3D::PlatformOnLeave CharacterBody3D::get_platform_on_leave() const { + return platform_on_leave; +} + +int CharacterBody3D::get_max_slides() const { + return max_slides; +} + +void CharacterBody3D::set_max_slides(int p_max_slides) { + ERR_FAIL_COND(p_max_slides < 1); + max_slides = p_max_slides; +} + +real_t CharacterBody3D::get_floor_max_angle() const { + return floor_max_angle; +} + +void CharacterBody3D::set_floor_max_angle(real_t p_radians) { + floor_max_angle = p_radians; +} + +real_t CharacterBody3D::get_floor_snap_length() { + return floor_snap_length; +} + +void CharacterBody3D::set_floor_snap_length(real_t p_floor_snap_length) { + ERR_FAIL_COND(p_floor_snap_length < 0); + floor_snap_length = p_floor_snap_length; +} + +real_t CharacterBody3D::get_wall_min_slide_angle() const { + return wall_min_slide_angle; +} + +void CharacterBody3D::set_wall_min_slide_angle(real_t p_radians) { + wall_min_slide_angle = p_radians; +} + +const Vector3 &CharacterBody3D::get_up_direction() const { + return up_direction; +} + +void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { + ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Floating motion mode instead."); + up_direction = p_up_direction.normalized(); +} + +void CharacterBody3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + // Reset move_and_slide() data. + collision_state.state = 0; + platform_rid = RID(); + platform_object_id = ObjectID(); + motion_results.clear(); + platform_velocity = Vector3(); + platform_angular_velocity = Vector3(); + } break; + } +} + +void CharacterBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); + ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody3D::apply_floor_snap); + + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity); + + ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody3D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); + ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody3D::set_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody3D::is_floor_constant_speed_enabled); + ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody3D::set_floor_block_on_wall_enabled); + ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody3D::is_floor_block_on_wall_enabled); + ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled); + ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled); + + ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_platform_floor_layers); + ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody3D::get_platform_floor_layers); + ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_platform_wall_layers); + ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody3D::get_platform_wall_layers); + + ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides); + ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides); + ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle); + ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle); + ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody3D::get_floor_snap_length); + ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody3D::set_floor_snap_length); + ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody3D::get_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody3D::set_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction); + ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction); + ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode); + ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode); + ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_platform_on_leave); + ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody3D::get_platform_on_leave); + + ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody3D::is_on_ceiling_only); + ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall); + ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody3D::is_on_wall_only); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody3D::get_wall_normal); + ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody3D::get_last_motion); + ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody3D::get_position_delta); + ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity); + ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0))); + ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity); + ClassDB::bind_method(D_METHOD("get_platform_angular_velocity"), &CharacterBody3D::get_platform_angular_velocity); + ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count); + ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); + ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "suffix:m/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); + + ADD_GROUP("Floor", "floor_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees"), "set_floor_max_angle", "get_floor_max_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater,suffix:m"), "set_floor_snap_length", "get_floor_snap_length"); + + ADD_GROUP("Moving Platform", "platform_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); + + ADD_GROUP("Collision", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin"); + + BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); + BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); + + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); + BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); +} + +void CharacterBody3D::_validate_property(PropertyInfo &p_property) const { + if (motion_mode == MOTION_MODE_FLOATING) { + if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } +} + +CharacterBody3D::CharacterBody3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { +} + +CharacterBody3D::~CharacterBody3D() { + for (int i = 0; i < slide_colliders.size(); i++) { + if (slide_colliders[i].is_valid()) { + slide_colliders.write[i]->owner = nullptr; + } + } +} diff --git a/scene/3d/physics/character_body_3d.h b/scene/3d/physics/character_body_3d.h new file mode 100644 index 0000000000..cffc0f8e63 --- /dev/null +++ b/scene/3d/physics/character_body_3d.h @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* character_body_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef CHARACTER_BODY_3D_H +#define CHARACTER_BODY_3D_H + +#include "scene/3d/physics/kinematic_collision_3d.h" +#include "scene/3d/physics/physics_body_3d.h" + +class CharacterBody3D : public PhysicsBody3D { + GDCLASS(CharacterBody3D, PhysicsBody3D); + +public: + enum MotionMode { + MOTION_MODE_GROUNDED, + MOTION_MODE_FLOATING, + }; + enum PlatformOnLeave { + PLATFORM_ON_LEAVE_ADD_VELOCITY, + PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, + PLATFORM_ON_LEAVE_DO_NOTHING, + }; + bool move_and_slide(); + void apply_floor_snap(); + + const Vector3 &get_velocity() const; + void set_velocity(const Vector3 &p_velocity); + + bool is_on_floor() const; + bool is_on_floor_only() const; + bool is_on_wall() const; + bool is_on_wall_only() const; + bool is_on_ceiling() const; + bool is_on_ceiling_only() const; + const Vector3 &get_last_motion() const; + Vector3 get_position_delta() const; + const Vector3 &get_floor_normal() const; + const Vector3 &get_wall_normal() const; + const Vector3 &get_real_velocity() const; + real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const; + const Vector3 &get_platform_velocity() const; + const Vector3 &get_platform_angular_velocity() const; + + virtual Vector3 get_linear_velocity() const override; + + int get_slide_collision_count() const; + PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const; + + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; + + bool is_floor_stop_on_slope_enabled() const; + void set_floor_stop_on_slope_enabled(bool p_enabled); + + bool is_floor_constant_speed_enabled() const; + void set_floor_constant_speed_enabled(bool p_enabled); + + bool is_floor_block_on_wall_enabled() const; + void set_floor_block_on_wall_enabled(bool p_enabled); + + bool is_slide_on_ceiling_enabled() const; + void set_slide_on_ceiling_enabled(bool p_enabled); + + int get_max_slides() const; + void set_max_slides(int p_max_slides); + + real_t get_floor_max_angle() const; + void set_floor_max_angle(real_t p_radians); + + real_t get_floor_snap_length(); + void set_floor_snap_length(real_t p_floor_snap_length); + + real_t get_wall_min_slide_angle() const; + void set_wall_min_slide_angle(real_t p_radians); + + uint32_t get_platform_floor_layers() const; + void set_platform_floor_layers(const uint32_t p_exclude_layer); + + uint32_t get_platform_wall_layers() const; + void set_platform_wall_layers(const uint32_t p_exclude_layer); + + void set_motion_mode(MotionMode p_mode); + MotionMode get_motion_mode() const; + + void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); + PlatformOnLeave get_platform_on_leave() const; + + CharacterBody3D(); + ~CharacterBody3D(); + +private: + real_t margin = 0.001; + MotionMode motion_mode = MOTION_MODE_GROUNDED; + PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; + union CollisionState { + uint32_t state = 0; + struct { + bool floor; + bool wall; + bool ceiling; + }; + + CollisionState() { + } + + CollisionState(bool p_floor, bool p_wall, bool p_ceiling) { + floor = p_floor; + wall = p_wall; + ceiling = p_ceiling; + } + }; + + CollisionState collision_state; + bool floor_constant_speed = false; + bool floor_stop_on_slope = true; + bool floor_block_on_wall = true; + bool slide_on_ceiling = true; + int max_slides = 6; + int platform_layer = 0; + RID platform_rid; + ObjectID platform_object_id; + uint32_t platform_floor_layers = UINT32_MAX; + uint32_t platform_wall_layers = 0; + real_t floor_snap_length = 0.1; + real_t floor_max_angle = Math::deg_to_rad((real_t)45.0); + real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0); + Vector3 up_direction = Vector3(0.0, 1.0, 0.0); + Vector3 velocity; + Vector3 floor_normal; + Vector3 wall_normal; + Vector3 ceiling_normal; + Vector3 last_motion; + Vector3 platform_velocity; + Vector3 platform_angular_velocity; + Vector3 platform_ceiling_velocity; + Vector3 previous_position; + Vector3 real_velocity; + + Vector<PhysicsServer3D::MotionResult> motion_results; + Vector<Ref<KinematicCollision3D>> slide_colliders; + + void _move_and_slide_floating(double p_delta); + void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); + + Ref<KinematicCollision3D> _get_slide_collision(int p_bounce); + Ref<KinematicCollision3D> _get_last_slide_collision(); + const Vector3 &get_up_direction() const; + bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up); + void set_up_direction(const Vector3 &p_up_direction); + void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state = CollisionState(true, true, true)); + void _set_platform_data(const PhysicsServer3D::MotionCollision &p_collision); + void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up); + +protected: + void _notification(int p_what); + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; +}; + +VARIANT_ENUM_CAST(CharacterBody3D::MotionMode); +VARIANT_ENUM_CAST(CharacterBody3D::PlatformOnLeave); + +#endif // CHARACTER_BODY_3D_H diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/physics/collision_object_3d.cpp index bbd2ef2fb8..bbd2ef2fb8 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/physics/collision_object_3d.cpp diff --git a/scene/3d/collision_object_3d.h b/scene/3d/physics/collision_object_3d.h index b51423f021..b51423f021 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/physics/collision_object_3d.h diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/physics/collision_polygon_3d.cpp index abde05778d..76cd4db779 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/physics/collision_polygon_3d.cpp @@ -30,8 +30,8 @@ #include "collision_polygon_3d.h" -#include "collision_object_3d.h" #include "core/math/geometry_2d.h" +#include "scene/3d/physics/collision_object_3d.h" #include "scene/resources/3d/convex_polygon_shape_3d.h" void CollisionPolygon3D::_build_polygon() { diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/physics/collision_polygon_3d.h index fe4cf40ee3..fe4cf40ee3 100644 --- a/scene/3d/collision_polygon_3d.h +++ b/scene/3d/physics/collision_polygon_3d.h diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/physics/collision_shape_3d.cpp index 08fc62ae4f..f3492a3cf3 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/physics/collision_shape_3d.cpp @@ -30,12 +30,13 @@ #include "collision_shape_3d.h" -#include "mesh_instance_3d.h" -#include "physics_body_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics/character_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/vehicle_body_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" #include "scene/resources/3d/convex_polygon_shape_3d.h" #include "scene/resources/3d/world_boundary_shape_3d.h" -#include "vehicle_body_3d.h" void CollisionShape3D::make_convex_from_siblings() { Node *p = get_parent(); diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/physics/collision_shape_3d.h index 15f6ef73cb..15f6ef73cb 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/physics/collision_shape_3d.h diff --git a/scene/3d/physics/joints/SCsub b/scene/3d/physics/joints/SCsub new file mode 100644 index 0000000000..fc61250247 --- /dev/null +++ b/scene/3d/physics/joints/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/3d/physics/joints/cone_twist_joint_3d.cpp b/scene/3d/physics/joints/cone_twist_joint_3d.cpp new file mode 100644 index 0000000000..404c074911 --- /dev/null +++ b/scene/3d/physics/joints/cone_twist_joint_3d.cpp @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* cone_twist_joint_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "cone_twist_joint_3d.h" + +#include "scene/scene_string_names.h" + +void ConeTwistJoint3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint3D::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint3D::get_param); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_SWING_SPAN); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_TWIST_SPAN); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION); + + BIND_ENUM_CONSTANT(PARAM_SWING_SPAN); + BIND_ENUM_CONSTANT(PARAM_TWIST_SPAN); + BIND_ENUM_CONSTANT(PARAM_BIAS); + BIND_ENUM_CONSTANT(PARAM_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_RELAXATION); + BIND_ENUM_CONSTANT(PARAM_MAX); +} + +void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + params[p_param] = p_value; + if (is_configured()) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_rid(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value); + } + + update_gizmos(); +} + +real_t ConeTwistJoint3D::get_param(Param p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + return params[p_param]; +} + +void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { + Transform3D gt = get_global_transform(); + + Transform3D ainv = body_a->get_global_transform().affine_inverse(); + + Transform3D local_a = ainv * gt; + local_a.orthonormalize(); + Transform3D local_b = gt; + + if (body_b) { + Transform3D binv = body_b->get_global_transform().affine_inverse(); + local_b = binv * gt; + } + + local_b.orthonormalize(); + + PhysicsServer3D::get_singleton()->joint_make_cone_twist(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + for (int i = 0; i < PARAM_MAX; i++) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(p_joint, PhysicsServer3D::ConeTwistJointParam(i), params[i]); + } +} + +ConeTwistJoint3D::ConeTwistJoint3D() { + params[PARAM_SWING_SPAN] = Math_PI * 0.25; + params[PARAM_TWIST_SPAN] = Math_PI; + params[PARAM_BIAS] = 0.3; + params[PARAM_SOFTNESS] = 0.8; + params[PARAM_RELAXATION] = 1.0; +} diff --git a/scene/3d/physics/joints/cone_twist_joint_3d.h b/scene/3d/physics/joints/cone_twist_joint_3d.h new file mode 100644 index 0000000000..a24c805390 --- /dev/null +++ b/scene/3d/physics/joints/cone_twist_joint_3d.h @@ -0,0 +1,63 @@ +/**************************************************************************/ +/* cone_twist_joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef CONE_TWIST_JOINT_3D_H +#define CONE_TWIST_JOINT_3D_H + +#include "scene/3d/physics/joints/joint_3d.h" + +class ConeTwistJoint3D : public Joint3D { + GDCLASS(ConeTwistJoint3D, Joint3D); + +public: + enum Param { + PARAM_SWING_SPAN, + PARAM_TWIST_SPAN, + PARAM_BIAS, + PARAM_SOFTNESS, + PARAM_RELAXATION, + PARAM_MAX + }; + +protected: + real_t params[PARAM_MAX]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + static void _bind_methods(); + +public: + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; + + ConeTwistJoint3D(); +}; + +VARIANT_ENUM_CAST(ConeTwistJoint3D::Param); + +#endif // CONE_TWIST_JOINT_3D_H diff --git a/scene/3d/joint_3d.cpp b/scene/3d/physics/joints/generic_6dof_joint_3d.cpp index 1e4e50182c..9f440b65cc 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/physics/joints/generic_6dof_joint_3d.cpp @@ -1,5 +1,5 @@ /**************************************************************************/ -/* joint_3d.cpp */ +/* generic_6dof_joint_3d.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,562 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "joint_3d.h" - -#include "scene/scene_string_names.h" - -void Joint3D::_disconnect_signals() { - Node *node_a = get_node_or_null(a); - PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); - if (body_a) { - body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); - } - - Node *node_b = get_node_or_null(b); - PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); - if (body_b) { - body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); - } -} - -void Joint3D::_body_exit_tree() { - _disconnect_signals(); - _update_joint(true); - update_configuration_warnings(); -} - -void Joint3D::_update_joint(bool p_only_free) { - if (ba.is_valid() && bb.is_valid()) { - PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb); - PhysicsServer3D::get_singleton()->body_remove_collision_exception(bb, ba); - } - - ba = RID(); - bb = RID(); - - configured = false; - - if (p_only_free || !is_inside_tree()) { - PhysicsServer3D::get_singleton()->joint_clear(joint); - warning = String(); - return; - } - - Node *node_a = get_node_or_null(a); - Node *node_b = get_node_or_null(b); - - PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); - PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); - - if (node_a && !body_a && node_b && !body_b) { - warning = RTR("Node A and Node B must be PhysicsBody3Ds"); - } else if (node_a && !body_a) { - warning = RTR("Node A must be a PhysicsBody3D"); - } else if (node_b && !body_b) { - warning = RTR("Node B must be a PhysicsBody3D"); - } else if (!body_a && !body_b) { - warning = RTR("Joint is not connected to any PhysicsBody3Ds"); - } else if (body_a == body_b) { - warning = RTR("Node A and Node B must be different PhysicsBody3Ds"); - } else { - warning = String(); - } - - update_configuration_warnings(); - - if (!warning.is_empty()) { - PhysicsServer3D::get_singleton()->joint_clear(joint); - return; - } - - configured = true; - - if (body_a) { - _configure_joint(joint, body_a, body_b); - } else if (body_b) { - _configure_joint(joint, body_b, nullptr); - } - - PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority); - - if (body_a) { - ba = body_a->get_rid(); - body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); - } - - if (body_b) { - bb = body_b->get_rid(); - body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); - } - - PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); -} - -void Joint3D::set_node_a(const NodePath &p_node_a) { - if (a == p_node_a) { - return; - } - - if (is_configured()) { - _disconnect_signals(); - } - - a = p_node_a; - _update_joint(); -} - -NodePath Joint3D::get_node_a() const { - return a; -} - -void Joint3D::set_node_b(const NodePath &p_node_b) { - if (b == p_node_b) { - return; - } - - if (is_configured()) { - _disconnect_signals(); - } - - b = p_node_b; - _update_joint(); -} - -NodePath Joint3D::get_node_b() const { - return b; -} - -void Joint3D::set_solver_priority(int p_priority) { - solver_priority = p_priority; - if (joint.is_valid()) { - PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority); - } -} - -int Joint3D::get_solver_priority() const { - return solver_priority; -} - -void Joint3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_POST_ENTER_TREE: { - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(); - } break; - - case NOTIFICATION_EXIT_TREE: { - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(true); - } break; - } -} - -void Joint3D::set_exclude_nodes_from_collision(bool p_enable) { - if (exclude_from_collision == p_enable) { - return; - } - if (is_configured()) { - _disconnect_signals(); - } - _update_joint(true); - exclude_from_collision = p_enable; - _update_joint(); -} - -bool Joint3D::get_exclude_nodes_from_collision() const { - return exclude_from_collision; -} - -PackedStringArray Joint3D::get_configuration_warnings() const { - PackedStringArray warnings = Node3D::get_configuration_warnings(); - - if (!warning.is_empty()) { - warnings.push_back(warning); - } - - return warnings; -} - -void Joint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint3D::set_node_a); - ClassDB::bind_method(D_METHOD("get_node_a"), &Joint3D::get_node_a); - - ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint3D::set_node_b); - ClassDB::bind_method(D_METHOD("get_node_b"), &Joint3D::get_node_b); - - ClassDB::bind_method(D_METHOD("set_solver_priority", "priority"), &Joint3D::set_solver_priority); - ClassDB::bind_method(D_METHOD("get_solver_priority"), &Joint3D::get_solver_priority); - - ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision); - ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision); - - ClassDB::bind_method(D_METHOD("get_rid"), &Joint3D::get_rid); - - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "solver_priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_nodes_from_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); -} - -Joint3D::Joint3D() { - set_notify_transform(true); - joint = PhysicsServer3D::get_singleton()->joint_create(); -} - -Joint3D::~Joint3D() { - ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); - PhysicsServer3D::get_singleton()->free(joint); -} - -/////////////////////////////////// - -void PinJoint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &PinJoint3D::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &PinJoint3D::get_param); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP); - - BIND_ENUM_CONSTANT(PARAM_BIAS); - BIND_ENUM_CONSTANT(PARAM_DAMPING); - BIND_ENUM_CONSTANT(PARAM_IMPULSE_CLAMP); -} - -void PinJoint3D::set_param(Param p_param, real_t p_value) { - ERR_FAIL_INDEX(p_param, 3); - params[p_param] = p_value; - if (is_configured()) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer3D::PinJointParam(p_param), p_value); - } -} - -real_t PinJoint3D::get_param(Param p_param) const { - ERR_FAIL_INDEX_V(p_param, 3, 0); - return params[p_param]; -} - -void PinJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Vector3 pinpos = get_global_transform().origin; - Vector3 local_a = body_a->to_local(pinpos); - Vector3 local_b; - - if (body_b) { - local_b = body_b->to_local(pinpos); - } else { - local_b = pinpos; - } - - PhysicsServer3D::get_singleton()->joint_make_pin(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); - for (int i = 0; i < 3; i++) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer3D::PinJointParam(i), params[i]); - } -} - -PinJoint3D::PinJoint3D() { - params[PARAM_BIAS] = 0.3; - params[PARAM_DAMPING] = 1; - params[PARAM_IMPULSE_CLAMP] = 0; -} - -///////////////////////////////////////////////// - -/////////////////////////////////// - -void HingeJoint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint3D::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint3D::get_param); - - ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint3D::set_flag); - ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint3D::get_flag); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); - - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_LIMIT_UPPER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_LIMIT_LOWER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); - - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, U"-200,200,0.01,or_greater,or_less,radians_as_degrees,suffix:\u00B0/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); - - BIND_ENUM_CONSTANT(PARAM_BIAS); - BIND_ENUM_CONSTANT(PARAM_LIMIT_UPPER); - BIND_ENUM_CONSTANT(PARAM_LIMIT_LOWER); - BIND_ENUM_CONSTANT(PARAM_LIMIT_BIAS); - BIND_ENUM_CONSTANT(PARAM_LIMIT_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_LIMIT_RELAXATION); - BIND_ENUM_CONSTANT(PARAM_MOTOR_TARGET_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_MOTOR_MAX_IMPULSE); - BIND_ENUM_CONSTANT(PARAM_MAX); - - BIND_ENUM_CONSTANT(FLAG_USE_LIMIT); - BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR); - BIND_ENUM_CONSTANT(FLAG_MAX); -} - -void HingeJoint3D::set_param(Param p_param, real_t p_value) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - params[p_param] = p_value; - if (is_configured()) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_rid(), PhysicsServer3D::HingeJointParam(p_param), p_value); - } - - update_gizmos(); -} - -real_t HingeJoint3D::get_param(Param p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - return params[p_param]; -} - -void HingeJoint3D::set_flag(Flag p_flag, bool p_value) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_value; - if (is_configured()) { - PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_rid(), PhysicsServer3D::HingeJointFlag(p_flag), p_value); - } - - update_gizmos(); -} - -bool HingeJoint3D::get_flag(Flag p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; -} - -void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform3D gt = get_global_transform(); - Transform3D ainv = body_a->get_global_transform().affine_inverse(); - - Transform3D local_a = ainv * gt; - local_a.orthonormalize(); - Transform3D local_b = gt; - - if (body_b) { - Transform3D binv = body_b->get_global_transform().affine_inverse(); - local_b = binv * gt; - } - - local_b.orthonormalize(); - - PhysicsServer3D::get_singleton()->joint_make_hinge(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); - for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(p_joint, PhysicsServer3D::HingeJointParam(i), params[i]); - } - for (int i = 0; i < FLAG_MAX; i++) { - set_flag(Flag(i), flags[i]); - PhysicsServer3D::get_singleton()->hinge_joint_set_flag(p_joint, PhysicsServer3D::HingeJointFlag(i), flags[i]); - } -} - -HingeJoint3D::HingeJoint3D() { - params[PARAM_BIAS] = 0.3; - params[PARAM_LIMIT_UPPER] = Math_PI * 0.5; - params[PARAM_LIMIT_LOWER] = -Math_PI * 0.5; - params[PARAM_LIMIT_BIAS] = 0.3; - params[PARAM_LIMIT_SOFTNESS] = 0.9; - params[PARAM_LIMIT_RELAXATION] = 1.0; - params[PARAM_MOTOR_TARGET_VELOCITY] = 1; - params[PARAM_MOTOR_MAX_IMPULSE] = 1; - - flags[FLAG_USE_LIMIT] = false; - flags[FLAG_ENABLE_MOTOR] = false; -} - -///////////////////////////////////////////////// - -void SliderJoint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint3D::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint3D::get_param); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_UPPER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_LOWER); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING); - - BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_UPPER); - BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_LOWER); - BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_DAMPING); - BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_DAMPING); - BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_DAMPING); - - BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_UPPER); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_LOWER); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_DAMPING); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_DAMPING); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_DAMPING); - - BIND_ENUM_CONSTANT(PARAM_MAX); -} - -void SliderJoint3D::set_param(Param p_param, real_t p_value) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - params[p_param] = p_value; - if (is_configured()) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(get_rid(), PhysicsServer3D::SliderJointParam(p_param), p_value); - } - update_gizmos(); -} - -real_t SliderJoint3D::get_param(Param p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - return params[p_param]; -} - -void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform3D gt = get_global_transform(); - Transform3D ainv = body_a->get_global_transform().affine_inverse(); - - Transform3D local_a = ainv * gt; - local_a.orthonormalize(); - Transform3D local_b = gt; - - if (body_b) { - Transform3D binv = body_b->get_global_transform().affine_inverse(); - local_b = binv * gt; - } - - local_b.orthonormalize(); - - PhysicsServer3D::get_singleton()->joint_make_slider(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); - for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(p_joint, PhysicsServer3D::SliderJointParam(i), params[i]); - } -} - -SliderJoint3D::SliderJoint3D() { - params[PARAM_LINEAR_LIMIT_UPPER] = 1.0; - params[PARAM_LINEAR_LIMIT_LOWER] = -1.0; - params[PARAM_LINEAR_LIMIT_SOFTNESS] = 1.0; - params[PARAM_LINEAR_LIMIT_RESTITUTION] = 0.7; - params[PARAM_LINEAR_LIMIT_DAMPING] = 1.0; - params[PARAM_LINEAR_MOTION_SOFTNESS] = 1.0; - params[PARAM_LINEAR_MOTION_RESTITUTION] = 0.7; - params[PARAM_LINEAR_MOTION_DAMPING] = 0; //1.0; - params[PARAM_LINEAR_ORTHOGONAL_SOFTNESS] = 1.0; - params[PARAM_LINEAR_ORTHOGONAL_RESTITUTION] = 0.7; - params[PARAM_LINEAR_ORTHOGONAL_DAMPING] = 1.0; - - params[PARAM_ANGULAR_LIMIT_UPPER] = 0; - params[PARAM_ANGULAR_LIMIT_LOWER] = 0; - params[PARAM_ANGULAR_LIMIT_SOFTNESS] = 1.0; - params[PARAM_ANGULAR_LIMIT_RESTITUTION] = 0.7; - params[PARAM_ANGULAR_LIMIT_DAMPING] = 0; //1.0; - params[PARAM_ANGULAR_MOTION_SOFTNESS] = 1.0; - params[PARAM_ANGULAR_MOTION_RESTITUTION] = 0.7; - params[PARAM_ANGULAR_MOTION_DAMPING] = 1.0; - params[PARAM_ANGULAR_ORTHOGONAL_SOFTNESS] = 1.0; - params[PARAM_ANGULAR_ORTHOGONAL_RESTITUTION] = 0.7; - params[PARAM_ANGULAR_ORTHOGONAL_DAMPING] = 1.0; -} - -////////////////////////////////// - -void ConeTwistJoint3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint3D::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint3D::get_param); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_SWING_SPAN); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_TWIST_SPAN); - - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_RELAXATION); - - BIND_ENUM_CONSTANT(PARAM_SWING_SPAN); - BIND_ENUM_CONSTANT(PARAM_TWIST_SPAN); - BIND_ENUM_CONSTANT(PARAM_BIAS); - BIND_ENUM_CONSTANT(PARAM_SOFTNESS); - BIND_ENUM_CONSTANT(PARAM_RELAXATION); - BIND_ENUM_CONSTANT(PARAM_MAX); -} - -void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) { - ERR_FAIL_INDEX(p_param, PARAM_MAX); - params[p_param] = p_value; - if (is_configured()) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_rid(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value); - } - - update_gizmos(); -} - -real_t ConeTwistJoint3D::get_param(Param p_param) const { - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - return params[p_param]; -} - -void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform3D gt = get_global_transform(); - - Transform3D ainv = body_a->get_global_transform().affine_inverse(); - - Transform3D local_a = ainv * gt; - local_a.orthonormalize(); - Transform3D local_b = gt; - - if (body_b) { - Transform3D binv = body_b->get_global_transform().affine_inverse(); - local_b = binv * gt; - } - - local_b.orthonormalize(); - - PhysicsServer3D::get_singleton()->joint_make_cone_twist(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); - for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(p_joint, PhysicsServer3D::ConeTwistJointParam(i), params[i]); - } -} - -ConeTwistJoint3D::ConeTwistJoint3D() { - params[PARAM_SWING_SPAN] = Math_PI * 0.25; - params[PARAM_TWIST_SPAN] = Math_PI; - params[PARAM_BIAS] = 0.3; - params[PARAM_SOFTNESS] = 0.8; - params[PARAM_RELAXATION] = 1.0; -} - -///////////////////////////////////////////////////////////////////// +#include "generic_6dof_joint_3d.h" void Generic6DOFJoint3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_param_x", "param", "value"), &Generic6DOFJoint3D::set_param_x); diff --git a/scene/3d/physics/joints/generic_6dof_joint_3d.h b/scene/3d/physics/joints/generic_6dof_joint_3d.h new file mode 100644 index 0000000000..9b3e4c01b3 --- /dev/null +++ b/scene/3d/physics/joints/generic_6dof_joint_3d.h @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* generic_6dof_joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef GENERIC_6DOF_JOINT_3D_H +#define GENERIC_6DOF_JOINT_3D_H + +#include "scene/3d/physics/joints/joint_3d.h" + +class Generic6DOFJoint3D : public Joint3D { + GDCLASS(Generic6DOFJoint3D, Joint3D); + +public: + enum Param { + PARAM_LINEAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, + PARAM_LINEAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, + PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, + PARAM_LINEAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, + PARAM_LINEAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, + PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY, + PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT, + PARAM_LINEAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, + PARAM_LINEAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, + PARAM_LINEAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, + PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, + PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, + PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, + PARAM_ANGULAR_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, + PARAM_ANGULAR_RESTITUTION = PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, + PARAM_ANGULAR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_FORCE_LIMIT, + PARAM_ANGULAR_ERP = PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, + PARAM_ANGULAR_MOTOR_TARGET_VELOCITY = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY, + PARAM_ANGULAR_MOTOR_FORCE_LIMIT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT, + PARAM_ANGULAR_SPRING_STIFFNESS = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, + PARAM_ANGULAR_SPRING_DAMPING = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, + PARAM_ANGULAR_SPRING_EQUILIBRIUM_POINT = PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, + PARAM_MAX = PhysicsServer3D::G6DOF_JOINT_MAX, + }; + + enum Flag { + FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, + FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, + FLAG_ENABLE_LINEAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, + FLAG_ENABLE_ANGULAR_SPRING = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, + FLAG_ENABLE_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_MOTOR, + FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR, + FLAG_MAX = PhysicsServer3D::G6DOF_JOINT_FLAG_MAX + }; + +protected: + real_t params_x[PARAM_MAX]; + bool flags_x[FLAG_MAX]; + real_t params_y[PARAM_MAX]; + bool flags_y[FLAG_MAX]; + real_t params_z[PARAM_MAX]; + bool flags_z[FLAG_MAX]; + + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + static void _bind_methods(); + +public: + void set_param_x(Param p_param, real_t p_value); + real_t get_param_x(Param p_param) const; + + void set_param_y(Param p_param, real_t p_value); + real_t get_param_y(Param p_param) const; + + void set_param_z(Param p_param, real_t p_value); + real_t get_param_z(Param p_param) const; + + void set_flag_x(Flag p_flag, bool p_enabled); + bool get_flag_x(Flag p_flag) const; + + void set_flag_y(Flag p_flag, bool p_enabled); + bool get_flag_y(Flag p_flag) const; + + void set_flag_z(Flag p_flag, bool p_enabled); + bool get_flag_z(Flag p_flag) const; + + Generic6DOFJoint3D(); +}; + +VARIANT_ENUM_CAST(Generic6DOFJoint3D::Param); +VARIANT_ENUM_CAST(Generic6DOFJoint3D::Flag); + +#endif // GENERIC_6DOF_JOINT_3D_H diff --git a/scene/3d/physics/joints/hinge_joint_3d.cpp b/scene/3d/physics/joints/hinge_joint_3d.cpp new file mode 100644 index 0000000000..92472a45e4 --- /dev/null +++ b/scene/3d/physics/joints/hinge_joint_3d.cpp @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* hinge_joint_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "hinge_joint_3d.h" + +void HingeJoint3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint3D::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint3D::get_param); + + ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint3D::set_flag); + ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint3D::get_flag); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_LIMIT_LOWER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); + + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, U"-200,200,0.01,or_greater,or_less,radians_as_degrees,suffix:\u00B0/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); + + BIND_ENUM_CONSTANT(PARAM_BIAS); + BIND_ENUM_CONSTANT(PARAM_LIMIT_UPPER); + BIND_ENUM_CONSTANT(PARAM_LIMIT_LOWER); + BIND_ENUM_CONSTANT(PARAM_LIMIT_BIAS); + BIND_ENUM_CONSTANT(PARAM_LIMIT_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_LIMIT_RELAXATION); + BIND_ENUM_CONSTANT(PARAM_MOTOR_TARGET_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_MOTOR_MAX_IMPULSE); + BIND_ENUM_CONSTANT(PARAM_MAX); + + BIND_ENUM_CONSTANT(FLAG_USE_LIMIT); + BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR); + BIND_ENUM_CONSTANT(FLAG_MAX); +} + +void HingeJoint3D::set_param(Param p_param, real_t p_value) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + params[p_param] = p_value; + if (is_configured()) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_rid(), PhysicsServer3D::HingeJointParam(p_param), p_value); + } + + update_gizmos(); +} + +real_t HingeJoint3D::get_param(Param p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + return params[p_param]; +} + +void HingeJoint3D::set_flag(Flag p_flag, bool p_value) { + ERR_FAIL_INDEX(p_flag, FLAG_MAX); + flags[p_flag] = p_value; + if (is_configured()) { + PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_rid(), PhysicsServer3D::HingeJointFlag(p_flag), p_value); + } + + update_gizmos(); +} + +bool HingeJoint3D::get_flag(Flag p_flag) const { + ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); + return flags[p_flag]; +} + +void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { + Transform3D gt = get_global_transform(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); + + Transform3D local_a = ainv * gt; + local_a.orthonormalize(); + Transform3D local_b = gt; + + if (body_b) { + Transform3D binv = body_b->get_global_transform().affine_inverse(); + local_b = binv * gt; + } + + local_b.orthonormalize(); + + PhysicsServer3D::get_singleton()->joint_make_hinge(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + for (int i = 0; i < PARAM_MAX; i++) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(p_joint, PhysicsServer3D::HingeJointParam(i), params[i]); + } + for (int i = 0; i < FLAG_MAX; i++) { + set_flag(Flag(i), flags[i]); + PhysicsServer3D::get_singleton()->hinge_joint_set_flag(p_joint, PhysicsServer3D::HingeJointFlag(i), flags[i]); + } +} + +HingeJoint3D::HingeJoint3D() { + params[PARAM_BIAS] = 0.3; + params[PARAM_LIMIT_UPPER] = Math_PI * 0.5; + params[PARAM_LIMIT_LOWER] = -Math_PI * 0.5; + params[PARAM_LIMIT_BIAS] = 0.3; + params[PARAM_LIMIT_SOFTNESS] = 0.9; + params[PARAM_LIMIT_RELAXATION] = 1.0; + params[PARAM_MOTOR_TARGET_VELOCITY] = 1; + params[PARAM_MOTOR_MAX_IMPULSE] = 1; + + flags[FLAG_USE_LIMIT] = false; + flags[FLAG_ENABLE_MOTOR] = false; +} diff --git a/scene/3d/physics/joints/hinge_joint_3d.h b/scene/3d/physics/joints/hinge_joint_3d.h new file mode 100644 index 0000000000..cd19a8771f --- /dev/null +++ b/scene/3d/physics/joints/hinge_joint_3d.h @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* hinge_joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef HINGE_JOINT_3D_H +#define HINGE_JOINT_3D_H + +#include "scene/3d/physics/joints/joint_3d.h" + +class HingeJoint3D : public Joint3D { + GDCLASS(HingeJoint3D, Joint3D); + +public: + enum Param { + PARAM_BIAS = PhysicsServer3D::HINGE_JOINT_BIAS, + PARAM_LIMIT_UPPER = PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, + PARAM_LIMIT_LOWER = PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, + PARAM_LIMIT_BIAS = PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, + PARAM_LIMIT_SOFTNESS = PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, + PARAM_LIMIT_RELAXATION = PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, + PARAM_MOTOR_TARGET_VELOCITY = PhysicsServer3D::HINGE_JOINT_MOTOR_TARGET_VELOCITY, + PARAM_MOTOR_MAX_IMPULSE = PhysicsServer3D::HINGE_JOINT_MOTOR_MAX_IMPULSE, + PARAM_MAX = PhysicsServer3D::HINGE_JOINT_MAX + }; + + enum Flag { + FLAG_USE_LIMIT = PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, + FLAG_ENABLE_MOTOR = PhysicsServer3D::HINGE_JOINT_FLAG_ENABLE_MOTOR, + FLAG_MAX = PhysicsServer3D::HINGE_JOINT_FLAG_MAX + }; + +protected: + real_t params[PARAM_MAX]; + bool flags[FLAG_MAX]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + static void _bind_methods(); + +public: + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; + + void set_flag(Flag p_flag, bool p_value); + bool get_flag(Flag p_flag) const; + + HingeJoint3D(); +}; + +VARIANT_ENUM_CAST(HingeJoint3D::Param); +VARIANT_ENUM_CAST(HingeJoint3D::Flag); + +#endif // HINGE_JOINT_3D_H diff --git a/scene/3d/physics/joints/joint_3d.cpp b/scene/3d/physics/joints/joint_3d.cpp new file mode 100644 index 0000000000..a9c2526bd0 --- /dev/null +++ b/scene/3d/physics/joints/joint_3d.cpp @@ -0,0 +1,241 @@ +/**************************************************************************/ +/* joint_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "joint_3d.h" + +#include "scene/scene_string_names.h" + +void Joint3D::_disconnect_signals() { + Node *node_a = get_node_or_null(a); + PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); + if (body_a) { + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } + + Node *node_b = get_node_or_null(b); + PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); + if (body_b) { + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } +} + +void Joint3D::_body_exit_tree() { + _disconnect_signals(); + _update_joint(true); + update_configuration_warnings(); +} + +void Joint3D::_update_joint(bool p_only_free) { + if (ba.is_valid() && bb.is_valid()) { + PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb); + PhysicsServer3D::get_singleton()->body_remove_collision_exception(bb, ba); + } + + ba = RID(); + bb = RID(); + + configured = false; + + if (p_only_free || !is_inside_tree()) { + PhysicsServer3D::get_singleton()->joint_clear(joint); + warning = String(); + return; + } + + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); + + PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); + PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); + + if (node_a && !body_a && node_b && !body_b) { + warning = RTR("Node A and Node B must be PhysicsBody3Ds"); + } else if (node_a && !body_a) { + warning = RTR("Node A must be a PhysicsBody3D"); + } else if (node_b && !body_b) { + warning = RTR("Node B must be a PhysicsBody3D"); + } else if (!body_a && !body_b) { + warning = RTR("Joint is not connected to any PhysicsBody3Ds"); + } else if (body_a == body_b) { + warning = RTR("Node A and Node B must be different PhysicsBody3Ds"); + } else { + warning = String(); + } + + update_configuration_warnings(); + + if (!warning.is_empty()) { + PhysicsServer3D::get_singleton()->joint_clear(joint); + return; + } + + configured = true; + + if (body_a) { + _configure_joint(joint, body_a, body_b); + } else if (body_b) { + _configure_joint(joint, body_b, nullptr); + } + + PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority); + + if (body_a) { + ba = body_a->get_rid(); + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } + + if (body_b) { + bb = body_b->get_rid(); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } + + PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); +} + +void Joint3D::set_node_a(const NodePath &p_node_a) { + if (a == p_node_a) { + return; + } + + if (is_configured()) { + _disconnect_signals(); + } + + a = p_node_a; + _update_joint(); +} + +NodePath Joint3D::get_node_a() const { + return a; +} + +void Joint3D::set_node_b(const NodePath &p_node_b) { + if (b == p_node_b) { + return; + } + + if (is_configured()) { + _disconnect_signals(); + } + + b = p_node_b; + _update_joint(); +} + +NodePath Joint3D::get_node_b() const { + return b; +} + +void Joint3D::set_solver_priority(int p_priority) { + solver_priority = p_priority; + if (joint.is_valid()) { + PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority); + } +} + +int Joint3D::get_solver_priority() const { + return solver_priority; +} + +void Joint3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POST_ENTER_TREE: { + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(); + } break; + + case NOTIFICATION_EXIT_TREE: { + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(true); + } break; + } +} + +void Joint3D::set_exclude_nodes_from_collision(bool p_enable) { + if (exclude_from_collision == p_enable) { + return; + } + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(true); + exclude_from_collision = p_enable; + _update_joint(); +} + +bool Joint3D::get_exclude_nodes_from_collision() const { + return exclude_from_collision; +} + +PackedStringArray Joint3D::get_configuration_warnings() const { + PackedStringArray warnings = Node3D::get_configuration_warnings(); + + if (!warning.is_empty()) { + warnings.push_back(warning); + } + + return warnings; +} + +void Joint3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_node_a", "node"), &Joint3D::set_node_a); + ClassDB::bind_method(D_METHOD("get_node_a"), &Joint3D::get_node_a); + + ClassDB::bind_method(D_METHOD("set_node_b", "node"), &Joint3D::set_node_b); + ClassDB::bind_method(D_METHOD("get_node_b"), &Joint3D::get_node_b); + + ClassDB::bind_method(D_METHOD("set_solver_priority", "priority"), &Joint3D::set_solver_priority); + ClassDB::bind_method(D_METHOD("get_solver_priority"), &Joint3D::get_solver_priority); + + ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision); + ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision); + + ClassDB::bind_method(D_METHOD("get_rid"), &Joint3D::get_rid); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "solver_priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_nodes_from_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); +} + +Joint3D::Joint3D() { + set_notify_transform(true); + joint = PhysicsServer3D::get_singleton()->joint_create(); +} + +Joint3D::~Joint3D() { + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + PhysicsServer3D::get_singleton()->free(joint); +} diff --git a/scene/3d/physics/joints/joint_3d.h b/scene/3d/physics/joints/joint_3d.h new file mode 100644 index 0000000000..ed502ab245 --- /dev/null +++ b/scene/3d/physics/joints/joint_3d.h @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef JOINT_3D_H +#define JOINT_3D_H + +#include "scene/3d/node_3d.h" +#include "scene/3d/physics/physics_body_3d.h" + +class Joint3D : public Node3D { + GDCLASS(Joint3D, Node3D); + + RID ba, bb; + + RID joint; + + NodePath a; + NodePath b; + + int solver_priority = 1; + bool exclude_from_collision = true; + String warning; + bool configured = false; + +protected: + void _disconnect_signals(); + void _body_exit_tree(); + void _update_joint(bool p_only_free = false); + + void _notification(int p_what); + + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0; + + static void _bind_methods(); + + _FORCE_INLINE_ bool is_configured() const { return configured; } + +public: + virtual PackedStringArray get_configuration_warnings() const override; + + void set_node_a(const NodePath &p_node_a); + NodePath get_node_a() const; + + void set_node_b(const NodePath &p_node_b); + NodePath get_node_b() const; + + void set_solver_priority(int p_priority); + int get_solver_priority() const; + + void set_exclude_nodes_from_collision(bool p_enable); + bool get_exclude_nodes_from_collision() const; + + RID get_rid() const { return joint; } + Joint3D(); + ~Joint3D(); +}; + +#endif // JOINT_3D_H diff --git a/scene/3d/physics/joints/pin_joint_3d.cpp b/scene/3d/physics/joints/pin_joint_3d.cpp new file mode 100644 index 0000000000..8e367c5ef6 --- /dev/null +++ b/scene/3d/physics/joints/pin_joint_3d.cpp @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* pin_joint_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "pin_joint_3d.h" + +void PinJoint3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &PinJoint3D::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &PinJoint3D::get_param); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"), "set_param", "get_param", PARAM_IMPULSE_CLAMP); + + BIND_ENUM_CONSTANT(PARAM_BIAS); + BIND_ENUM_CONSTANT(PARAM_DAMPING); + BIND_ENUM_CONSTANT(PARAM_IMPULSE_CLAMP); +} + +void PinJoint3D::set_param(Param p_param, real_t p_value) { + ERR_FAIL_INDEX(p_param, 3); + params[p_param] = p_value; + if (is_configured()) { + PhysicsServer3D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer3D::PinJointParam(p_param), p_value); + } +} + +real_t PinJoint3D::get_param(Param p_param) const { + ERR_FAIL_INDEX_V(p_param, 3, 0); + return params[p_param]; +} + +void PinJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { + Vector3 pinpos = get_global_transform().origin; + Vector3 local_a = body_a->to_local(pinpos); + Vector3 local_b; + + if (body_b) { + local_b = body_b->to_local(pinpos); + } else { + local_b = pinpos; + } + + PhysicsServer3D::get_singleton()->joint_make_pin(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + for (int i = 0; i < 3; i++) { + PhysicsServer3D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer3D::PinJointParam(i), params[i]); + } +} + +PinJoint3D::PinJoint3D() { + params[PARAM_BIAS] = 0.3; + params[PARAM_DAMPING] = 1; + params[PARAM_IMPULSE_CLAMP] = 0; +} diff --git a/scene/3d/physics/joints/pin_joint_3d.h b/scene/3d/physics/joints/pin_joint_3d.h new file mode 100644 index 0000000000..34c8db2890 --- /dev/null +++ b/scene/3d/physics/joints/pin_joint_3d.h @@ -0,0 +1,60 @@ +/**************************************************************************/ +/* pin_joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PIN_JOINT_3D_H +#define PIN_JOINT_3D_H + +#include "scene/3d/physics/joints/joint_3d.h" + +class PinJoint3D : public Joint3D { + GDCLASS(PinJoint3D, Joint3D); + +public: + enum Param { + PARAM_BIAS = PhysicsServer3D::PIN_JOINT_BIAS, + PARAM_DAMPING = PhysicsServer3D::PIN_JOINT_DAMPING, + PARAM_IMPULSE_CLAMP = PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP + }; + +protected: + real_t params[3]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + static void _bind_methods(); + +public: + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; + + PinJoint3D(); +}; + +VARIANT_ENUM_CAST(PinJoint3D::Param); + +#endif // PIN_JOINT_3D_H diff --git a/scene/3d/physics/joints/slider_joint_3d.cpp b/scene/3d/physics/joints/slider_joint_3d.cpp new file mode 100644 index 0000000000..2e87ae1e83 --- /dev/null +++ b/scene/3d/physics/joints/slider_joint_3d.cpp @@ -0,0 +1,149 @@ +/**************************************************************************/ +/* slider_joint_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "slider_joint_3d.h" + +#include "scene/scene_string_names.h" + +void SliderJoint3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint3D::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint3D::get_param); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_MOTION_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING); + + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_UPPER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians_as_degrees"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_LOWER); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_motion/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_MOTION_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_ORTHOGONAL_DAMPING); + + BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_UPPER); + BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_LOWER); + BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_DAMPING); + BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTION_DAMPING); + BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_LINEAR_ORTHOGONAL_DAMPING); + + BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_UPPER); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_LOWER); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_DAMPING); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_MOTION_DAMPING); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_SOFTNESS); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_RESTITUTION); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_ORTHOGONAL_DAMPING); + + BIND_ENUM_CONSTANT(PARAM_MAX); +} + +void SliderJoint3D::set_param(Param p_param, real_t p_value) { + ERR_FAIL_INDEX(p_param, PARAM_MAX); + params[p_param] = p_value; + if (is_configured()) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(get_rid(), PhysicsServer3D::SliderJointParam(p_param), p_value); + } + update_gizmos(); +} + +real_t SliderJoint3D::get_param(Param p_param) const { + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + return params[p_param]; +} + +void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { + Transform3D gt = get_global_transform(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); + + Transform3D local_a = ainv * gt; + local_a.orthonormalize(); + Transform3D local_b = gt; + + if (body_b) { + Transform3D binv = body_b->get_global_transform().affine_inverse(); + local_b = binv * gt; + } + + local_b.orthonormalize(); + + PhysicsServer3D::get_singleton()->joint_make_slider(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + for (int i = 0; i < PARAM_MAX; i++) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(p_joint, PhysicsServer3D::SliderJointParam(i), params[i]); + } +} + +SliderJoint3D::SliderJoint3D() { + params[PARAM_LINEAR_LIMIT_UPPER] = 1.0; + params[PARAM_LINEAR_LIMIT_LOWER] = -1.0; + params[PARAM_LINEAR_LIMIT_SOFTNESS] = 1.0; + params[PARAM_LINEAR_LIMIT_RESTITUTION] = 0.7; + params[PARAM_LINEAR_LIMIT_DAMPING] = 1.0; + params[PARAM_LINEAR_MOTION_SOFTNESS] = 1.0; + params[PARAM_LINEAR_MOTION_RESTITUTION] = 0.7; + params[PARAM_LINEAR_MOTION_DAMPING] = 0; //1.0; + params[PARAM_LINEAR_ORTHOGONAL_SOFTNESS] = 1.0; + params[PARAM_LINEAR_ORTHOGONAL_RESTITUTION] = 0.7; + params[PARAM_LINEAR_ORTHOGONAL_DAMPING] = 1.0; + + params[PARAM_ANGULAR_LIMIT_UPPER] = 0; + params[PARAM_ANGULAR_LIMIT_LOWER] = 0; + params[PARAM_ANGULAR_LIMIT_SOFTNESS] = 1.0; + params[PARAM_ANGULAR_LIMIT_RESTITUTION] = 0.7; + params[PARAM_ANGULAR_LIMIT_DAMPING] = 0; //1.0; + params[PARAM_ANGULAR_MOTION_SOFTNESS] = 1.0; + params[PARAM_ANGULAR_MOTION_RESTITUTION] = 0.7; + params[PARAM_ANGULAR_MOTION_DAMPING] = 1.0; + params[PARAM_ANGULAR_ORTHOGONAL_SOFTNESS] = 1.0; + params[PARAM_ANGULAR_ORTHOGONAL_RESTITUTION] = 0.7; + params[PARAM_ANGULAR_ORTHOGONAL_DAMPING] = 1.0; +} diff --git a/scene/3d/physics/joints/slider_joint_3d.h b/scene/3d/physics/joints/slider_joint_3d.h new file mode 100644 index 0000000000..e0b059e6e3 --- /dev/null +++ b/scene/3d/physics/joints/slider_joint_3d.h @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* slider_joint_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef SLIDER_JOINT_3D_H +#define SLIDER_JOINT_3D_H + +#include "scene/3d/physics/joints/joint_3d.h" + +class SliderJoint3D : public Joint3D { + GDCLASS(SliderJoint3D, Joint3D); + +public: + enum Param { + PARAM_LINEAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, + PARAM_LINEAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, + PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, + PARAM_LINEAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, + PARAM_LINEAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, + PARAM_LINEAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_SOFTNESS, + PARAM_LINEAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_RESTITUTION, + PARAM_LINEAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_MOTION_DAMPING, + PARAM_LINEAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_SOFTNESS, + PARAM_LINEAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_RESTITUTION, + PARAM_LINEAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_LINEAR_ORTHOGONAL_DAMPING, + + PARAM_ANGULAR_LIMIT_UPPER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, + PARAM_ANGULAR_LIMIT_LOWER = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, + PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, + PARAM_ANGULAR_LIMIT_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_RESTITUTION, + PARAM_ANGULAR_LIMIT_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, + PARAM_ANGULAR_MOTION_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_SOFTNESS, + PARAM_ANGULAR_MOTION_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_RESTITUTION, + PARAM_ANGULAR_MOTION_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_MOTION_DAMPING, + PARAM_ANGULAR_ORTHOGONAL_SOFTNESS = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_SOFTNESS, + PARAM_ANGULAR_ORTHOGONAL_RESTITUTION = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_RESTITUTION, + PARAM_ANGULAR_ORTHOGONAL_DAMPING = PhysicsServer3D::SLIDER_JOINT_ANGULAR_ORTHOGONAL_DAMPING, + PARAM_MAX = PhysicsServer3D::SLIDER_JOINT_MAX + + }; + +protected: + real_t params[PARAM_MAX]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + static void _bind_methods(); + +public: + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; + + SliderJoint3D(); +}; + +VARIANT_ENUM_CAST(SliderJoint3D::Param); + +#endif // SLIDER_JOINT_3D_H diff --git a/scene/3d/physics/kinematic_collision_3d.cpp b/scene/3d/physics/kinematic_collision_3d.cpp new file mode 100644 index 0000000000..54371425bc --- /dev/null +++ b/scene/3d/physics/kinematic_collision_3d.cpp @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* kinematic_collision_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "kinematic_collision_3d.h" + +#include "scene/3d/physics/character_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" + +Vector3 KinematicCollision3D::get_travel() const { + return result.travel; +} + +Vector3 KinematicCollision3D::get_remainder() const { + return result.remainder; +} + +int KinematicCollision3D::get_collision_count() const { + return result.collision_count; +} + +real_t KinematicCollision3D::get_depth() const { + return result.collision_depth; +} + +Vector3 KinematicCollision3D::get_position(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].position; +} + +Vector3 KinematicCollision3D::get_normal(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].normal; +} + +real_t KinematicCollision3D::get_angle(int p_collision_index, const Vector3 &p_up_direction) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0); + ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); + return result.collisions[p_collision_index].get_angle(p_up_direction); +} + +Object *KinematicCollision3D::get_local_shape(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr); + if (!owner) { + return nullptr; + } + uint32_t ownerid = owner->shape_find_owner(result.collisions[p_collision_index].local_shape); + return owner->shape_owner_get_owner(ownerid); +} + +Object *KinematicCollision3D::get_collider(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr); + if (result.collisions[p_collision_index].collider_id.is_valid()) { + return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id); + } + + return nullptr; +} + +ObjectID KinematicCollision3D::get_collider_id(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID()); + return result.collisions[p_collision_index].collider_id; +} + +RID KinematicCollision3D::get_collider_rid(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID()); + return result.collisions[p_collision_index].collider; +} + +Object *KinematicCollision3D::get_collider_shape(int p_collision_index) const { + Object *collider = get_collider(p_collision_index); + if (collider) { + CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider); + if (obj2d) { + uint32_t ownerid = obj2d->shape_find_owner(result.collisions[p_collision_index].collider_shape); + return obj2d->shape_owner_get_owner(ownerid); + } + } + + return nullptr; +} + +int KinematicCollision3D::get_collider_shape_index(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0); + return result.collisions[p_collision_index].collider_shape; +} + +Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].collider_velocity; +} + +void KinematicCollision3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel); + ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder); + ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision3D::get_depth); + ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count); + ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_angle", "collision_index", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(0), DEFVAL(Vector3(0.0, 1.0, 0.0))); + ClassDB::bind_method(D_METHOD("get_local_shape", "collision_index"), &KinematicCollision3D::get_local_shape, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &KinematicCollision3D::get_collider, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &KinematicCollision3D::get_collider_id, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &KinematicCollision3D::get_collider_rid, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0)); +} diff --git a/scene/3d/physics/kinematic_collision_3d.h b/scene/3d/physics/kinematic_collision_3d.h new file mode 100644 index 0000000000..656531c82b --- /dev/null +++ b/scene/3d/physics/kinematic_collision_3d.h @@ -0,0 +1,68 @@ +/**************************************************************************/ +/* kinematic_collision_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef KINEMATIC_COLLISION_3D_H +#define KINEMATIC_COLLISION_3D_H + +#include "core/object/ref_counted.h" +#include "servers/physics_server_3d.h" + +class CharacterBody3D; +class PhysicsBody3D; + +class KinematicCollision3D : public RefCounted { + GDCLASS(KinematicCollision3D, RefCounted); + + PhysicsBody3D *owner = nullptr; + friend class PhysicsBody3D; + friend class CharacterBody3D; + PhysicsServer3D::MotionResult result; + +protected: + static void _bind_methods(); + +public: + Vector3 get_travel() const; + Vector3 get_remainder() const; + int get_collision_count() const; + real_t get_depth() const; + Vector3 get_position(int p_collision_index = 0) const; + Vector3 get_normal(int p_collision_index = 0) const; + real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const; + Object *get_local_shape(int p_collision_index = 0) const; + Object *get_collider(int p_collision_index = 0) const; + ObjectID get_collider_id(int p_collision_index = 0) const; + RID get_collider_rid(int p_collision_index = 0) const; + Object *get_collider_shape(int p_collision_index = 0) const; + int get_collider_shape_index(int p_collision_index = 0) const; + Vector3 get_collider_velocity(int p_collision_index = 0) const; +}; + +#endif // KINEMATIC_COLLISION_3D_H diff --git a/scene/3d/physics/physical_bone_3d.cpp b/scene/3d/physics/physical_bone_3d.cpp new file mode 100644 index 0000000000..10c1fceb94 --- /dev/null +++ b/scene/3d/physics/physical_bone_3d.cpp @@ -0,0 +1,1346 @@ +/**************************************************************************/ +/* physical_bone_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "physical_bone_3d.h" + +bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + return false; +} + +bool PhysicalBone3D::JointData::_get(const StringName &p_name, Variant &r_ret) const { + return false; +} + +void PhysicalBone3D::JointData::_get_property_list(List<PropertyInfo> *p_list) const { +} + +void PhysicalBone3D::apply_central_impulse(const Vector3 &p_impulse) { + PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + +void PhysicalBone3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { + PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); +} + +void PhysicalBone3D::set_linear_velocity(const Vector3 &p_velocity) { + linear_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +Vector3 PhysicalBone3D::get_linear_velocity() const { + return linear_velocity; +} + +void PhysicalBone3D::set_angular_velocity(const Vector3 &p_velocity) { + angular_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); +} + +Vector3 PhysicalBone3D::get_angular_velocity() const { + return angular_velocity; +} + +void PhysicalBone3D::set_use_custom_integrator(bool p_enable) { + if (custom_integrator == p_enable) { + return; + } + + custom_integrator = p_enable; + PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); +} + +bool PhysicalBone3D::is_using_custom_integrator() { + return custom_integrator; +} + +void PhysicalBone3D::reset_physics_simulation_state() { + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } +} + +void PhysicalBone3D::reset_to_rest_position() { + if (parent_skeleton) { + Transform3D new_transform = parent_skeleton->get_global_transform(); + if (bone_id == -1) { + new_transform *= body_offset; + } else { + new_transform *= parent_skeleton->get_bone_global_pose(bone_id) * body_offset; + } + new_transform.orthonormalize(); + set_global_transform(new_transform); + } +} + +bool PhysicalBone3D::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + bool is_valid_pin = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_PIN; + if ("joint_constraints/bias" == p_name) { + bias = p_value; + if (is_valid_pin) { + PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_BIAS, bias); + } + + } else if ("joint_constraints/damping" == p_name) { + damping = p_value; + if (is_valid_pin) { + PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_DAMPING, damping); + } + + } else if ("joint_constraints/impulse_clamp" == p_name) { + impulse_clamp = p_value; + if (is_valid_pin) { + PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp); + } + + } else { + return false; + } + + return true; +} + +bool PhysicalBone3D::PinJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/bias" == p_name) { + r_ret = bias; + } else if ("joint_constraints/damping" == p_name) { + r_ret = damping; + } else if ("joint_constraints/impulse_clamp" == p_name) { + r_ret = impulse_clamp; + } else { + return false; + } + + return true; +} + +void PhysicalBone3D::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/damping"), PROPERTY_HINT_RANGE, "0.01,8.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/impulse_clamp"), PROPERTY_HINT_RANGE, "0.0,64.0,0.01")); +} + +bool PhysicalBone3D::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + bool is_valid_cone = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_CONE_TWIST; + if ("joint_constraints/swing_span" == p_name) { + swing_span = Math::deg_to_rad(real_t(p_value)); + if (is_valid_cone) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, swing_span); + } + + } else if ("joint_constraints/twist_span" == p_name) { + twist_span = Math::deg_to_rad(real_t(p_value)); + if (is_valid_cone) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, twist_span); + } + + } else if ("joint_constraints/bias" == p_name) { + bias = p_value; + if (is_valid_cone) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, bias); + } + + } else if ("joint_constraints/softness" == p_name) { + softness = p_value; + if (is_valid_cone) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, softness); + } + + } else if ("joint_constraints/relaxation" == p_name) { + relaxation = p_value; + if (is_valid_cone) { + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, relaxation); + } + + } else { + return false; + } + + return true; +} + +bool PhysicalBone3D::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/swing_span" == p_name) { + r_ret = Math::rad_to_deg(swing_span); + } else if ("joint_constraints/twist_span" == p_name) { + r_ret = Math::rad_to_deg(twist_span); + } else if ("joint_constraints/bias" == p_name) { + r_ret = bias; + } else if ("joint_constraints/softness" == p_name) { + r_ret = softness; + } else if ("joint_constraints/relaxation" == p_name) { + r_ret = relaxation; + } else { + return false; + } + + return true; +} + +void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/swing_span"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_less,or_greater")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/relaxation"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); +} + +bool PhysicalBone3D::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + bool is_valid_hinge = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_HINGE; + if ("joint_constraints/angular_limit_enabled" == p_name) { + angular_limit_enabled = p_value; + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled); + } + + } else if ("joint_constraints/angular_limit_upper" == p_name) { + angular_limit_upper = Math::deg_to_rad(real_t(p_value)); + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper); + } + + } else if ("joint_constraints/angular_limit_lower" == p_name) { + angular_limit_lower = Math::deg_to_rad(real_t(p_value)); + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower); + } + + } else if ("joint_constraints/angular_limit_bias" == p_name) { + angular_limit_bias = p_value; + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias); + } + + } else if ("joint_constraints/angular_limit_softness" == p_name) { + angular_limit_softness = p_value; + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness); + } + + } else if ("joint_constraints/angular_limit_relaxation" == p_name) { + angular_limit_relaxation = p_value; + if (is_valid_hinge) { + PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation); + } + + } else { + return false; + } + + return true; +} + +bool PhysicalBone3D::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/angular_limit_enabled" == p_name) { + r_ret = angular_limit_enabled; + } else if ("joint_constraints/angular_limit_upper" == p_name) { + r_ret = Math::rad_to_deg(angular_limit_upper); + } else if ("joint_constraints/angular_limit_lower" == p_name) { + r_ret = Math::rad_to_deg(angular_limit_lower); + } else if ("joint_constraints/angular_limit_bias" == p_name) { + r_ret = angular_limit_bias; + } else if ("joint_constraints/angular_limit_softness" == p_name) { + r_ret = angular_limit_softness; + } else if ("joint_constraints/angular_limit_relaxation" == p_name) { + r_ret = angular_limit_relaxation; + } else { + return false; + } + + return true; +} + +void PhysicalBone3D::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("joint_constraints/angular_limit_enabled"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_bias"), PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_relaxation"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); +} + +bool PhysicalBone3D::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + bool is_valid_slider = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_SLIDER; + if ("joint_constraints/linear_limit_upper" == p_name) { + linear_limit_upper = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper); + } + + } else if ("joint_constraints/linear_limit_lower" == p_name) { + linear_limit_lower = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower); + } + + } else if ("joint_constraints/linear_limit_softness" == p_name) { + linear_limit_softness = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness); + } + + } else if ("joint_constraints/linear_limit_restitution" == p_name) { + linear_limit_restitution = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution); + } + + } else if ("joint_constraints/linear_limit_damping" == p_name) { + linear_limit_damping = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution); + } + + } else if ("joint_constraints/angular_limit_upper" == p_name) { + angular_limit_upper = Math::deg_to_rad(real_t(p_value)); + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper); + } + + } else if ("joint_constraints/angular_limit_lower" == p_name) { + angular_limit_lower = Math::deg_to_rad(real_t(p_value)); + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower); + } + + } else if ("joint_constraints/angular_limit_softness" == p_name) { + angular_limit_softness = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + } + + } else if ("joint_constraints/angular_limit_restitution" == p_name) { + angular_limit_restitution = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + } + + } else if ("joint_constraints/angular_limit_damping" == p_name) { + angular_limit_damping = p_value; + if (is_valid_slider) { + PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping); + } + + } else { + return false; + } + + return true; +} + +bool PhysicalBone3D::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/linear_limit_upper" == p_name) { + r_ret = linear_limit_upper; + } else if ("joint_constraints/linear_limit_lower" == p_name) { + r_ret = linear_limit_lower; + } else if ("joint_constraints/linear_limit_softness" == p_name) { + r_ret = linear_limit_softness; + } else if ("joint_constraints/linear_limit_restitution" == p_name) { + r_ret = linear_limit_restitution; + } else if ("joint_constraints/linear_limit_damping" == p_name) { + r_ret = linear_limit_damping; + } else if ("joint_constraints/angular_limit_upper" == p_name) { + r_ret = Math::rad_to_deg(angular_limit_upper); + } else if ("joint_constraints/angular_limit_lower" == p_name) { + r_ret = Math::rad_to_deg(angular_limit_lower); + } else if ("joint_constraints/angular_limit_softness" == p_name) { + r_ret = angular_limit_softness; + } else if ("joint_constraints/angular_limit_restitution" == p_name) { + r_ret = angular_limit_restitution; + } else if ("joint_constraints/angular_limit_damping" == p_name) { + r_ret = angular_limit_damping; + } else { + return false; + } + + return true; +} + +void PhysicalBone3D::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_upper"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_lower"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_restitution"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_damping"), PROPERTY_HINT_RANGE, "0,16.0,0.01")); + + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_restitution"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_damping"), PROPERTY_HINT_RANGE, "0,16.0,0.01")); +} + +bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + String path = p_name; + + if (!path.begins_with("joint_constraints/")) { + return false; + } + + Vector3::Axis axis; + { + const String axis_s = path.get_slicec('/', 1); + if ("x" == axis_s) { + axis = Vector3::AXIS_X; + } else if ("y" == axis_s) { + axis = Vector3::AXIS_Y; + } else if ("z" == axis_s) { + axis = Vector3::AXIS_Z; + } else { + return false; + } + } + + String var_name = path.get_slicec('/', 2); + bool is_valid_6dof = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_6DOF; + if ("linear_limit_enabled" == var_name) { + axis_data[axis].linear_limit_enabled = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled); + } + + } else if ("linear_limit_upper" == var_name) { + axis_data[axis].linear_limit_upper = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper); + } + + } else if ("linear_limit_lower" == var_name) { + axis_data[axis].linear_limit_lower = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower); + } + + } else if ("linear_limit_softness" == var_name) { + axis_data[axis].linear_limit_softness = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness); + } + + } else if ("linear_spring_enabled" == var_name) { + axis_data[axis].linear_spring_enabled = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, axis_data[axis].linear_spring_enabled); + } + + } else if ("linear_spring_stiffness" == var_name) { + axis_data[axis].linear_spring_stiffness = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, axis_data[axis].linear_spring_stiffness); + } + + } else if ("linear_spring_damping" == var_name) { + axis_data[axis].linear_spring_damping = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, axis_data[axis].linear_spring_damping); + } + + } else if ("linear_equilibrium_point" == var_name) { + axis_data[axis].linear_equilibrium_point = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].linear_equilibrium_point); + } + + } else if ("linear_restitution" == var_name) { + axis_data[axis].linear_restitution = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution); + } + + } else if ("linear_damping" == var_name) { + axis_data[axis].linear_damping = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping); + } + + } else if ("angular_limit_enabled" == var_name) { + axis_data[axis].angular_limit_enabled = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled); + } + + } else if ("angular_limit_upper" == var_name) { + axis_data[axis].angular_limit_upper = Math::deg_to_rad(real_t(p_value)); + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper); + } + + } else if ("angular_limit_lower" == var_name) { + axis_data[axis].angular_limit_lower = Math::deg_to_rad(real_t(p_value)); + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower); + } + + } else if ("angular_limit_softness" == var_name) { + axis_data[axis].angular_limit_softness = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness); + } + + } else if ("angular_restitution" == var_name) { + axis_data[axis].angular_restitution = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution); + } + + } else if ("angular_damping" == var_name) { + axis_data[axis].angular_damping = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping); + } + + } else if ("erp" == var_name) { + axis_data[axis].erp = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp); + } + + } else if ("angular_spring_enabled" == var_name) { + axis_data[axis].angular_spring_enabled = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, axis_data[axis].angular_spring_enabled); + } + + } else if ("angular_spring_stiffness" == var_name) { + axis_data[axis].angular_spring_stiffness = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, axis_data[axis].angular_spring_stiffness); + } + + } else if ("angular_spring_damping" == var_name) { + axis_data[axis].angular_spring_damping = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, axis_data[axis].angular_spring_damping); + } + + } else if ("angular_equilibrium_point" == var_name) { + axis_data[axis].angular_equilibrium_point = p_value; + if (is_valid_6dof) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].angular_equilibrium_point); + } + + } else { + return false; + } + + return true; +} + +bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + String path = p_name; + + if (!path.begins_with("joint_constraints/")) { + return false; + } + + int axis; + { + const String axis_s = path.get_slicec('/', 1); + if ("x" == axis_s) { + axis = 0; + } else if ("y" == axis_s) { + axis = 1; + } else if ("z" == axis_s) { + axis = 2; + } else { + return false; + } + } + + String var_name = path.get_slicec('/', 2); + + if ("linear_limit_enabled" == var_name) { + r_ret = axis_data[axis].linear_limit_enabled; + } else if ("linear_limit_upper" == var_name) { + r_ret = axis_data[axis].linear_limit_upper; + } else if ("linear_limit_lower" == var_name) { + r_ret = axis_data[axis].linear_limit_lower; + } else if ("linear_limit_softness" == var_name) { + r_ret = axis_data[axis].linear_limit_softness; + } else if ("linear_spring_enabled" == var_name) { + r_ret = axis_data[axis].linear_spring_enabled; + } else if ("linear_spring_stiffness" == var_name) { + r_ret = axis_data[axis].linear_spring_stiffness; + } else if ("linear_spring_damping" == var_name) { + r_ret = axis_data[axis].linear_spring_damping; + } else if ("linear_equilibrium_point" == var_name) { + r_ret = axis_data[axis].linear_equilibrium_point; + } else if ("linear_restitution" == var_name) { + r_ret = axis_data[axis].linear_restitution; + } else if ("linear_damping" == var_name) { + r_ret = axis_data[axis].linear_damping; + } else if ("angular_limit_enabled" == var_name) { + r_ret = axis_data[axis].angular_limit_enabled; + } else if ("angular_limit_upper" == var_name) { + r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_upper); + } else if ("angular_limit_lower" == var_name) { + r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_lower); + } else if ("angular_limit_softness" == var_name) { + r_ret = axis_data[axis].angular_limit_softness; + } else if ("angular_restitution" == var_name) { + r_ret = axis_data[axis].angular_restitution; + } else if ("angular_damping" == var_name) { + r_ret = axis_data[axis].angular_damping; + } else if ("erp" == var_name) { + r_ret = axis_data[axis].erp; + } else if ("angular_spring_enabled" == var_name) { + r_ret = axis_data[axis].angular_spring_enabled; + } else if ("angular_spring_stiffness" == var_name) { + r_ret = axis_data[axis].angular_spring_stiffness; + } else if ("angular_spring_damping" == var_name) { + r_ret = axis_data[axis].angular_spring_damping; + } else if ("angular_equilibrium_point" == var_name) { + r_ret = axis_data[axis].angular_equilibrium_point; + } else { + return false; + } + + return true; +} + +void PhysicalBone3D::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const { + const StringName axis_names[] = { PNAME("x"), PNAME("y"), PNAME("z") }; + for (int i = 0; i < 3; ++i) { + const String prefix = vformat("%s/%s/", PNAME("joint_constraints"), axis_names[i]); + p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("linear_limit_enabled"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_upper"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_lower"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("linear_spring_enabled"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_spring_stiffness"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_spring_damping"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_equilibrium_point"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_restitution"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_damping"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("angular_limit_enabled"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_restitution"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_damping"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("erp"))); + p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("angular_spring_enabled"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_spring_stiffness"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_spring_damping"))); + p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_equilibrium_point"))); + } +} + +bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "bone_name") { + set_bone_name(p_value); + return true; + } + + if (joint_data) { + if (joint_data->_set(p_name, p_value, joint)) { +#ifdef TOOLS_ENABLED + update_gizmos(); +#endif + return true; + } + } + + return false; +} + +bool PhysicalBone3D::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "bone_name") { + r_ret = get_bone_name(); + return true; + } + + if (joint_data) { + return joint_data->_get(p_name, r_ret); + } + + return false; +} + +void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const { + Skeleton3D *parent = find_skeleton_parent(get_parent()); + + if (parent) { + String names; + for (int i = 0; i < parent->get_bone_count(); i++) { + if (i > 0) { + names += ","; + } + names += parent->get_bone_name(i); + } + + p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("bone_name"), PROPERTY_HINT_ENUM, names)); + } else { + p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("bone_name"))); + } + + if (joint_data) { + joint_data->_get_property_list(p_list); + } +} + +void PhysicalBone3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + parent_skeleton = find_skeleton_parent(get_parent()); + update_bone_id(); + reset_to_rest_position(); + reset_physics_simulation_state(); + if (joint_data) { + _reload_joint(); + } + break; + + case NOTIFICATION_EXIT_TREE: { + if (parent_skeleton) { + if (-1 != bone_id) { + parent_skeleton->unbind_physical_bone_from_bone(bone_id); + bone_id = -1; + } + } + parent_skeleton = nullptr; + PhysicsServer3D::get_singleton()->joint_clear(joint); + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_offset(); + } + } break; + } +} + +void PhysicalBone3D::_sync_body_state(PhysicsDirectBodyState3D *p_state) { + set_ignore_transform_notification(true); + set_global_transform(p_state->get_transform()); + set_ignore_transform_notification(false); + + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); +} + +void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + if (!simulate_physics || !_internal_simulate_physics) { + return; + } + + if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { + _sync_body_state(p_state); + + Transform3D old_transform = get_global_transform(); + GDVIRTUAL_CALL(_integrate_forces, p_state); + Transform3D new_transform = get_global_transform(); + + if (new_transform != old_transform) { + // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + } + } + + _sync_body_state(p_state); + _on_transform_changed(); + + Transform3D global_transform(p_state->get_transform()); + + // Update skeleton + if (parent_skeleton) { + if (-1 != bone_id) { + parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true); + } + } +} + +void PhysicalBone3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse); + ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3()); + + ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type); + ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type); + + ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone3D::set_joint_offset); + ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset); + ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation); + ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation); + + ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset); + ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset); + + ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone3D::get_simulate_physics); + + ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone3D::is_simulating_physics); + + ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone3D::get_bone_id); + + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone3D::set_mass); + ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone3D::get_mass); + + ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone3D::set_friction); + ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone3D::get_friction); + + ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone3D::set_bounce); + ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone3D::get_bounce); + + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone3D::set_gravity_scale); + ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone3D::get_gravity_scale); + + ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &PhysicalBone3D::set_linear_damp_mode); + ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &PhysicalBone3D::get_linear_damp_mode); + + ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &PhysicalBone3D::set_angular_damp_mode); + ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &PhysicalBone3D::get_angular_damp_mode); + + ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &PhysicalBone3D::set_linear_damp); + ClassDB::bind_method(D_METHOD("get_linear_damp"), &PhysicalBone3D::get_linear_damp); + + ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &PhysicalBone3D::set_angular_damp); + ClassDB::bind_method(D_METHOD("get_angular_damp"), &PhysicalBone3D::get_angular_damp); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &PhysicalBone3D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicalBone3D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &PhysicalBone3D::set_angular_velocity); + ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicalBone3D::get_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &PhysicalBone3D::set_use_custom_integrator); + ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &PhysicalBone3D::is_using_custom_integrator); + + ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep); + ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep); + + GDVIRTUAL_BIND(_integrate_forces, "state"); + + ADD_GROUP("Joint", "joint_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_joint_offset", "get_joint_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_less,or_greater,radians_as_degrees"), "set_joint_rotation", "get_joint_rotation"); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_body_offset", "get_body_offset"); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); + + BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); + BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); + + BIND_ENUM_CONSTANT(JOINT_TYPE_NONE); + BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); + BIND_ENUM_CONSTANT(JOINT_TYPE_CONE); + BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE); + BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER); + BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF); +} + +Skeleton3D *PhysicalBone3D::find_skeleton_parent(Node *p_parent) { + if (!p_parent) { + return nullptr; + } + Skeleton3D *s = Object::cast_to<Skeleton3D>(p_parent); + return s ? s : find_skeleton_parent(p_parent->get_parent()); +} + +void PhysicalBone3D::_update_joint_offset() { + _fix_joint_offset(); + + set_ignore_transform_notification(true); + reset_to_rest_position(); + set_ignore_transform_notification(false); + +#ifdef TOOLS_ENABLED + update_gizmos(); +#endif +} + +void PhysicalBone3D::_fix_joint_offset() { + // Clamp joint origin to bone origin + if (parent_skeleton) { + joint_offset.origin = body_offset.affine_inverse().origin; + } +} + +void PhysicalBone3D::_reload_joint() { + if (!parent_skeleton) { + PhysicsServer3D::get_singleton()->joint_clear(joint); + return; + } + + PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id); + if (!body_a) { + PhysicsServer3D::get_singleton()->joint_clear(joint); + return; + } + + Transform3D joint_transf = get_global_transform() * joint_offset; + Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf; + local_a.orthonormalize(); + + switch (get_joint_type()) { + case JOINT_TYPE_PIN: { + PhysicsServer3D::get_singleton()->joint_make_pin(joint, body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); + const PinJointData *pjd(static_cast<const PinJointData *>(joint_data)); + PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_BIAS, pjd->bias); + PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_DAMPING, pjd->damping); + PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp); + + } break; + case JOINT_TYPE_CONE: { + PhysicsServer3D::get_singleton()->joint_make_cone_twist(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); + const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data)); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, cjd->bias); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, cjd->softness); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation); + + } break; + case JOINT_TYPE_HINGE: { + PhysicsServer3D::get_singleton()->joint_make_hinge(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); + const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data)); + PhysicsServer3D::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation); + + } break; + case JOINT_TYPE_SLIDER: { + PhysicsServer3D::get_singleton()->joint_make_slider(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); + const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data)); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); + PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping); + + } break; + case JOINT_TYPE_6DOF: { + PhysicsServer3D::get_singleton()->joint_make_generic_6dof(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); + const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data)); + for (int axis = 0; axis < 3; ++axis) { + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, g6dofjd->axis_data[axis].linear_spring_enabled); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].linear_spring_stiffness); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, g6dofjd->axis_data[axis].linear_spring_damping); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].linear_equilibrium_point); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, g6dofjd->axis_data[axis].angular_spring_enabled); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].angular_spring_stiffness); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, g6dofjd->axis_data[axis].angular_spring_damping); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].angular_equilibrium_point); + } + + } break; + case JOINT_TYPE_NONE: { + } break; + } +} + +void PhysicalBone3D::_on_bone_parent_changed() { + _reload_joint(); +} + +#ifdef TOOLS_ENABLED +void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) { + gizmo_move_joint = p_move_joint; +} + +Transform3D PhysicalBone3D::get_global_gizmo_transform() const { + return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform(); +} + +Transform3D PhysicalBone3D::get_local_gizmo_transform() const { + return gizmo_move_joint ? get_transform() * joint_offset : get_transform(); +} +#endif + +const PhysicalBone3D::JointData *PhysicalBone3D::get_joint_data() const { + return joint_data; +} + +Skeleton3D *PhysicalBone3D::find_skeleton_parent() { + return find_skeleton_parent(this); +} + +void PhysicalBone3D::set_joint_type(JointType p_joint_type) { + if (p_joint_type == get_joint_type()) { + return; + } + + if (joint_data) { + memdelete(joint_data); + } + joint_data = nullptr; + switch (p_joint_type) { + case JOINT_TYPE_PIN: + joint_data = memnew(PinJointData); + break; + case JOINT_TYPE_CONE: + joint_data = memnew(ConeJointData); + break; + case JOINT_TYPE_HINGE: + joint_data = memnew(HingeJointData); + break; + case JOINT_TYPE_SLIDER: + joint_data = memnew(SliderJointData); + break; + case JOINT_TYPE_6DOF: + joint_data = memnew(SixDOFJointData); + break; + case JOINT_TYPE_NONE: + break; + } + + _reload_joint(); + +#ifdef TOOLS_ENABLED + notify_property_list_changed(); + update_gizmos(); +#endif +} + +PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const { + return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE; +} + +void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) { + joint_offset = p_offset; + + _update_joint_offset(); +} + +const Transform3D &PhysicalBone3D::get_joint_offset() const { + return joint_offset; +} + +void PhysicalBone3D::set_joint_rotation(const Vector3 &p_euler_rad) { + joint_offset.basis.set_euler_scale(p_euler_rad, joint_offset.basis.get_scale()); + + _update_joint_offset(); +} + +Vector3 PhysicalBone3D::get_joint_rotation() const { + return joint_offset.basis.get_euler_normalized(); +} + +const Transform3D &PhysicalBone3D::get_body_offset() const { + return body_offset; +} + +void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) { + body_offset = p_offset; + body_offset_inverse = body_offset.affine_inverse(); + + _update_joint_offset(); +} + +void PhysicalBone3D::set_simulate_physics(bool p_simulate) { + if (simulate_physics == p_simulate) { + return; + } + + simulate_physics = p_simulate; + reset_physics_simulation_state(); +} + +bool PhysicalBone3D::get_simulate_physics() { + return simulate_physics; +} + +bool PhysicalBone3D::is_simulating_physics() { + return _internal_simulate_physics; +} + +void PhysicalBone3D::set_bone_name(const String &p_name) { + bone_name = p_name; + bone_id = -1; + + update_bone_id(); + reset_to_rest_position(); +} + +const String &PhysicalBone3D::get_bone_name() const { + return bone_name; +} + +void PhysicalBone3D::set_mass(real_t p_mass) { + ERR_FAIL_COND(p_mass <= 0); + mass = p_mass; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); +} + +real_t PhysicalBone3D::get_mass() const { + return mass; +} + +void PhysicalBone3D::set_friction(real_t p_friction) { + ERR_FAIL_COND(p_friction < 0 || p_friction > 1); + + friction = p_friction; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, friction); +} + +real_t PhysicalBone3D::get_friction() const { + return friction; +} + +void PhysicalBone3D::set_bounce(real_t p_bounce) { + ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); + + bounce = p_bounce; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, bounce); +} + +real_t PhysicalBone3D::get_bounce() const { + return bounce; +} + +void PhysicalBone3D::set_gravity_scale(real_t p_gravity_scale) { + gravity_scale = p_gravity_scale; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); +} + +real_t PhysicalBone3D::get_gravity_scale() const { + return gravity_scale; +} + +void PhysicalBone3D::set_linear_damp_mode(DampMode p_mode) { + linear_damp_mode = p_mode; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); +} + +PhysicalBone3D::DampMode PhysicalBone3D::get_linear_damp_mode() const { + return linear_damp_mode; +} + +void PhysicalBone3D::set_angular_damp_mode(DampMode p_mode) { + angular_damp_mode = p_mode; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); +} + +PhysicalBone3D::DampMode PhysicalBone3D::get_angular_damp_mode() const { + return angular_damp_mode; +} + +void PhysicalBone3D::set_linear_damp(real_t p_linear_damp) { + ERR_FAIL_COND(p_linear_damp < 0); + + linear_damp = p_linear_damp; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp); +} + +real_t PhysicalBone3D::get_linear_damp() const { + return linear_damp; +} + +void PhysicalBone3D::set_angular_damp(real_t p_angular_damp) { + ERR_FAIL_COND(p_angular_damp < 0); + + angular_damp = p_angular_damp; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp); +} + +real_t PhysicalBone3D::get_angular_damp() const { + return angular_damp; +} + +void PhysicalBone3D::set_can_sleep(bool p_active) { + can_sleep = p_active; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active); +} + +bool PhysicalBone3D::is_able_to_sleep() const { + return can_sleep; +} + +PhysicalBone3D::PhysicalBone3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { + joint = PhysicsServer3D::get_singleton()->joint_create(); + reset_physics_simulation_state(); +} + +PhysicalBone3D::~PhysicalBone3D() { + if (joint_data) { + memdelete(joint_data); + } + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + PhysicsServer3D::get_singleton()->free(joint); +} + +void PhysicalBone3D::update_bone_id() { + if (!parent_skeleton) { + return; + } + + const int new_bone_id = parent_skeleton->find_bone(bone_name); + + if (new_bone_id != bone_id) { + if (-1 != bone_id) { + // Assert the unbind from old node + parent_skeleton->unbind_physical_bone_from_bone(bone_id); + } + + bone_id = new_bone_id; + + parent_skeleton->bind_physical_bone_to_bone(bone_id, this); + + _fix_joint_offset(); + reset_physics_simulation_state(); + } +} + +void PhysicalBone3D::update_offset() { +#ifdef TOOLS_ENABLED + if (parent_skeleton) { + Transform3D bone_transform(parent_skeleton->get_global_transform()); + if (-1 != bone_id) { + bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); + } + + if (gizmo_move_joint) { + bone_transform *= body_offset; + set_joint_offset(bone_transform.affine_inverse() * get_global_transform()); + } else { + set_body_offset(bone_transform.affine_inverse() * get_global_transform()); + } + } +#endif +} + +void PhysicalBone3D::_start_physics_simulation() { + if (_internal_simulate_physics || !parent_skeleton) { + return; + } + reset_to_rest_position(); + set_body_mode(PhysicsServer3D::BODY_MODE_RIGID); + PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_body_state_changed)); + set_as_top_level(true); + _internal_simulate_physics = true; +} + +void PhysicalBone3D::_stop_physics_simulation() { + if (!parent_skeleton) { + return; + } + if (parent_skeleton->get_animate_physical_bones()) { + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); + PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); + } else { + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); + PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); + } + if (_internal_simulate_physics) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable()); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false); + set_as_top_level(false); + _internal_simulate_physics = false; + } +} diff --git a/scene/3d/physics/physical_bone_3d.h b/scene/3d/physics/physical_bone_3d.h new file mode 100644 index 0000000000..953400da2f --- /dev/null +++ b/scene/3d/physics/physical_bone_3d.h @@ -0,0 +1,306 @@ +/**************************************************************************/ +/* physical_bone_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PHYSICAL_BONE_3D_H +#define PHYSICAL_BONE_3D_H + +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/skeleton_3d.h" + +class PhysicalBone3D : public PhysicsBody3D { + GDCLASS(PhysicalBone3D, PhysicsBody3D); + +public: + enum DampMode { + DAMP_MODE_COMBINE, + DAMP_MODE_REPLACE, + }; + + enum JointType { + JOINT_TYPE_NONE, + JOINT_TYPE_PIN, + JOINT_TYPE_CONE, + JOINT_TYPE_HINGE, + JOINT_TYPE_SLIDER, + JOINT_TYPE_6DOF + }; + + struct JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_NONE; } + + /// "j" is used to set the parameter inside the PhysicsServer3D + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + virtual ~JointData() {} + }; + + struct PinJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_PIN; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t bias = 0.3; + real_t damping = 1.0; + real_t impulse_clamp = 0.0; + }; + + struct ConeJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_CONE; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t swing_span = Math_PI * 0.25; + real_t twist_span = Math_PI; + real_t bias = 0.3; + real_t softness = 0.8; + real_t relaxation = 1.; + }; + + struct HingeJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + bool angular_limit_enabled = false; + real_t angular_limit_upper = Math_PI * 0.5; + real_t angular_limit_lower = -Math_PI * 0.5; + real_t angular_limit_bias = 0.3; + real_t angular_limit_softness = 0.9; + real_t angular_limit_relaxation = 1.; + }; + + struct SliderJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t linear_limit_upper = 1.0; + real_t linear_limit_lower = -1.0; + real_t linear_limit_softness = 1.0; + real_t linear_limit_restitution = 0.7; + real_t linear_limit_damping = 1.0; + real_t angular_limit_upper = 0.0; + real_t angular_limit_lower = 0.0; + real_t angular_limit_softness = 1.0; + real_t angular_limit_restitution = 0.7; + real_t angular_limit_damping = 1.0; + }; + + struct SixDOFJointData : public JointData { + struct SixDOFAxisData { + bool linear_limit_enabled = true; + real_t linear_limit_upper = 0.0; + real_t linear_limit_lower = 0.0; + real_t linear_limit_softness = 0.7; + real_t linear_restitution = 0.5; + real_t linear_damping = 1.0; + bool linear_spring_enabled = false; + real_t linear_spring_stiffness = 0.0; + real_t linear_spring_damping = 0.0; + real_t linear_equilibrium_point = 0.0; + bool angular_limit_enabled = true; + real_t angular_limit_upper = 0.0; + real_t angular_limit_lower = 0.0; + real_t angular_limit_softness = 0.5; + real_t angular_restitution = 0.0; + real_t angular_damping = 1.0; + real_t erp = 0.5; + bool angular_spring_enabled = false; + real_t angular_spring_stiffness = 0.0; + real_t angular_spring_damping = 0.0; + real_t angular_equilibrium_point = 0.0; + }; + + virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + SixDOFAxisData axis_data[3]; + + SixDOFJointData() {} + }; + +private: +#ifdef TOOLS_ENABLED + // if false gizmo move body + bool gizmo_move_joint = false; +#endif + + JointData *joint_data = nullptr; + Transform3D joint_offset; + RID joint; + + Skeleton3D *parent_skeleton = nullptr; + Transform3D body_offset; + Transform3D body_offset_inverse; + bool simulate_physics = false; + bool _internal_simulate_physics = false; + int bone_id = -1; + + String bone_name; + real_t bounce = 0.0; + real_t mass = 1.0; + real_t friction = 1.0; + Vector3 linear_velocity; + Vector3 angular_velocity; + real_t gravity_scale = 1.0; + bool can_sleep = true; + + bool custom_integrator = false; + + DampMode linear_damp_mode = DAMP_MODE_COMBINE; + DampMode angular_damp_mode = DAMP_MODE_COMBINE; + + real_t linear_damp = 0.0; + real_t angular_damp = 0.0; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + void _notification(int p_what); + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); + void _body_state_changed(PhysicsDirectBodyState3D *p_state); + + static void _bind_methods(); + +private: + void _sync_body_state(PhysicsDirectBodyState3D *p_state); + static Skeleton3D *find_skeleton_parent(Node *p_parent); + + void _update_joint_offset(); + void _fix_joint_offset(); + void _reload_joint(); + +public: + void _on_bone_parent_changed(); + + void set_linear_velocity(const Vector3 &p_velocity); + Vector3 get_linear_velocity() const override; + + void set_angular_velocity(const Vector3 &p_velocity); + Vector3 get_angular_velocity() const override; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + +#ifdef TOOLS_ENABLED + void _set_gizmo_move_joint(bool p_move_joint); + virtual Transform3D get_global_gizmo_transform() const override; + virtual Transform3D get_local_gizmo_transform() const override; +#endif + + const JointData *get_joint_data() const; + Skeleton3D *find_skeleton_parent(); + + int get_bone_id() const { + return bone_id; + } + + void set_joint_type(JointType p_joint_type); + JointType get_joint_type() const; + + void set_joint_offset(const Transform3D &p_offset); + const Transform3D &get_joint_offset() const; + + void set_joint_rotation(const Vector3 &p_euler_rad); + Vector3 get_joint_rotation() const; + + void set_body_offset(const Transform3D &p_offset); + const Transform3D &get_body_offset() const; + + void set_simulate_physics(bool p_simulate); + bool get_simulate_physics(); + bool is_simulating_physics(); + + void set_bone_name(const String &p_name); + const String &get_bone_name() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_bounce(real_t p_bounce); + real_t get_bounce() const; + + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + void set_linear_damp_mode(DampMode p_mode); + DampMode get_linear_damp_mode() const; + + void set_angular_damp_mode(DampMode p_mode); + DampMode get_angular_damp_mode() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; + + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_can_sleep(bool p_active); + bool is_able_to_sleep() const; + + void apply_central_impulse(const Vector3 &p_impulse); + void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); + + void reset_physics_simulation_state(); + void reset_to_rest_position(); + + PhysicalBone3D(); + ~PhysicalBone3D(); + +private: + void update_bone_id(); + void update_offset(); + + void _start_physics_simulation(); + void _stop_physics_simulation(); +}; + +VARIANT_ENUM_CAST(PhysicalBone3D::JointType); +VARIANT_ENUM_CAST(PhysicalBone3D::DampMode); + +#endif // PHYSICAL_BONE_3D_H diff --git a/scene/3d/physics/physics_body_3d.cpp b/scene/3d/physics/physics_body_3d.cpp new file mode 100644 index 0000000000..711ca60a81 --- /dev/null +++ b/scene/3d/physics/physics_body_3d.cpp @@ -0,0 +1,228 @@ +/**************************************************************************/ +/* physics_body_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "physics_body_3d.h" + +#include "scene/scene_string_names.h" + +void PhysicsBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody3D::get_gravity); + + ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); + ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); + + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); + + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); +} + +PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : + CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { + set_body_mode(p_mode); +} + +PhysicsBody3D::~PhysicsBody3D() { + if (motion_cache.is_valid()) { + motion_cache->owner = nullptr; + } +} + +TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() { + List<RID> exceptions; + PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); + Array ret; + for (const RID &body : exceptions) { + ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body); + Object *obj = ObjectDB::get_instance(instance_id); + PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj); + ret.append(physics_body); + } + return ret; +} + +void PhysicsBody3D::add_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); + ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); + PhysicsServer3D::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid()); +} + +void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); + ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); + PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); +} + +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); + parameters.max_collisions = p_max_collisions; + parameters.recovery_as_collision = p_recovery_as_collision; + + PhysicsServer3D::MotionResult result; + + if (move_and_collide(parameters, result, p_test_only)) { + // Create a new instance when the cached reference is invalid or still in use in script. + if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { + motion_cache.instantiate(); + motion_cache->owner = this; + } + + motion_cache->result = result; + + return motion_cache; + } + + return Ref<KinematicCollision3D>(); +} + +bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) { + bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result); + + // Restore direction of motion to be along original motion, + // in order to avoid sliding due to recovery, + // but only if collision depth is low enough to avoid tunneling. + if (p_cancel_sliding) { + real_t motion_length = p_parameters.motion.length(); + real_t precision = 0.001; + + if (colliding) { + // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, + // so even in normal resting cases the depth can be a bit more than the margin. + precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); + + if (r_result.collisions[0].depth > p_parameters.margin + precision) { + p_cancel_sliding = false; + } + } + + if (p_cancel_sliding) { + // When motion is null, recovery is the resulting motion. + Vector3 motion_normal; + if (motion_length > CMP_EPSILON) { + motion_normal = p_parameters.motion / motion_length; + } + + // Check depth of recovery. + real_t projected_length = r_result.travel.dot(motion_normal); + Vector3 recovery = r_result.travel - motion_normal * projected_length; + real_t recovery_length = recovery.length(); + // Fixes cases where canceling slide causes the motion to go too deep into the ground, + // because we're only taking rest information into account and not general recovery. + if (recovery_length < p_parameters.margin + precision) { + // Apply adjustment to motion. + r_result.travel = motion_normal * projected_length; + r_result.remainder = p_parameters.motion - r_result.travel; + } + } + } + + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + r_result.travel[i] = 0; + } + } + + if (!p_test_only) { + Transform3D gt = p_parameters.from; + gt.origin += r_result.travel; + set_global_transform(gt); + } + + return colliding; +} + +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { + ERR_FAIL_COND_V(!is_inside_tree(), false); + + PhysicsServer3D::MotionResult *r = nullptr; + PhysicsServer3D::MotionResult temp_result; + if (r_collision.is_valid()) { + // Needs const_cast because method bindings don't support non-const Ref. + r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result); + } else { + r = &temp_result; + } + + PhysicsServer3D::MotionParameters parameters(p_from, p_motion, p_margin); + parameters.recovery_as_collision = p_recovery_as_collision; + parameters.max_collisions = p_max_collisions; + + return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); +} + +Vector3 PhysicsBody3D::get_gravity() const { + PhysicsDirectBodyState3D *state = PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid()); + ERR_FAIL_NULL_V(state, Vector3()); + return state->get_total_gravity(); +} + +void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { + if (p_lock) { + locked_axis |= p_axis; + } else { + locked_axis &= (~p_axis); + } + PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +} + +bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { + return (locked_axis & p_axis); +} + +Vector3 PhysicsBody3D::get_linear_velocity() const { + return Vector3(); +} + +Vector3 PhysicsBody3D::get_angular_velocity() const { + return Vector3(); +} + +real_t PhysicsBody3D::get_inverse_mass() const { + return 0; +} + +/////////////////////////////////////// + +//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. + +/////////////////////////////////////// + +/////////////////////////////////////// diff --git a/scene/3d/physics/physics_body_3d.h b/scene/3d/physics/physics_body_3d.h new file mode 100644 index 0000000000..92b3850085 --- /dev/null +++ b/scene/3d/physics/physics_body_3d.h @@ -0,0 +1,72 @@ +/**************************************************************************/ +/* physics_body_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef PHYSICS_BODY_3D_H +#define PHYSICS_BODY_3D_H + +#include "core/templates/vset.h" +#include "scene/3d/physics/collision_object_3d.h" +#include "scene/3d/physics/kinematic_collision_3d.h" +#include "scene/resources/physics_material.h" +#include "servers/physics_server_3d.h" + +class PhysicsBody3D : public CollisionObject3D { + GDCLASS(PhysicsBody3D, CollisionObject3D); + +protected: + static void _bind_methods(); + PhysicsBody3D(PhysicsServer3D::BodyMode p_mode); + + Ref<KinematicCollision3D> motion_cache; + + uint16_t locked_axis = 0; + + Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); + +public: + bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); + bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); + Vector3 get_gravity() const; + + void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); + bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; + + virtual Vector3 get_linear_velocity() const; + virtual Vector3 get_angular_velocity() const; + virtual real_t get_inverse_mass() const; + + TypedArray<PhysicsBody3D> get_collision_exceptions(); + void add_collision_exception_with(Node *p_node); //must be physicsbody + void remove_collision_exception_with(Node *p_node); + + virtual ~PhysicsBody3D(); +}; + +#endif // PHYSICS_BODY_3D_H diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/physics/ray_cast_3d.cpp index b821181d29..0cb722a77e 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/physics/ray_cast_3d.cpp @@ -30,8 +30,8 @@ #include "ray_cast_3d.h" -#include "collision_object_3d.h" -#include "mesh_instance_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics/collision_object_3d.h" void RayCast3D::set_target_position(const Vector3 &p_point) { target_position = p_point; @@ -41,7 +41,7 @@ void RayCast3D::set_target_position(const Vector3 &p_point) { if (is_inside_tree()) { _update_debug_shape_vertices(); } - } else if (debug_shape) { + } else if (debug_instance.is_valid()) { _update_debug_shape(); } } @@ -186,11 +186,17 @@ void RayCast3D::_notification(int p_what) { set_physics_process_internal(false); } - if (debug_shape) { + if (debug_instance.is_valid()) { _clear_debug_shape(); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_inside_tree() && debug_instance.is_valid()) { + RenderingServer::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + } + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; @@ -200,6 +206,9 @@ void RayCast3D::_notification(int p_what) { _update_raycast_state(); if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) { _update_debug_shape_material(true); + if (is_inside_tree() && debug_instance.is_valid()) { + RenderingServer::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } } } break; } @@ -416,7 +425,7 @@ void RayCast3D::set_debug_shape_thickness(const int p_debug_shape_thickness) { if (is_inside_tree()) { _update_debug_shape_vertices(); } - } else if (debug_shape) { + } else if (debug_instance.is_valid()) { _update_debug_shape(); } } @@ -448,13 +457,13 @@ const Color &RayCast3D::get_debug_shape_custom_color() const { void RayCast3D::_create_debug_shape() { _update_debug_shape_material(); - Ref<ArrayMesh> mesh = memnew(ArrayMesh); - - MeshInstance3D *mi = memnew(MeshInstance3D); - mi->set_mesh(mesh); + if (!debug_instance.is_valid()) { + debug_instance = RenderingServer::get_singleton()->instance_create(); + } - add_child(mi); - debug_shape = mi; + if (debug_mesh.is_null()) { + debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + } } void RayCast3D::_update_debug_shape_material(bool p_check_collision) { @@ -494,19 +503,17 @@ void RayCast3D::_update_debug_shape() { return; } - if (!debug_shape) { + if (!debug_instance.is_valid()) { _create_debug_shape(); } - MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); - Ref<ArrayMesh> mesh = mi->get_mesh(); - if (!mesh.is_valid()) { + if (!debug_instance.is_valid() || debug_mesh.is_null()) { return; } _update_debug_shape_vertices(); - mesh->clear_surfaces(); + debug_mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -516,32 +523,36 @@ void RayCast3D::_update_debug_shape() { if (!debug_line_vertices.is_empty()) { a[Mesh::ARRAY_VERTEX] = debug_line_vertices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); - mesh->surface_set_material(surface_count, debug_material); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); + debug_mesh->surface_set_material(surface_count, debug_material); ++surface_count; } if (!debug_shape_vertices.is_empty()) { a[Mesh::ARRAY_VERTEX] = debug_shape_vertices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, a, Array(), Dictionary(), flags); - mesh->surface_set_material(surface_count, debug_material); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, a, Array(), Dictionary(), flags); + debug_mesh->surface_set_material(surface_count, debug_material); ++surface_count; } + + RenderingServer::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); + if (is_inside_tree()) { + RenderingServer::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); + RenderingServer::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + RenderingServer::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } } void RayCast3D::_clear_debug_shape() { - if (!debug_shape) { - return; + ERR_FAIL_NULL(RenderingServer::get_singleton()); + if (debug_instance.is_valid()) { + RenderingServer::get_singleton()->free(debug_instance); + debug_instance = RID(); } - - MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); - if (mi->is_inside_tree()) { - mi->queue_free(); - } else { - memdelete(mi); + if (debug_mesh.is_valid()) { + RenderingServer::get_singleton()->free(debug_mesh->get_rid()); + debug_mesh = Ref<ArrayMesh>(); } - - debug_shape = nullptr; } RayCast3D::RayCast3D() { diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/physics/ray_cast_3d.h index 7b7f698114..40f2223602 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/physics/ray_cast_3d.h @@ -53,7 +53,6 @@ class RayCast3D : public Node3D { uint32_t collision_mask = 1; bool exclude_parent_body = true; - Node *debug_shape = nullptr; Ref<Material> debug_material; Color debug_shape_custom_color = Color(0.0, 0.0, 0.0); int debug_shape_thickness = 2; @@ -72,6 +71,9 @@ class RayCast3D : public Node3D { bool hit_from_inside = false; bool hit_back_faces = true; + RID debug_instance; + Ref<ArrayMesh> debug_mesh; + protected: void _notification(int p_what); void _update_raycast_state(); diff --git a/scene/3d/physics/rigid_body_3d.cpp b/scene/3d/physics/rigid_body_3d.cpp new file mode 100644 index 0000000000..54bd1c0d25 --- /dev/null +++ b/scene/3d/physics/rigid_body_3d.cpp @@ -0,0 +1,825 @@ +/**************************************************************************/ +/* rigid_body_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "rigid_body_3d.h" + +#include "scene/scene_string_names.h" + +void RigidBody3D::_body_enter_tree(ObjectID p_id) { + Object *obj = ObjectDB::get_instance(p_id); + Node *node = Object::cast_to<Node>(obj); + ERR_FAIL_NULL(node); + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->value.in_tree); + + E->value.in_tree = true; + + contact_monitor->locked = true; + + emit_signal(SceneStringNames::get_singleton()->body_entered, node); + + for (int i = 0; i < E->value.shapes.size(); i++) { + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); + } + + contact_monitor->locked = false; +} + +void RigidBody3D::_body_exit_tree(ObjectID p_id) { + Object *obj = ObjectDB::get_instance(p_id); + Node *node = Object::cast_to<Node>(obj); + ERR_FAIL_NULL(node); + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->value.in_tree); + E->value.in_tree = false; + + contact_monitor->locked = true; + + emit_signal(SceneStringNames::get_singleton()->body_exited, node); + + for (int i = 0; i < E->value.shapes.size(); i++) { + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); + } + + contact_monitor->locked = false; +} + +void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) { + bool body_in = p_status == 1; + ObjectID objid = p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = Object::cast_to<Node>(obj); + + ERR_FAIL_NULL(contact_monitor); + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + E = contact_monitor->body_map.insert(objid, BodyState()); + E->value.rid = p_body; + //E->value.rc=0; + E->value.in_tree = node && node->is_inside_tree(); + if (node) { + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree).bind(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree).bind(objid)); + if (E->value.in_tree) { + emit_signal(SceneStringNames::get_singleton()->body_entered, node); + } + } + } + //E->value.rc++; + if (node) { + E->value.shapes.insert(ShapePair(p_body_shape, p_local_shape)); + } + + if (E->value.in_tree) { + emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape); + } + + } else { + //E->value.rc--; + + if (node) { + E->value.shapes.erase(ShapePair(p_body_shape, p_local_shape)); + } + + bool in_tree = E->value.in_tree; + + if (E->value.shapes.is_empty()) { + if (node) { + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); + if (in_tree) { + emit_signal(SceneStringNames::get_singleton()->body_exited, node); + } + } + + contact_monitor->body_map.remove(E); + } + if (node && in_tree) { + emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_local_shape); + } + } +} + +struct _RigidBodyInOut { + RID rid; + ObjectID id; + int shape = 0; + int local_shape = 0; +}; + +void RigidBody3D::_sync_body_state(PhysicsDirectBodyState3D *p_state) { + set_ignore_transform_notification(true); + set_global_transform(p_state->get_transform()); + set_ignore_transform_notification(false); + + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + inverse_inertia_tensor = p_state->get_inverse_inertia_tensor(); + + contact_count = p_state->get_contact_count(); + + if (sleeping != p_state->is_sleeping()) { + sleeping = p_state->is_sleeping(); + emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); + } +} + +void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + lock_callback(); + + if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { + _sync_body_state(p_state); + + Transform3D old_transform = get_global_transform(); + GDVIRTUAL_CALL(_integrate_forces, p_state); + Transform3D new_transform = get_global_transform(); + + if (new_transform != old_transform) { + // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + } + } + + _sync_body_state(p_state); + _on_transform_changed(); + + if (contact_monitor) { + contact_monitor->locked = true; + + //untag all + int rc = 0; + for (KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + for (int i = 0; i < E.value.shapes.size(); i++) { + E.value.shapes[i].tagged = false; + rc++; + } + } + + _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut)); + int toadd_count = 0; + RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction)); + int toremove_count = 0; + + //put the ones to add + + for (int i = 0; i < p_state->get_contact_count(); i++) { + RID col_rid = p_state->get_contact_collider(i); + ObjectID col_obj = p_state->get_contact_collider_id(i); + int local_shape = p_state->get_contact_local_shape(i); + int col_shape = p_state->get_contact_collider_shape(i); + + HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj); + if (!E) { + toadd[toadd_count].rid = col_rid; + toadd[toadd_count].local_shape = local_shape; + toadd[toadd_count].id = col_obj; + toadd[toadd_count].shape = col_shape; + toadd_count++; + continue; + } + + ShapePair sp(col_shape, local_shape); + int idx = E->value.shapes.find(sp); + if (idx == -1) { + toadd[toadd_count].rid = col_rid; + toadd[toadd_count].local_shape = local_shape; + toadd[toadd_count].id = col_obj; + toadd[toadd_count].shape = col_shape; + toadd_count++; + continue; + } + + E->value.shapes[idx].tagged = true; + } + + //put the ones to remove + + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + for (int i = 0; i < E.value.shapes.size(); i++) { + if (!E.value.shapes[i].tagged) { + toremove[toremove_count].rid = E.value.rid; + toremove[toremove_count].body_id = E.key; + toremove[toremove_count].pair = E.value.shapes[i]; + toremove_count++; + } + } + } + + //process removals + + for (int i = 0; i < toremove_count; i++) { + _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); + } + + //process additions + + for (int i = 0; i < toadd_count; i++) { + _body_inout(1, toremove[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape); + } + + contact_monitor->locked = false; + } + + unlock_callback(); +} + +void RigidBody3D::_notification(int p_what) { +#ifdef TOOLS_ENABLED + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); // Used for warnings and only in editor. + } + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + update_configuration_warnings(); + } break; + } +#endif +} + +void RigidBody3D::_apply_body_mode() { + if (freeze) { + switch (freeze_mode) { + case FREEZE_MODE_STATIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); + } break; + case FREEZE_MODE_KINEMATIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); + } break; + } + } else if (lock_rotation) { + set_body_mode(PhysicsServer3D::BODY_MODE_RIGID_LINEAR); + } else { + set_body_mode(PhysicsServer3D::BODY_MODE_RIGID); + } +} + +void RigidBody3D::set_lock_rotation_enabled(bool p_lock_rotation) { + if (p_lock_rotation == lock_rotation) { + return; + } + + lock_rotation = p_lock_rotation; + _apply_body_mode(); +} + +bool RigidBody3D::is_lock_rotation_enabled() const { + return lock_rotation; +} + +void RigidBody3D::set_freeze_enabled(bool p_freeze) { + if (p_freeze == freeze) { + return; + } + + freeze = p_freeze; + _apply_body_mode(); +} + +bool RigidBody3D::is_freeze_enabled() const { + return freeze; +} + +void RigidBody3D::set_freeze_mode(FreezeMode p_freeze_mode) { + if (p_freeze_mode == freeze_mode) { + return; + } + + freeze_mode = p_freeze_mode; + _apply_body_mode(); +} + +RigidBody3D::FreezeMode RigidBody3D::get_freeze_mode() const { + return freeze_mode; +} + +void RigidBody3D::set_mass(real_t p_mass) { + ERR_FAIL_COND(p_mass <= 0); + mass = p_mass; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); +} + +real_t RigidBody3D::get_mass() const { + return mass; +} + +void RigidBody3D::set_inertia(const Vector3 &p_inertia) { + ERR_FAIL_COND(p_inertia.x < 0); + ERR_FAIL_COND(p_inertia.y < 0); + ERR_FAIL_COND(p_inertia.z < 0); + + inertia = p_inertia; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); +} + +const Vector3 &RigidBody3D::get_inertia() const { + return inertia; +} + +void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) { + if (center_of_mass_mode == p_mode) { + return; + } + + center_of_mass_mode = p_mode; + + switch (center_of_mass_mode) { + case CENTER_OF_MASS_MODE_AUTO: { + center_of_mass = Vector3(); + PhysicsServer3D::get_singleton()->body_reset_mass_properties(get_rid()); + if (inertia != Vector3()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); + } + } break; + + case CENTER_OF_MASS_MODE_CUSTOM: { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); + } break; + } +} + +RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const { + return center_of_mass_mode; +} + +void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) { + if (center_of_mass == p_center_of_mass) { + return; + } + + ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); + center_of_mass = p_center_of_mass; + + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); +} + +const Vector3 &RigidBody3D::get_center_of_mass() const { + return center_of_mass; +} + +void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics)); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics)); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const { + return physics_material_override; +} + +void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) { + gravity_scale = p_gravity_scale; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); +} + +real_t RigidBody3D::get_gravity_scale() const { + return gravity_scale; +} + +void RigidBody3D::set_linear_damp_mode(DampMode p_mode) { + linear_damp_mode = p_mode; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); +} + +RigidBody3D::DampMode RigidBody3D::get_linear_damp_mode() const { + return linear_damp_mode; +} + +void RigidBody3D::set_angular_damp_mode(DampMode p_mode) { + angular_damp_mode = p_mode; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); +} + +RigidBody3D::DampMode RigidBody3D::get_angular_damp_mode() const { + return angular_damp_mode; +} + +void RigidBody3D::set_linear_damp(real_t p_linear_damp) { + ERR_FAIL_COND(p_linear_damp < 0.0); + linear_damp = p_linear_damp; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp); +} + +real_t RigidBody3D::get_linear_damp() const { + return linear_damp; +} + +void RigidBody3D::set_angular_damp(real_t p_angular_damp) { + ERR_FAIL_COND(p_angular_damp < 0.0); + angular_damp = p_angular_damp; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp); +} + +real_t RigidBody3D::get_angular_damp() const { + return angular_damp; +} + +void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) { + Vector3 axis = p_axis.normalized(); + linear_velocity -= axis * axis.dot(linear_velocity); + linear_velocity += p_axis; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) { + linear_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +Vector3 RigidBody3D::get_linear_velocity() const { + return linear_velocity; +} + +void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) { + angular_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); +} + +Vector3 RigidBody3D::get_angular_velocity() const { + return angular_velocity; +} + +Basis RigidBody3D::get_inverse_inertia_tensor() const { + return inverse_inertia_tensor; +} + +void RigidBody3D::set_use_custom_integrator(bool p_enable) { + if (custom_integrator == p_enable) { + return; + } + + custom_integrator = p_enable; + PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); +} + +bool RigidBody3D::is_using_custom_integrator() { + return custom_integrator; +} + +void RigidBody3D::set_sleeping(bool p_sleeping) { + sleeping = p_sleeping; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping); +} + +void RigidBody3D::set_can_sleep(bool p_active) { + can_sleep = p_active; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active); +} + +bool RigidBody3D::is_able_to_sleep() const { + return can_sleep; +} + +bool RigidBody3D::is_sleeping() const { + return sleeping; +} + +void RigidBody3D::set_max_contacts_reported(int p_amount) { + max_contacts_reported = p_amount; + PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount); +} + +int RigidBody3D::get_max_contacts_reported() const { + return max_contacts_reported; +} + +int RigidBody3D::get_contact_count() const { + return contact_count; +} + +void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) { + PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + +void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { + PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); + singleton->body_apply_impulse(get_rid(), p_impulse, p_position); +} + +void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) { + PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse); +} + +void RigidBody3D::apply_central_force(const Vector3 &p_force) { + PhysicsServer3D::get_singleton()->body_apply_central_force(get_rid(), p_force); +} + +void RigidBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) { + PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); + singleton->body_apply_force(get_rid(), p_force, p_position); +} + +void RigidBody3D::apply_torque(const Vector3 &p_torque) { + PhysicsServer3D::get_singleton()->body_apply_torque(get_rid(), p_torque); +} + +void RigidBody3D::add_constant_central_force(const Vector3 &p_force) { + PhysicsServer3D::get_singleton()->body_add_constant_central_force(get_rid(), p_force); +} + +void RigidBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) { + PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); + singleton->body_add_constant_force(get_rid(), p_force, p_position); +} + +void RigidBody3D::add_constant_torque(const Vector3 &p_torque) { + PhysicsServer3D::get_singleton()->body_add_constant_torque(get_rid(), p_torque); +} + +void RigidBody3D::set_constant_force(const Vector3 &p_force) { + PhysicsServer3D::get_singleton()->body_set_constant_force(get_rid(), p_force); +} + +Vector3 RigidBody3D::get_constant_force() const { + return PhysicsServer3D::get_singleton()->body_get_constant_force(get_rid()); +} + +void RigidBody3D::set_constant_torque(const Vector3 &p_torque) { + PhysicsServer3D::get_singleton()->body_set_constant_torque(get_rid(), p_torque); +} + +Vector3 RigidBody3D::get_constant_torque() const { + return PhysicsServer3D::get_singleton()->body_get_constant_torque(get_rid()); +} + +void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) { + ccd = p_enable; + PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable); +} + +bool RigidBody3D::is_using_continuous_collision_detection() const { + return ccd; +} + +void RigidBody3D::set_contact_monitor(bool p_enabled) { + if (p_enabled == is_contact_monitor_enabled()) { + return; + } + + if (!p_enabled) { + ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead."); + + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + //clean up mess + Object *obj = ObjectDB::get_instance(E.key); + Node *node = Object::cast_to<Node>(obj); + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); + } + } + + memdelete(contact_monitor); + contact_monitor = nullptr; + } else { + contact_monitor = memnew(ContactMonitor); + contact_monitor->locked = false; + } +} + +bool RigidBody3D::is_contact_monitor_enabled() const { + return contact_monitor != nullptr; +} + +TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const { + ERR_FAIL_NULL_V(contact_monitor, TypedArray<Node3D>()); + + TypedArray<Node3D> ret; + ret.resize(contact_monitor->body_map.size()); + int idx = 0; + for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { + Object *obj = ObjectDB::get_instance(E.key); + if (!obj) { + ret.resize(ret.size() - 1); //ops + } else { + ret[idx++] = obj; + } + } + + return ret; +} + +void RigidBody3D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } +} + +PackedStringArray RigidBody3D::get_configuration_warnings() const { + PackedStringArray warnings = CollisionObject3D::get_configuration_warnings(); + + Vector3 scale = get_transform().get_basis().get_scale(); + if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) { + warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead.")); + } + + return warnings; +} + +void RigidBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass); + ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass); + + ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia); + ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia); + + ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode); + ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode); + + ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass); + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity); + ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity); + + ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor); + + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale); + ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale); + + ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody3D::set_linear_damp_mode); + ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody3D::get_linear_damp_mode); + + ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody3D::set_angular_damp_mode); + ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody3D::get_angular_damp_mode); + + ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp); + ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp); + + ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp); + ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp); + + ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported); + ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody3D::get_contact_count); + + ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator); + ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator); + + ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor); + ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled); + + ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection); + ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection); + + ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity); + + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse); + ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3()); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse); + + ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody3D::apply_central_force); + ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody3D::apply_force, Vector3()); + ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody3D::apply_torque); + + ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody3D::add_constant_central_force); + ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody3D::add_constant_force, Vector3()); + ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody3D::add_constant_torque); + + ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody3D::set_constant_force); + ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody3D::get_constant_force); + + ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody3D::set_constant_torque); + ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody3D::get_constant_torque); + + ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping); + ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping); + + ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep); + ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep); + + ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody3D::set_lock_rotation_enabled); + ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody3D::is_lock_rotation_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody3D::set_freeze_enabled); + ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody3D::is_freeze_enabled); + + ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody3D::set_freeze_mode); + ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody3D::get_freeze_mode); + + ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies); + + GDVIRTUAL_BIND(_integrate_forces, "state"); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); + ADD_GROUP("Mass Distribution", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass"); + ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5m\u00B2"), "set_inertia", "get_inertia"); + ADD_GROUP("Deactivation", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); + ADD_GROUP("Solver", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); + ADD_GROUP("Linear", "linear_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); + ADD_GROUP("Angular", "angular_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_GROUP("Constant Forces", "constant_"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m/s\u00B2 (N)"), "set_constant_force", "get_constant_force"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque"); + + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("sleeping_state_changed")); + + BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); + BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); + + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); + + BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); + BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); +} + +void RigidBody3D::_validate_property(PropertyInfo &p_property) const { + if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { + if (p_property.name == "center_of_mass") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + } +} + +RigidBody3D::RigidBody3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody3D::_body_state_changed)); +} + +RigidBody3D::~RigidBody3D() { + if (contact_monitor) { + memdelete(contact_monitor); + } +} diff --git a/scene/3d/physics/rigid_body_3d.h b/scene/3d/physics/rigid_body_3d.h new file mode 100644 index 0000000000..ec051e5e0f --- /dev/null +++ b/scene/3d/physics/rigid_body_3d.h @@ -0,0 +1,248 @@ +/**************************************************************************/ +/* rigid_body_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef RIGID_BODY_3D_H +#define RIGID_BODY_3D_H + +#include "scene/3d/physics/static_body_3d.h" + +class RigidBody3D : public PhysicsBody3D { + GDCLASS(RigidBody3D, PhysicsBody3D); + +public: + enum FreezeMode { + FREEZE_MODE_STATIC, + FREEZE_MODE_KINEMATIC, + }; + + enum CenterOfMassMode { + CENTER_OF_MASS_MODE_AUTO, + CENTER_OF_MASS_MODE_CUSTOM, + }; + + enum DampMode { + DAMP_MODE_COMBINE, + DAMP_MODE_REPLACE, + }; + +private: + bool can_sleep = true; + bool lock_rotation = false; + bool freeze = false; + FreezeMode freeze_mode = FREEZE_MODE_STATIC; + + real_t mass = 1.0; + Vector3 inertia; + CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; + Vector3 center_of_mass; + + Ref<PhysicsMaterial> physics_material_override; + + Vector3 linear_velocity; + Vector3 angular_velocity; + Basis inverse_inertia_tensor; + real_t gravity_scale = 1.0; + + DampMode linear_damp_mode = DAMP_MODE_COMBINE; + DampMode angular_damp_mode = DAMP_MODE_COMBINE; + + real_t linear_damp = 0.0; + real_t angular_damp = 0.0; + + bool sleeping = false; + bool ccd = false; + + int max_contacts_reported = 0; + int contact_count = 0; + + bool custom_integrator = false; + + struct ShapePair { + int body_shape = 0; + int local_shape = 0; + bool tagged = false; + bool operator<(const ShapePair &p_sp) const { + if (body_shape == p_sp.body_shape) { + return local_shape < p_sp.local_shape; + } else { + return body_shape < p_sp.body_shape; + } + } + + ShapePair() {} + ShapePair(int p_bs, int p_ls) { + body_shape = p_bs; + local_shape = p_ls; + tagged = false; + } + }; + struct RigidBody3D_RemoveAction { + RID rid; + ObjectID body_id; + ShapePair pair; + }; + struct BodyState { + RID rid; + //int rc; + bool in_tree = false; + VSet<ShapePair> shapes; + }; + + struct ContactMonitor { + bool locked = false; + HashMap<ObjectID, BodyState> body_map; + }; + + ContactMonitor *contact_monitor = nullptr; + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); + + void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); + + void _sync_body_state(PhysicsDirectBodyState3D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + + void _validate_property(PropertyInfo &p_property) const; + + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) + + virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state); + + void _apply_body_mode(); + +public: + void set_lock_rotation_enabled(bool p_lock_rotation); + bool is_lock_rotation_enabled() const; + + void set_freeze_enabled(bool p_freeze); + bool is_freeze_enabled() const; + + void set_freeze_mode(FreezeMode p_freeze_mode); + FreezeMode get_freeze_mode() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + virtual real_t get_inverse_mass() const override { return 1.0 / mass; } + + void set_inertia(const Vector3 &p_inertia); + const Vector3 &get_inertia() const; + + void set_center_of_mass_mode(CenterOfMassMode p_mode); + CenterOfMassMode get_center_of_mass_mode() const; + + void set_center_of_mass(const Vector3 &p_center_of_mass); + const Vector3 &get_center_of_mass() const; + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; + + void set_linear_velocity(const Vector3 &p_velocity); + Vector3 get_linear_velocity() const override; + + void set_axis_velocity(const Vector3 &p_axis); + + void set_angular_velocity(const Vector3 &p_velocity); + Vector3 get_angular_velocity() const override; + + Basis get_inverse_inertia_tensor() const; + + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + void set_linear_damp_mode(DampMode p_mode); + DampMode get_linear_damp_mode() const; + + void set_angular_damp_mode(DampMode p_mode); + DampMode get_angular_damp_mode() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; + + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + + void set_sleeping(bool p_sleeping); + bool is_sleeping() const; + + void set_can_sleep(bool p_active); + bool is_able_to_sleep() const; + + void set_contact_monitor(bool p_enabled); + bool is_contact_monitor_enabled() const; + + void set_max_contacts_reported(int p_amount); + int get_max_contacts_reported() const; + int get_contact_count() const; + + void set_use_continuous_collision_detection(bool p_enable); + bool is_using_continuous_collision_detection() const; + + TypedArray<Node3D> get_colliding_bodies() const; + + void apply_central_impulse(const Vector3 &p_impulse); + void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); + void apply_torque_impulse(const Vector3 &p_impulse); + + void apply_central_force(const Vector3 &p_force); + void apply_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()); + void apply_torque(const Vector3 &p_torque); + + void add_constant_central_force(const Vector3 &p_force); + void add_constant_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()); + void add_constant_torque(const Vector3 &p_torque); + + void set_constant_force(const Vector3 &p_force); + Vector3 get_constant_force() const; + + void set_constant_torque(const Vector3 &p_torque); + Vector3 get_constant_torque() const; + + virtual PackedStringArray get_configuration_warnings() const override; + + RigidBody3D(); + ~RigidBody3D(); + +private: + void _reload_physics_characteristics(); +}; + +VARIANT_ENUM_CAST(RigidBody3D::FreezeMode); +VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode); +VARIANT_ENUM_CAST(RigidBody3D::DampMode); + +#endif // RIGID_BODY_3D_H diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/physics/shape_cast_3d.cpp index 2da5f52928..ada238c7f2 100644 --- a/scene/3d/shape_cast_3d.cpp +++ b/scene/3d/physics/shape_cast_3d.cpp @@ -30,8 +30,8 @@ #include "shape_cast_3d.h" -#include "scene/3d/collision_object_3d.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics/collision_object_3d.h" #include "scene/resources/3d/concave_polygon_shape_3d.h" void ShapeCast3D::_notification(int p_what) { @@ -64,11 +64,17 @@ void ShapeCast3D::_notification(int p_what) { set_physics_process_internal(false); } - if (debug_shape) { + if (debug_instance.is_valid()) { _clear_debug_shape(); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_inside_tree() && debug_instance.is_valid()) { + RenderingServer::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + } + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; @@ -86,6 +92,9 @@ void ShapeCast3D::_notification(int p_what) { if (prev_collision_state == collided && !collided) { _update_debug_shape(); } + if (is_inside_tree() && debug_instance.is_valid()) { + RenderingServer::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } } } break; } @@ -217,7 +226,7 @@ void ShapeCast3D::set_target_position(const Vector3 &p_point) { if (is_inside_tree()) { _update_debug_shape_vertices(); } - } else if (debug_shape) { + } else if (debug_instance.is_valid()) { _update_debug_shape(); } } @@ -532,13 +541,13 @@ const Color &ShapeCast3D::get_debug_shape_custom_color() const { void ShapeCast3D::_create_debug_shape() { _update_debug_shape_material(); - Ref<ArrayMesh> mesh = memnew(ArrayMesh); - - MeshInstance3D *mi = memnew(MeshInstance3D); - mi->set_mesh(mesh); + if (!debug_instance.is_valid()) { + debug_instance = RenderingServer::get_singleton()->instance_create(); + } - add_child(mi); - debug_shape = mi; + if (debug_mesh.is_null()) { + debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + } } void ShapeCast3D::_update_debug_shape_material(bool p_check_collision) { @@ -578,7 +587,7 @@ void ShapeCast3D::_update_debug_shape() { return; } - if (!debug_shape) { + if (!debug_instance.is_valid()) { _create_debug_shape(); } @@ -588,13 +597,11 @@ void ShapeCast3D::_update_debug_shape() { return; } - MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); - Ref<ArrayMesh> mesh = mi->get_mesh(); - if (!mesh.is_valid()) { + if (!debug_instance.is_valid() || debug_mesh.is_null()) { return; } - mesh->clear_surfaces(); + debug_mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -604,30 +611,34 @@ void ShapeCast3D::_update_debug_shape() { if (!debug_shape_vertices.is_empty()) { a[Mesh::ARRAY_VERTEX] = debug_shape_vertices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); - mesh->surface_set_material(surface_count, debug_material); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); + debug_mesh->surface_set_material(surface_count, debug_material); ++surface_count; } if (!debug_line_vertices.is_empty()) { a[Mesh::ARRAY_VERTEX] = debug_line_vertices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); - mesh->surface_set_material(surface_count, debug_material); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); + debug_mesh->surface_set_material(surface_count, debug_material); ++surface_count; } + + RenderingServer::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); + if (is_inside_tree()) { + RenderingServer::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); + RenderingServer::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + RenderingServer::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } } void ShapeCast3D::_clear_debug_shape() { - if (!debug_shape) { - return; + ERR_FAIL_NULL(RenderingServer::get_singleton()); + if (debug_instance.is_valid()) { + RenderingServer::get_singleton()->free(debug_instance); + debug_instance = RID(); } - - MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); - if (mi->is_inside_tree()) { - mi->queue_free(); - } else { - memdelete(mi); + if (debug_mesh.is_valid()) { + RenderingServer::get_singleton()->free(debug_mesh->get_rid()); + debug_mesh = Ref<ArrayMesh>(); } - - debug_shape = nullptr; } diff --git a/scene/3d/shape_cast_3d.h b/scene/3d/physics/shape_cast_3d.h index 9052db9046..19b73e3f72 100644 --- a/scene/3d/shape_cast_3d.h +++ b/scene/3d/physics/shape_cast_3d.h @@ -55,7 +55,6 @@ class ShapeCast3D : public Node3D { bool collide_with_areas = false; bool collide_with_bodies = true; - Node *debug_shape = nullptr; Ref<Material> debug_material; Color debug_shape_custom_color = Color(0.0, 0.0, 0.0); Vector<Vector3> debug_shape_vertices; @@ -76,6 +75,9 @@ class ShapeCast3D : public Node3D { Array _get_collision_result() const; + RID debug_instance; + Ref<ArrayMesh> debug_mesh; + protected: void _notification(int p_what); void _update_shapecast_state(); diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/physics/spring_arm_3d.cpp index 8d2f10310c..8d2f10310c 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/physics/spring_arm_3d.cpp diff --git a/scene/3d/spring_arm_3d.h b/scene/3d/physics/spring_arm_3d.h index c7e1da35f0..c7e1da35f0 100644 --- a/scene/3d/spring_arm_3d.h +++ b/scene/3d/physics/spring_arm_3d.h diff --git a/scene/3d/physics/static_body_3d.cpp b/scene/3d/physics/static_body_3d.cpp new file mode 100644 index 0000000000..30e796f92e --- /dev/null +++ b/scene/3d/physics/static_body_3d.cpp @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* static_body_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "static_body_3d.h" + +void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics)); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics)); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const { + return physics_material_override; +} + +void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { + constant_linear_velocity = p_vel; + + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); +} + +void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { + constant_angular_velocity = p_vel; + + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); +} + +Vector3 StaticBody3D::get_constant_linear_velocity() const { + return constant_linear_velocity; +} + +Vector3 StaticBody3D::get_constant_angular_velocity() const { + return constant_angular_velocity; +} + +void StaticBody3D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } +} + +void StaticBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_constant_angular_velocity", "get_constant_angular_velocity"); +} + +StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) : + PhysicsBody3D(p_mode) { +} diff --git a/scene/3d/physics/static_body_3d.h b/scene/3d/physics/static_body_3d.h new file mode 100644 index 0000000000..7d7f7a4acc --- /dev/null +++ b/scene/3d/physics/static_body_3d.h @@ -0,0 +1,64 @@ +/**************************************************************************/ +/* static_body_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef STATIC_BODY_3D_H +#define STATIC_BODY_3D_H + +#include "scene/3d/physics/physics_body_3d.h" + +class StaticBody3D : public PhysicsBody3D { + GDCLASS(StaticBody3D, PhysicsBody3D); + +private: + Vector3 constant_linear_velocity; + Vector3 constant_angular_velocity; + + Ref<PhysicsMaterial> physics_material_override; + +protected: + static void _bind_methods(); + +public: + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; + + void set_constant_linear_velocity(const Vector3 &p_vel); + void set_constant_angular_velocity(const Vector3 &p_vel); + + Vector3 get_constant_linear_velocity() const; + Vector3 get_constant_angular_velocity() const; + + StaticBody3D(PhysicsServer3D::BodyMode p_mode = PhysicsServer3D::BODY_MODE_STATIC); + +private: + void _reload_physics_characteristics(); +}; + +#endif // STATIC_BODY_3D_H diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/physics/vehicle_body_3d.cpp index c23032d3b9..c23032d3b9 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/physics/vehicle_body_3d.cpp diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/physics/vehicle_body_3d.h index ce913f152d..def9984440 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/physics/vehicle_body_3d.h @@ -31,7 +31,8 @@ #ifndef VEHICLE_BODY_3D_H #define VEHICLE_BODY_3D_H -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/rigid_body_3d.h" class VehicleBody3D; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp deleted file mode 100644 index 67a7f76d7d..0000000000 --- a/scene/3d/physics_body_3d.cpp +++ /dev/null @@ -1,3503 +0,0 @@ -/**************************************************************************/ -/* physics_body_3d.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#include "physics_body_3d.h" - -#include "scene/scene_string_names.h" - -void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(false), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("get_gravity"), &PhysicsBody3D::get_gravity); - - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); - - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); - ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); - ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); - - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); -} - -PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : - CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { - set_body_mode(p_mode); -} - -PhysicsBody3D::~PhysicsBody3D() { - if (motion_cache.is_valid()) { - motion_cache->owner = nullptr; - } -} - -TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() { - List<RID> exceptions; - PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); - Array ret; - for (const RID &body : exceptions) { - ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body); - Object *obj = ObjectDB::get_instance(instance_id); - PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj); - ret.append(physics_body); - } - return ret; -} - -void PhysicsBody3D::add_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); - CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); - PhysicsServer3D::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid()); -} - -void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { - ERR_FAIL_NULL(p_node); - CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node); - ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D)."); - PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); -} - -Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { - PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_motion, p_margin); - parameters.max_collisions = p_max_collisions; - parameters.recovery_as_collision = p_recovery_as_collision; - - PhysicsServer3D::MotionResult result; - - if (move_and_collide(parameters, result, p_test_only)) { - // Create a new instance when the cached reference is invalid or still in use in script. - if (motion_cache.is_null() || motion_cache->get_reference_count() > 1) { - motion_cache.instantiate(); - motion_cache->owner = this; - } - - motion_cache->result = result; - - return motion_cache; - } - - return Ref<KinematicCollision3D>(); -} - -bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) { - bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result); - - // Restore direction of motion to be along original motion, - // in order to avoid sliding due to recovery, - // but only if collision depth is low enough to avoid tunneling. - if (p_cancel_sliding) { - real_t motion_length = p_parameters.motion.length(); - real_t precision = 0.001; - - if (colliding) { - // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, - // so even in normal resting cases the depth can be a bit more than the margin. - precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); - - if (r_result.collisions[0].depth > p_parameters.margin + precision) { - p_cancel_sliding = false; - } - } - - if (p_cancel_sliding) { - // When motion is null, recovery is the resulting motion. - Vector3 motion_normal; - if (motion_length > CMP_EPSILON) { - motion_normal = p_parameters.motion / motion_length; - } - - // Check depth of recovery. - real_t projected_length = r_result.travel.dot(motion_normal); - Vector3 recovery = r_result.travel - motion_normal * projected_length; - real_t recovery_length = recovery.length(); - // Fixes cases where canceling slide causes the motion to go too deep into the ground, - // because we're only taking rest information into account and not general recovery. - if (recovery_length < p_parameters.margin + precision) { - // Apply adjustment to motion. - r_result.travel = motion_normal * projected_length; - r_result.remainder = p_parameters.motion - r_result.travel; - } - } - } - - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - r_result.travel[i] = 0; - } - } - - if (!p_test_only) { - Transform3D gt = p_parameters.from; - gt.origin += r_result.travel; - set_global_transform(gt); - } - - return colliding; -} - -bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, bool p_recovery_as_collision, int p_max_collisions) { - ERR_FAIL_COND_V(!is_inside_tree(), false); - - PhysicsServer3D::MotionResult *r = nullptr; - PhysicsServer3D::MotionResult temp_result; - if (r_collision.is_valid()) { - // Needs const_cast because method bindings don't support non-const Ref. - r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result); - } else { - r = &temp_result; - } - - PhysicsServer3D::MotionParameters parameters(p_from, p_motion, p_margin); - parameters.recovery_as_collision = p_recovery_as_collision; - parameters.max_collisions = p_max_collisions; - - return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); -} - -Vector3 PhysicsBody3D::get_gravity() const { - PhysicsDirectBodyState3D *state = PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid()); - ERR_FAIL_NULL_V(state, Vector3()); - return state->get_total_gravity(); -} - -void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - if (p_lock) { - locked_axis |= p_axis; - } else { - locked_axis &= (~p_axis); - } - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); -} - -bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return (locked_axis & p_axis); -} - -Vector3 PhysicsBody3D::get_linear_velocity() const { - return Vector3(); -} - -Vector3 PhysicsBody3D::get_angular_velocity() const { - return Vector3(); -} - -real_t PhysicsBody3D::get_inverse_mass() const { - return 0; -} - -void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { - if (physics_material_override.is_valid()) { - physics_material_override->disconnect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics)); - } - - physics_material_override = p_physics_material_override; - - if (physics_material_override.is_valid()) { - physics_material_override->connect_changed(callable_mp(this, &StaticBody3D::_reload_physics_characteristics)); - } - _reload_physics_characteristics(); -} - -Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const { - return physics_material_override; -} - -void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { - constant_linear_velocity = p_vel; - - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); -} - -void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { - constant_angular_velocity = p_vel; - - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); -} - -Vector3 StaticBody3D::get_constant_linear_velocity() const { - return constant_linear_velocity; -} - -Vector3 StaticBody3D::get_constant_angular_velocity() const { - return constant_angular_velocity; -} - -void StaticBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); - ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_constant_linear_velocity", "get_constant_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_constant_angular_velocity", "get_constant_angular_velocity"); -} - -StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) : - PhysicsBody3D(p_mode) { -} - -void StaticBody3D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -Vector3 AnimatableBody3D::get_linear_velocity() const { - return linear_velocity; -} - -Vector3 AnimatableBody3D::get_angular_velocity() const { - return angular_velocity; -} - -void AnimatableBody3D::set_sync_to_physics(bool p_enable) { - if (sync_to_physics == p_enable) { - return; - } - - sync_to_physics = p_enable; - - _update_kinematic_motion(); -} - -bool AnimatableBody3D::is_sync_to_physics_enabled() const { - return sync_to_physics; -} - -void AnimatableBody3D::_update_kinematic_motion() { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - - if (sync_to_physics) { - set_only_update_transform_changes(true); - set_notify_local_transform(true); - } else { - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } -} - -void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { - linear_velocity = p_state->get_linear_velocity(); - angular_velocity = p_state->get_angular_velocity(); - - if (!sync_to_physics) { - return; - } - - last_valid_transform = p_state->get_transform(); - set_notify_local_transform(false); - set_global_transform(last_valid_transform); - set_notify_local_transform(true); - _on_transform_changed(); -} - -void AnimatableBody3D::_notification(int p_what) { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - last_valid_transform = get_global_transform(); - _update_kinematic_motion(); - } break; - - case NOTIFICATION_EXIT_TREE: { - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } break; - - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - // Used by sync to physics, send the new transform to the physics... - Transform3D new_transform = get_global_transform(); - - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); - - // ... but then revert changes. - set_notify_local_transform(false); - set_global_transform(last_valid_transform); - set_notify_local_transform(true); - _on_transform_changed(); - } break; - } -} - -void AnimatableBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody3D::set_sync_to_physics); - ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody3D::is_sync_to_physics_enabled); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); -} - -AnimatableBody3D::AnimatableBody3D() : - StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &AnimatableBody3D::_body_state_changed)); -} - -void RigidBody3D::_body_enter_tree(ObjectID p_id) { - Object *obj = ObjectDB::get_instance(p_id); - Node *node = Object::cast_to<Node>(obj); - ERR_FAIL_NULL(node); - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); - ERR_FAIL_COND(!E); - ERR_FAIL_COND(E->value.in_tree); - - E->value.in_tree = true; - - contact_monitor->locked = true; - - emit_signal(SceneStringNames::get_singleton()->body_entered, node); - - for (int i = 0; i < E->value.shapes.size(); i++) { - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); - } - - contact_monitor->locked = false; -} - -void RigidBody3D::_body_exit_tree(ObjectID p_id) { - Object *obj = ObjectDB::get_instance(p_id); - Node *node = Object::cast_to<Node>(obj); - ERR_FAIL_NULL(node); - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id); - ERR_FAIL_COND(!E); - ERR_FAIL_COND(!E->value.in_tree); - E->value.in_tree = false; - - contact_monitor->locked = true; - - emit_signal(SceneStringNames::get_singleton()->body_exited, node); - - for (int i = 0; i < E->value.shapes.size(); i++) { - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape); - } - - contact_monitor->locked = false; -} - -void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) { - bool body_in = p_status == 1; - ObjectID objid = p_instance; - - Object *obj = ObjectDB::get_instance(objid); - Node *node = Object::cast_to<Node>(obj); - - ERR_FAIL_NULL(contact_monitor); - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(objid); - - ERR_FAIL_COND(!body_in && !E); - - if (body_in) { - if (!E) { - E = contact_monitor->body_map.insert(objid, BodyState()); - E->value.rid = p_body; - //E->value.rc=0; - E->value.in_tree = node && node->is_inside_tree(); - if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree).bind(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree).bind(objid)); - if (E->value.in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_entered, node); - } - } - } - //E->value.rc++; - if (node) { - E->value.shapes.insert(ShapePair(p_body_shape, p_local_shape)); - } - - if (E->value.in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape); - } - - } else { - //E->value.rc--; - - if (node) { - E->value.shapes.erase(ShapePair(p_body_shape, p_local_shape)); - } - - bool in_tree = E->value.in_tree; - - if (E->value.shapes.is_empty()) { - if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); - if (in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_exited, node); - } - } - - contact_monitor->body_map.remove(E); - } - if (node && in_tree) { - emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, obj, p_body_shape, p_local_shape); - } - } -} - -struct _RigidBodyInOut { - RID rid; - ObjectID id; - int shape = 0; - int local_shape = 0; -}; - -void RigidBody3D::_sync_body_state(PhysicsDirectBodyState3D *p_state) { - set_ignore_transform_notification(true); - set_global_transform(p_state->get_transform()); - set_ignore_transform_notification(false); - - linear_velocity = p_state->get_linear_velocity(); - angular_velocity = p_state->get_angular_velocity(); - - inverse_inertia_tensor = p_state->get_inverse_inertia_tensor(); - - contact_count = p_state->get_contact_count(); - - if (sleeping != p_state->is_sleeping()) { - sleeping = p_state->is_sleeping(); - emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed); - } -} - -void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { - lock_callback(); - - if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { - _sync_body_state(p_state); - - Transform3D old_transform = get_global_transform(); - GDVIRTUAL_CALL(_integrate_forces, p_state); - Transform3D new_transform = get_global_transform(); - - if (new_transform != old_transform) { - // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); - } - } - - _sync_body_state(p_state); - _on_transform_changed(); - - if (contact_monitor) { - contact_monitor->locked = true; - - //untag all - int rc = 0; - for (KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - for (int i = 0; i < E.value.shapes.size(); i++) { - E.value.shapes[i].tagged = false; - rc++; - } - } - - _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut)); - int toadd_count = 0; - RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction)); - int toremove_count = 0; - - //put the ones to add - - for (int i = 0; i < p_state->get_contact_count(); i++) { - RID col_rid = p_state->get_contact_collider(i); - ObjectID col_obj = p_state->get_contact_collider_id(i); - int local_shape = p_state->get_contact_local_shape(i); - int col_shape = p_state->get_contact_collider_shape(i); - - HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj); - if (!E) { - toadd[toadd_count].rid = col_rid; - toadd[toadd_count].local_shape = local_shape; - toadd[toadd_count].id = col_obj; - toadd[toadd_count].shape = col_shape; - toadd_count++; - continue; - } - - ShapePair sp(col_shape, local_shape); - int idx = E->value.shapes.find(sp); - if (idx == -1) { - toadd[toadd_count].rid = col_rid; - toadd[toadd_count].local_shape = local_shape; - toadd[toadd_count].id = col_obj; - toadd[toadd_count].shape = col_shape; - toadd_count++; - continue; - } - - E->value.shapes[idx].tagged = true; - } - - //put the ones to remove - - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - for (int i = 0; i < E.value.shapes.size(); i++) { - if (!E.value.shapes[i].tagged) { - toremove[toremove_count].rid = E.value.rid; - toremove[toremove_count].body_id = E.key; - toremove[toremove_count].pair = E.value.shapes[i]; - toremove_count++; - } - } - } - - //process removals - - for (int i = 0; i < toremove_count; i++) { - _body_inout(0, toremove[i].rid, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); - } - - //process additions - - for (int i = 0; i < toadd_count; i++) { - _body_inout(1, toremove[i].rid, toadd[i].id, toadd[i].shape, toadd[i].local_shape); - } - - contact_monitor->locked = false; - } - - unlock_callback(); -} - -void RigidBody3D::_notification(int p_what) { -#ifdef TOOLS_ENABLED - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); // Used for warnings and only in editor. - } - } break; - - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - update_configuration_warnings(); - } break; - } -#endif -} - -void RigidBody3D::_apply_body_mode() { - if (freeze) { - switch (freeze_mode) { - case FREEZE_MODE_STATIC: { - set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); - } break; - case FREEZE_MODE_KINEMATIC: { - set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); - } break; - } - } else if (lock_rotation) { - set_body_mode(PhysicsServer3D::BODY_MODE_RIGID_LINEAR); - } else { - set_body_mode(PhysicsServer3D::BODY_MODE_RIGID); - } -} - -void RigidBody3D::set_lock_rotation_enabled(bool p_lock_rotation) { - if (p_lock_rotation == lock_rotation) { - return; - } - - lock_rotation = p_lock_rotation; - _apply_body_mode(); -} - -bool RigidBody3D::is_lock_rotation_enabled() const { - return lock_rotation; -} - -void RigidBody3D::set_freeze_enabled(bool p_freeze) { - if (p_freeze == freeze) { - return; - } - - freeze = p_freeze; - _apply_body_mode(); -} - -bool RigidBody3D::is_freeze_enabled() const { - return freeze; -} - -void RigidBody3D::set_freeze_mode(FreezeMode p_freeze_mode) { - if (p_freeze_mode == freeze_mode) { - return; - } - - freeze_mode = p_freeze_mode; - _apply_body_mode(); -} - -RigidBody3D::FreezeMode RigidBody3D::get_freeze_mode() const { - return freeze_mode; -} - -void RigidBody3D::set_mass(real_t p_mass) { - ERR_FAIL_COND(p_mass <= 0); - mass = p_mass; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); -} - -real_t RigidBody3D::get_mass() const { - return mass; -} - -void RigidBody3D::set_inertia(const Vector3 &p_inertia) { - ERR_FAIL_COND(p_inertia.x < 0); - ERR_FAIL_COND(p_inertia.y < 0); - ERR_FAIL_COND(p_inertia.z < 0); - - inertia = p_inertia; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); -} - -const Vector3 &RigidBody3D::get_inertia() const { - return inertia; -} - -void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) { - if (center_of_mass_mode == p_mode) { - return; - } - - center_of_mass_mode = p_mode; - - switch (center_of_mass_mode) { - case CENTER_OF_MASS_MODE_AUTO: { - center_of_mass = Vector3(); - PhysicsServer3D::get_singleton()->body_reset_mass_properties(get_rid()); - if (inertia != Vector3()) { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); - } - } break; - - case CENTER_OF_MASS_MODE_CUSTOM: { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); - } break; - } -} - -RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const { - return center_of_mass_mode; -} - -void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) { - if (center_of_mass == p_center_of_mass) { - return; - } - - ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); - center_of_mass = p_center_of_mass; - - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); -} - -const Vector3 &RigidBody3D::get_center_of_mass() const { - return center_of_mass; -} - -void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { - if (physics_material_override.is_valid()) { - physics_material_override->disconnect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics)); - } - - physics_material_override = p_physics_material_override; - - if (physics_material_override.is_valid()) { - physics_material_override->connect_changed(callable_mp(this, &RigidBody3D::_reload_physics_characteristics)); - } - _reload_physics_characteristics(); -} - -Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const { - return physics_material_override; -} - -void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) { - gravity_scale = p_gravity_scale; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); -} - -real_t RigidBody3D::get_gravity_scale() const { - return gravity_scale; -} - -void RigidBody3D::set_linear_damp_mode(DampMode p_mode) { - linear_damp_mode = p_mode; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); -} - -RigidBody3D::DampMode RigidBody3D::get_linear_damp_mode() const { - return linear_damp_mode; -} - -void RigidBody3D::set_angular_damp_mode(DampMode p_mode) { - angular_damp_mode = p_mode; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); -} - -RigidBody3D::DampMode RigidBody3D::get_angular_damp_mode() const { - return angular_damp_mode; -} - -void RigidBody3D::set_linear_damp(real_t p_linear_damp) { - ERR_FAIL_COND(p_linear_damp < 0.0); - linear_damp = p_linear_damp; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp); -} - -real_t RigidBody3D::get_linear_damp() const { - return linear_damp; -} - -void RigidBody3D::set_angular_damp(real_t p_angular_damp) { - ERR_FAIL_COND(p_angular_damp < 0.0); - angular_damp = p_angular_damp; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp); -} - -real_t RigidBody3D::get_angular_damp() const { - return angular_damp; -} - -void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) { - Vector3 axis = p_axis.normalized(); - linear_velocity -= axis * axis.dot(linear_velocity); - linear_velocity += p_axis; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); -} - -void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) { - linear_velocity = p_velocity; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); -} - -Vector3 RigidBody3D::get_linear_velocity() const { - return linear_velocity; -} - -void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) { - angular_velocity = p_velocity; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); -} - -Vector3 RigidBody3D::get_angular_velocity() const { - return angular_velocity; -} - -Basis RigidBody3D::get_inverse_inertia_tensor() const { - return inverse_inertia_tensor; -} - -void RigidBody3D::set_use_custom_integrator(bool p_enable) { - if (custom_integrator == p_enable) { - return; - } - - custom_integrator = p_enable; - PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); -} - -bool RigidBody3D::is_using_custom_integrator() { - return custom_integrator; -} - -void RigidBody3D::set_sleeping(bool p_sleeping) { - sleeping = p_sleeping; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping); -} - -void RigidBody3D::set_can_sleep(bool p_active) { - can_sleep = p_active; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active); -} - -bool RigidBody3D::is_able_to_sleep() const { - return can_sleep; -} - -bool RigidBody3D::is_sleeping() const { - return sleeping; -} - -void RigidBody3D::set_max_contacts_reported(int p_amount) { - max_contacts_reported = p_amount; - PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount); -} - -int RigidBody3D::get_max_contacts_reported() const { - return max_contacts_reported; -} - -int RigidBody3D::get_contact_count() const { - return contact_count; -} - -void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) { - PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); -} - -void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { - PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); - singleton->body_apply_impulse(get_rid(), p_impulse, p_position); -} - -void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) { - PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse); -} - -void RigidBody3D::apply_central_force(const Vector3 &p_force) { - PhysicsServer3D::get_singleton()->body_apply_central_force(get_rid(), p_force); -} - -void RigidBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) { - PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); - singleton->body_apply_force(get_rid(), p_force, p_position); -} - -void RigidBody3D::apply_torque(const Vector3 &p_torque) { - PhysicsServer3D::get_singleton()->body_apply_torque(get_rid(), p_torque); -} - -void RigidBody3D::add_constant_central_force(const Vector3 &p_force) { - PhysicsServer3D::get_singleton()->body_add_constant_central_force(get_rid(), p_force); -} - -void RigidBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) { - PhysicsServer3D *singleton = PhysicsServer3D::get_singleton(); - singleton->body_add_constant_force(get_rid(), p_force, p_position); -} - -void RigidBody3D::add_constant_torque(const Vector3 &p_torque) { - PhysicsServer3D::get_singleton()->body_add_constant_torque(get_rid(), p_torque); -} - -void RigidBody3D::set_constant_force(const Vector3 &p_force) { - PhysicsServer3D::get_singleton()->body_set_constant_force(get_rid(), p_force); -} - -Vector3 RigidBody3D::get_constant_force() const { - return PhysicsServer3D::get_singleton()->body_get_constant_force(get_rid()); -} - -void RigidBody3D::set_constant_torque(const Vector3 &p_torque) { - PhysicsServer3D::get_singleton()->body_set_constant_torque(get_rid(), p_torque); -} - -Vector3 RigidBody3D::get_constant_torque() const { - return PhysicsServer3D::get_singleton()->body_get_constant_torque(get_rid()); -} - -void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) { - ccd = p_enable; - PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable); -} - -bool RigidBody3D::is_using_continuous_collision_detection() const { - return ccd; -} - -void RigidBody3D::set_contact_monitor(bool p_enabled) { - if (p_enabled == is_contact_monitor_enabled()) { - return; - } - - if (!p_enabled) { - ERR_FAIL_COND_MSG(contact_monitor->locked, "Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\", false) instead."); - - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - //clean up mess - Object *obj = ObjectDB::get_instance(E.key); - Node *node = Object::cast_to<Node>(obj); - - if (node) { - node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); - } - } - - memdelete(contact_monitor); - contact_monitor = nullptr; - } else { - contact_monitor = memnew(ContactMonitor); - contact_monitor->locked = false; - } -} - -bool RigidBody3D::is_contact_monitor_enabled() const { - return contact_monitor != nullptr; -} - -TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const { - ERR_FAIL_NULL_V(contact_monitor, TypedArray<Node3D>()); - - TypedArray<Node3D> ret; - ret.resize(contact_monitor->body_map.size()); - int idx = 0; - for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) { - Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; - } - } - - return ret; -} - -PackedStringArray RigidBody3D::get_configuration_warnings() const { - PackedStringArray warnings = CollisionObject3D::get_configuration_warnings(); - - Vector3 scale = get_transform().get_basis().get_scale(); - if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) { - warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead.")); - } - - return warnings; -} - -void RigidBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass); - ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass); - - ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia); - ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia); - - ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode); - ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode); - - ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass); - ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override); - - ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity); - ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity); - - ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity); - ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity); - - ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor); - - ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale); - ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale); - - ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody3D::set_linear_damp_mode); - ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody3D::get_linear_damp_mode); - - ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody3D::set_angular_damp_mode); - ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody3D::get_angular_damp_mode); - - ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp); - ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp); - - ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp); - ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp); - - ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported); - ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported); - ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody3D::get_contact_count); - - ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator); - ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator); - - ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor); - ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled); - - ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection); - ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection); - - ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity); - - ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse); - ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3()); - ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse); - - ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody3D::apply_central_force); - ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody3D::apply_force, Vector3()); - ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody3D::apply_torque); - - ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody3D::add_constant_central_force); - ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody3D::add_constant_force, Vector3()); - ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody3D::add_constant_torque); - - ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody3D::set_constant_force); - ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody3D::get_constant_force); - - ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody3D::set_constant_torque); - ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody3D::get_constant_torque); - - ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping); - ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping); - - ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep); - ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep); - - ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody3D::set_lock_rotation_enabled); - ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody3D::is_lock_rotation_enabled); - - ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody3D::set_freeze_enabled); - ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody3D::is_freeze_enabled); - - ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody3D::set_freeze_mode); - ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody3D::get_freeze_mode); - - ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies); - - GDVIRTUAL_BIND(_integrate_forces, "state"); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); - ADD_GROUP("Mass Distribution", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass"); - ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5m\u00B2"), "set_inertia", "get_inertia"); - ADD_GROUP("Deactivation", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_rotation"), "set_lock_rotation_enabled", "is_lock_rotation_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode"); - ADD_GROUP("Solver", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); - ADD_GROUP("Linear", "linear_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_linear_velocity", "get_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); - ADD_GROUP("Angular", "angular_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); - ADD_GROUP("Constant Forces", "constant_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m/s\u00B2 (N)"), "set_constant_force", "get_constant_force"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque"); - - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - - BIND_ENUM_CONSTANT(FREEZE_MODE_STATIC); - BIND_ENUM_CONSTANT(FREEZE_MODE_KINEMATIC); - - BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); - BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); - - BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); - BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); -} - -void RigidBody3D::_validate_property(PropertyInfo &p_property) const { - if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { - if (p_property.name == "center_of_mass") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } -} - -RigidBody3D::RigidBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &RigidBody3D::_body_state_changed)); -} - -RigidBody3D::~RigidBody3D() { - if (contact_monitor) { - memdelete(contact_monitor); - } -} - -void RigidBody3D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -/////////////////////////////////////// - -//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. -#define FLOOR_ANGLE_THRESHOLD 0.01 - -bool CharacterBody3D::move_and_slide() { - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - velocity[i] = 0.0; - } - } - - Transform3D gt = get_global_transform(); - previous_position = gt.origin; - - Vector3 current_platform_velocity = platform_velocity; - - if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) { - bool excluded = false; - if (collision_state.floor) { - excluded = (platform_floor_layers & platform_layer) == 0; - } else if (collision_state.wall) { - excluded = (platform_wall_layers & platform_layer) == 0; - } - if (!excluded) { - //this approach makes sure there is less delay between the actual body velocity and the one we saved - PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(platform_rid); - if (bs) { - Vector3 local_position = gt.origin - bs->get_transform().origin; - current_platform_velocity = bs->get_velocity_at_local_position(local_position); - } else { - // Body is removed or destroyed, invalidate floor. - current_platform_velocity = Vector3(); - platform_rid = RID(); - } - } else { - current_platform_velocity = Vector3(); - } - } - - motion_results.clear(); - - bool was_on_floor = collision_state.floor; - collision_state.state = 0; - - last_motion = Vector3(); - - if (!current_platform_velocity.is_zero_approx()) { - PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - - parameters.exclude_bodies.insert(platform_rid); - if (platform_object_id.is_valid()) { - parameters.exclude_objects.insert(platform_object_id); - } - - PhysicsServer3D::MotionResult floor_result; - if (move_and_collide(parameters, floor_result, false, false)) { - motion_results.push_back(floor_result); - - CollisionState result_state; - _set_collision_direction(floor_result, result_state); - } - } - - if (motion_mode == MOTION_MODE_GROUNDED) { - _move_and_slide_grounded(delta, was_on_floor); - } else { - _move_and_slide_floating(delta); - } - - // Compute real velocity. - real_velocity = get_position_delta() / delta; - - if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) { - // Add last platform velocity when just left a moving platform. - if (!collision_state.floor && !collision_state.wall) { - if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) { - current_platform_velocity = current_platform_velocity.slide(up_direction); - } - velocity += current_platform_velocity; - } - } - - return motion_results.size() > 0; -} - -void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector3 motion = velocity * p_delta; - Vector3 motion_slide_up = motion.slide(up_direction); - Vector3 prev_floor_normal = floor_normal; - - platform_rid = RID(); - platform_object_id = ObjectID(); - platform_velocity = Vector3(); - platform_angular_velocity = Vector3(); - platform_ceiling_velocity = Vector3(); - floor_normal = Vector3(); - wall_normal = Vector3(); - ceiling_normal = Vector3(); - - // No sliding on first attempt to keep floor motion stable when possible, - // When stop on slope is enabled or when there is no up direction. - bool sliding_enabled = !floor_stop_on_slope; - // Constant speed can be applied only the first time sliding is enabled. - bool can_apply_constant_speed = sliding_enabled; - // If the platform's ceiling push down the body. - bool apply_ceiling_velocity = false; - bool first_slide = true; - bool vel_dir_facing_up = velocity.dot(up_direction) > 0; - Vector3 total_travel; - - for (int iteration = 0; iteration < max_slides; ++iteration) { - PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.max_collisions = 6; // There can be 4 collisions between 2 walls + 2 more for the floor. - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - - PhysicsServer3D::MotionResult result; - bool collided = move_and_collide(parameters, result, false, !sliding_enabled); - - last_motion = result.travel; - - if (collided) { - motion_results.push_back(result); - - CollisionState previous_state = collision_state; - - CollisionState result_state; - _set_collision_direction(result, result_state); - - // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. - if (collision_state.ceiling && platform_ceiling_velocity != Vector3() && platform_ceiling_velocity.dot(up_direction) < 0) { - // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. - if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (ceiling_normal + up_direction).length() < 0.01) { - apply_ceiling_velocity = true; - Vector3 ceiling_vertical_velocity = up_direction * up_direction.dot(platform_ceiling_velocity); - Vector3 motion_vertical_velocity = up_direction * up_direction.dot(velocity); - if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - velocity = ceiling_vertical_velocity + velocity.slide(up_direction); - } - } - } - - if (collision_state.floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { - Transform3D gt = get_global_transform(); - if (result.travel.length() <= margin + CMP_EPSILON) { - gt.origin -= result.travel; - } - set_global_transform(gt); - velocity = Vector3(); - motion = Vector3(); - last_motion = Vector3(); - break; - } - - if (result.remainder.is_zero_approx()) { - motion = Vector3(); - break; - } - - // Apply regular sliding by default. - bool apply_default_sliding = true; - - // Wall collision checks. - if (result_state.wall && (motion_slide_up.dot(wall_normal) <= 0)) { - // Move on floor only checks. - if (floor_block_on_wall) { - // Needs horizontal motion from current motion instead of motion_slide_up - // to properly test the angle and avoid standing on slopes - Vector3 horizontal_motion = motion.slide(up_direction); - Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized(); - real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(horizontal_motion.normalized()))); - - // Avoid to move forward on a wall if floor_block_on_wall is true. - // Applies only when the motion angle is under 90 degrees, - // in order to avoid blocking lateral motion along a wall. - if (motion_angle < .5 * Math_PI) { - apply_default_sliding = false; - if (p_was_on_floor && !vel_dir_facing_up) { - // Cancel the motion. - Transform3D gt = get_global_transform(); - real_t travel_total = result.travel.length(); - real_t cancel_dist_max = MIN(0.1, margin * 20); - if (travel_total <= margin + CMP_EPSILON) { - gt.origin -= result.travel; - result.travel = Vector3(); // Cancel for constant speed computation. - } else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls. - gt.origin -= result.travel.slide(up_direction); - // Keep remaining motion in sync with amount canceled. - motion = motion.slide(up_direction); - result.travel = Vector3(); - } else { - // Travel is too high to be safely canceled, we take it into account. - result.travel = result.travel.slide(up_direction); - motion = motion.normalized() * result.travel.length(); - } - set_global_transform(gt); - // Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations. - _snap_on_floor(true, false); - } else { - // If the movement is not canceled we only keep the remaining. - motion = result.remainder; - } - - // Apply slide on forward in order to allow only lateral motion on next step. - Vector3 forward = wall_normal.slide(up_direction).normalized(); - motion = motion.slide(forward); - - // Scales the horizontal velocity according to the wall slope. - if (vel_dir_facing_up) { - Vector3 slide_motion = velocity.slide(result.collisions[0].normal); - // Keeps the vertical motion from velocity and add the horizontal motion of the projection. - velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); - } else { - velocity = velocity.slide(forward); - } - - // Allow only lateral motion along previous floor when already on floor. - // Fixes slowing down when moving in diagonal against an inclined wall. - if (p_was_on_floor && !vel_dir_facing_up && (motion.dot(up_direction) > 0.0)) { - // Slide along the corner between the wall and previous floor. - Vector3 floor_side = prev_floor_normal.cross(wall_normal); - if (floor_side != Vector3()) { - motion = floor_side * motion.dot(floor_side); - } - } - - // Stop all motion when a second wall is hit (unless sliding down or jumping), - // in order to avoid jittering in corner cases. - bool stop_all_motion = previous_state.wall && !vel_dir_facing_up; - - // Allow sliding when the body falls. - if (!collision_state.floor && motion.dot(up_direction) < 0) { - Vector3 slide_motion = motion.slide(wall_normal); - // Test again to allow sliding only if the result goes downwards. - // Fixes jittering issues at the bottom of inclined walls. - if (slide_motion.dot(up_direction) < 0) { - stop_all_motion = false; - motion = slide_motion; - } - } - - if (stop_all_motion) { - motion = Vector3(); - velocity = Vector3(); - } - } - } - - // Stop horizontal motion when under wall slide threshold. - if (p_was_on_floor && (wall_min_slide_angle > 0.0) && result_state.wall) { - Vector3 horizontal_normal = wall_normal.slide(up_direction).normalized(); - real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized()))); - if (motion_angle < wall_min_slide_angle) { - motion = up_direction * motion.dot(up_direction); - velocity = up_direction * velocity.dot(up_direction); - - apply_default_sliding = false; - } - } - } - - if (apply_default_sliding) { - // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. - if ((sliding_enabled || !collision_state.floor) && (!collision_state.ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { - const PhysicsServer3D::MotionCollision &collision = result.collisions[0]; - - Vector3 slide_motion = result.remainder.slide(collision.normal); - if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_zero_approx()) { - // Slide using the intersection between the motion plane and the floor plane, - // in order to keep the direction intact. - real_t motion_length = slide_motion.length(); - slide_motion = up_direction.cross(result.remainder).cross(floor_normal); - - // Keep the length from default slide to change speed in slopes by default, - // when constant speed is not enabled. - slide_motion.normalize(); - slide_motion *= motion_length; - } - - if (slide_motion.dot(velocity) > 0.0) { - motion = slide_motion; - } else { - motion = Vector3(); - } - - if (slide_on_ceiling && result_state.ceiling) { - // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. - if (vel_dir_facing_up) { - velocity = velocity.slide(collision.normal); - } else { - // Avoid acceleration in slope when falling. - velocity = up_direction * up_direction.dot(velocity); - } - } - } - // No sliding on first attempt to keep floor motion stable when possible. - else { - motion = result.remainder; - if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) { - velocity = velocity.slide(up_direction); - motion = motion.slide(up_direction); - } - } - } - - total_travel += result.travel; - - // Apply Constant Speed. - if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_zero_approx()) { - Vector3 travel_slide_up = total_travel.slide(up_direction); - motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length())); - } - } - // When you move forward in a downward slope you don’t collide because you will be in the air. - // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied. - else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) { - can_apply_constant_speed = false; - sliding_enabled = true; - Transform3D gt = get_global_transform(); - gt.origin = gt.origin - result.travel; - set_global_transform(gt); - - // Slide using the intersection between the motion plane and the floor plane, - // in order to keep the direction intact. - Vector3 motion_slide_norm = up_direction.cross(motion).cross(prev_floor_normal); - motion_slide_norm.normalize(); - - motion = motion_slide_norm * (motion_slide_up.length()); - collided = true; - } - - if (!collided || motion.is_zero_approx()) { - break; - } - - can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled; - sliding_enabled = true; - first_slide = false; - } - - _snap_on_floor(p_was_on_floor, vel_dir_facing_up); - - // Reset the gravity accumulation when touching the ground. - if (collision_state.floor && !vel_dir_facing_up) { - velocity = velocity.slide(up_direction); - } -} - -void CharacterBody3D::_move_and_slide_floating(double p_delta) { - Vector3 motion = velocity * p_delta; - - platform_rid = RID(); - platform_object_id = ObjectID(); - floor_normal = Vector3(); - platform_velocity = Vector3(); - platform_angular_velocity = Vector3(); - - bool first_slide = true; - for (int iteration = 0; iteration < max_slides; ++iteration) { - PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin); - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - - PhysicsServer3D::MotionResult result; - bool collided = move_and_collide(parameters, result, false, false); - - last_motion = result.travel; - - if (collided) { - motion_results.push_back(result); - - CollisionState result_state; - _set_collision_direction(result, result_state); - - if (result.remainder.is_zero_approx()) { - motion = Vector3(); - break; - } - - if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { - motion = Vector3(); - if (result.travel.length() < margin + CMP_EPSILON) { - Transform3D gt = get_global_transform(); - gt.origin -= result.travel; - set_global_transform(gt); - } - } else if (first_slide) { - Vector3 motion_slide_norm = result.remainder.slide(wall_normal).normalized(); - motion = motion_slide_norm * (motion.length() - result.travel.length()); - } else { - motion = result.remainder.slide(wall_normal); - } - - if (motion.dot(velocity) <= 0.0) { - motion = Vector3(); - } - } - - if (!collided || motion.is_zero_approx()) { - break; - } - - first_slide = false; - } -} - -void CharacterBody3D::apply_floor_snap() { - if (collision_state.floor) { - return; - } - - // Snap by at least collision margin to keep floor state consistent. - real_t length = MAX(floor_snap_length, margin); - - PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.max_collisions = 4; - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - parameters.collide_separation_ray = true; - - PhysicsServer3D::MotionResult result; - if (move_and_collide(parameters, result, true, false)) { - CollisionState result_state; - // Apply direction for floor only. - _set_collision_direction(result, result_state, CollisionState(true, false, false)); - - if (result_state.floor) { - if (floor_stop_on_slope) { - // move and collide may stray the object a bit because of pre un-stucking, - // so only ensure that motion happens on floor direction in this case. - if (result.travel.length() > margin) { - result.travel = up_direction * up_direction.dot(result.travel); - } else { - result.travel = Vector3(); - } - } - - parameters.from.origin += result.travel; - set_global_transform(parameters.from); - } - } -} - -void CharacterBody3D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up) { - if (collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) { - return; - } - - apply_floor_snap(); -} - -bool CharacterBody3D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) { - if (up_direction == Vector3() || collision_state.floor || !p_was_on_floor || p_vel_dir_facing_up) { - return false; - } - - // Snap by at least collision margin to keep floor state consistent. - real_t length = MAX(floor_snap_length, margin); - - PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin); - parameters.max_collisions = 4; - parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. - parameters.collide_separation_ray = true; - - PhysicsServer3D::MotionResult result; - if (move_and_collide(parameters, result, true, false)) { - CollisionState result_state; - // Don't apply direction for any type. - _set_collision_direction(result, result_state, CollisionState()); - - return result_state.floor; - } - - return false; -} - -void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state) { - r_state.state = 0; - - real_t wall_depth = -1.0; - real_t floor_depth = -1.0; - - bool was_on_wall = collision_state.wall; - Vector3 prev_wall_normal = wall_normal; - int wall_collision_count = 0; - Vector3 combined_wall_normal; - Vector3 tmp_wall_col; // Avoid duplicate on average calculation. - - for (int i = p_result.collision_count - 1; i >= 0; i--) { - const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i]; - - if (motion_mode == MOTION_MODE_GROUNDED) { - // Check if any collision is floor. - real_t floor_angle = collision.get_angle(up_direction); - if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { - r_state.floor = true; - if (p_apply_state.floor && collision.depth > floor_depth) { - collision_state.floor = true; - floor_normal = collision.normal; - floor_depth = collision.depth; - _set_platform_data(collision); - } - continue; - } - - // Check if any collision is ceiling. - real_t ceiling_angle = collision.get_angle(-up_direction); - if (ceiling_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { - r_state.ceiling = true; - if (p_apply_state.ceiling) { - platform_ceiling_velocity = collision.collider_velocity; - ceiling_normal = collision.normal; - collision_state.ceiling = true; - } - continue; - } - } - - // Collision is wall by default. - r_state.wall = true; - - if (p_apply_state.wall && collision.depth > wall_depth) { - collision_state.wall = true; - wall_depth = collision.depth; - wall_normal = collision.normal; - - // Don't apply wall velocity when the collider is a CharacterBody3D. - if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(collision.collider_id)) == nullptr) { - _set_platform_data(collision); - } - } - - // Collect normal for calculating average. - if (!collision.normal.is_equal_approx(tmp_wall_col)) { - tmp_wall_col = collision.normal; - combined_wall_normal += collision.normal; - wall_collision_count++; - } - } - - if (r_state.wall) { - if (wall_collision_count > 1 && !r_state.floor) { - // Check if wall normals cancel out to floor support. - if (!r_state.floor && motion_mode == MOTION_MODE_GROUNDED) { - combined_wall_normal.normalize(); - real_t floor_angle = Math::acos(combined_wall_normal.dot(up_direction)); - if (floor_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { - r_state.floor = true; - r_state.wall = false; - if (p_apply_state.floor) { - collision_state.floor = true; - floor_normal = combined_wall_normal; - } - if (p_apply_state.wall) { - collision_state.wall = was_on_wall; - wall_normal = prev_wall_normal; - } - return; - } - } - } - } -} - -void CharacterBody3D::_set_platform_data(const PhysicsServer3D::MotionCollision &p_collision) { - platform_rid = p_collision.collider; - platform_object_id = p_collision.collider_id; - platform_velocity = p_collision.collider_velocity; - platform_angular_velocity = p_collision.collider_angular_velocity; - platform_layer = PhysicsServer3D::get_singleton()->body_get_collision_layer(platform_rid); -} - -void CharacterBody3D::set_safe_margin(real_t p_margin) { - margin = p_margin; -} - -real_t CharacterBody3D::get_safe_margin() const { - return margin; -} - -const Vector3 &CharacterBody3D::get_velocity() const { - return velocity; -} - -void CharacterBody3D::set_velocity(const Vector3 &p_velocity) { - velocity = p_velocity; -} - -bool CharacterBody3D::is_on_floor() const { - return collision_state.floor; -} - -bool CharacterBody3D::is_on_floor_only() const { - return collision_state.floor && !collision_state.wall && !collision_state.ceiling; -} - -bool CharacterBody3D::is_on_wall() const { - return collision_state.wall; -} - -bool CharacterBody3D::is_on_wall_only() const { - return collision_state.wall && !collision_state.floor && !collision_state.ceiling; -} - -bool CharacterBody3D::is_on_ceiling() const { - return collision_state.ceiling; -} - -bool CharacterBody3D::is_on_ceiling_only() const { - return collision_state.ceiling && !collision_state.floor && !collision_state.wall; -} - -const Vector3 &CharacterBody3D::get_floor_normal() const { - return floor_normal; -} - -const Vector3 &CharacterBody3D::get_wall_normal() const { - return wall_normal; -} - -const Vector3 &CharacterBody3D::get_last_motion() const { - return last_motion; -} - -Vector3 CharacterBody3D::get_position_delta() const { - return get_global_transform().origin - previous_position; -} - -const Vector3 &CharacterBody3D::get_real_velocity() const { - return real_velocity; -} - -real_t CharacterBody3D::get_floor_angle(const Vector3 &p_up_direction) const { - ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); - return Math::acos(floor_normal.dot(p_up_direction)); -} - -const Vector3 &CharacterBody3D::get_platform_velocity() const { - return platform_velocity; -} - -const Vector3 &CharacterBody3D::get_platform_angular_velocity() const { - return platform_angular_velocity; -} - -Vector3 CharacterBody3D::get_linear_velocity() const { - return get_real_velocity(); -} - -int CharacterBody3D::get_slide_collision_count() const { - return motion_results.size(); -} - -PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const { - ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult()); - return motion_results[p_bounce]; -} - -Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { - ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>()); - if (p_bounce >= slide_colliders.size()) { - slide_colliders.resize(p_bounce + 1); - } - - // Create a new instance when the cached reference is invalid or still in use in script. - if (slide_colliders[p_bounce].is_null() || slide_colliders[p_bounce]->get_reference_count() > 1) { - slide_colliders.write[p_bounce].instantiate(); - slide_colliders.write[p_bounce]->owner = this; - } - - slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; - return slide_colliders[p_bounce]; -} - -Ref<KinematicCollision3D> CharacterBody3D::_get_last_slide_collision() { - if (motion_results.size() == 0) { - return Ref<KinematicCollision3D>(); - } - return _get_slide_collision(motion_results.size() - 1); -} - -bool CharacterBody3D::is_floor_stop_on_slope_enabled() const { - return floor_stop_on_slope; -} - -void CharacterBody3D::set_floor_stop_on_slope_enabled(bool p_enabled) { - floor_stop_on_slope = p_enabled; -} - -bool CharacterBody3D::is_floor_constant_speed_enabled() const { - return floor_constant_speed; -} - -void CharacterBody3D::set_floor_constant_speed_enabled(bool p_enabled) { - floor_constant_speed = p_enabled; -} - -bool CharacterBody3D::is_floor_block_on_wall_enabled() const { - return floor_block_on_wall; -} - -void CharacterBody3D::set_floor_block_on_wall_enabled(bool p_enabled) { - floor_block_on_wall = p_enabled; -} - -bool CharacterBody3D::is_slide_on_ceiling_enabled() const { - return slide_on_ceiling; -} - -void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) { - slide_on_ceiling = p_enabled; -} - -uint32_t CharacterBody3D::get_platform_floor_layers() const { - return platform_floor_layers; -} - -void CharacterBody3D::set_platform_floor_layers(uint32_t p_exclude_layers) { - platform_floor_layers = p_exclude_layers; -} - -uint32_t CharacterBody3D::get_platform_wall_layers() const { - return platform_wall_layers; -} - -void CharacterBody3D::set_platform_wall_layers(uint32_t p_exclude_layers) { - platform_wall_layers = p_exclude_layers; -} - -void CharacterBody3D::set_motion_mode(MotionMode p_mode) { - motion_mode = p_mode; -} - -CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const { - return motion_mode; -} - -void CharacterBody3D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) { - platform_on_leave = p_on_leave_apply_velocity; -} - -CharacterBody3D::PlatformOnLeave CharacterBody3D::get_platform_on_leave() const { - return platform_on_leave; -} - -int CharacterBody3D::get_max_slides() const { - return max_slides; -} - -void CharacterBody3D::set_max_slides(int p_max_slides) { - ERR_FAIL_COND(p_max_slides < 1); - max_slides = p_max_slides; -} - -real_t CharacterBody3D::get_floor_max_angle() const { - return floor_max_angle; -} - -void CharacterBody3D::set_floor_max_angle(real_t p_radians) { - floor_max_angle = p_radians; -} - -real_t CharacterBody3D::get_floor_snap_length() { - return floor_snap_length; -} - -void CharacterBody3D::set_floor_snap_length(real_t p_floor_snap_length) { - ERR_FAIL_COND(p_floor_snap_length < 0); - floor_snap_length = p_floor_snap_length; -} - -real_t CharacterBody3D::get_wall_min_slide_angle() const { - return wall_min_slide_angle; -} - -void CharacterBody3D::set_wall_min_slide_angle(real_t p_radians) { - wall_min_slide_angle = p_radians; -} - -const Vector3 &CharacterBody3D::get_up_direction() const { - return up_direction; -} - -void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { - ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Floating motion mode instead."); - up_direction = p_up_direction.normalized(); -} - -void CharacterBody3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - // Reset move_and_slide() data. - collision_state.state = 0; - platform_rid = RID(); - platform_object_id = ObjectID(); - motion_results.clear(); - platform_velocity = Vector3(); - platform_angular_velocity = Vector3(); - } break; - } -} - -void CharacterBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); - ClassDB::bind_method(D_METHOD("apply_floor_snap"), &CharacterBody3D::apply_floor_snap); - - ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity); - ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity); - - ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody3D::set_safe_margin); - ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); - ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled); - ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody3D::set_floor_constant_speed_enabled); - ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody3D::is_floor_constant_speed_enabled); - ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody3D::set_floor_block_on_wall_enabled); - ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody3D::is_floor_block_on_wall_enabled); - ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled); - ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled); - - ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_platform_floor_layers); - ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody3D::get_platform_floor_layers); - ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_platform_wall_layers); - ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody3D::get_platform_wall_layers); - - ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides); - ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides); - ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle); - ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle); - ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody3D::get_floor_snap_length); - ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody3D::set_floor_snap_length); - ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody3D::get_wall_min_slide_angle); - ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody3D::set_wall_min_slide_angle); - ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction); - ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction); - ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode); - ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode); - ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_platform_on_leave); - ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody3D::get_platform_on_leave); - - ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor); - ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only); - ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling); - ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody3D::is_on_ceiling_only); - ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall); - ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody3D::is_on_wall_only); - ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal); - ClassDB::bind_method(D_METHOD("get_wall_normal"), &CharacterBody3D::get_wall_normal); - ClassDB::bind_method(D_METHOD("get_last_motion"), &CharacterBody3D::get_last_motion); - ClassDB::bind_method(D_METHOD("get_position_delta"), &CharacterBody3D::get_position_delta); - ClassDB::bind_method(D_METHOD("get_real_velocity"), &CharacterBody3D::get_real_velocity); - ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody3D::get_floor_angle, DEFVAL(Vector3(0.0, 1.0, 0.0))); - ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody3D::get_platform_velocity); - ClassDB::bind_method(D_METHOD("get_platform_angular_velocity"), &CharacterBody3D::get_platform_angular_velocity); - ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody3D::get_slide_collision_count); - ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); - ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "suffix:m/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); - - ADD_GROUP("Floor", "floor_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians_as_degrees"), "set_floor_max_angle", "get_floor_max_angle"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater,suffix:m"), "set_floor_snap_length", "get_floor_snap_length"); - - ADD_GROUP("Moving Platform", "platform_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers"); - - ADD_GROUP("Collision", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin"); - - BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); - BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); - - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY); - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY); - BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING); -} - -void CharacterBody3D::_validate_property(PropertyInfo &p_property) const { - if (motion_mode == MOTION_MODE_FLOATING) { - if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } - } -} - -CharacterBody3D::CharacterBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { -} - -CharacterBody3D::~CharacterBody3D() { - for (int i = 0; i < slide_colliders.size(); i++) { - if (slide_colliders[i].is_valid()) { - slide_colliders.write[i]->owner = nullptr; - } - } -} - -/////////////////////////////////////// - -Vector3 KinematicCollision3D::get_travel() const { - return result.travel; -} - -Vector3 KinematicCollision3D::get_remainder() const { - return result.remainder; -} - -int KinematicCollision3D::get_collision_count() const { - return result.collision_count; -} - -real_t KinematicCollision3D::get_depth() const { - return result.collision_depth; -} - -Vector3 KinematicCollision3D::get_position(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); - return result.collisions[p_collision_index].position; -} - -Vector3 KinematicCollision3D::get_normal(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); - return result.collisions[p_collision_index].normal; -} - -real_t KinematicCollision3D::get_angle(int p_collision_index, const Vector3 &p_up_direction) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0); - ERR_FAIL_COND_V(p_up_direction == Vector3(), 0); - return result.collisions[p_collision_index].get_angle(p_up_direction); -} - -Object *KinematicCollision3D::get_local_shape(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr); - if (!owner) { - return nullptr; - } - uint32_t ownerid = owner->shape_find_owner(result.collisions[p_collision_index].local_shape); - return owner->shape_owner_get_owner(ownerid); -} - -Object *KinematicCollision3D::get_collider(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr); - if (result.collisions[p_collision_index].collider_id.is_valid()) { - return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id); - } - - return nullptr; -} - -ObjectID KinematicCollision3D::get_collider_id(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID()); - return result.collisions[p_collision_index].collider_id; -} - -RID KinematicCollision3D::get_collider_rid(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID()); - return result.collisions[p_collision_index].collider; -} - -Object *KinematicCollision3D::get_collider_shape(int p_collision_index) const { - Object *collider = get_collider(p_collision_index); - if (collider) { - CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider); - if (obj2d) { - uint32_t ownerid = obj2d->shape_find_owner(result.collisions[p_collision_index].collider_shape); - return obj2d->shape_owner_get_owner(ownerid); - } - } - - return nullptr; -} - -int KinematicCollision3D::get_collider_shape_index(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0); - return result.collisions[p_collision_index].collider_shape; -} - -Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const { - ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); - return result.collisions[p_collision_index].collider_velocity; -} - -void KinematicCollision3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel); - ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder); - ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision3D::get_depth); - ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count); - ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_angle", "collision_index", "up_direction"), &KinematicCollision3D::get_angle, DEFVAL(0), DEFVAL(Vector3(0.0, 1.0, 0.0))); - ClassDB::bind_method(D_METHOD("get_local_shape", "collision_index"), &KinematicCollision3D::get_local_shape, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &KinematicCollision3D::get_collider, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &KinematicCollision3D::get_collider_id, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &KinematicCollision3D::get_collider_rid, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0)); -} - -/////////////////////////////////////// - -bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - return false; -} - -bool PhysicalBone3D::JointData::_get(const StringName &p_name, Variant &r_ret) const { - return false; -} - -void PhysicalBone3D::JointData::_get_property_list(List<PropertyInfo> *p_list) const { -} - -void PhysicalBone3D::apply_central_impulse(const Vector3 &p_impulse) { - PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); -} - -void PhysicalBone3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { - PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); -} - -void PhysicalBone3D::set_linear_velocity(const Vector3 &p_velocity) { - linear_velocity = p_velocity; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); -} - -Vector3 PhysicalBone3D::get_linear_velocity() const { - return linear_velocity; -} - -void PhysicalBone3D::set_angular_velocity(const Vector3 &p_velocity) { - angular_velocity = p_velocity; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); -} - -Vector3 PhysicalBone3D::get_angular_velocity() const { - return angular_velocity; -} - -void PhysicalBone3D::set_use_custom_integrator(bool p_enable) { - if (custom_integrator == p_enable) { - return; - } - - custom_integrator = p_enable; - PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); -} - -bool PhysicalBone3D::is_using_custom_integrator() { - return custom_integrator; -} - -void PhysicalBone3D::reset_physics_simulation_state() { - if (simulate_physics) { - _start_physics_simulation(); - } else { - _stop_physics_simulation(); - } -} - -void PhysicalBone3D::reset_to_rest_position() { - if (parent_skeleton) { - Transform3D new_transform = parent_skeleton->get_global_transform(); - if (bone_id == -1) { - new_transform *= body_offset; - } else { - new_transform *= parent_skeleton->get_bone_global_pose(bone_id) * body_offset; - } - new_transform.orthonormalize(); - set_global_transform(new_transform); - } -} - -bool PhysicalBone3D::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - if (JointData::_set(p_name, p_value, j)) { - return true; - } - - bool is_valid_pin = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_PIN; - if ("joint_constraints/bias" == p_name) { - bias = p_value; - if (is_valid_pin) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_BIAS, bias); - } - - } else if ("joint_constraints/damping" == p_name) { - damping = p_value; - if (is_valid_pin) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_DAMPING, damping); - } - - } else if ("joint_constraints/impulse_clamp" == p_name) { - impulse_clamp = p_value; - if (is_valid_pin) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp); - } - - } else { - return false; - } - - return true; -} - -bool PhysicalBone3D::PinJointData::_get(const StringName &p_name, Variant &r_ret) const { - if (JointData::_get(p_name, r_ret)) { - return true; - } - - if ("joint_constraints/bias" == p_name) { - r_ret = bias; - } else if ("joint_constraints/damping" == p_name) { - r_ret = damping; - } else if ("joint_constraints/impulse_clamp" == p_name) { - r_ret = impulse_clamp; - } else { - return false; - } - - return true; -} - -void PhysicalBone3D::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const { - JointData::_get_property_list(p_list); - - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/damping"), PROPERTY_HINT_RANGE, "0.01,8.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/impulse_clamp"), PROPERTY_HINT_RANGE, "0.0,64.0,0.01")); -} - -bool PhysicalBone3D::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - if (JointData::_set(p_name, p_value, j)) { - return true; - } - - bool is_valid_cone = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_CONE_TWIST; - if ("joint_constraints/swing_span" == p_name) { - swing_span = Math::deg_to_rad(real_t(p_value)); - if (is_valid_cone) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, swing_span); - } - - } else if ("joint_constraints/twist_span" == p_name) { - twist_span = Math::deg_to_rad(real_t(p_value)); - if (is_valid_cone) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, twist_span); - } - - } else if ("joint_constraints/bias" == p_name) { - bias = p_value; - if (is_valid_cone) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, bias); - } - - } else if ("joint_constraints/softness" == p_name) { - softness = p_value; - if (is_valid_cone) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, softness); - } - - } else if ("joint_constraints/relaxation" == p_name) { - relaxation = p_value; - if (is_valid_cone) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, relaxation); - } - - } else { - return false; - } - - return true; -} - -bool PhysicalBone3D::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const { - if (JointData::_get(p_name, r_ret)) { - return true; - } - - if ("joint_constraints/swing_span" == p_name) { - r_ret = Math::rad_to_deg(swing_span); - } else if ("joint_constraints/twist_span" == p_name) { - r_ret = Math::rad_to_deg(twist_span); - } else if ("joint_constraints/bias" == p_name) { - r_ret = bias; - } else if ("joint_constraints/softness" == p_name) { - r_ret = softness; - } else if ("joint_constraints/relaxation" == p_name) { - r_ret = relaxation; - } else { - return false; - } - - return true; -} - -void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const { - JointData::_get_property_list(p_list); - - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/swing_span"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_less,or_greater")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/relaxation"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); -} - -bool PhysicalBone3D::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - if (JointData::_set(p_name, p_value, j)) { - return true; - } - - bool is_valid_hinge = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_HINGE; - if ("joint_constraints/angular_limit_enabled" == p_name) { - angular_limit_enabled = p_value; - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled); - } - - } else if ("joint_constraints/angular_limit_upper" == p_name) { - angular_limit_upper = Math::deg_to_rad(real_t(p_value)); - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper); - } - - } else if ("joint_constraints/angular_limit_lower" == p_name) { - angular_limit_lower = Math::deg_to_rad(real_t(p_value)); - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower); - } - - } else if ("joint_constraints/angular_limit_bias" == p_name) { - angular_limit_bias = p_value; - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias); - } - - } else if ("joint_constraints/angular_limit_softness" == p_name) { - angular_limit_softness = p_value; - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness); - } - - } else if ("joint_constraints/angular_limit_relaxation" == p_name) { - angular_limit_relaxation = p_value; - if (is_valid_hinge) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation); - } - - } else { - return false; - } - - return true; -} - -bool PhysicalBone3D::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const { - if (JointData::_get(p_name, r_ret)) { - return true; - } - - if ("joint_constraints/angular_limit_enabled" == p_name) { - r_ret = angular_limit_enabled; - } else if ("joint_constraints/angular_limit_upper" == p_name) { - r_ret = Math::rad_to_deg(angular_limit_upper); - } else if ("joint_constraints/angular_limit_lower" == p_name) { - r_ret = Math::rad_to_deg(angular_limit_lower); - } else if ("joint_constraints/angular_limit_bias" == p_name) { - r_ret = angular_limit_bias; - } else if ("joint_constraints/angular_limit_softness" == p_name) { - r_ret = angular_limit_softness; - } else if ("joint_constraints/angular_limit_relaxation" == p_name) { - r_ret = angular_limit_relaxation; - } else { - return false; - } - - return true; -} - -void PhysicalBone3D::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const { - JointData::_get_property_list(p_list); - - p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("joint_constraints/angular_limit_enabled"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_bias"), PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_relaxation"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); -} - -bool PhysicalBone3D::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - if (JointData::_set(p_name, p_value, j)) { - return true; - } - - bool is_valid_slider = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_SLIDER; - if ("joint_constraints/linear_limit_upper" == p_name) { - linear_limit_upper = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper); - } - - } else if ("joint_constraints/linear_limit_lower" == p_name) { - linear_limit_lower = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower); - } - - } else if ("joint_constraints/linear_limit_softness" == p_name) { - linear_limit_softness = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness); - } - - } else if ("joint_constraints/linear_limit_restitution" == p_name) { - linear_limit_restitution = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution); - } - - } else if ("joint_constraints/linear_limit_damping" == p_name) { - linear_limit_damping = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution); - } - - } else if ("joint_constraints/angular_limit_upper" == p_name) { - angular_limit_upper = Math::deg_to_rad(real_t(p_value)); - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper); - } - - } else if ("joint_constraints/angular_limit_lower" == p_name) { - angular_limit_lower = Math::deg_to_rad(real_t(p_value)); - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower); - } - - } else if ("joint_constraints/angular_limit_softness" == p_name) { - angular_limit_softness = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); - } - - } else if ("joint_constraints/angular_limit_restitution" == p_name) { - angular_limit_restitution = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); - } - - } else if ("joint_constraints/angular_limit_damping" == p_name) { - angular_limit_damping = p_value; - if (is_valid_slider) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping); - } - - } else { - return false; - } - - return true; -} - -bool PhysicalBone3D::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const { - if (JointData::_get(p_name, r_ret)) { - return true; - } - - if ("joint_constraints/linear_limit_upper" == p_name) { - r_ret = linear_limit_upper; - } else if ("joint_constraints/linear_limit_lower" == p_name) { - r_ret = linear_limit_lower; - } else if ("joint_constraints/linear_limit_softness" == p_name) { - r_ret = linear_limit_softness; - } else if ("joint_constraints/linear_limit_restitution" == p_name) { - r_ret = linear_limit_restitution; - } else if ("joint_constraints/linear_limit_damping" == p_name) { - r_ret = linear_limit_damping; - } else if ("joint_constraints/angular_limit_upper" == p_name) { - r_ret = Math::rad_to_deg(angular_limit_upper); - } else if ("joint_constraints/angular_limit_lower" == p_name) { - r_ret = Math::rad_to_deg(angular_limit_lower); - } else if ("joint_constraints/angular_limit_softness" == p_name) { - r_ret = angular_limit_softness; - } else if ("joint_constraints/angular_limit_restitution" == p_name) { - r_ret = angular_limit_restitution; - } else if ("joint_constraints/angular_limit_damping" == p_name) { - r_ret = angular_limit_damping; - } else { - return false; - } - - return true; -} - -void PhysicalBone3D::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const { - JointData::_get_property_list(p_list); - - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_upper"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_lower"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_restitution"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/linear_limit_damping"), PROPERTY_HINT_RANGE, "0,16.0,0.01")); - - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_restitution"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/angular_limit_damping"), PROPERTY_HINT_RANGE, "0,16.0,0.01")); -} - -bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { - if (JointData::_set(p_name, p_value, j)) { - return true; - } - - String path = p_name; - - if (!path.begins_with("joint_constraints/")) { - return false; - } - - Vector3::Axis axis; - { - const String axis_s = path.get_slicec('/', 1); - if ("x" == axis_s) { - axis = Vector3::AXIS_X; - } else if ("y" == axis_s) { - axis = Vector3::AXIS_Y; - } else if ("z" == axis_s) { - axis = Vector3::AXIS_Z; - } else { - return false; - } - } - - String var_name = path.get_slicec('/', 2); - bool is_valid_6dof = j.is_valid() && PhysicsServer3D::get_singleton()->joint_get_type(j) == PhysicsServer3D::JOINT_TYPE_6DOF; - if ("linear_limit_enabled" == var_name) { - axis_data[axis].linear_limit_enabled = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled); - } - - } else if ("linear_limit_upper" == var_name) { - axis_data[axis].linear_limit_upper = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper); - } - - } else if ("linear_limit_lower" == var_name) { - axis_data[axis].linear_limit_lower = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower); - } - - } else if ("linear_limit_softness" == var_name) { - axis_data[axis].linear_limit_softness = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness); - } - - } else if ("linear_spring_enabled" == var_name) { - axis_data[axis].linear_spring_enabled = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, axis_data[axis].linear_spring_enabled); - } - - } else if ("linear_spring_stiffness" == var_name) { - axis_data[axis].linear_spring_stiffness = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, axis_data[axis].linear_spring_stiffness); - } - - } else if ("linear_spring_damping" == var_name) { - axis_data[axis].linear_spring_damping = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, axis_data[axis].linear_spring_damping); - } - - } else if ("linear_equilibrium_point" == var_name) { - axis_data[axis].linear_equilibrium_point = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].linear_equilibrium_point); - } - - } else if ("linear_restitution" == var_name) { - axis_data[axis].linear_restitution = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution); - } - - } else if ("linear_damping" == var_name) { - axis_data[axis].linear_damping = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping); - } - - } else if ("angular_limit_enabled" == var_name) { - axis_data[axis].angular_limit_enabled = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled); - } - - } else if ("angular_limit_upper" == var_name) { - axis_data[axis].angular_limit_upper = Math::deg_to_rad(real_t(p_value)); - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper); - } - - } else if ("angular_limit_lower" == var_name) { - axis_data[axis].angular_limit_lower = Math::deg_to_rad(real_t(p_value)); - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower); - } - - } else if ("angular_limit_softness" == var_name) { - axis_data[axis].angular_limit_softness = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness); - } - - } else if ("angular_restitution" == var_name) { - axis_data[axis].angular_restitution = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution); - } - - } else if ("angular_damping" == var_name) { - axis_data[axis].angular_damping = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping); - } - - } else if ("erp" == var_name) { - axis_data[axis].erp = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp); - } - - } else if ("angular_spring_enabled" == var_name) { - axis_data[axis].angular_spring_enabled = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, axis_data[axis].angular_spring_enabled); - } - - } else if ("angular_spring_stiffness" == var_name) { - axis_data[axis].angular_spring_stiffness = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, axis_data[axis].angular_spring_stiffness); - } - - } else if ("angular_spring_damping" == var_name) { - axis_data[axis].angular_spring_damping = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, axis_data[axis].angular_spring_damping); - } - - } else if ("angular_equilibrium_point" == var_name) { - axis_data[axis].angular_equilibrium_point = p_value; - if (is_valid_6dof) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, axis_data[axis].angular_equilibrium_point); - } - - } else { - return false; - } - - return true; -} - -bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const { - if (JointData::_get(p_name, r_ret)) { - return true; - } - - String path = p_name; - - if (!path.begins_with("joint_constraints/")) { - return false; - } - - int axis; - { - const String axis_s = path.get_slicec('/', 1); - if ("x" == axis_s) { - axis = 0; - } else if ("y" == axis_s) { - axis = 1; - } else if ("z" == axis_s) { - axis = 2; - } else { - return false; - } - } - - String var_name = path.get_slicec('/', 2); - - if ("linear_limit_enabled" == var_name) { - r_ret = axis_data[axis].linear_limit_enabled; - } else if ("linear_limit_upper" == var_name) { - r_ret = axis_data[axis].linear_limit_upper; - } else if ("linear_limit_lower" == var_name) { - r_ret = axis_data[axis].linear_limit_lower; - } else if ("linear_limit_softness" == var_name) { - r_ret = axis_data[axis].linear_limit_softness; - } else if ("linear_spring_enabled" == var_name) { - r_ret = axis_data[axis].linear_spring_enabled; - } else if ("linear_spring_stiffness" == var_name) { - r_ret = axis_data[axis].linear_spring_stiffness; - } else if ("linear_spring_damping" == var_name) { - r_ret = axis_data[axis].linear_spring_damping; - } else if ("linear_equilibrium_point" == var_name) { - r_ret = axis_data[axis].linear_equilibrium_point; - } else if ("linear_restitution" == var_name) { - r_ret = axis_data[axis].linear_restitution; - } else if ("linear_damping" == var_name) { - r_ret = axis_data[axis].linear_damping; - } else if ("angular_limit_enabled" == var_name) { - r_ret = axis_data[axis].angular_limit_enabled; - } else if ("angular_limit_upper" == var_name) { - r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_upper); - } else if ("angular_limit_lower" == var_name) { - r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_lower); - } else if ("angular_limit_softness" == var_name) { - r_ret = axis_data[axis].angular_limit_softness; - } else if ("angular_restitution" == var_name) { - r_ret = axis_data[axis].angular_restitution; - } else if ("angular_damping" == var_name) { - r_ret = axis_data[axis].angular_damping; - } else if ("erp" == var_name) { - r_ret = axis_data[axis].erp; - } else if ("angular_spring_enabled" == var_name) { - r_ret = axis_data[axis].angular_spring_enabled; - } else if ("angular_spring_stiffness" == var_name) { - r_ret = axis_data[axis].angular_spring_stiffness; - } else if ("angular_spring_damping" == var_name) { - r_ret = axis_data[axis].angular_spring_damping; - } else if ("angular_equilibrium_point" == var_name) { - r_ret = axis_data[axis].angular_equilibrium_point; - } else { - return false; - } - - return true; -} - -void PhysicalBone3D::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const { - const StringName axis_names[] = { PNAME("x"), PNAME("y"), PNAME("z") }; - for (int i = 0; i < 3; ++i) { - const String prefix = vformat("%s/%s/", PNAME("joint_constraints"), axis_names[i]); - p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("linear_limit_enabled"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_upper"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_lower"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("linear_spring_enabled"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_spring_stiffness"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_spring_damping"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_equilibrium_point"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_restitution"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("linear_damping"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("angular_limit_enabled"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_upper"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_lower"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_limit_softness"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_restitution"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_damping"), PROPERTY_HINT_RANGE, "0.01,16,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("erp"))); - p_list->push_back(PropertyInfo(Variant::BOOL, prefix + PNAME("angular_spring_enabled"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_spring_stiffness"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_spring_damping"))); - p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + PNAME("angular_equilibrium_point"))); - } -} - -bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) { - if (p_name == "bone_name") { - set_bone_name(p_value); - return true; - } - - if (joint_data) { - if (joint_data->_set(p_name, p_value, joint)) { -#ifdef TOOLS_ENABLED - update_gizmos(); -#endif - return true; - } - } - - return false; -} - -bool PhysicalBone3D::_get(const StringName &p_name, Variant &r_ret) const { - if (p_name == "bone_name") { - r_ret = get_bone_name(); - return true; - } - - if (joint_data) { - return joint_data->_get(p_name, r_ret); - } - - return false; -} - -void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const { - Skeleton3D *parent = find_skeleton_parent(get_parent()); - - if (parent) { - String names; - for (int i = 0; i < parent->get_bone_count(); i++) { - if (i > 0) { - names += ","; - } - names += parent->get_bone_name(i); - } - - p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("bone_name"), PROPERTY_HINT_ENUM, names)); - } else { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("bone_name"))); - } - - if (joint_data) { - joint_data->_get_property_list(p_list); - } -} - -void PhysicalBone3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: - parent_skeleton = find_skeleton_parent(get_parent()); - update_bone_id(); - reset_to_rest_position(); - reset_physics_simulation_state(); - if (joint_data) { - _reload_joint(); - } - break; - - case NOTIFICATION_EXIT_TREE: { - if (parent_skeleton) { - if (-1 != bone_id) { - parent_skeleton->unbind_physical_bone_from_bone(bone_id); - bone_id = -1; - } - } - parent_skeleton = nullptr; - PhysicsServer3D::get_singleton()->joint_clear(joint); - } break; - - case NOTIFICATION_TRANSFORM_CHANGED: { - if (Engine::get_singleton()->is_editor_hint()) { - update_offset(); - } - } break; - } -} - -void PhysicalBone3D::_sync_body_state(PhysicsDirectBodyState3D *p_state) { - set_ignore_transform_notification(true); - set_global_transform(p_state->get_transform()); - set_ignore_transform_notification(false); - - linear_velocity = p_state->get_linear_velocity(); - angular_velocity = p_state->get_angular_velocity(); -} - -void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { - if (!simulate_physics || !_internal_simulate_physics) { - return; - } - - if (GDVIRTUAL_IS_OVERRIDDEN(_integrate_forces)) { - _sync_body_state(p_state); - - Transform3D old_transform = get_global_transform(); - GDVIRTUAL_CALL(_integrate_forces, p_state); - Transform3D new_transform = get_global_transform(); - - if (new_transform != old_transform) { - // Update the physics server with the new transform, to prevent it from being overwritten at the sync below. - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); - } - } - - _sync_body_state(p_state); - _on_transform_changed(); - - Transform3D global_transform(p_state->get_transform()); - - // Update skeleton - if (parent_skeleton) { - if (-1 != bone_id) { - parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true); - } - } -} - -void PhysicalBone3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse); - ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3()); - - ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type); - ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type); - - ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone3D::set_joint_offset); - ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset); - ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation); - ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation); - - ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset); - ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset); - - ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone3D::get_simulate_physics); - - ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone3D::is_simulating_physics); - - ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone3D::get_bone_id); - - ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone3D::set_mass); - ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone3D::get_mass); - - ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone3D::set_friction); - ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone3D::get_friction); - - ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone3D::set_bounce); - ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone3D::get_bounce); - - ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone3D::set_gravity_scale); - ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone3D::get_gravity_scale); - - ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &PhysicalBone3D::set_linear_damp_mode); - ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &PhysicalBone3D::get_linear_damp_mode); - - ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &PhysicalBone3D::set_angular_damp_mode); - ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &PhysicalBone3D::get_angular_damp_mode); - - ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &PhysicalBone3D::set_linear_damp); - ClassDB::bind_method(D_METHOD("get_linear_damp"), &PhysicalBone3D::get_linear_damp); - - ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &PhysicalBone3D::set_angular_damp); - ClassDB::bind_method(D_METHOD("get_angular_damp"), &PhysicalBone3D::get_angular_damp); - - ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &PhysicalBone3D::set_linear_velocity); - ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicalBone3D::get_linear_velocity); - - ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &PhysicalBone3D::set_angular_velocity); - ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicalBone3D::get_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &PhysicalBone3D::set_use_custom_integrator); - ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &PhysicalBone3D::is_using_custom_integrator); - - ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep); - ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep); - - GDVIRTUAL_BIND(_integrate_forces, "state"); - - ADD_GROUP("Joint", "joint_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_joint_offset", "get_joint_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_less,or_greater,radians_as_degrees"), "set_joint_rotation", "get_joint_rotation"); - - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_body_offset", "get_body_offset"); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-8,8,0.001,or_less,or_greater"), "set_gravity_scale", "get_gravity_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity", PROPERTY_HINT_NONE, "suffix:m/s"), "set_linear_velocity", "get_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity", PROPERTY_HINT_NONE, U"radians_as_degrees,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - - BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); - BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE); - - BIND_ENUM_CONSTANT(JOINT_TYPE_NONE); - BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); - BIND_ENUM_CONSTANT(JOINT_TYPE_CONE); - BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE); - BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER); - BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF); -} - -Skeleton3D *PhysicalBone3D::find_skeleton_parent(Node *p_parent) { - if (!p_parent) { - return nullptr; - } - Skeleton3D *s = Object::cast_to<Skeleton3D>(p_parent); - return s ? s : find_skeleton_parent(p_parent->get_parent()); -} - -void PhysicalBone3D::_update_joint_offset() { - _fix_joint_offset(); - - set_ignore_transform_notification(true); - reset_to_rest_position(); - set_ignore_transform_notification(false); - -#ifdef TOOLS_ENABLED - update_gizmos(); -#endif -} - -void PhysicalBone3D::_fix_joint_offset() { - // Clamp joint origin to bone origin - if (parent_skeleton) { - joint_offset.origin = body_offset.affine_inverse().origin; - } -} - -void PhysicalBone3D::_reload_joint() { - if (!parent_skeleton) { - PhysicsServer3D::get_singleton()->joint_clear(joint); - return; - } - - PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id); - if (!body_a) { - PhysicsServer3D::get_singleton()->joint_clear(joint); - return; - } - - Transform3D joint_transf = get_global_transform() * joint_offset; - Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf; - local_a.orthonormalize(); - - switch (get_joint_type()) { - case JOINT_TYPE_PIN: { - PhysicsServer3D::get_singleton()->joint_make_pin(joint, body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); - const PinJointData *pjd(static_cast<const PinJointData *>(joint_data)); - PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_BIAS, pjd->bias); - PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_DAMPING, pjd->damping); - PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp); - - } break; - case JOINT_TYPE_CONE: { - PhysicsServer3D::get_singleton()->joint_make_cone_twist(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); - const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data)); - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span); - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span); - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_BIAS, cjd->bias); - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SOFTNESS, cjd->softness); - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation); - - } break; - case JOINT_TYPE_HINGE: { - PhysicsServer3D::get_singleton()->joint_make_hinge(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); - const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data)); - PhysicsServer3D::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled); - PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper); - PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower); - PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias); - PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness); - PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation); - - } break; - case JOINT_TYPE_SLIDER: { - PhysicsServer3D::get_singleton()->joint_make_slider(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); - const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data)); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); - PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping); - - } break; - case JOINT_TYPE_6DOF: { - PhysicsServer3D::get_singleton()->joint_make_generic_6dof(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); - const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data)); - for (int axis = 0; axis < 3; ++axis) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, g6dofjd->axis_data[axis].linear_spring_enabled); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].linear_spring_stiffness); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_DAMPING, g6dofjd->axis_data[axis].linear_spring_damping); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].linear_equilibrium_point); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, g6dofjd->axis_data[axis].angular_spring_enabled); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, g6dofjd->axis_data[axis].angular_spring_stiffness); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_DAMPING, g6dofjd->axis_data[axis].angular_spring_damping); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, g6dofjd->axis_data[axis].angular_equilibrium_point); - } - - } break; - case JOINT_TYPE_NONE: { - } break; - } -} - -void PhysicalBone3D::_on_bone_parent_changed() { - _reload_joint(); -} - -#ifdef TOOLS_ENABLED -void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) { - gizmo_move_joint = p_move_joint; -} - -Transform3D PhysicalBone3D::get_global_gizmo_transform() const { - return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform(); -} - -Transform3D PhysicalBone3D::get_local_gizmo_transform() const { - return gizmo_move_joint ? get_transform() * joint_offset : get_transform(); -} -#endif - -const PhysicalBone3D::JointData *PhysicalBone3D::get_joint_data() const { - return joint_data; -} - -Skeleton3D *PhysicalBone3D::find_skeleton_parent() { - return find_skeleton_parent(this); -} - -void PhysicalBone3D::set_joint_type(JointType p_joint_type) { - if (p_joint_type == get_joint_type()) { - return; - } - - if (joint_data) { - memdelete(joint_data); - } - joint_data = nullptr; - switch (p_joint_type) { - case JOINT_TYPE_PIN: - joint_data = memnew(PinJointData); - break; - case JOINT_TYPE_CONE: - joint_data = memnew(ConeJointData); - break; - case JOINT_TYPE_HINGE: - joint_data = memnew(HingeJointData); - break; - case JOINT_TYPE_SLIDER: - joint_data = memnew(SliderJointData); - break; - case JOINT_TYPE_6DOF: - joint_data = memnew(SixDOFJointData); - break; - case JOINT_TYPE_NONE: - break; - } - - _reload_joint(); - -#ifdef TOOLS_ENABLED - notify_property_list_changed(); - update_gizmos(); -#endif -} - -PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const { - return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE; -} - -void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) { - joint_offset = p_offset; - - _update_joint_offset(); -} - -const Transform3D &PhysicalBone3D::get_joint_offset() const { - return joint_offset; -} - -void PhysicalBone3D::set_joint_rotation(const Vector3 &p_euler_rad) { - joint_offset.basis.set_euler_scale(p_euler_rad, joint_offset.basis.get_scale()); - - _update_joint_offset(); -} - -Vector3 PhysicalBone3D::get_joint_rotation() const { - return joint_offset.basis.get_euler_normalized(); -} - -const Transform3D &PhysicalBone3D::get_body_offset() const { - return body_offset; -} - -void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) { - body_offset = p_offset; - body_offset_inverse = body_offset.affine_inverse(); - - _update_joint_offset(); -} - -void PhysicalBone3D::set_simulate_physics(bool p_simulate) { - if (simulate_physics == p_simulate) { - return; - } - - simulate_physics = p_simulate; - reset_physics_simulation_state(); -} - -bool PhysicalBone3D::get_simulate_physics() { - return simulate_physics; -} - -bool PhysicalBone3D::is_simulating_physics() { - return _internal_simulate_physics; -} - -void PhysicalBone3D::set_bone_name(const String &p_name) { - bone_name = p_name; - bone_id = -1; - - update_bone_id(); - reset_to_rest_position(); -} - -const String &PhysicalBone3D::get_bone_name() const { - return bone_name; -} - -void PhysicalBone3D::set_mass(real_t p_mass) { - ERR_FAIL_COND(p_mass <= 0); - mass = p_mass; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass); -} - -real_t PhysicalBone3D::get_mass() const { - return mass; -} - -void PhysicalBone3D::set_friction(real_t p_friction) { - ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - - friction = p_friction; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, friction); -} - -real_t PhysicalBone3D::get_friction() const { - return friction; -} - -void PhysicalBone3D::set_bounce(real_t p_bounce) { - ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - - bounce = p_bounce; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, bounce); -} - -real_t PhysicalBone3D::get_bounce() const { - return bounce; -} - -void PhysicalBone3D::set_gravity_scale(real_t p_gravity_scale) { - gravity_scale = p_gravity_scale; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale); -} - -real_t PhysicalBone3D::get_gravity_scale() const { - return gravity_scale; -} - -void PhysicalBone3D::set_linear_damp_mode(DampMode p_mode) { - linear_damp_mode = p_mode; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode); -} - -PhysicalBone3D::DampMode PhysicalBone3D::get_linear_damp_mode() const { - return linear_damp_mode; -} - -void PhysicalBone3D::set_angular_damp_mode(DampMode p_mode) { - angular_damp_mode = p_mode; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode); -} - -PhysicalBone3D::DampMode PhysicalBone3D::get_angular_damp_mode() const { - return angular_damp_mode; -} - -void PhysicalBone3D::set_linear_damp(real_t p_linear_damp) { - ERR_FAIL_COND(p_linear_damp < 0); - - linear_damp = p_linear_damp; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp); -} - -real_t PhysicalBone3D::get_linear_damp() const { - return linear_damp; -} - -void PhysicalBone3D::set_angular_damp(real_t p_angular_damp) { - ERR_FAIL_COND(p_angular_damp < 0); - - angular_damp = p_angular_damp; - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp); -} - -real_t PhysicalBone3D::get_angular_damp() const { - return angular_damp; -} - -void PhysicalBone3D::set_can_sleep(bool p_active) { - can_sleep = p_active; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active); -} - -bool PhysicalBone3D::is_able_to_sleep() const { - return can_sleep; -} - -PhysicalBone3D::PhysicalBone3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { - joint = PhysicsServer3D::get_singleton()->joint_create(); - reset_physics_simulation_state(); -} - -PhysicalBone3D::~PhysicalBone3D() { - if (joint_data) { - memdelete(joint_data); - } - ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); - PhysicsServer3D::get_singleton()->free(joint); -} - -void PhysicalBone3D::update_bone_id() { - if (!parent_skeleton) { - return; - } - - const int new_bone_id = parent_skeleton->find_bone(bone_name); - - if (new_bone_id != bone_id) { - if (-1 != bone_id) { - // Assert the unbind from old node - parent_skeleton->unbind_physical_bone_from_bone(bone_id); - } - - bone_id = new_bone_id; - - parent_skeleton->bind_physical_bone_to_bone(bone_id, this); - - _fix_joint_offset(); - reset_physics_simulation_state(); - } -} - -void PhysicalBone3D::update_offset() { -#ifdef TOOLS_ENABLED - if (parent_skeleton) { - Transform3D bone_transform(parent_skeleton->get_global_transform()); - if (-1 != bone_id) { - bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); - } - - if (gizmo_move_joint) { - bone_transform *= body_offset; - set_joint_offset(bone_transform.affine_inverse() * get_global_transform()); - } else { - set_body_offset(bone_transform.affine_inverse() * get_global_transform()); - } - } -#endif -} - -void PhysicalBone3D::_start_physics_simulation() { - if (_internal_simulate_physics || !parent_skeleton) { - return; - } - reset_to_rest_position(); - set_body_mode(PhysicsServer3D::BODY_MODE_RIGID); - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_body_state_changed)); - set_as_top_level(true); - _internal_simulate_physics = true; -} - -void PhysicalBone3D::_stop_physics_simulation() { - if (!parent_skeleton) { - return; - } - if (parent_skeleton->get_animate_physical_bones()) { - set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); - } else { - set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); - PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); - PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); - PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); - } - if (_internal_simulate_physics) { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), Callable()); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false); - set_as_top_level(false); - _internal_simulate_physics = false; - } -} diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h deleted file mode 100644 index b84b7c4f02..0000000000 --- a/scene/3d/physics_body_3d.h +++ /dev/null @@ -1,797 +0,0 @@ -/**************************************************************************/ -/* physics_body_3d.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* 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. */ -/**************************************************************************/ - -#ifndef PHYSICS_BODY_3D_H -#define PHYSICS_BODY_3D_H - -#include "core/templates/vset.h" -#include "scene/3d/collision_object_3d.h" -#include "scene/resources/physics_material.h" -#include "servers/physics_server_3d.h" -#include "skeleton_3d.h" - -class KinematicCollision3D; - -class PhysicsBody3D : public CollisionObject3D { - GDCLASS(PhysicsBody3D, CollisionObject3D); - -protected: - static void _bind_methods(); - PhysicsBody3D(PhysicsServer3D::BodyMode p_mode); - - Ref<KinematicCollision3D> motion_cache; - - uint16_t locked_axis = 0; - - Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); - -public: - bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); - Vector3 get_gravity() const; - - void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); - bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; - - virtual Vector3 get_linear_velocity() const; - virtual Vector3 get_angular_velocity() const; - virtual real_t get_inverse_mass() const; - - TypedArray<PhysicsBody3D> get_collision_exceptions(); - void add_collision_exception_with(Node *p_node); //must be physicsbody - void remove_collision_exception_with(Node *p_node); - - virtual ~PhysicsBody3D(); -}; - -class StaticBody3D : public PhysicsBody3D { - GDCLASS(StaticBody3D, PhysicsBody3D); - -private: - Vector3 constant_linear_velocity; - Vector3 constant_angular_velocity; - - Ref<PhysicsMaterial> physics_material_override; - -protected: - static void _bind_methods(); - -public: - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); - Ref<PhysicsMaterial> get_physics_material_override() const; - - void set_constant_linear_velocity(const Vector3 &p_vel); - void set_constant_angular_velocity(const Vector3 &p_vel); - - Vector3 get_constant_linear_velocity() const; - Vector3 get_constant_angular_velocity() const; - - StaticBody3D(PhysicsServer3D::BodyMode p_mode = PhysicsServer3D::BODY_MODE_STATIC); - -private: - void _reload_physics_characteristics(); -}; - -class AnimatableBody3D : public StaticBody3D { - GDCLASS(AnimatableBody3D, StaticBody3D); - -private: - Vector3 linear_velocity; - Vector3 angular_velocity; - - bool sync_to_physics = true; - - Transform3D last_valid_transform; - - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); - void _body_state_changed(PhysicsDirectBodyState3D *p_state); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - virtual Vector3 get_linear_velocity() const override; - virtual Vector3 get_angular_velocity() const override; - - AnimatableBody3D(); - -private: - void _update_kinematic_motion(); - - void set_sync_to_physics(bool p_enable); - bool is_sync_to_physics_enabled() const; -}; - -class RigidBody3D : public PhysicsBody3D { - GDCLASS(RigidBody3D, PhysicsBody3D); - -public: - enum FreezeMode { - FREEZE_MODE_STATIC, - FREEZE_MODE_KINEMATIC, - }; - - enum CenterOfMassMode { - CENTER_OF_MASS_MODE_AUTO, - CENTER_OF_MASS_MODE_CUSTOM, - }; - - enum DampMode { - DAMP_MODE_COMBINE, - DAMP_MODE_REPLACE, - }; - -private: - bool can_sleep = true; - bool lock_rotation = false; - bool freeze = false; - FreezeMode freeze_mode = FREEZE_MODE_STATIC; - - real_t mass = 1.0; - Vector3 inertia; - CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; - Vector3 center_of_mass; - - Ref<PhysicsMaterial> physics_material_override; - - Vector3 linear_velocity; - Vector3 angular_velocity; - Basis inverse_inertia_tensor; - real_t gravity_scale = 1.0; - - DampMode linear_damp_mode = DAMP_MODE_COMBINE; - DampMode angular_damp_mode = DAMP_MODE_COMBINE; - - real_t linear_damp = 0.0; - real_t angular_damp = 0.0; - - bool sleeping = false; - bool ccd = false; - - int max_contacts_reported = 0; - int contact_count = 0; - - bool custom_integrator = false; - - struct ShapePair { - int body_shape = 0; - int local_shape = 0; - bool tagged = false; - bool operator<(const ShapePair &p_sp) const { - if (body_shape == p_sp.body_shape) { - return local_shape < p_sp.local_shape; - } else { - return body_shape < p_sp.body_shape; - } - } - - ShapePair() {} - ShapePair(int p_bs, int p_ls) { - body_shape = p_bs; - local_shape = p_ls; - tagged = false; - } - }; - struct RigidBody3D_RemoveAction { - RID rid; - ObjectID body_id; - ShapePair pair; - }; - struct BodyState { - RID rid; - //int rc; - bool in_tree = false; - VSet<ShapePair> shapes; - }; - - struct ContactMonitor { - bool locked = false; - HashMap<ObjectID, BodyState> body_map; - }; - - ContactMonitor *contact_monitor = nullptr; - void _body_enter_tree(ObjectID p_id); - void _body_exit_tree(ObjectID p_id); - - void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); - - void _sync_body_state(PhysicsDirectBodyState3D *p_state); - -protected: - void _notification(int p_what); - static void _bind_methods(); - - void _validate_property(PropertyInfo &p_property) const; - - GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) - - virtual void _body_state_changed(PhysicsDirectBodyState3D *p_state); - - void _apply_body_mode(); - -public: - void set_lock_rotation_enabled(bool p_lock_rotation); - bool is_lock_rotation_enabled() const; - - void set_freeze_enabled(bool p_freeze); - bool is_freeze_enabled() const; - - void set_freeze_mode(FreezeMode p_freeze_mode); - FreezeMode get_freeze_mode() const; - - void set_mass(real_t p_mass); - real_t get_mass() const; - - virtual real_t get_inverse_mass() const override { return 1.0 / mass; } - - void set_inertia(const Vector3 &p_inertia); - const Vector3 &get_inertia() const; - - void set_center_of_mass_mode(CenterOfMassMode p_mode); - CenterOfMassMode get_center_of_mass_mode() const; - - void set_center_of_mass(const Vector3 &p_center_of_mass); - const Vector3 &get_center_of_mass() const; - - void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); - Ref<PhysicsMaterial> get_physics_material_override() const; - - void set_linear_velocity(const Vector3 &p_velocity); - Vector3 get_linear_velocity() const override; - - void set_axis_velocity(const Vector3 &p_axis); - - void set_angular_velocity(const Vector3 &p_velocity); - Vector3 get_angular_velocity() const override; - - Basis get_inverse_inertia_tensor() const; - - void set_gravity_scale(real_t p_gravity_scale); - real_t get_gravity_scale() const; - - void set_linear_damp_mode(DampMode p_mode); - DampMode get_linear_damp_mode() const; - - void set_angular_damp_mode(DampMode p_mode); - DampMode get_angular_damp_mode() const; - - void set_linear_damp(real_t p_linear_damp); - real_t get_linear_damp() const; - - void set_angular_damp(real_t p_angular_damp); - real_t get_angular_damp() const; - - void set_use_custom_integrator(bool p_enable); - bool is_using_custom_integrator(); - - void set_sleeping(bool p_sleeping); - bool is_sleeping() const; - - void set_can_sleep(bool p_active); - bool is_able_to_sleep() const; - - void set_contact_monitor(bool p_enabled); - bool is_contact_monitor_enabled() const; - - void set_max_contacts_reported(int p_amount); - int get_max_contacts_reported() const; - int get_contact_count() const; - - void set_use_continuous_collision_detection(bool p_enable); - bool is_using_continuous_collision_detection() const; - - TypedArray<Node3D> get_colliding_bodies() const; - - void apply_central_impulse(const Vector3 &p_impulse); - void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); - void apply_torque_impulse(const Vector3 &p_impulse); - - void apply_central_force(const Vector3 &p_force); - void apply_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()); - void apply_torque(const Vector3 &p_torque); - - void add_constant_central_force(const Vector3 &p_force); - void add_constant_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()); - void add_constant_torque(const Vector3 &p_torque); - - void set_constant_force(const Vector3 &p_force); - Vector3 get_constant_force() const; - - void set_constant_torque(const Vector3 &p_torque); - Vector3 get_constant_torque() const; - - virtual PackedStringArray get_configuration_warnings() const override; - - RigidBody3D(); - ~RigidBody3D(); - -private: - void _reload_physics_characteristics(); -}; - -VARIANT_ENUM_CAST(RigidBody3D::FreezeMode); -VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode); -VARIANT_ENUM_CAST(RigidBody3D::DampMode); - -class KinematicCollision3D; - -class CharacterBody3D : public PhysicsBody3D { - GDCLASS(CharacterBody3D, PhysicsBody3D); - -public: - enum MotionMode { - MOTION_MODE_GROUNDED, - MOTION_MODE_FLOATING, - }; - enum PlatformOnLeave { - PLATFORM_ON_LEAVE_ADD_VELOCITY, - PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY, - PLATFORM_ON_LEAVE_DO_NOTHING, - }; - bool move_and_slide(); - void apply_floor_snap(); - - const Vector3 &get_velocity() const; - void set_velocity(const Vector3 &p_velocity); - - bool is_on_floor() const; - bool is_on_floor_only() const; - bool is_on_wall() const; - bool is_on_wall_only() const; - bool is_on_ceiling() const; - bool is_on_ceiling_only() const; - const Vector3 &get_last_motion() const; - Vector3 get_position_delta() const; - const Vector3 &get_floor_normal() const; - const Vector3 &get_wall_normal() const; - const Vector3 &get_real_velocity() const; - real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const; - const Vector3 &get_platform_velocity() const; - const Vector3 &get_platform_angular_velocity() const; - - virtual Vector3 get_linear_velocity() const override; - - int get_slide_collision_count() const; - PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const; - - void set_safe_margin(real_t p_margin); - real_t get_safe_margin() const; - - bool is_floor_stop_on_slope_enabled() const; - void set_floor_stop_on_slope_enabled(bool p_enabled); - - bool is_floor_constant_speed_enabled() const; - void set_floor_constant_speed_enabled(bool p_enabled); - - bool is_floor_block_on_wall_enabled() const; - void set_floor_block_on_wall_enabled(bool p_enabled); - - bool is_slide_on_ceiling_enabled() const; - void set_slide_on_ceiling_enabled(bool p_enabled); - - int get_max_slides() const; - void set_max_slides(int p_max_slides); - - real_t get_floor_max_angle() const; - void set_floor_max_angle(real_t p_radians); - - real_t get_floor_snap_length(); - void set_floor_snap_length(real_t p_floor_snap_length); - - real_t get_wall_min_slide_angle() const; - void set_wall_min_slide_angle(real_t p_radians); - - uint32_t get_platform_floor_layers() const; - void set_platform_floor_layers(const uint32_t p_exclude_layer); - - uint32_t get_platform_wall_layers() const; - void set_platform_wall_layers(const uint32_t p_exclude_layer); - - void set_motion_mode(MotionMode p_mode); - MotionMode get_motion_mode() const; - - void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity); - PlatformOnLeave get_platform_on_leave() const; - - CharacterBody3D(); - ~CharacterBody3D(); - -private: - real_t margin = 0.001; - MotionMode motion_mode = MOTION_MODE_GROUNDED; - PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY; - union CollisionState { - uint32_t state = 0; - struct { - bool floor; - bool wall; - bool ceiling; - }; - - CollisionState() { - } - - CollisionState(bool p_floor, bool p_wall, bool p_ceiling) { - floor = p_floor; - wall = p_wall; - ceiling = p_ceiling; - } - }; - - CollisionState collision_state; - bool floor_constant_speed = false; - bool floor_stop_on_slope = true; - bool floor_block_on_wall = true; - bool slide_on_ceiling = true; - int max_slides = 6; - int platform_layer = 0; - RID platform_rid; - ObjectID platform_object_id; - uint32_t platform_floor_layers = UINT32_MAX; - uint32_t platform_wall_layers = 0; - real_t floor_snap_length = 0.1; - real_t floor_max_angle = Math::deg_to_rad((real_t)45.0); - real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0); - Vector3 up_direction = Vector3(0.0, 1.0, 0.0); - Vector3 velocity; - Vector3 floor_normal; - Vector3 wall_normal; - Vector3 ceiling_normal; - Vector3 last_motion; - Vector3 platform_velocity; - Vector3 platform_angular_velocity; - Vector3 platform_ceiling_velocity; - Vector3 previous_position; - Vector3 real_velocity; - - Vector<PhysicsServer3D::MotionResult> motion_results; - Vector<Ref<KinematicCollision3D>> slide_colliders; - - void _move_and_slide_floating(double p_delta); - void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); - - Ref<KinematicCollision3D> _get_slide_collision(int p_bounce); - Ref<KinematicCollision3D> _get_last_slide_collision(); - const Vector3 &get_up_direction() const; - bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up); - void set_up_direction(const Vector3 &p_up_direction); - void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state = CollisionState(true, true, true)); - void _set_platform_data(const PhysicsServer3D::MotionCollision &p_collision); - void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up); - -protected: - void _notification(int p_what); - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; -}; - -VARIANT_ENUM_CAST(CharacterBody3D::MotionMode); -VARIANT_ENUM_CAST(CharacterBody3D::PlatformOnLeave); - -class KinematicCollision3D : public RefCounted { - GDCLASS(KinematicCollision3D, RefCounted); - - PhysicsBody3D *owner = nullptr; - friend class PhysicsBody3D; - friend class CharacterBody3D; - PhysicsServer3D::MotionResult result; - -protected: - static void _bind_methods(); - -public: - Vector3 get_travel() const; - Vector3 get_remainder() const; - int get_collision_count() const; - real_t get_depth() const; - Vector3 get_position(int p_collision_index = 0) const; - Vector3 get_normal(int p_collision_index = 0) const; - real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const; - Object *get_local_shape(int p_collision_index = 0) const; - Object *get_collider(int p_collision_index = 0) const; - ObjectID get_collider_id(int p_collision_index = 0) const; - RID get_collider_rid(int p_collision_index = 0) const; - Object *get_collider_shape(int p_collision_index = 0) const; - int get_collider_shape_index(int p_collision_index = 0) const; - Vector3 get_collider_velocity(int p_collision_index = 0) const; -}; - -class PhysicalBone3D : public PhysicsBody3D { - GDCLASS(PhysicalBone3D, PhysicsBody3D); - -public: - enum DampMode { - DAMP_MODE_COMBINE, - DAMP_MODE_REPLACE, - }; - - enum JointType { - JOINT_TYPE_NONE, - JOINT_TYPE_PIN, - JOINT_TYPE_CONE, - JOINT_TYPE_HINGE, - JOINT_TYPE_SLIDER, - JOINT_TYPE_6DOF - }; - - struct JointData { - virtual JointType get_joint_type() { return JOINT_TYPE_NONE; } - - /// "j" is used to set the parameter inside the PhysicsServer3D - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - virtual ~JointData() {} - }; - - struct PinJointData : public JointData { - virtual JointType get_joint_type() { return JOINT_TYPE_PIN; } - - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - real_t bias = 0.3; - real_t damping = 1.0; - real_t impulse_clamp = 0.0; - }; - - struct ConeJointData : public JointData { - virtual JointType get_joint_type() { return JOINT_TYPE_CONE; } - - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - real_t swing_span = Math_PI * 0.25; - real_t twist_span = Math_PI; - real_t bias = 0.3; - real_t softness = 0.8; - real_t relaxation = 1.; - }; - - struct HingeJointData : public JointData { - virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; } - - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - bool angular_limit_enabled = false; - real_t angular_limit_upper = Math_PI * 0.5; - real_t angular_limit_lower = -Math_PI * 0.5; - real_t angular_limit_bias = 0.3; - real_t angular_limit_softness = 0.9; - real_t angular_limit_relaxation = 1.; - }; - - struct SliderJointData : public JointData { - virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; } - - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - real_t linear_limit_upper = 1.0; - real_t linear_limit_lower = -1.0; - real_t linear_limit_softness = 1.0; - real_t linear_limit_restitution = 0.7; - real_t linear_limit_damping = 1.0; - real_t angular_limit_upper = 0.0; - real_t angular_limit_lower = 0.0; - real_t angular_limit_softness = 1.0; - real_t angular_limit_restitution = 0.7; - real_t angular_limit_damping = 1.0; - }; - - struct SixDOFJointData : public JointData { - struct SixDOFAxisData { - bool linear_limit_enabled = true; - real_t linear_limit_upper = 0.0; - real_t linear_limit_lower = 0.0; - real_t linear_limit_softness = 0.7; - real_t linear_restitution = 0.5; - real_t linear_damping = 1.0; - bool linear_spring_enabled = false; - real_t linear_spring_stiffness = 0.0; - real_t linear_spring_damping = 0.0; - real_t linear_equilibrium_point = 0.0; - bool angular_limit_enabled = true; - real_t angular_limit_upper = 0.0; - real_t angular_limit_lower = 0.0; - real_t angular_limit_softness = 0.5; - real_t angular_restitution = 0.0; - real_t angular_damping = 1.0; - real_t erp = 0.5; - bool angular_spring_enabled = false; - real_t angular_spring_stiffness = 0.0; - real_t angular_spring_damping = 0.0; - real_t angular_equilibrium_point = 0.0; - }; - - virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; } - - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); - virtual bool _get(const StringName &p_name, Variant &r_ret) const; - virtual void _get_property_list(List<PropertyInfo> *p_list) const; - - SixDOFAxisData axis_data[3]; - - SixDOFJointData() {} - }; - -private: -#ifdef TOOLS_ENABLED - // if false gizmo move body - bool gizmo_move_joint = false; -#endif - - JointData *joint_data = nullptr; - Transform3D joint_offset; - RID joint; - - Skeleton3D *parent_skeleton = nullptr; - Transform3D body_offset; - Transform3D body_offset_inverse; - bool simulate_physics = false; - bool _internal_simulate_physics = false; - int bone_id = -1; - - String bone_name; - real_t bounce = 0.0; - real_t mass = 1.0; - real_t friction = 1.0; - Vector3 linear_velocity; - Vector3 angular_velocity; - real_t gravity_scale = 1.0; - bool can_sleep = true; - - bool custom_integrator = false; - - DampMode linear_damp_mode = DAMP_MODE_COMBINE; - DampMode angular_damp_mode = DAMP_MODE_COMBINE; - - real_t linear_damp = 0.0; - real_t angular_damp = 0.0; - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - void _notification(int p_what); - GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); - void _body_state_changed(PhysicsDirectBodyState3D *p_state); - - static void _bind_methods(); - -private: - void _sync_body_state(PhysicsDirectBodyState3D *p_state); - static Skeleton3D *find_skeleton_parent(Node *p_parent); - - void _update_joint_offset(); - void _fix_joint_offset(); - void _reload_joint(); - -public: - void _on_bone_parent_changed(); - - void set_linear_velocity(const Vector3 &p_velocity); - Vector3 get_linear_velocity() const override; - - void set_angular_velocity(const Vector3 &p_velocity); - Vector3 get_angular_velocity() const override; - - void set_use_custom_integrator(bool p_enable); - bool is_using_custom_integrator(); - -#ifdef TOOLS_ENABLED - void _set_gizmo_move_joint(bool p_move_joint); - virtual Transform3D get_global_gizmo_transform() const override; - virtual Transform3D get_local_gizmo_transform() const override; -#endif - - const JointData *get_joint_data() const; - Skeleton3D *find_skeleton_parent(); - - int get_bone_id() const { - return bone_id; - } - - void set_joint_type(JointType p_joint_type); - JointType get_joint_type() const; - - void set_joint_offset(const Transform3D &p_offset); - const Transform3D &get_joint_offset() const; - - void set_joint_rotation(const Vector3 &p_euler_rad); - Vector3 get_joint_rotation() const; - - void set_body_offset(const Transform3D &p_offset); - const Transform3D &get_body_offset() const; - - void set_simulate_physics(bool p_simulate); - bool get_simulate_physics(); - bool is_simulating_physics(); - - void set_bone_name(const String &p_name); - const String &get_bone_name() const; - - void set_mass(real_t p_mass); - real_t get_mass() const; - - void set_friction(real_t p_friction); - real_t get_friction() const; - - void set_bounce(real_t p_bounce); - real_t get_bounce() const; - - void set_gravity_scale(real_t p_gravity_scale); - real_t get_gravity_scale() const; - - void set_linear_damp_mode(DampMode p_mode); - DampMode get_linear_damp_mode() const; - - void set_angular_damp_mode(DampMode p_mode); - DampMode get_angular_damp_mode() const; - - void set_linear_damp(real_t p_linear_damp); - real_t get_linear_damp() const; - - void set_angular_damp(real_t p_angular_damp); - real_t get_angular_damp() const; - - void set_can_sleep(bool p_active); - bool is_able_to_sleep() const; - - void apply_central_impulse(const Vector3 &p_impulse); - void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); - - void reset_physics_simulation_state(); - void reset_to_rest_position(); - - PhysicalBone3D(); - ~PhysicalBone3D(); - -private: - void update_bone_id(); - void update_offset(); - - void _start_physics_simulation(); - void _stop_physics_simulation(); -}; - -VARIANT_ENUM_CAST(PhysicalBone3D::JointType); -VARIANT_ENUM_CAST(PhysicalBone3D::DampMode); - -#endif // PHYSICS_BODY_3D_H diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index f448d1c6e2..f0ffb7b2d5 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -32,7 +32,8 @@ #include "skeleton_3d.compat.inc" #include "core/variant/type_info.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physical_bone_3d.h" +#include "scene/3d/physics/physics_body_3d.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index bd03a97a36..f02cd9b700 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -30,7 +30,7 @@ #include "soft_body_3d.h" -#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics/physics_body_3d.h" SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {} diff --git a/scene/3d/xr_body_modifier_3d.cpp b/scene/3d/xr_body_modifier_3d.cpp new file mode 100644 index 0000000000..3414ce13ae --- /dev/null +++ b/scene/3d/xr_body_modifier_3d.cpp @@ -0,0 +1,415 @@ +/**************************************************************************/ +/* xr_body_modifier_3d.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "xr_body_modifier_3d.h" + +#include "scene/3d/skeleton_3d.h" +#include "servers/xr/xr_pose.h" +#include "servers/xr_server.h" + +void XRBodyModifier3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_body_tracker", "tracker_name"), &XRBodyModifier3D::set_body_tracker); + ClassDB::bind_method(D_METHOD("get_body_tracker"), &XRBodyModifier3D::get_body_tracker); + + ClassDB::bind_method(D_METHOD("set_target", "target"), &XRBodyModifier3D::set_target); + ClassDB::bind_method(D_METHOD("get_target"), &XRBodyModifier3D::get_target); + + ClassDB::bind_method(D_METHOD("set_body_update", "body_update"), &XRBodyModifier3D::set_body_update); + ClassDB::bind_method(D_METHOD("get_body_update"), &XRBodyModifier3D::get_body_update); + + ClassDB::bind_method(D_METHOD("set_bone_update", "bone_update"), &XRBodyModifier3D::set_bone_update); + ClassDB::bind_method(D_METHOD("get_bone_update"), &XRBodyModifier3D::get_bone_update); + + ClassDB::bind_method(D_METHOD("set_show_when_tracked", "show"), &XRBodyModifier3D::set_show_when_tracked); + ClassDB::bind_method(D_METHOD("get_show_when_tracked"), &XRBodyModifier3D::get_show_when_tracked); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/body"), "set_body_tracker", "get_body_tracker"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_target", "get_target"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "body_update", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_update", "get_body_update"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_when_tracked"), "set_show_when_tracked", "get_show_when_tracked"); + + BIND_BITFIELD_FLAG(BODY_UPDATE_UPPER_BODY); + BIND_BITFIELD_FLAG(BODY_UPDATE_LOWER_BODY); + BIND_BITFIELD_FLAG(BODY_UPDATE_HANDS); + + BIND_ENUM_CONSTANT(BONE_UPDATE_FULL); + BIND_ENUM_CONSTANT(BONE_UPDATE_ROTATION_ONLY); + BIND_ENUM_CONSTANT(BONE_UPDATE_MAX); +} + +void XRBodyModifier3D::set_body_tracker(const StringName &p_tracker_name) { + tracker_name = p_tracker_name; +} + +StringName XRBodyModifier3D::get_body_tracker() const { + return tracker_name; +} + +void XRBodyModifier3D::set_target(const NodePath &p_target) { + target = p_target; + + if (is_inside_tree()) { + _get_joint_data(); + } +} + +NodePath XRBodyModifier3D::get_target() const { + return target; +} + +void XRBodyModifier3D::set_body_update(BitField<BodyUpdate> p_body_update) { + body_update = p_body_update; +} + +BitField<XRBodyModifier3D::BodyUpdate> XRBodyModifier3D::get_body_update() const { + return body_update; +} + +void XRBodyModifier3D::set_bone_update(BoneUpdate p_bone_update) { + ERR_FAIL_INDEX(p_bone_update, BONE_UPDATE_MAX); + bone_update = p_bone_update; +} + +XRBodyModifier3D::BoneUpdate XRBodyModifier3D::get_bone_update() const { + return bone_update; +} + +void XRBodyModifier3D::set_show_when_tracked(bool p_show_when_tracked) { + show_when_tracked = p_show_when_tracked; +} + +bool XRBodyModifier3D::get_show_when_tracked() const { + return show_when_tracked; +} + +Skeleton3D *XRBodyModifier3D::get_skeleton() { + if (!has_node(target)) { + return nullptr; + } + + Node *node = get_node(target); + if (!node) { + return nullptr; + } + + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + return skeleton; +} + +void XRBodyModifier3D::_get_joint_data() { + // Table of Godot Humanoid bone names. + static const String bone_names[XRBodyTracker::JOINT_MAX] = { + "Root", // XRBodyTracker::JOINT_ROOT + + // Upper Body Joints. + "Hips", // XRBodyTracker::JOINT_HIPS + "Spine", // XRBodyTracker::JOINT_SPINE + "Chest", // XRBodyTracker::JOINT_CHEST + "UpperChest", // XRBodyTracker::JOINT_UPPER_CHEST + "Neck", // XRBodyTracker::JOINT_NECK" + "Head", // XRBodyTracker::JOINT_HEAD" + "HeadTip", // XRBodyTracker::JOINT_HEAD_TIP" + "LeftShoulder", // XRBodyTracker::JOINT_LEFT_SHOULDER" + "LeftUpperArm", // XRBodyTracker::JOINT_LEFT_UPPER_ARM" + "LeftLowerArm", // XRBodyTracker::JOINT_LEFT_LOWER_ARM" + "RightShoulder", // XRBodyTracker::JOINT_RIGHT_SHOULDER" + "RightUpperArm", // XRBodyTracker::JOINT_RIGHT_UPPER_ARM" + "RightLowerArm", // XRBodyTracker::JOINT_RIGHT_LOWER_ARM" + + // Lower Body Joints. + "LeftUpperLeg", // XRBodyTracker::JOINT_LEFT_UPPER_LEG + "LeftLowerLeg", // XRBodyTracker::JOINT_LEFT_LOWER_LEG + "LeftFoot", // XRBodyTracker::JOINT_LEFT_FOOT + "LeftToes", // XRBodyTracker::JOINT_LEFT_TOES + "RightUpperLeg", // XRBodyTracker::JOINT_RIGHT_UPPER_LEG + "RightLowerLeg", // XRBodyTracker::JOINT_RIGHT_LOWER_LEG + "RightFoot", // XRBodyTracker::JOINT_RIGHT_FOOT + "RightToes", // XRBodyTracker::JOINT_RIGHT_TOES + + // Left Hand Joints. + "LeftHand", // XRBodyTracker::JOINT_LEFT_HAND + "LeftPalm", // XRBodyTracker::JOINT_LEFT_PALM + "LeftWrist", // XRBodyTracker::JOINT_LEFT_WRIST + "LeftThumbMetacarpal", // XRBodyTracker::JOINT_LEFT_THUMB_METACARPAL + "LeftThumbProximal", // XRBodyTracker::JOINT_LEFT_THUMB_PHALANX_PROXIMAL + "LeftThumbDistal", // XRBodyTracker::JOINT_LEFT_THUMB_PHALANX_DISTAL + "LeftThumbTip", // XRBodyTracker::JOINT_LEFT_THUMB_TIP + "LeftIndexMetacarpal", // XRBodyTracker::JOINT_LEFT_INDEX_FINGER_METACARPAL + "LeftIndexProximal", // XRBodyTracker::JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL + "LeftIndexIntermediate", // XRBodyTracker::JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE + "LeftIndexDistal", // XRBodyTracker::JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL + "LeftIndexTip", // XRBodyTracker::JOINT_LEFT_INDEX_FINGER_TIP + "LeftMiddleMetacarpal", // XRBodyTracker::JOINT_LEFT_MIDDLE_FINGER_METACARPAL + "LeftMiddleProximal", // XRBodyTracker::JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL + "LeftMiddleIntermediate", // XRBodyTracker::JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE + "LeftMiddleDistal", // XRBodyTracker::JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL + "LeftMiddleTip", // XRBodyTracker::JOINT_LEFT_MIDDLE_FINGER_TIP + "LeftRingMetacarpal", // XRBodyTracker::JOINT_LEFT_RING_FINGER_METACARPAL + "LeftRingProximal", // XRBodyTracker::JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL + "LeftRingIntermediate", // XRBodyTracker::JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE + "LeftRingDistal", // XRBodyTracker::JOINT_LEFT_RING_FINGER_PHALANX_DISTAL + "LeftRingTip", // XRBodyTracker::JOINT_LEFT_RING_FINGER_TIP + "LeftLittleMetacarpal", // XRBodyTracker::JOINT_LEFT_PINKY_FINGER_METACARPAL + "LeftLittleProximal", // XRBodyTracker::JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL + "LeftLittleIntermediate", // XRBodyTracker::JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE + "LeftLittleDistal", // XRBodyTracker::JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL + "LeftLittleTip", // XRBodyTracker::JOINT_LEFT_PINKY_FINGER_TIP + + // Right Hand Joints. + "RightHand", // XRBodyTracker::JOINT_RIGHT_HAND + "RightPalm", // XRBodyTracker::JOINT_RIGHT_PALM + "RightWrist", // XRBodyTracker::JOINT_RIGHT_WRIST + "RightThumbMetacarpal", // XRBodyTracker::JOINT_RIGHT_THUMB_METACARPAL + "RightThumbProximal", // XRBodyTracker::JOINT_RIGHT_THUMB_PHALANX_PROXIMAL + "RightThumbDistal", // XRBodyTracker::JOINT_RIGHT_THUMB_PHALANX_DISTAL + "RightThumbTip", // XRBodyTracker::JOINT_RIGHT_THUMB_TIP + "RightIndexMetacarpal", // XRBodyTracker::JOINT_RIGHT_INDEX_FINGER_METACARPAL + "RightIndexProximal", // XRBodyTracker::JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL + "RightIndexIntermediate", // XRBodyTracker::JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE + "RightIndexDistal", // XRBodyTracker::JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL + "RightIndexTip", // XRBodyTracker::JOINT_RIGHT_INDEX_FINGER_TIP + "RightMiddleMetacarpal", // XRBodyTracker::JOINT_RIGHT_MIDDLE_FINGER_METACARPAL + "RightMiddleProximal", // XRBodyTracker::JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL + "RightMiddleIntermediate", // XRBodyTracker::JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE + "RightMiddleDistal", // XRBodyTracker::JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL + "RightMiddleTip", // XRBodyTracker::JOINT_RIGHT_MIDDLE_FINGER_TIP + "RightRingMetacarpal", // XRBodyTracker::JOINT_RIGHT_RING_FINGER_METACARPAL + "RightRingProximal", // XRBodyTracker::JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL + "RightRingIntermediate", // XRBodyTracker::JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE + "RightRingDistal", // XRBodyTracker::JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL + "RightRingTip", // XRBodyTracker::JOINT_RIGHT_RING_FINGER_TIP + "RightLittleMetacarpal", // XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_METACARPAL + "RightLittleProximal", // XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL + "RightLittleIntermediate", // XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE + "RightLittleDistal", // XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL + "RightLittleTip", // XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_TIP + }; + + // reset JIC. + for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { + joints[i].bone = -1; + joints[i].parent_joint = -1; + } + + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + // Find the skeleton-bones associated with each joint. + int bones[XRBodyTracker::JOINT_MAX]; + for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { + // Skip upper body joints if not enabled. + if (!body_update.has_flag(BODY_UPDATE_UPPER_BODY) && i >= XRBodyTracker::JOINT_HIPS && i <= XRBodyTracker::JOINT_RIGHT_LOWER_ARM) { + bones[i] = -1; + continue; + } + + // Skip lower body joints if not enabled. + if (!body_update.has_flag(BODY_UPDATE_LOWER_BODY) && i >= XRBodyTracker::JOINT_LEFT_UPPER_LEG && i <= XRBodyTracker::JOINT_RIGHT_TOES) { + bones[i] = -1; + continue; + } + + // Skip hand joints if not enabled. + if (!body_update.has_flag(BODY_UPDATE_HANDS) && i >= XRBodyTracker::JOINT_LEFT_HAND && i <= XRBodyTracker::JOINT_RIGHT_PINKY_FINGER_TIP) { + bones[i] = -1; + continue; + } + + // Find the skeleton bone. + bones[i] = skeleton->find_bone(bone_names[i]); + if (bones[i] == -1) { + WARN_PRINT(vformat("Couldn't obtain bone for %s", bone_names[i])); + } + } + + // If the root bone is not found then use the skeleton root bone. + if (bones[XRBodyTracker::JOINT_ROOT] == -1) { + bones[XRBodyTracker::JOINT_ROOT] = 0; + } + + // Assemble the joint relationship to the available skeleton bones. + for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { + // Get the skeleton bone (skip if not found). + const int bone = bones[i]; + if (bone == -1) { + continue; + } + + // Find the parent skeleton-bone. + const int parent_bone = skeleton->get_bone_parent(bone); + if (parent_bone == -1) { + // If no parent skeleton-bone exists then drive this relative to the root joint. + joints[i].bone = bone; + joints[i].parent_joint = XRBodyTracker::JOINT_ROOT; + continue; + } + + // Find the joint associated with the parent skeleton-bone. + for (int j = 0; j < XRBodyTracker::JOINT_MAX; ++j) { + if (bones[j] == parent_bone) { + // If a parent joint is found then drive this bone relative to it. + joints[i].bone = bone; + joints[i].parent_joint = j; + break; + } + } + } +} + +void XRBodyModifier3D::_update_skeleton() { + Skeleton3D *skeleton = get_skeleton(); + if (!skeleton) { + return; + } + + XRServer *xr_server = XRServer::get_singleton(); + if (!xr_server) { + return; + } + + Ref<XRBodyTracker> tracker = xr_server->get_body_tracker(tracker_name); + if (tracker.is_null()) { + return; + } + + // Handle no tracking data. + if (!tracker->get_has_tracking_data()) { + // If tracking-state determines visibility then hide the node. + if (show_when_tracked) { + set_visible(false); + } + return; + } + + // Read the relevant tracking data. + bool has_valid_data[XRBodyTracker::JOINT_MAX]; + Transform3D transforms[XRBodyTracker::JOINT_MAX]; + Transform3D inv_transforms[XRBodyTracker::JOINT_MAX]; + const float ws = xr_server->get_world_scale(); + for (int joint = 0; joint < XRBodyTracker::JOINT_MAX; joint++) { + BitField<XRBodyTracker::JointFlags> flags = tracker->get_joint_flags(static_cast<XRBodyTracker::Joint>(joint)); + has_valid_data[joint] = flags.has_flag(XRBodyTracker::JOINT_FLAG_ORIENTATION_VALID) && flags.has_flag(XRBodyTracker::JOINT_FLAG_POSITION_VALID); + + if (has_valid_data[joint]) { + transforms[joint] = tracker->get_joint_transform(static_cast<XRBodyTracker::Joint>(joint)); + transforms[joint].origin *= ws; + inv_transforms[joint] = transforms[joint].inverse(); + } + } + + // Handle root joint not tracked. + if (!has_valid_data[XRBodyTracker::JOINT_ROOT]) { + // If tracking-state determines visibility then hide the node. + if (show_when_tracked) { + set_visible(false); + } + return; + } + + // Apply the joint information to the skeleton. + for (int joint = 0; joint < XRBodyTracker::JOINT_MAX; joint++) { + // Skip if no valid joint data + if (!has_valid_data[joint]) { + continue; + } + + // Get the skeleton bone (skip if none). + const int bone = joints[joint].bone; + if (bone == -1) { + continue; + } + + // Calculate the relative relationship to the parent bone joint. + const int parent_joint = joints[joint].parent_joint; + const Transform3D relative_transform = inv_transforms[parent_joint] * transforms[joint]; + + // Update the bone position if enabled by update mode. + if (bone_update == BONE_UPDATE_FULL) { + skeleton->set_bone_pose_position(joints[joint].bone, relative_transform.origin); + } + + // Always update the bone rotation. + skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); + } + + // Transform to the skeleton pose. + set_transform(transforms[XRBodyTracker::JOINT_ROOT]); + + // If tracking-state determines visibility then show the node. + if (show_when_tracked) { + set_visible(true); + } +} + +void XRBodyModifier3D::_tracker_changed(const StringName &p_tracker_name, const Ref<XRBodyTracker> &p_tracker) { + if (tracker_name == p_tracker_name) { + _get_joint_data(); + } +} + +void XRBodyModifier3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + xr_server->connect("body_tracker_added", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); + xr_server->connect("body_tracker_updated", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); + xr_server->connect("body_tracker_removed", callable_mp(this, &XRBodyModifier3D::_tracker_changed).bind(Ref<XRBodyTracker>())); + } + + _get_joint_data(); + + set_process_internal(true); + } break; + case NOTIFICATION_EXIT_TREE: { + XRServer *xr_server = XRServer::get_singleton(); + if (xr_server) { + xr_server->disconnect("body_tracker_added", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); + xr_server->disconnect("body_tracker_updated", callable_mp(this, &XRBodyModifier3D::_tracker_changed)); + xr_server->disconnect("body_tracker_removed", callable_mp(this, &XRBodyModifier3D::_tracker_changed).bind(Ref<XRBodyTracker>())); + } + + set_process_internal(false); + + for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { + joints[i].bone = -1; + joints[i].parent_joint = -1; + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + _update_skeleton(); + } break; + default: { + } break; + } +} diff --git a/scene/3d/xr_body_modifier_3d.h b/scene/3d/xr_body_modifier_3d.h new file mode 100644 index 0000000000..89ac69b6b0 --- /dev/null +++ b/scene/3d/xr_body_modifier_3d.h @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* xr_body_modifier_3d.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef XR_BODY_MODIFIER_3D_H +#define XR_BODY_MODIFIER_3D_H + +#include "scene/3d/node_3d.h" +#include "servers/xr/xr_body_tracker.h" + +class Skeleton3D; + +/** + The XRBodyModifier3D node drives a body skeleton using body tracking + data from an XRBodyTracker instance. + */ + +class XRBodyModifier3D : public Node3D { + GDCLASS(XRBodyModifier3D, Node3D); + +public: + enum BodyUpdate { + BODY_UPDATE_UPPER_BODY = 1, + BODY_UPDATE_LOWER_BODY = 2, + BODY_UPDATE_HANDS = 4, + }; + + enum BoneUpdate { + BONE_UPDATE_FULL, + BONE_UPDATE_ROTATION_ONLY, + BONE_UPDATE_MAX + }; + + void set_body_tracker(const StringName &p_tracker_name); + StringName get_body_tracker() const; + + void set_target(const NodePath &p_target); + NodePath get_target() const; + + void set_body_update(BitField<BodyUpdate> p_body_update); + BitField<BodyUpdate> get_body_update() const; + + void set_bone_update(BoneUpdate p_bone_update); + BoneUpdate get_bone_update() const; + + void set_show_when_tracked(bool p_show_when_tracked); + bool get_show_when_tracked() const; + + void _notification(int p_what); + +protected: + static void _bind_methods(); + +private: + struct JointData { + int bone = -1; + int parent_joint = -1; + }; + + StringName tracker_name = "/user/body"; + NodePath target; + BitField<BodyUpdate> body_update = BODY_UPDATE_UPPER_BODY | BODY_UPDATE_LOWER_BODY | BODY_UPDATE_HANDS; + BoneUpdate bone_update = BONE_UPDATE_FULL; + bool show_when_tracked = true; + JointData joints[XRBodyTracker::JOINT_MAX]; + + Skeleton3D *get_skeleton(); + void _get_joint_data(); + void _update_skeleton(); + void _tracker_changed(const StringName &p_tracker_name, const Ref<XRBodyTracker> &p_tracker); +}; + +VARIANT_BITFIELD_CAST(XRBodyModifier3D::BodyUpdate) +VARIANT_ENUM_CAST(XRBodyModifier3D::BoneUpdate) + +#endif // XR_BODY_MODIFIER_3D_H diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 2e5fd6180c..56c582e2d7 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -54,11 +54,11 @@ Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = { }; void Tweener::set_tween(const Ref<Tween> &p_tween) { - tween = p_tween; + tween_id = p_tween->get_instance_id(); } -void Tweener::clear_tween() { - tween.unref(); +Ref<Tween> Tweener::_get_tween() { + return Ref<Tween>(ObjectDB::get_instance(tween_id)); } void Tweener::_bind_methods() { @@ -192,12 +192,6 @@ bool Tween::is_valid() { void Tween::clear() { valid = false; - - for (List<Ref<Tweener>> &step : tweeners) { - for (Ref<Tweener> &tweener : step) { - tweener->clear_tween(); - } - } tweeners.clear(); } @@ -504,6 +498,7 @@ Tween::Tween(bool p_valid) { } Ref<PropertyTweener> PropertyTweener::from(const Variant &p_value) { + Ref<Tween> tween = _get_tween(); ERR_FAIL_COND_V(tween.is_null(), nullptr); Variant from_value = p_value; @@ -592,6 +587,8 @@ bool PropertyTweener::step(double &r_delta) { do_continue_delayed = false; } + Ref<Tween> tween = _get_tween(); + double time = MIN(elapsed_time - delay, duration); if (time < duration) { if (custom_method.is_valid()) { @@ -623,12 +620,12 @@ bool PropertyTweener::step(double &r_delta) { } void PropertyTweener::set_tween(const Ref<Tween> &p_tween) { - tween = p_tween; + Tweener::set_tween(p_tween); if (trans_type == Tween::TRANS_MAX) { - trans_type = tween->get_trans(); + trans_type = p_tween->get_trans(); } if (ease_type == Tween::EASE_MAX) { - ease_type = tween->get_ease(); + ease_type = p_tween->get_ease(); } } @@ -781,6 +778,8 @@ bool MethodTweener::step(double &r_delta) { return true; } + Ref<Tween> tween = _get_tween(); + Variant current_val; double time = MIN(elapsed_time - delay, duration); if (time < duration) { @@ -810,12 +809,12 @@ bool MethodTweener::step(double &r_delta) { } void MethodTweener::set_tween(const Ref<Tween> &p_tween) { - tween = p_tween; + Tweener::set_tween(p_tween); if (trans_type == Tween::TRANS_MAX) { - trans_type = tween->get_trans(); + trans_type = p_tween->get_trans(); } if (ease_type == Tween::EASE_MAX) { - ease_type = tween->get_ease(); + ease_type = p_tween->get_ease(); } } diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 8dcc3ad7b6..f5ae5e9776 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -39,16 +39,18 @@ class Node; class Tweener : public RefCounted { GDCLASS(Tweener, RefCounted); + ObjectID tween_id; + public: virtual void set_tween(const Ref<Tween> &p_tween); virtual void start() = 0; virtual bool step(double &r_delta) = 0; - void clear_tween(); protected: static void _bind_methods(); - Ref<Tween> tween; + Ref<Tween> _get_tween(); + double elapsed_time = 0; bool finished = false; }; @@ -291,7 +293,6 @@ private: Tween::TransitionType trans_type = Tween::TRANS_MAX; Tween::EaseType ease_type = Tween::EASE_MAX; - Ref<Tween> tween; Variant initial_val; Variant delta_val; Variant final_val; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 73cbfceea4..b8af4c3f79 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1824,14 +1824,14 @@ void CodeEdit::create_code_region() { } int to_line = get_selection_to_line(caret_idx); set_line(to_line, get_line(to_line) + "\n" + code_region_end_string); - insert_line_at(from_line, code_region_start_string + " " + RTR("New Code Region")); + insert_line_at(from_line, code_region_start_string + " " + atr(ETR("New Code Region"))); fold_line(from_line); } // Select name of the first region to allow quick edit. remove_secondary_carets(); set_caret_line(first_region_start); - int tag_length = code_region_start_string.length() + RTR("New Code Region").length() + 1; + int tag_length = code_region_start_string.length() + atr(ETR("New Code Region")).length() + 1; set_caret_column(tag_length); select(first_region_start, code_region_start_string.length() + 1, first_region_start, tag_length); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index cdb091cb32..ee2122f269 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -54,6 +54,22 @@ void ColorPicker::_notification(int p_what) { _update_color(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { + List<BaseButton *> buttons; + preset_group->get_buttons(&buttons); + for (List<BaseButton *>::Element *E = buttons.front(); E; E = E->next()) { + Color preset_color = ((ColorPresetButton *)E->get())->get_preset_color(); + E->get()->set_tooltip_text(vformat(atr(ETR("Color: #%s\nLMB: Apply color\nRMB: Remove preset")), preset_color.to_html(preset_color.a < 1))); + } + + buttons.clear(); + recent_preset_group->get_buttons(&buttons); + for (List<BaseButton *>::Element *E = buttons.front(); E; E = E->next()) { + Color preset_color = ((ColorPresetButton *)E->get())->get_preset_color(); + E->get()->set_tooltip_text(vformat(atr(ETR("Color: #%s\nLMB: Apply color")), preset_color.to_html(preset_color.a < 1))); + } + } break; + case NOTIFICATION_THEME_CHANGED: { btn_pick->set_icon(theme_cache.screen_picker); _update_drop_down_arrow(btn_preset->is_pressed(), btn_preset); @@ -689,7 +705,7 @@ void ColorPicker::_text_type_toggled() { text_type->set_icon(nullptr); c_text->set_editable(true); - c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\").")); + c_text->set_tooltip_text(ETR("Enter a hex code (\"#ff0000\") or named color (\"red\").")); } _update_color(); } @@ -735,7 +751,7 @@ inline int ColorPicker::_get_preset_size() { void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size)); - btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1))); + btn_preset_new->set_tooltip_text(vformat(atr(ETR("Color: #%s\nLMB: Apply color\nRMB: Remove preset")), p_color.to_html(p_color.a < 1))); SET_DRAG_FORWARDING_GCDU(btn_preset_new, ColorPicker); btn_preset_new->set_button_group(preset_group); preset_container->add_child(btn_preset_new); @@ -745,7 +761,7 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) { void ColorPicker::_add_recent_preset_button(int p_size, const Color &p_color) { ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size)); - btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color"), p_color.to_html(p_color.a < 1))); + btn_preset_new->set_tooltip_text(vformat(atr(ETR("Color: #%s\nLMB: Apply color")), p_color.to_html(p_color.a < 1))); btn_preset_new->set_button_group(recent_preset_group); recent_preset_hbc->add_child(btn_preset_new); recent_preset_hbc->move_child(btn_preset_new, 0); @@ -1807,11 +1823,11 @@ ColorPicker::ColorPicker() { btn_pick = memnew(Button); sample_hbc->add_child(btn_pick); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SCREEN_CAPTURE)) { - btn_pick->set_tooltip_text(RTR("Pick a color from the screen.")); + btn_pick->set_tooltip_text(ETR("Pick a color from the screen.")); btn_pick->connect(SNAME("pressed"), callable_mp(this, &ColorPicker::_pick_button_pressed)); } else { // On unsupported platforms, use a legacy method for color picking. - btn_pick->set_tooltip_text(RTR("Pick a color from the application window.")); + btn_pick->set_tooltip_text(ETR("Pick a color from the application window.")); btn_pick->connect(SNAME("pressed"), callable_mp(this, &ColorPicker::_pick_button_pressed_legacy)); } @@ -1825,7 +1841,7 @@ ColorPicker::ColorPicker() { btn_shape->set_flat(false); sample_hbc->add_child(btn_shape); btn_shape->set_toggle_mode(true); - btn_shape->set_tooltip_text(RTR("Select a picker shape.")); + btn_shape->set_tooltip_text(ETR("Select a picker shape.")); current_shape = SHAPE_HSV_RECTANGLE; @@ -1864,7 +1880,7 @@ ColorPicker::ColorPicker() { btn_mode->set_flat(false); mode_hbc->add_child(btn_mode); btn_mode->set_toggle_mode(true); - btn_mode->set_tooltip_text(RTR("Select a picker mode.")); + btn_mode->set_tooltip_text(ETR("Select a picker mode.")); current_mode = MODE_RGB; @@ -1918,8 +1934,8 @@ ColorPicker::ColorPicker() { hex_hbc->add_child(c_text); c_text->set_h_size_flags(SIZE_EXPAND_FILL); c_text->set_select_all_on_focus(true); - c_text->set_tooltip_text(RTR("Enter a hex code (\"#ff0000\") or named color (\"red\").")); - c_text->set_placeholder(RTR("Hex code or named color")); + c_text->set_tooltip_text(ETR("Enter a hex code (\"#ff0000\") or named color (\"red\").")); + c_text->set_placeholder(ETR("Hex code or named color")); c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed)); c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit)); @@ -1997,7 +2013,7 @@ ColorPicker::ColorPicker() { btn_add_preset = memnew(Button); btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER); - btn_add_preset->set_tooltip_text(RTR("Add current color as a preset.")); + btn_add_preset->set_tooltip_text(ETR("Add current color as a preset.")); btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed)); preset_container->add_child(btn_add_preset); } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 8f58c1e6f5..abed3cf594 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -187,6 +187,7 @@ void FileDialog::_notification(int p_what) { } refresh->set_icon(theme_cache.reload); show_hidden->set_icon(theme_cache.toggle_hidden); + makedir->set_icon(theme_cache.create_folder); dir_up->begin_bulk_theme_override(); dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); @@ -223,6 +224,13 @@ void FileDialog::_notification(int p_what) { show_hidden->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color); show_hidden->end_bulk_theme_override(); + makedir->begin_bulk_theme_override(); + makedir->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + makedir->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); + makedir->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + makedir->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color); + makedir->end_bulk_theme_override(); + invalidate(); } break; @@ -294,7 +302,7 @@ void FileDialog::update_dir() { if (drives->is_visible()) { if (dir_access->get_current_dir().is_network_share_path()) { _update_drives(false); - drives->add_item(RTR("Network")); + drives->add_item(ETR("Network")); drives->set_item_disabled(-1, true); drives->select(drives->get_item_count() - 1); } else { @@ -451,7 +459,7 @@ void FileDialog::_action_pressed() { } if (dir_access->file_exists(f)) { - confirm_save->set_text(vformat(RTR("File \"%s\" already exists.\nDo you want to overwrite it?"), f)); + confirm_save->set_text(vformat(atr(ETR("File \"%s\" already exists.\nDo you want to overwrite it?")), f)); confirm_save->popup_centered(Size2(250, 80)); } else { emit_signal(SNAME("file_selected"), f); @@ -531,10 +539,10 @@ void FileDialog::deselect_all() { switch (mode) { case FILE_MODE_OPEN_FILE: case FILE_MODE_OPEN_FILES: - set_ok_button_text(RTR("Open")); + set_ok_button_text(ETR("Open")); break; case FILE_MODE_OPEN_DIR: - set_ok_button_text(RTR("Select Current Folder")); + set_ok_button_text(ETR("Select Current Folder")); break; case FILE_MODE_OPEN_ANY: case FILE_MODE_SAVE_FILE: @@ -558,7 +566,7 @@ void FileDialog::_tree_selected() { if (!d["dir"]) { file->set_text(d["name"]); } else if (mode == FILE_MODE_OPEN_DIR) { - set_ok_button_text(RTR("Select This Folder")); + set_ok_button_text(ETR("Select This Folder")); } get_ok_button()->set_disabled(_is_open_should_be_disabled()); @@ -613,7 +621,7 @@ void FileDialog::update_file_list() { if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) { message->hide(); } else { - message->set_text(RTR("You don't have permission to access contents of this folder.")); + message->set_text(ETR("You don't have permission to access contents of this folder.")); message->show(); } @@ -763,7 +771,7 @@ void FileDialog::update_filters() { all_filters += ", ..."; } - filter->add_item(RTR("All Recognized") + " (" + all_filters + ")"); + filter->add_item(atr(ETR("All Recognized")) + " (" + all_filters + ")"); } for (int i = 0; i < filters.size(); i++) { String flt = filters[i].get_slice(";", 0).strip_edges(); @@ -775,7 +783,7 @@ void FileDialog::update_filters() { } } - filter->add_item(RTR("All Files") + " (*)"); + filter->add_item(atr(ETR("All Files")) + " (*)"); } void FileDialog::clear_filters() { @@ -888,37 +896,37 @@ void FileDialog::set_file_mode(FileMode p_mode) { mode = p_mode; switch (mode) { case FILE_MODE_OPEN_FILE: - set_ok_button_text(RTR("Open")); + set_ok_button_text(ETR("Open")); if (mode_overrides_title) { - set_title(TTRC("Open a File")); + set_title(ETR("Open a File")); } makedir->hide(); break; case FILE_MODE_OPEN_FILES: - set_ok_button_text(RTR("Open")); + set_ok_button_text(ETR("Open")); if (mode_overrides_title) { - set_title(TTRC("Open File(s)")); + set_title(ETR("Open File(s)")); } makedir->hide(); break; case FILE_MODE_OPEN_DIR: - set_ok_button_text(RTR("Select Current Folder")); + set_ok_button_text(ETR("Select Current Folder")); if (mode_overrides_title) { - set_title(TTRC("Open a Directory")); + set_title(ETR("Open a Directory")); } makedir->show(); break; case FILE_MODE_OPEN_ANY: - set_ok_button_text(RTR("Open")); + set_ok_button_text(ETR("Open")); if (mode_overrides_title) { - set_title(TTRC("Open a File or Directory")); + set_title(ETR("Open a File or Directory")); } makedir->show(); break; case FILE_MODE_SAVE_FILE: - set_ok_button_text(RTR("Save")); + set_ok_button_text(ETR("Save")); if (mode_overrides_title) { - set_title(TTRC("Save a File")); + set_title(ETR("Save a File")); } makedir->show(); break; @@ -1331,6 +1339,7 @@ void FileDialog::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, toggle_hidden); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, folder); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, file); + BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, create_folder); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, folder_icon_color); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, file_icon_color); @@ -1380,13 +1389,13 @@ FileDialog::FileDialog() { dir_prev = memnew(Button); dir_prev->set_theme_type_variation("FlatButton"); - dir_prev->set_tooltip_text(RTR("Go to previous folder.")); + dir_prev->set_tooltip_text(ETR("Go to previous folder.")); dir_next = memnew(Button); dir_next->set_theme_type_variation("FlatButton"); - dir_next->set_tooltip_text(RTR("Go to next folder.")); + dir_next->set_tooltip_text(ETR("Go to next folder.")); dir_up = memnew(Button); dir_up->set_theme_type_variation("FlatButton"); - dir_up->set_tooltip_text(RTR("Go to parent folder.")); + dir_up->set_tooltip_text(ETR("Go to parent folder.")); hbc->add_child(dir_prev); hbc->add_child(dir_next); hbc->add_child(dir_up); @@ -1394,7 +1403,7 @@ FileDialog::FileDialog() { dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward)); dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up)); - hbc->add_child(memnew(Label(RTR("Path:")))); + hbc->add_child(memnew(Label(ETR("Path:")))); drives_container = memnew(HBoxContainer); hbc->add_child(drives_container); @@ -1410,7 +1419,7 @@ FileDialog::FileDialog() { refresh = memnew(Button); refresh->set_theme_type_variation("FlatButton"); - refresh->set_tooltip_text(RTR("Refresh files.")); + refresh->set_tooltip_text(ETR("Refresh files.")); refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list)); hbc->add_child(refresh); @@ -1418,7 +1427,7 @@ FileDialog::FileDialog() { show_hidden->set_theme_type_variation("FlatButton"); show_hidden->set_toggle_mode(true); show_hidden->set_pressed(is_showing_hidden_files()); - show_hidden->set_tooltip_text(RTR("Toggle the visibility of hidden files.")); + show_hidden->set_tooltip_text(ETR("Toggle the visibility of hidden files.")); show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files)); hbc->add_child(show_hidden); @@ -1426,14 +1435,15 @@ FileDialog::FileDialog() { hbc->add_child(shortcuts_container); makedir = memnew(Button); - makedir->set_text(RTR("Create Folder")); + makedir->set_theme_type_variation("FlatButton"); + makedir->set_tooltip_text(ETR("Create a new folder.")); makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir)); hbc->add_child(makedir); vbox->add_child(hbc); tree = memnew(Tree); tree->set_hide_root(true); - vbox->add_margin_child(RTR("Directories & Files:"), tree, true); + vbox->add_margin_child(ETR("Directories & Files:"), tree, true); message = memnew(Label); message->hide(); @@ -1443,7 +1453,7 @@ FileDialog::FileDialog() { tree->add_child(message); file_box = memnew(HBoxContainer); - file_box->add_child(memnew(Label(RTR("File:")))); + file_box->add_child(memnew(Label(ETR("File:")))); file = memnew(LineEdit); file->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); file->set_stretch_ratio(4); @@ -1479,22 +1489,22 @@ FileDialog::FileDialog() { confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); makedialog = memnew(ConfirmationDialog); - makedialog->set_title(RTR("Create Folder")); + makedialog->set_title(ETR("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); makedialog->add_child(makevb); makedirname = memnew(LineEdit); makedirname->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); - makevb->add_margin_child(RTR("Name:"), makedirname); + makevb->add_margin_child(ETR("Name:"), makedirname); add_child(makedialog, false, INTERNAL_MODE_FRONT); makedialog->register_text_enter(makedirname); makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm)); mkdirerr = memnew(AcceptDialog); - mkdirerr->set_text(RTR("Could not create folder.")); + mkdirerr->set_text(ETR("Could not create folder.")); add_child(mkdirerr, false, INTERNAL_MODE_FRONT); exterr = memnew(AcceptDialog); - exterr->set_text(RTR("Invalid extension, or empty filename.")); + exterr->set_text(ETR("Invalid extension, or empty filename.")); add_child(exterr, false, INTERNAL_MODE_FRONT); update_filters(); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 7356e1c9e3..1b53c7e05e 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -120,6 +120,7 @@ private: Ref<Texture2D> toggle_hidden; Ref<Texture2D> folder; Ref<Texture2D> file; + Ref<Texture2D> create_folder; Color folder_icon_color; Color file_icon_color; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index b7118d595f..056872a4fe 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -2435,7 +2435,7 @@ GraphEdit::GraphEdit() { zoom_minus_button = memnew(Button); zoom_minus_button->set_theme_type_variation("FlatButton"); zoom_minus_button->set_visible(show_zoom_buttons); - zoom_minus_button->set_tooltip_text(RTR("Zoom Out")); + zoom_minus_button->set_tooltip_text(ETR("Zoom Out")); zoom_minus_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_minus_button); zoom_minus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus)); @@ -2443,7 +2443,7 @@ GraphEdit::GraphEdit() { zoom_reset_button = memnew(Button); zoom_reset_button->set_theme_type_variation("FlatButton"); zoom_reset_button->set_visible(show_zoom_buttons); - zoom_reset_button->set_tooltip_text(RTR("Zoom Reset")); + zoom_reset_button->set_tooltip_text(ETR("Zoom Reset")); zoom_reset_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_reset_button); zoom_reset_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset)); @@ -2451,7 +2451,7 @@ GraphEdit::GraphEdit() { zoom_plus_button = memnew(Button); zoom_plus_button->set_theme_type_variation("FlatButton"); zoom_plus_button->set_visible(show_zoom_buttons); - zoom_plus_button->set_tooltip_text(RTR("Zoom In")); + zoom_plus_button->set_tooltip_text(ETR("Zoom In")); zoom_plus_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(zoom_plus_button); zoom_plus_button->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus)); @@ -2463,7 +2463,7 @@ GraphEdit::GraphEdit() { toggle_grid_button->set_visible(show_grid_buttons); toggle_grid_button->set_toggle_mode(true); toggle_grid_button->set_pressed(true); - toggle_grid_button->set_tooltip_text(RTR("Toggle the visual grid.")); + toggle_grid_button->set_tooltip_text(ETR("Toggle the visual grid.")); toggle_grid_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(toggle_grid_button); toggle_grid_button->connect("pressed", callable_mp(this, &GraphEdit::_show_grid_toggled)); @@ -2472,7 +2472,7 @@ GraphEdit::GraphEdit() { toggle_snapping_button->set_theme_type_variation("FlatButton"); toggle_snapping_button->set_visible(show_grid_buttons); toggle_snapping_button->set_toggle_mode(true); - toggle_snapping_button->set_tooltip_text(RTR("Toggle snapping to the grid.")); + toggle_snapping_button->set_tooltip_text(ETR("Toggle snapping to the grid.")); toggle_snapping_button->set_pressed(snapping_enabled); toggle_snapping_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(toggle_snapping_button); @@ -2484,7 +2484,7 @@ GraphEdit::GraphEdit() { snapping_distance_spinbox->set_max(GRID_MAX_SNAPPING_DISTANCE); snapping_distance_spinbox->set_step(1); snapping_distance_spinbox->set_value(snapping_distance); - snapping_distance_spinbox->set_tooltip_text(RTR("Change the snapping distance.")); + snapping_distance_spinbox->set_tooltip_text(ETR("Change the snapping distance.")); menu_hbox->add_child(snapping_distance_spinbox); snapping_distance_spinbox->connect("value_changed", callable_mp(this, &GraphEdit::_snapping_distance_changed)); @@ -2494,7 +2494,7 @@ GraphEdit::GraphEdit() { minimap_button->set_theme_type_variation("FlatButton"); minimap_button->set_visible(show_minimap_button); minimap_button->set_toggle_mode(true); - minimap_button->set_tooltip_text(RTR("Toggle the graph minimap.")); + minimap_button->set_tooltip_text(ETR("Toggle the graph minimap.")); minimap_button->set_pressed(show_grid); minimap_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(minimap_button); @@ -2506,7 +2506,7 @@ GraphEdit::GraphEdit() { arrange_button->connect("pressed", callable_mp(this, &GraphEdit::arrange_nodes)); arrange_button->set_focus_mode(FOCUS_NONE); menu_hbox->add_child(arrange_button); - arrange_button->set_tooltip_text(RTR("Automatically arrange selected nodes.")); + arrange_button->set_tooltip_text(ETR("Automatically arrange selected nodes.")); // Minimap. diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 162c9cf801..8376ef48b6 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1150,10 +1150,6 @@ void ItemList::_notification(int p_what) { if (should_draw_selected_bg || should_draw_hovered_bg || should_draw_custom_bg) { Rect2 r = rcache; r.position += base_ofs; - r.position.y -= theme_cache.v_separation / 2; - r.size.y += theme_cache.v_separation; - r.position.x -= theme_cache.h_separation / 2; - r.size.x += theme_cache.h_separation; if (rtl) { r.position.x = size.width - r.position.x - r.size.x; @@ -1186,6 +1182,12 @@ void ItemList::_notification(int p_what) { Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs; if (icon_mode == ICON_MODE_TOP) { + pos.y += theme_cache.v_separation / 2; + } else { + pos.x += theme_cache.h_separation / 2; + } + + if (icon_mode == ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2); pos.y += theme_cache.icon_margin; text_ofs.y = icon_size.height + theme_cache.icon_margin * 2; @@ -1224,6 +1226,8 @@ void ItemList::_notification(int p_what) { if (items[i].tag_icon.is_valid()) { Point2 draw_pos = items[i].rect_cache.position; + draw_pos.x += theme_cache.h_separation / 2; + draw_pos.y += theme_cache.v_separation / 2; if (rtl) { draw_pos.x = size.width - draw_pos.x - items[i].tag_icon->get_width(); } @@ -1261,12 +1265,18 @@ void ItemList::_notification(int p_what) { text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; + text_ofs.x += theme_cache.h_separation / 2; + text_ofs.y += theme_cache.v_separation / 2; + if (rtl) { text_ofs.x = size.width - text_ofs.x - max_len; } items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER); + float text_w = items[i].rect_cache.size.width - theme_cache.h_separation; + items.write[i].text_buf->set_width(text_w); + if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color); } @@ -1279,14 +1289,17 @@ void ItemList::_notification(int p_what) { if (icon_mode == ICON_MODE_TOP) { text_ofs.x += (items[i].rect_cache.size.width - size2.x) / 2; + text_ofs.x += theme_cache.h_separation / 2; + text_ofs.y += theme_cache.v_separation / 2; } else { text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; + text_ofs.x += theme_cache.h_separation / 2; } text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; - float text_w = width - text_ofs.x; + float text_w = width - text_ofs.x - theme_cache.h_separation; items.write[i].text_buf->set_width(text_w); if (rtl) { @@ -1309,10 +1322,6 @@ void ItemList::_notification(int p_what) { if (select_mode == SELECT_MULTI && i == current) { Rect2 r = rcache; r.position += base_ofs; - r.position.y -= theme_cache.v_separation / 2; - r.size.y += theme_cache.v_separation; - r.position.x -= theme_cache.h_separation / 2; - r.size.x += theme_cache.h_separation; if (rtl) { r.position.x = size.width - r.position.x - r.size.x; @@ -1382,9 +1391,10 @@ void ItemList::force_update_list_size() { } max_column_width = MAX(max_column_width, minsize.x); - // elements need to adapt to the selected size + // Elements need to adapt to the selected size. minsize.y += theme_cache.v_separation; minsize.x += theme_cache.h_separation; + items.write[i].rect_cache.size = minsize; items.write[i].min_rect_cache.size = minsize; } @@ -1415,18 +1425,18 @@ void ItemList::force_update_list_size() { } if (same_column_width) { - items.write[i].rect_cache.size.x = max_column_width; + items.write[i].rect_cache.size.x = max_column_width + theme_cache.h_separation; } items.write[i].rect_cache.position = ofs; max_h = MAX(max_h, items[i].rect_cache.size.y); - ofs.x += items[i].rect_cache.size.x + theme_cache.h_separation; + ofs.x += items[i].rect_cache.size.x; items.write[i].column = col; col++; if (col == current_columns) { if (i < items.size() - 1) { - separators.push_back(ofs.y + max_h + theme_cache.v_separation / 2); + separators.push_back(ofs.y + max_h); } for (int j = i; j >= 0 && col > 0; j--, col--) { @@ -1434,7 +1444,7 @@ void ItemList::force_update_list_size() { } ofs.x = 0; - ofs.y += max_h + theme_cache.v_separation; + ofs.y += max_h; col = 0; max_h = 0; } @@ -1496,12 +1506,6 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { for (int i = 0; i < items.size(); i++) { Rect2 rc = items[i].rect_cache; - // Grow the detection rectangle to match the grown selection indicator. - rc.position.y -= theme_cache.v_separation / 2; - rc.size.y += theme_cache.v_separation; - rc.position.x -= theme_cache.h_separation / 2; - rc.size.x += theme_cache.h_separation; - if (i % current_columns == current_columns - 1) { rc.size.width = get_size().width - rc.position.x; // Make sure you can still select the last item when clicking past the column. } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 75474c060e..aa6d52cc36 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2406,45 +2406,45 @@ void LineEdit::_generate_context_menu() { add_child(menu, false, INTERNAL_MODE_FRONT); menu_dir = memnew(PopupMenu); - menu_dir->add_radio_check_item(RTR("Same as Layout Direction"), MENU_DIR_INHERITED); - menu_dir->add_radio_check_item(RTR("Auto-Detect Direction"), MENU_DIR_AUTO); - menu_dir->add_radio_check_item(RTR("Left-to-Right"), MENU_DIR_LTR); - menu_dir->add_radio_check_item(RTR("Right-to-Left"), MENU_DIR_RTL); + menu_dir->add_radio_check_item(ETR("Same as Layout Direction"), MENU_DIR_INHERITED); + menu_dir->add_radio_check_item(ETR("Auto-Detect Direction"), MENU_DIR_AUTO); + menu_dir->add_radio_check_item(ETR("Left-to-Right"), MENU_DIR_LTR); + menu_dir->add_radio_check_item(ETR("Right-to-Left"), MENU_DIR_RTL); menu_ctl = memnew(PopupMenu); - menu_ctl->add_item(RTR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM); - menu_ctl->add_item(RTR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM); - menu_ctl->add_item(RTR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE); - menu_ctl->add_item(RTR("Start of Right-to-Left Embedding (RLE)"), MENU_INSERT_RLE); - menu_ctl->add_item(RTR("Start of Left-to-Right Override (LRO)"), MENU_INSERT_LRO); - menu_ctl->add_item(RTR("Start of Right-to-Left Override (RLO)"), MENU_INSERT_RLO); - menu_ctl->add_item(RTR("Pop Direction Formatting (PDF)"), MENU_INSERT_PDF); + menu_ctl->add_item(ETR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM); + menu_ctl->add_item(ETR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM); + menu_ctl->add_item(ETR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE); + menu_ctl->add_item(ETR("Start of Right-to-Left Embedding (RLE)"), MENU_INSERT_RLE); + menu_ctl->add_item(ETR("Start of Left-to-Right Override (LRO)"), MENU_INSERT_LRO); + menu_ctl->add_item(ETR("Start of Right-to-Left Override (RLO)"), MENU_INSERT_RLO); + menu_ctl->add_item(ETR("Pop Direction Formatting (PDF)"), MENU_INSERT_PDF); menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Arabic Letter Mark (ALM)"), MENU_INSERT_ALM); - menu_ctl->add_item(RTR("Left-to-Right Isolate (LRI)"), MENU_INSERT_LRI); - menu_ctl->add_item(RTR("Right-to-Left Isolate (RLI)"), MENU_INSERT_RLI); - menu_ctl->add_item(RTR("First Strong Isolate (FSI)"), MENU_INSERT_FSI); - menu_ctl->add_item(RTR("Pop Direction Isolate (PDI)"), MENU_INSERT_PDI); + menu_ctl->add_item(ETR("Arabic Letter Mark (ALM)"), MENU_INSERT_ALM); + menu_ctl->add_item(ETR("Left-to-Right Isolate (LRI)"), MENU_INSERT_LRI); + menu_ctl->add_item(ETR("Right-to-Left Isolate (RLI)"), MENU_INSERT_RLI); + menu_ctl->add_item(ETR("First Strong Isolate (FSI)"), MENU_INSERT_FSI); + menu_ctl->add_item(ETR("Pop Direction Isolate (PDI)"), MENU_INSERT_PDI); menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Zero-Width Joiner (ZWJ)"), MENU_INSERT_ZWJ); - menu_ctl->add_item(RTR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ); - menu_ctl->add_item(RTR("Word Joiner (WJ)"), MENU_INSERT_WJ); - menu_ctl->add_item(RTR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); - - menu->add_item(RTR("Cut"), MENU_CUT); - menu->add_item(RTR("Copy"), MENU_COPY); - menu->add_item(RTR("Paste"), MENU_PASTE); + menu_ctl->add_item(ETR("Zero-Width Joiner (ZWJ)"), MENU_INSERT_ZWJ); + menu_ctl->add_item(ETR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ); + menu_ctl->add_item(ETR("Word Joiner (WJ)"), MENU_INSERT_WJ); + menu_ctl->add_item(ETR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); + + menu->add_item(ETR("Cut"), MENU_CUT); + menu->add_item(ETR("Copy"), MENU_COPY); + menu->add_item(ETR("Paste"), MENU_PASTE); menu->add_separator(); - menu->add_item(RTR("Select All"), MENU_SELECT_ALL); - menu->add_item(RTR("Clear"), MENU_CLEAR); + menu->add_item(ETR("Select All"), MENU_SELECT_ALL); + menu->add_item(ETR("Clear"), MENU_CLEAR); menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO); - menu->add_item(RTR("Redo"), MENU_REDO); + menu->add_item(ETR("Undo"), MENU_UNDO); + menu->add_item(ETR("Redo"), MENU_REDO); menu->add_separator(); - menu->add_submenu_node_item(RTR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR); + menu->add_submenu_node_item(ETR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR); menu->add_separator(); - menu->add_check_item(RTR("Display Control Characters"), MENU_DISPLAY_UCC); - menu->add_submenu_node_item(RTR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); + menu->add_check_item(ETR("Display Control Characters"), MENU_DISPLAY_UCC); + menu->add_submenu_node_item(ETR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); menu->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); menu_dir->connect("id_pressed", callable_mp(this, &LineEdit::menu_option)); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 4f25fed335..1b88caef15 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -6270,8 +6270,8 @@ void RichTextLabel::_generate_context_menu() { add_child(menu, false, INTERNAL_MODE_FRONT); menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option)); - menu->add_item(RTR("Copy"), MENU_COPY); - menu->add_item(RTR("Select All"), MENU_SELECT_ALL); + menu->add_item(ETR("Copy"), MENU_COPY); + menu->add_item(ETR("Select All"), MENU_SELECT_ALL); } void RichTextLabel::_update_context_menu() { diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index d482495ca0..70acaf7adf 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -83,6 +83,7 @@ void SpinBox::_text_submitted(const String &p_string) { err = expr->parse(text); if (err != OK) { + _update_text(); return; } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 79a5f2b557..c2716c9ef6 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -6873,45 +6873,45 @@ void TextEdit::_generate_context_menu() { add_child(menu, false, INTERNAL_MODE_FRONT); menu_dir = memnew(PopupMenu); - menu_dir->add_radio_check_item(RTR("Same as Layout Direction"), MENU_DIR_INHERITED); - menu_dir->add_radio_check_item(RTR("Auto-Detect Direction"), MENU_DIR_AUTO); - menu_dir->add_radio_check_item(RTR("Left-to-Right"), MENU_DIR_LTR); - menu_dir->add_radio_check_item(RTR("Right-to-Left"), MENU_DIR_RTL); + menu_dir->add_radio_check_item(ETR("Same as Layout Direction"), MENU_DIR_INHERITED); + menu_dir->add_radio_check_item(ETR("Auto-Detect Direction"), MENU_DIR_AUTO); + menu_dir->add_radio_check_item(ETR("Left-to-Right"), MENU_DIR_LTR); + menu_dir->add_radio_check_item(ETR("Right-to-Left"), MENU_DIR_RTL); menu_ctl = memnew(PopupMenu); - menu_ctl->add_item(RTR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM); - menu_ctl->add_item(RTR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM); - menu_ctl->add_item(RTR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE); - menu_ctl->add_item(RTR("Start of Right-to-Left Embedding (RLE)"), MENU_INSERT_RLE); - menu_ctl->add_item(RTR("Start of Left-to-Right Override (LRO)"), MENU_INSERT_LRO); - menu_ctl->add_item(RTR("Start of Right-to-Left Override (RLO)"), MENU_INSERT_RLO); - menu_ctl->add_item(RTR("Pop Direction Formatting (PDF)"), MENU_INSERT_PDF); + menu_ctl->add_item(ETR("Left-to-Right Mark (LRM)"), MENU_INSERT_LRM); + menu_ctl->add_item(ETR("Right-to-Left Mark (RLM)"), MENU_INSERT_RLM); + menu_ctl->add_item(ETR("Start of Left-to-Right Embedding (LRE)"), MENU_INSERT_LRE); + menu_ctl->add_item(ETR("Start of Right-to-Left Embedding (RLE)"), MENU_INSERT_RLE); + menu_ctl->add_item(ETR("Start of Left-to-Right Override (LRO)"), MENU_INSERT_LRO); + menu_ctl->add_item(ETR("Start of Right-to-Left Override (RLO)"), MENU_INSERT_RLO); + menu_ctl->add_item(ETR("Pop Direction Formatting (PDF)"), MENU_INSERT_PDF); menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Arabic Letter Mark (ALM)"), MENU_INSERT_ALM); - menu_ctl->add_item(RTR("Left-to-Right Isolate (LRI)"), MENU_INSERT_LRI); - menu_ctl->add_item(RTR("Right-to-Left Isolate (RLI)"), MENU_INSERT_RLI); - menu_ctl->add_item(RTR("First Strong Isolate (FSI)"), MENU_INSERT_FSI); - menu_ctl->add_item(RTR("Pop Direction Isolate (PDI)"), MENU_INSERT_PDI); + menu_ctl->add_item(ETR("Arabic Letter Mark (ALM)"), MENU_INSERT_ALM); + menu_ctl->add_item(ETR("Left-to-Right Isolate (LRI)"), MENU_INSERT_LRI); + menu_ctl->add_item(ETR("Right-to-Left Isolate (RLI)"), MENU_INSERT_RLI); + menu_ctl->add_item(ETR("First Strong Isolate (FSI)"), MENU_INSERT_FSI); + menu_ctl->add_item(ETR("Pop Direction Isolate (PDI)"), MENU_INSERT_PDI); menu_ctl->add_separator(); - menu_ctl->add_item(RTR("Zero-Width Joiner (ZWJ)"), MENU_INSERT_ZWJ); - menu_ctl->add_item(RTR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ); - menu_ctl->add_item(RTR("Word Joiner (WJ)"), MENU_INSERT_WJ); - menu_ctl->add_item(RTR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); - - menu->add_item(RTR("Cut"), MENU_CUT); - menu->add_item(RTR("Copy"), MENU_COPY); - menu->add_item(RTR("Paste"), MENU_PASTE); + menu_ctl->add_item(ETR("Zero-Width Joiner (ZWJ)"), MENU_INSERT_ZWJ); + menu_ctl->add_item(ETR("Zero-Width Non-Joiner (ZWNJ)"), MENU_INSERT_ZWNJ); + menu_ctl->add_item(ETR("Word Joiner (WJ)"), MENU_INSERT_WJ); + menu_ctl->add_item(ETR("Soft Hyphen (SHY)"), MENU_INSERT_SHY); + + menu->add_item(ETR("Cut"), MENU_CUT); + menu->add_item(ETR("Copy"), MENU_COPY); + menu->add_item(ETR("Paste"), MENU_PASTE); menu->add_separator(); - menu->add_item(RTR("Select All"), MENU_SELECT_ALL); - menu->add_item(RTR("Clear"), MENU_CLEAR); + menu->add_item(ETR("Select All"), MENU_SELECT_ALL); + menu->add_item(ETR("Clear"), MENU_CLEAR); menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO); - menu->add_item(RTR("Redo"), MENU_REDO); + menu->add_item(ETR("Undo"), MENU_UNDO); + menu->add_item(ETR("Redo"), MENU_REDO); menu->add_separator(); - menu->add_submenu_node_item(RTR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR); + menu->add_submenu_node_item(ETR("Text Writing Direction"), menu_dir, MENU_SUBMENU_TEXT_DIR); menu->add_separator(); - menu->add_check_item(RTR("Display Control Characters"), MENU_DISPLAY_UCC); - menu->add_submenu_node_item(RTR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); + menu->add_check_item(ETR("Display Control Characters"), MENU_DISPLAY_UCC); + menu->add_submenu_node_item(ETR("Insert Control Character"), menu_ctl, MENU_SUBMENU_INSERT_UCC); menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index bf456cd048..0c841dabbe 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -120,6 +120,10 @@ void TreeItem::_change_tree(Tree *p_tree) { } if (tree->selected_item == this) { + for (int i = 0; i < tree->selected_item->cells.size(); i++) { + tree->selected_item->cells.write[i].selected = false; + } + tree->selected_item = nullptr; } @@ -1945,7 +1949,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) { int option = (int)p_item->cells[p_col].val; - valtext = RTR("(Other)"); + valtext = atr(ETR("(Other)")); Vector<String> strings = p_item->cells[p_col].text.split(","); for (int j = 0; j < strings.size(); j++) { int value = j; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 67f8a97212..9fe4fc88b9 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2958,17 +2958,24 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { remove_child(child); if (!child->is_owned_by_parent()) { // add the custom children to the p_node + Node *child_owner = child->get_owner() == this ? p_node : child->get_owner(); + child->set_owner(nullptr); p_node->add_child(child); + child->set_owner(child_owner); } } p_node->set_owner(owner); for (Node *E : owned) { - E->set_owner(p_node); + if (E->data.owner != p_node) { + E->set_owner(p_node); + } } for (Node *E : owned_by_owner) { - E->set_owner(owner); + if (E->data.owner != owner) { + E->set_owner(owner); + } } p_node->set_scene_file_path(get_scene_file_path()); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 0bb2688fea..f596114d99 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -37,11 +37,11 @@ #include "core/templates/sort_array.h" #include "scene/2d/audio_listener_2d.h" #include "scene/2d/camera_2d.h" -#include "scene/2d/collision_object_2d.h" +#include "scene/2d/physics/collision_object_2d.h" #ifndef _3D_DISABLED #include "scene/3d/audio_listener_3d.h" #include "scene/3d/camera_3d.h" -#include "scene/3d/collision_object_3d.h" +#include "scene/3d/physics/collision_object_3d.h" #include "scene/3d/world_environment.h" #endif // _3D_DISABLED #include "scene/gui/control.h" @@ -1447,7 +1447,7 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont String tooltip; while (p_control) { - tooltip = p_control->get_tooltip(pos); + tooltip = p_control->atr(p_control->get_tooltip(pos)); // Temporary solution for PopupMenus. PopupMenu *menu = Object::cast_to<PopupMenu>(this); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index b156cd0422..9f741db7da 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -34,18 +34,14 @@ #include "core/object/class_db.h" #include "core/os/os.h" #include "scene/2d/animated_sprite_2d.h" -#include "scene/2d/area_2d.h" #include "scene/2d/audio_listener_2d.h" #include "scene/2d/audio_stream_player_2d.h" #include "scene/2d/back_buffer_copy.h" #include "scene/2d/camera_2d.h" #include "scene/2d/canvas_group.h" #include "scene/2d/canvas_modulate.h" -#include "scene/2d/collision_polygon_2d.h" -#include "scene/2d/collision_shape_2d.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/2d/gpu_particles_2d.h" -#include "scene/2d/joint_2d.h" #include "scene/2d/light_2d.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/line_2d.h" @@ -59,12 +55,24 @@ #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" #include "scene/2d/path_2d.h" -#include "scene/2d/physical_bone_2d.h" -#include "scene/2d/physics_body_2d.h" +#include "scene/2d/physics/animatable_body_2d.h" +#include "scene/2d/physics/area_2d.h" +#include "scene/2d/physics/character_body_2d.h" +#include "scene/2d/physics/collision_polygon_2d.h" +#include "scene/2d/physics/collision_shape_2d.h" +#include "scene/2d/physics/joints/damped_spring_joint_2d.h" +#include "scene/2d/physics/joints/groove_joint_2d.h" +#include "scene/2d/physics/joints/joint_2d.h" +#include "scene/2d/physics/joints/pin_joint_2d.h" +#include "scene/2d/physics/kinematic_collision_2d.h" +#include "scene/2d/physics/physical_bone_2d.h" +#include "scene/2d/physics/physics_body_2d.h" +#include "scene/2d/physics/ray_cast_2d.h" +#include "scene/2d/physics/rigid_body_2d.h" +#include "scene/2d/physics/shape_cast_2d.h" +#include "scene/2d/physics/static_body_2d.h" #include "scene/2d/polygon_2d.h" -#include "scene/2d/ray_cast_2d.h" #include "scene/2d/remote_transform_2d.h" -#include "scene/2d/shape_cast_2d.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite_2d.h" #include "scene/2d/tile_map.h" @@ -218,20 +226,16 @@ #include "scene/main/shader_globals_override.h" #ifndef _3D_DISABLED -#include "scene/3d/area_3d.h" #include "scene/3d/audio_listener_3d.h" #include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/camera_3d.h" -#include "scene/3d/collision_polygon_3d.h" -#include "scene/3d/collision_shape_3d.h" #include "scene/3d/cpu_particles_3d.h" #include "scene/3d/decal.h" #include "scene/3d/fog_volume.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/3d/gpu_particles_collision_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/3d/joint_3d.h" #include "scene/3d/label_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/lightmap_gi.h" @@ -246,20 +250,36 @@ #include "scene/3d/node_3d.h" #include "scene/3d/occluder_instance_3d.h" #include "scene/3d/path_3d.h" -#include "scene/3d/physics_body_3d.h" -#include "scene/3d/ray_cast_3d.h" +#include "scene/3d/physics/animatable_body_3d.h" +#include "scene/3d/physics/area_3d.h" +#include "scene/3d/physics/character_body_3d.h" +#include "scene/3d/physics/collision_polygon_3d.h" +#include "scene/3d/physics/collision_shape_3d.h" +#include "scene/3d/physics/joints/cone_twist_joint_3d.h" +#include "scene/3d/physics/joints/generic_6dof_joint_3d.h" +#include "scene/3d/physics/joints/hinge_joint_3d.h" +#include "scene/3d/physics/joints/joint_3d.h" +#include "scene/3d/physics/joints/pin_joint_3d.h" +#include "scene/3d/physics/joints/slider_joint_3d.h" +#include "scene/3d/physics/kinematic_collision_3d.h" +#include "scene/3d/physics/physical_bone_3d.h" +#include "scene/3d/physics/physics_body_3d.h" +#include "scene/3d/physics/ray_cast_3d.h" +#include "scene/3d/physics/rigid_body_3d.h" +#include "scene/3d/physics/shape_cast_3d.h" +#include "scene/3d/physics/spring_arm_3d.h" +#include "scene/3d/physics/static_body_3d.h" +#include "scene/3d/physics/vehicle_body_3d.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/remote_transform_3d.h" -#include "scene/3d/shape_cast_3d.h" #include "scene/3d/skeleton_3d.h" #include "scene/3d/skeleton_ik_3d.h" #include "scene/3d/soft_body_3d.h" -#include "scene/3d/spring_arm_3d.h" #include "scene/3d/sprite_3d.h" -#include "scene/3d/vehicle_body_3d.h" #include "scene/3d/visible_on_screen_notifier_3d.h" #include "scene/3d/voxel_gi.h" #include "scene/3d/world_environment.h" +#include "scene/3d/xr_body_modifier_3d.h" #include "scene/3d/xr_face_modifier_3d.h" #include "scene/3d/xr_hand_modifier_3d.h" #include "scene/3d/xr_nodes.h" @@ -522,6 +542,7 @@ void register_scene_types() { GDREGISTER_CLASS(XRController3D); GDREGISTER_CLASS(XRAnchor3D); GDREGISTER_CLASS(XROrigin3D); + GDREGISTER_CLASS(XRBodyModifier3D); GDREGISTER_CLASS(XRHandModifier3D); GDREGISTER_CLASS(XRFaceModifier3D); GDREGISTER_CLASS(MeshInstance3D); diff --git a/scene/resources/2d/skeleton/skeleton_modification_2d.cpp b/scene/resources/2d/skeleton/skeleton_modification_2d.cpp index 88a0f7b92d..4e7563fdc3 100644 --- a/scene/resources/2d/skeleton/skeleton_modification_2d.cpp +++ b/scene/resources/2d/skeleton/skeleton_modification_2d.cpp @@ -31,9 +31,9 @@ #include "skeleton_modification_2d.h" #include "scene/2d/skeleton_2d.h" -#include "scene/2d/collision_object_2d.h" -#include "scene/2d/collision_shape_2d.h" -#include "scene/2d/physical_bone_2d.h" +#include "scene/2d/physics/collision_object_2d.h" +#include "scene/2d/physics/collision_shape_2d.h" +#include "scene/2d/physics/physical_bone_2d.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" diff --git a/scene/resources/2d/skeleton/skeleton_modification_2d_physicalbones.cpp b/scene/resources/2d/skeleton/skeleton_modification_2d_physicalbones.cpp index e000e947cd..61e5aed150 100644 --- a/scene/resources/2d/skeleton/skeleton_modification_2d_physicalbones.cpp +++ b/scene/resources/2d/skeleton/skeleton_modification_2d_physicalbones.cpp @@ -29,7 +29,7 @@ /**************************************************************************/ #include "skeleton_modification_2d_physicalbones.h" -#include "scene/2d/physical_bone_2d.h" +#include "scene/2d/physics/physical_bone_2d.h" #include "scene/2d/skeleton_2d.h" bool SkeletonModification2DPhysicalBones::_set(const StringName &p_path, const Variant &p_value) { diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index a51e28c9fe..907c0ab4ca 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -208,7 +208,7 @@ void ImmediateMesh::surface_end() { if (uses_tangents) { t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d); } else { - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[i].normalized()); + Vector3 tan = Vector3(normals[i].z, -normals[i].x, normals[i].y).cross(normals[i].normalized()).normalized(); t = tan.octahedron_tangent_encode(1.0); } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 89501aaa5a..2c92a3edb3 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -348,35 +348,16 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { //handle resources that are local to scene by duplicating them if needed Ref<Resource> res = value; if (res.is_valid()) { - if (res->is_local_to_scene()) { - if (n.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene. - value = get_remap_resource(res, resources_local_to_sub_scene, node->get(snames[nprops[j].name]), node); - } else { - HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res); - Node *base = i == 0 ? node : ret_nodes[0]; - if (E) { - value = E->value; - } else { - if (p_edit_state == GEN_EDIT_STATE_MAIN) { - //for the main scene, use the resource as is - res->configure_for_local_scene(base, resources_local_to_scene); - resources_local_to_scene[res] = res; - } else { - //for instances, a copy must be made - Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene); - resources_local_to_scene[res] = local_dupe; - value = local_dupe; - } - } - } - //must make a copy, because this res is local to scene - } + value = make_local_resource(value, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state); } } if (value.get_type() == Variant::ARRAY) { Array set_array = value; + value = setup_resources_in_array(set_array, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state); + bool is_get_valid = false; Variant get_value = node->get(snames[nprops[j].name], &is_get_valid); + if (is_get_valid && get_value.get_type() == Variant::ARRAY) { Array get_array = get_value; if (!set_array.is_same_typed(get_array)) { @@ -384,8 +365,26 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { } } } - if (p_edit_state == GEN_EDIT_STATE_INSTANCE && value.get_type() != Variant::OBJECT) { - value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor + if (value.get_type() == Variant::DICTIONARY) { + Dictionary dictionary = value; + const Array keys = dictionary.keys(); + const Array values = dictionary.values(); + + if (has_local_resource(values) || has_local_resource(keys)) { + Array duplicated_keys = keys.duplicate(true); + Array duplicated_values = values.duplicate(true); + + duplicated_keys = setup_resources_in_array(duplicated_keys, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state); + duplicated_values = setup_resources_in_array(duplicated_values, n, resources_local_to_sub_scene, node, snames[nprops[j].name], resources_local_to_scene, i, ret_nodes, p_edit_state); + + dictionary.clear(); + + for (int dictionary_index = 0; dictionary_index < keys.size(); dictionary_index++) { + dictionary[duplicated_keys[dictionary_index]] = duplicated_values[dictionary_index]; + } + + value = dictionary; + } } bool set_valid = true; @@ -400,6 +399,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { if (set_valid) { node->set(snames[nprops[j].name], value, &valid); } + if (p_edit_state == GEN_EDIT_STATE_INSTANCE && value.get_type() != Variant::OBJECT) { + value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor. + } } } if (!missing_resource_properties.is_empty()) { @@ -587,6 +589,50 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { return ret_nodes[0]; } +Variant SceneState::make_local_resource(Variant &p_value, const SceneState::NodeData &p_node_data, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const { + Ref<Resource> res = p_value; + if (res.is_null() || !res->is_local_to_scene()) { + return p_value; + } + + if (p_node_data.instance >= 0) { // For the root node of a sub-scene, treat it as part of the sub-scene. + return get_remap_resource(res, p_resources_local_to_sub_scene, p_node->get(p_sname), p_node); + } else { + HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = p_resources_local_to_scene.find(res); + Node *base = p_i == 0 ? p_node : p_ret_nodes[0]; + if (E) { + return E->value; + } else if (p_edit_state == GEN_EDIT_STATE_MAIN) { // For the main scene, use the resource as is + res->configure_for_local_scene(base, p_resources_local_to_scene); + p_resources_local_to_scene[res] = res; + return res; + } else { // For instances, a copy must be made. + Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, p_resources_local_to_scene); + p_resources_local_to_scene[res] = local_dupe; + return local_dupe; + } + } +} + +Array SceneState::setup_resources_in_array(Array &p_array_to_scan, const SceneState::NodeData &p_n, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const { + for (int i = 0; i < p_array_to_scan.size(); i++) { + if (p_array_to_scan[i].get_type() == Variant::OBJECT) { + p_array_to_scan[i] = make_local_resource(p_array_to_scan[i], p_n, p_resources_local_to_sub_scene, p_node, p_sname, p_resources_local_to_scene, p_i, p_ret_nodes, p_edit_state); + } + } + return p_array_to_scan; +} + +bool SceneState::has_local_resource(const Array &p_array) const { + for (int i = 0; i < p_array.size(); i++) { + Ref<Resource> res = p_array[i]; + if (res.is_valid() && res->is_local_to_scene()) { + return true; + } + } + return false; +} + static int _nm_get_string(const String &p_string, HashMap<StringName, int> &name_map) { if (name_map.has(p_string)) { return name_map[p_string]; @@ -751,8 +797,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has if (!pinned_props.has(name)) { bool is_valid_default = false; Variant default_value = PropertyUtils::get_property_default_value(p_node, name, &is_valid_default, &states_stack, true); + if (is_valid_default && !PropertyUtils::is_property_value_different(value, default_value)) { - continue; + if (value.get_type() == Variant::ARRAY && has_local_resource(value)) { + // Save anyway + } else if (value.get_type() == Variant::DICTIONARY) { + Dictionary dictionary = value; + if (!has_local_resource(dictionary.values()) && !has_local_resource(dictionary.keys())) { + continue; + } + } else { + continue; + } } } diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 2dc8540499..304e401602 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -157,6 +157,10 @@ public: bool can_instantiate() const; Node *instantiate(GenEditState p_edit_state) const; + Array setup_resources_in_array(Array &array_to_scan, const SceneState::NodeData &n, HashMap<Ref<Resource>, Ref<Resource>> &resources_local_to_sub_scene, Node *node, const StringName sname, HashMap<Ref<Resource>, Ref<Resource>> &resources_local_to_scene, int i, Node **ret_nodes, SceneState::GenEditState p_edit_state) const; + Variant make_local_resource(Variant &value, const SceneState::NodeData &p_node_data, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_sub_scene, Node *p_node, const StringName p_sname, HashMap<Ref<Resource>, Ref<Resource>> &p_resources_local_to_scene, int p_i, Node **p_ret_nodes, SceneState::GenEditState p_edit_state) const; + bool has_local_resource(const Array &p_array) const; + Ref<SceneState> get_base_scene_state() const; void update_instance_resource(String p_path, Ref<PackedScene> p_packed_scene); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 653f234d3d..06d53e4e2f 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -97,6 +97,10 @@ bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { return false; } + if (tangent != p_vertex.tangent) { + return false; + } + if (color != p_vertex.color) { return false; } @@ -880,9 +884,9 @@ void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays v.normal = narr[i]; } if (lformat & RS::ARRAY_FORMAT_TANGENT) { - Plane p(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2], tarr[i * 4 + 3]); - v.tangent = p.normal; - v.binormal = p.normal.cross(v.tangent).normalized() * p.d; + v.tangent = Vector3(tarr[i * 4 + 0], tarr[i * 4 + 1], tarr[i * 4 + 2]); + float d = tarr[i * 4 + 3]; + v.binormal = v.normal.cross(v.tangent).normalized() * d; } if (lformat & RS::ARRAY_FORMAT_COLOR) { v.color = carr[i]; diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index d5e3427344..04a15b0381 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -32,7 +32,6 @@ #define WORLD_2D_H #include "core/io/resource.h" -#include "scene/resources/world_2d.h" #include "servers/physics_server_2d.h" class VisibleOnScreenNotifier2D; diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index fa83e06315..e4c469b752 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -174,7 +174,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_focus_color", "Button", control_font_focus_color); theme->set_color("font_hover_pressed_color", "Button", control_font_pressed_color); theme->set_color("font_disabled_color", "Button", control_font_disabled_color); - theme->set_color("font_outline_color", "Button", Color(1, 1, 1)); + theme->set_color("font_outline_color", "Button", Color(0, 0, 0)); theme->set_color("icon_normal_color", "Button", Color(1, 1, 1, 1)); theme->set_color("icon_pressed_color", "Button", Color(1, 1, 1, 1)); @@ -202,7 +202,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_focus_color", "MenuBar", control_font_focus_color); theme->set_color("font_hover_pressed_color", "MenuBar", control_font_pressed_color); theme->set_color("font_disabled_color", "MenuBar", control_font_disabled_color); - theme->set_color("font_outline_color", "MenuBar", Color(1, 1, 1)); + theme->set_color("font_outline_color", "MenuBar", Color(0, 0, 0)); theme->set_constant("h_separation", "MenuBar", Math::round(4 * scale)); @@ -217,7 +217,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_pressed_color", "LinkButton", control_font_pressed_color); theme->set_color("font_hover_color", "LinkButton", control_font_hover_color); theme->set_color("font_focus_color", "LinkButton", control_font_focus_color); - theme->set_color("font_outline_color", "LinkButton", Color(1, 1, 1)); + theme->set_color("font_outline_color", "LinkButton", Color(0, 0, 0)); theme->set_constant("outline_size", "LinkButton", 0); theme->set_constant("underline_spacing", "LinkButton", Math::round(2 * scale)); @@ -256,7 +256,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hover_pressed_color", "OptionButton", control_font_pressed_color); theme->set_color("font_focus_color", "OptionButton", control_font_focus_color); theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color); - theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1)); + theme->set_color("font_outline_color", "OptionButton", Color(0, 0, 0)); theme->set_constant("h_separation", "OptionButton", Math::round(4 * scale)); theme->set_constant("arrow_margin", "OptionButton", Math::round(4 * scale)); @@ -279,7 +279,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hover_color", "MenuButton", control_font_hover_color); theme->set_color("font_focus_color", "MenuButton", control_font_focus_color); theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3)); - theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1)); + theme->set_color("font_outline_color", "MenuButton", Color(0, 0, 0)); theme->set_constant("h_separation", "MenuButton", Math::round(4 * scale)); theme->set_constant("outline_size", "MenuButton", 0); @@ -316,7 +316,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hover_pressed_color", "CheckBox", control_font_pressed_color); theme->set_color("font_focus_color", "CheckBox", control_font_focus_color); theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color); - theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1)); + theme->set_color("font_outline_color", "CheckBox", Color(0, 0, 0)); theme->set_constant("h_separation", "CheckBox", Math::round(4 * scale)); theme->set_constant("check_v_offset", "CheckBox", 0); @@ -353,7 +353,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hover_pressed_color", "CheckButton", control_font_pressed_color); theme->set_color("font_focus_color", "CheckButton", control_font_focus_color); theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color); - theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1)); + theme->set_color("font_outline_color", "CheckButton", Color(0, 0, 0)); theme->set_constant("h_separation", "CheckButton", Math::round(4 * scale)); theme->set_constant("check_v_offset", "CheckButton", 0); @@ -389,7 +389,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "Label", Color(1, 1, 1)); theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0)); - theme->set_color("font_outline_color", "Label", Color(1, 1, 1)); + theme->set_color("font_outline_color", "Label", Color(0, 0, 0)); theme->set_constant("shadow_offset_x", "Label", Math::round(1 * scale)); theme->set_constant("shadow_offset_y", "Label", Math::round(1 * scale)); @@ -429,7 +429,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_selected_color", "LineEdit", control_font_pressed_color); theme->set_color("font_uneditable_color", "LineEdit", control_font_disabled_color); theme->set_color("font_placeholder_color", "LineEdit", control_font_placeholder_color); - theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1)); + theme->set_color("font_outline_color", "LineEdit", Color(0, 0, 0)); theme->set_color("caret_color", "LineEdit", control_font_hover_color); theme->set_color("selection_color", "LineEdit", control_selection_color); theme->set_color("clear_button_color", "LineEdit", control_font_color); @@ -450,7 +450,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "ProgressBar", -1); theme->set_color("font_color", "ProgressBar", control_font_hover_color); - theme->set_color("font_outline_color", "ProgressBar", Color(1, 1, 1)); + theme->set_color("font_outline_color", "ProgressBar", Color(0, 0, 0)); theme->set_constant("outline_size", "ProgressBar", 0); @@ -471,7 +471,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0, 0)); theme->set_color("font_readonly_color", "TextEdit", control_font_disabled_color); theme->set_color("font_placeholder_color", "TextEdit", control_font_placeholder_color); - theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1)); + theme->set_color("font_outline_color", "TextEdit", Color(0, 0, 0)); theme->set_color("selection_color", "TextEdit", control_selection_color); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); @@ -515,7 +515,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0, 0)); theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); theme->set_color("font_placeholder_color", "CodeEdit", control_font_placeholder_color); - theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1)); + theme->set_color("font_outline_color", "CodeEdit", Color(0, 0, 0)); theme->set_color("selection_color", "CodeEdit", control_selection_color); theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8)); theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3)); @@ -626,7 +626,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("title_font", "Window", Ref<Font>()); theme->set_font_size("title_font_size", "Window", -1); theme->set_color("title_color", "Window", control_font_color); - theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1)); + theme->set_color("title_outline_modulate", "Window", Color(0, 0, 0)); theme->set_constant("title_outline_size", "Window", 0); theme->set_constant("title_height", "Window", 36 * scale); theme->set_constant("resize_margin", "Window", Math::round(4 * scale)); @@ -651,6 +651,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]); theme->set_icon("folder", "FileDialog", icons["folder"]); theme->set_icon("file", "FileDialog", icons["file"]); + theme->set_icon("create_folder", "FileDialog", icons["folder_create"]); theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1)); theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1)); theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25)); @@ -705,8 +706,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_disabled_color", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); theme->set_color("font_hover_color", "PopupMenu", control_font_color); theme->set_color("font_separator_color", "PopupMenu", control_font_color); - theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1)); - theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1)); + theme->set_color("font_outline_color", "PopupMenu", Color(0, 0, 0)); + theme->set_color("font_separator_outline_color", "PopupMenu", Color(0, 0, 0)); theme->set_constant("indent", "PopupMenu", Math::round(10 * scale)); theme->set_constant("h_separation", "PopupMenu", Math::round(4 * scale)); @@ -749,7 +750,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "GraphNodeTitleLabel", -1); theme->set_color("font_color", "GraphNodeTitleLabel", control_font_color); theme->set_color("font_shadow_color", "GraphNodeTitleLabel", Color(0, 0, 0, 0)); - theme->set_color("font_outline_color", "GraphNodeTitleLabel", control_font_color); + theme->set_color("font_outline_color", "GraphNodeTitleLabel", Color(0, 0, 0)); theme->set_constant("shadow_offset_x", "GraphNodeTitleLabel", Math::round(1 * scale)); theme->set_constant("shadow_offset_y", "GraphNodeTitleLabel", Math::round(1 * scale)); theme->set_constant("outline_size", "GraphNodeTitleLabel", 0); @@ -793,7 +794,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "Tree", control_font_low_color); theme->set_color("font_selected_color", "Tree", control_font_pressed_color); theme->set_color("font_disabled_color", "Tree", control_font_disabled_color); - theme->set_color("font_outline_color", "Tree", Color(1, 1, 1)); + theme->set_color("font_outline_color", "Tree", Color(0, 0, 0)); theme->set_color("guide_color", "Tree", Color(0.7, 0.7, 0.7, 0.25)); theme->set_color("drop_position_color", "Tree", Color(1, 1, 1)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); @@ -831,7 +832,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color)); theme->set_stylebox("focus", "ItemList", focus); theme->set_constant("h_separation", "ItemList", Math::round(4 * scale)); - theme->set_constant("v_separation", "ItemList", Math::round(2 * scale)); + theme->set_constant("v_separation", "ItemList", Math::round(4 * scale)); theme->set_constant("icon_margin", "ItemList", Math::round(4 * scale)); theme->set_constant("line_separation", "ItemList", Math::round(2 * scale)); @@ -841,7 +842,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "ItemList", control_font_lower_color); theme->set_color("font_hovered_color", "ItemList", control_font_hover_color); theme->set_color("font_selected_color", "ItemList", control_font_pressed_color); - theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1)); + theme->set_color("font_outline_color", "ItemList", Color(0, 0, 0)); theme->set_color("guide_color", "ItemList", Color(0.7, 0.7, 0.7, 0.25)); theme->set_stylebox("hovered", "ItemList", make_flat_stylebox(Color(1, 1, 1, 0.07))); theme->set_stylebox("selected", "ItemList", make_flat_stylebox(style_selected_color)); @@ -890,7 +891,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hovered_color", "TabContainer", control_font_hover_color); theme->set_color("font_unselected_color", "TabContainer", control_font_low_color); theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color); - theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1)); + theme->set_color("font_outline_color", "TabContainer", Color(0, 0, 0)); theme->set_color("drop_mark_color", "TabContainer", Color(1, 1, 1)); theme->set_constant("side_margin", "TabContainer", Math::round(8 * scale)); @@ -922,7 +923,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hovered_color", "TabBar", control_font_hover_color); theme->set_color("font_unselected_color", "TabBar", control_font_low_color); theme->set_color("font_disabled_color", "TabBar", control_font_disabled_color); - theme->set_color("font_outline_color", "TabBar", Color(1, 1, 1)); + theme->set_color("font_outline_color", "TabBar", Color(0, 0, 0)); theme->set_color("drop_mark_color", "TabBar", Color(1, 1, 1)); theme->set_constant("h_separation", "TabBar", Math::round(4 * scale)); @@ -1034,7 +1035,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1)); theme->set_color("font_focus_color", "ColorPickerButton", Color(1, 1, 1, 1)); theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); - theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1)); + theme->set_color("font_outline_color", "ColorPickerButton", Color(0, 0, 0)); theme->set_constant("h_separation", "ColorPickerButton", Math::round(4 * scale)); theme->set_constant("outline_size", "ColorPickerButton", 0); @@ -1062,7 +1063,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "TooltipLabel", control_font_color); theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0)); - theme->set_color("font_outline_color", "TooltipLabel", Color(0, 0, 0, 0)); + theme->set_color("font_outline_color", "TooltipLabel", Color(0, 0, 0)); theme->set_constant("shadow_offset_x", "TooltipLabel", 1); theme->set_constant("shadow_offset_y", "TooltipLabel", 1); @@ -1090,7 +1091,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0)); - theme->set_color("font_outline_color", "RichTextLabel", Color(1, 1, 1)); + theme->set_color("font_outline_color", "RichTextLabel", Color(0, 0, 0)); theme->set_constant("shadow_offset_x", "RichTextLabel", Math::round(1 * scale)); theme->set_constant("shadow_offset_y", "RichTextLabel", Math::round(1 * scale)); diff --git a/scene/theme/icons/folder_create.svg b/scene/theme/icons/folder_create.svg new file mode 100644 index 0000000000..d11d0715a1 --- /dev/null +++ b/scene/theme/icons/folder_create.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M2 3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h8v-1H8v-4h2V8h4v2h1V7a1 1 0 0 0-1-1h-4a1 1 0 0 1-1-1V4a1 1 0 0 0-1-1Z" fill="#b2b2b2"/><path d="M13 13h2v-2h-2V9h-2v2H9v2h2v2h2z" fill="#fefffe"/></svg>
\ No newline at end of file diff --git a/scu_builders.py b/scu_builders.py index 1a75f19b30..2579398ad6 100644 --- a/scu_builders.py +++ b/scu_builders.py @@ -310,7 +310,11 @@ def generate_scu_files(max_includes_per_scu): process_folder(["modules/gdscript/language_server"]) process_folder(["scene/2d"]) + process_folder(["scene/2d/physics"]) + process_folder(["scene/2d/physics/joints"]) process_folder(["scene/3d"]) + process_folder(["scene/3d/physics"]) + process_folder(["scene/3d/physics/joints"]) process_folder(["scene/animation"]) process_folder(["scene/gui"]) process_folder(["scene/main"]) diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 380500769c..ee2a65ad91 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -76,6 +76,7 @@ #include "text/text_server_dummy.h" #include "text/text_server_extension.h" #include "text_server.h" +#include "xr/xr_body_tracker.h" #include "xr/xr_face_tracker.h" #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" @@ -173,6 +174,7 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(RenderingDevice); + GDREGISTER_CLASS(XRBodyTracker); GDREGISTER_ABSTRACT_CLASS(XRInterface); GDREGISTER_CLASS(XRHandTracker); GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions. diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index ce7128d564..8c88c08950 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -39,7 +39,6 @@ #include "core/templates/rid_owner.h" #include "core/variant/typed_array.h" #include "servers/display_server.h" -#include "servers/rendering/rendering_device.h" #include "servers/rendering/rendering_device_commons.h" #include "servers/rendering/rendering_device_driver.h" #include "servers/rendering/rendering_device_graph.h" diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 9706d3219a..ee33dc103c 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -106,7 +106,7 @@ struct VersatileResourceTemplate { template <class T> static T *allocate(PagedAllocator<VersatileResourceTemplate> &p_allocator) { T *obj = (T *)p_allocator.alloc(); - *obj = T(); + memnew_placement(obj, T); return obj; } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 6e9b525f31..e5d8800366 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -340,7 +340,7 @@ void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r if (d < 0.0) { r_angle = CLAMP((1.0 - r_angle / Math_PI) * 0.5, 0.0, 0.49999); } else { - r_angle = (r_angle / Math_PI) * 0.5 + 0.5; + r_angle = CLAMP((r_angle / Math_PI) * 0.5 + 0.5, 0.500008, 1.0); } } @@ -566,7 +566,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint float angle; Vector3 axis; // Generate an arbitrary vector that is tangential to normal. - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + // This assumes that the normal is never (0,0,0). + Vector3 tan = Vector3(normal_src[i].z, -normal_src[i].x, normal_src[i].y).cross(normal_src[i].normalized()).normalized(); Vector4 tangent = Vector4(tan.x, tan.y, tan.z, 1.0); _get_axis_angle(normal_src[i], tangent, angle, axis); @@ -689,7 +690,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // Set data for tangent. for (int i = 0; i < p_vertex_array_len; i++) { // Generate an arbitrary vector that is tangential to normal. - Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + // This assumes that the normal is never (0,0,0). + Vector3 tan = Vector3(normal_src[i].z, -normal_src[i].x, normal_src[i].y).cross(normal_src[i].normalized()).normalized(); Vector2 res = tan.octahedron_tangent_encode(1.0); uint16_t vector[2] = { (uint16_t)CLAMP(res.x * 65535, 0, 65535), diff --git a/servers/xr/xr_body_tracker.cpp b/servers/xr/xr_body_tracker.cpp new file mode 100644 index 0000000000..cd58c14348 --- /dev/null +++ b/servers/xr/xr_body_tracker.cpp @@ -0,0 +1,171 @@ +/**************************************************************************/ +/* xr_body_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#include "xr_body_tracker.h" + +void XRBodyTracker::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_has_tracking_data", "has_data"), &XRBodyTracker::set_has_tracking_data); + ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRBodyTracker::get_has_tracking_data); + + ClassDB::bind_method(D_METHOD("set_body_flags", "flags"), &XRBodyTracker::set_body_flags); + ClassDB::bind_method(D_METHOD("get_body_flags"), &XRBodyTracker::get_body_flags); + + ClassDB::bind_method(D_METHOD("set_joint_flags", "joint", "flags"), &XRBodyTracker::set_joint_flags); + ClassDB::bind_method(D_METHOD("get_joint_flags", "joint"), &XRBodyTracker::get_joint_flags); + + ClassDB::bind_method(D_METHOD("set_joint_transform", "joint", "transform"), &XRBodyTracker::set_joint_transform); + ClassDB::bind_method(D_METHOD("get_joint_transform", "joint"), &XRBodyTracker::get_joint_transform); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_tracking_data", PROPERTY_HINT_NONE), "set_has_tracking_data", "get_has_tracking_data"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "body_flags", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_flags", "get_body_flags"); + + BIND_BITFIELD_FLAG(BODY_FLAG_UPPER_BODY_SUPPORTED); + BIND_BITFIELD_FLAG(BODY_FLAG_LOWER_BODY_SUPPORTED); + BIND_BITFIELD_FLAG(BODY_FLAG_HANDS_SUPPORTED); + + BIND_ENUM_CONSTANT(JOINT_ROOT); + BIND_ENUM_CONSTANT(JOINT_HIPS); + BIND_ENUM_CONSTANT(JOINT_SPINE); + BIND_ENUM_CONSTANT(JOINT_CHEST); + BIND_ENUM_CONSTANT(JOINT_UPPER_CHEST); + BIND_ENUM_CONSTANT(JOINT_NECK); + BIND_ENUM_CONSTANT(JOINT_HEAD); + BIND_ENUM_CONSTANT(JOINT_HEAD_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_SHOULDER); + BIND_ENUM_CONSTANT(JOINT_LEFT_UPPER_ARM); + BIND_ENUM_CONSTANT(JOINT_LEFT_LOWER_ARM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_SHOULDER); + BIND_ENUM_CONSTANT(JOINT_RIGHT_UPPER_ARM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_LOWER_ARM); + BIND_ENUM_CONSTANT(JOINT_LEFT_UPPER_LEG); + BIND_ENUM_CONSTANT(JOINT_LEFT_LOWER_LEG); + BIND_ENUM_CONSTANT(JOINT_LEFT_FOOT); + BIND_ENUM_CONSTANT(JOINT_LEFT_TOES); + BIND_ENUM_CONSTANT(JOINT_RIGHT_UPPER_LEG); + BIND_ENUM_CONSTANT(JOINT_RIGHT_LOWER_LEG); + BIND_ENUM_CONSTANT(JOINT_RIGHT_FOOT); + BIND_ENUM_CONSTANT(JOINT_RIGHT_TOES); + BIND_ENUM_CONSTANT(JOINT_LEFT_HAND); + BIND_ENUM_CONSTANT(JOINT_LEFT_PALM); + BIND_ENUM_CONSTANT(JOINT_LEFT_WRIST); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_HAND); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PALM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_WRIST); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_MAX); + + BIND_BITFIELD_FLAG(JOINT_FLAG_ORIENTATION_VALID); + BIND_BITFIELD_FLAG(JOINT_FLAG_ORIENTATION_TRACKED); + BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_VALID); + BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_TRACKED); +} + +void XRBodyTracker::set_has_tracking_data(bool p_has_tracking_data) { + has_tracking_data = p_has_tracking_data; +} + +bool XRBodyTracker::get_has_tracking_data() const { + return has_tracking_data; +} + +void XRBodyTracker::set_body_flags(BitField<BodyFlags> p_body_flags) { + body_flags = p_body_flags; +} + +BitField<XRBodyTracker::BodyFlags> XRBodyTracker::get_body_flags() const { + return body_flags; +} + +void XRBodyTracker::set_joint_flags(Joint p_joint, BitField<JointFlags> p_flags) { + ERR_FAIL_INDEX(p_joint, JOINT_MAX); + joint_flags[p_joint] = p_flags; +} + +BitField<XRBodyTracker::JointFlags> XRBodyTracker::get_joint_flags(Joint p_joint) const { + ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, BitField<JointFlags>()); + return joint_flags[p_joint]; +} + +void XRBodyTracker::set_joint_transform(Joint p_joint, const Transform3D &p_transform) { + ERR_FAIL_INDEX(p_joint, JOINT_MAX); + joint_transforms[p_joint] = p_transform; +} + +Transform3D XRBodyTracker::get_joint_transform(Joint p_joint) const { + ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, Transform3D()); + return joint_transforms[p_joint]; +} diff --git a/servers/xr/xr_body_tracker.h b/servers/xr/xr_body_tracker.h new file mode 100644 index 0000000000..659aa39df1 --- /dev/null +++ b/servers/xr/xr_body_tracker.h @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* xr_body_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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. */ +/**************************************************************************/ + +#ifndef XR_BODY_TRACKER_H +#define XR_BODY_TRACKER_H + +#include "core/object/ref_counted.h" + +class XRBodyTracker : public RefCounted { + GDCLASS(XRBodyTracker, RefCounted); + _THREAD_SAFE_CLASS_ + +public: + enum BodyFlags { + BODY_FLAG_UPPER_BODY_SUPPORTED = 1, + BODY_FLAG_LOWER_BODY_SUPPORTED = 2, + BODY_FLAG_HANDS_SUPPORTED = 4, + }; + + enum Joint { + JOINT_ROOT, + + // Upper Body Joints + JOINT_HIPS, + JOINT_SPINE, + JOINT_CHEST, + JOINT_UPPER_CHEST, + JOINT_NECK, + JOINT_HEAD, + JOINT_HEAD_TIP, + JOINT_LEFT_SHOULDER, + JOINT_LEFT_UPPER_ARM, + JOINT_LEFT_LOWER_ARM, + JOINT_RIGHT_SHOULDER, + JOINT_RIGHT_UPPER_ARM, + JOINT_RIGHT_LOWER_ARM, + + // Lower Body Joints + JOINT_LEFT_UPPER_LEG, + JOINT_LEFT_LOWER_LEG, + JOINT_LEFT_FOOT, + JOINT_LEFT_TOES, + JOINT_RIGHT_UPPER_LEG, + JOINT_RIGHT_LOWER_LEG, + JOINT_RIGHT_FOOT, + JOINT_RIGHT_TOES, + + // Left Hand Joints + JOINT_LEFT_HAND, + JOINT_LEFT_PALM, + JOINT_LEFT_WRIST, + JOINT_LEFT_THUMB_METACARPAL, + JOINT_LEFT_THUMB_PHALANX_PROXIMAL, + JOINT_LEFT_THUMB_PHALANX_DISTAL, + JOINT_LEFT_THUMB_TIP, + JOINT_LEFT_INDEX_FINGER_METACARPAL, + JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL, + JOINT_LEFT_INDEX_FINGER_TIP, + JOINT_LEFT_MIDDLE_FINGER_METACARPAL, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL, + JOINT_LEFT_MIDDLE_FINGER_TIP, + JOINT_LEFT_RING_FINGER_METACARPAL, + JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_RING_FINGER_PHALANX_DISTAL, + JOINT_LEFT_RING_FINGER_TIP, + JOINT_LEFT_PINKY_FINGER_METACARPAL, + JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL, + JOINT_LEFT_PINKY_FINGER_TIP, + + // Right Hand Joints + JOINT_RIGHT_HAND, + JOINT_RIGHT_PALM, + JOINT_RIGHT_WRIST, + JOINT_RIGHT_THUMB_METACARPAL, + JOINT_RIGHT_THUMB_PHALANX_PROXIMAL, + JOINT_RIGHT_THUMB_PHALANX_DISTAL, + JOINT_RIGHT_THUMB_TIP, + JOINT_RIGHT_INDEX_FINGER_METACARPAL, + JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_INDEX_FINGER_TIP, + JOINT_RIGHT_MIDDLE_FINGER_METACARPAL, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_MIDDLE_FINGER_TIP, + JOINT_RIGHT_RING_FINGER_METACARPAL, + JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_RING_FINGER_TIP, + JOINT_RIGHT_PINKY_FINGER_METACARPAL, + JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_PINKY_FINGER_TIP, + + JOINT_MAX, + }; + + enum JointFlags { + JOINT_FLAG_ORIENTATION_VALID = 1, + JOINT_FLAG_ORIENTATION_TRACKED = 2, + JOINT_FLAG_POSITION_VALID = 4, + JOINT_FLAG_POSITION_TRACKED = 8, + }; + + void set_has_tracking_data(bool p_has_tracking_data); + bool get_has_tracking_data() const; + + void set_body_flags(BitField<BodyFlags> p_body_flags); + BitField<BodyFlags> get_body_flags() const; + + void set_joint_flags(Joint p_joint, BitField<JointFlags> p_flags); + BitField<JointFlags> get_joint_flags(Joint p_joint) const; + + void set_joint_transform(Joint p_joint, const Transform3D &p_transform); + Transform3D get_joint_transform(Joint p_joint) const; + +protected: + static void _bind_methods(); + +private: + bool has_tracking_data = false; + BitField<BodyFlags> body_flags; + + BitField<JointFlags> joint_flags[JOINT_MAX]; + Transform3D joint_transforms[JOINT_MAX]; +}; + +VARIANT_BITFIELD_CAST(XRBodyTracker::BodyFlags) +VARIANT_ENUM_CAST(XRBodyTracker::Joint) +VARIANT_BITFIELD_CAST(XRBodyTracker::JointFlags) + +#endif // XR_BODY_TRACKER_H diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 1e497e22c3..af14ba4a00 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -30,6 +30,7 @@ #include "xr_server.h" #include "core/config/project_settings.h" +#include "xr/xr_body_tracker.h" #include "xr/xr_face_tracker.h" #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" @@ -86,6 +87,11 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_face_trackers"), &XRServer::get_face_trackers); ClassDB::bind_method(D_METHOD("get_face_tracker", "tracker_name"), &XRServer::get_face_tracker); + ClassDB::bind_method(D_METHOD("add_body_tracker", "tracker_name", "body_tracker"), &XRServer::add_body_tracker); + ClassDB::bind_method(D_METHOD("remove_body_tracker", "tracker_name"), &XRServer::remove_body_tracker); + ClassDB::bind_method(D_METHOD("get_body_trackers"), &XRServer::get_body_trackers); + ClassDB::bind_method(D_METHOD("get_body_tracker", "tracker_name"), &XRServer::get_body_tracker); + ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); @@ -117,6 +123,10 @@ void XRServer::_bind_methods() { ADD_SIGNAL(MethodInfo("face_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); ADD_SIGNAL(MethodInfo("face_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); ADD_SIGNAL(MethodInfo("face_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); + + ADD_SIGNAL(MethodInfo("body_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); + ADD_SIGNAL(MethodInfo("body_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); + ADD_SIGNAL(MethodInfo("body_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); }; double XRServer::get_world_scale() const { @@ -448,6 +458,44 @@ Ref<XRFaceTracker> XRServer::get_face_tracker(const StringName &p_tracker_name) return face_trackers[p_tracker_name]; } +void XRServer::add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_body_tracker) { + ERR_FAIL_COND(p_body_tracker.is_null()); + + if (!body_trackers.has(p_tracker_name)) { + // We don't have a tracker with this name, we're going to add it. + body_trackers[p_tracker_name] = p_body_tracker; + emit_signal(SNAME("body_tracker_added"), p_tracker_name, p_body_tracker); + } else if (body_trackers[p_tracker_name] != p_body_tracker) { + // We already have a tracker with this name, we're going to replace it. + body_trackers[p_tracker_name] = p_body_tracker; + emit_signal(SNAME("body_tracker_updated"), p_tracker_name, p_body_tracker); + } +} + +void XRServer::remove_body_tracker(const StringName &p_tracker_name) { + // Skip if no face tracker is found. + if (!body_trackers.has(p_tracker_name)) { + return; + } + + // Send the removed signal, then remove the face tracker. + emit_signal(SNAME("body_tracker_removed"), p_tracker_name); + body_trackers.erase(p_tracker_name); +} + +Dictionary XRServer::get_body_trackers() const { + return body_trackers; +} + +Ref<XRBodyTracker> XRServer::get_body_tracker(const StringName &p_tracker_name) const { + // Skip if no tracker is found. + if (!body_trackers.has(p_tracker_name)) { + return Ref<XRBodyTracker>(); + } + + return body_trackers[p_tracker_name]; +} + void XRServer::_process() { // called from our main game loop before we handle physics and game logic // note that we can have multiple interfaces active if we have interfaces that purely handle tracking diff --git a/servers/xr_server.h b/servers/xr_server.h index 3e45bbb76c..6aaa34b21d 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -41,6 +41,7 @@ class XRInterface; class XRPositionalTracker; class XRHandTracker; class XRFaceTracker; +class XRBodyTracker; /** The XR server is a singleton object that gives access to the various @@ -89,6 +90,7 @@ private: Dictionary trackers; Dictionary hand_trackers; Dictionary face_trackers; + Dictionary body_trackers; Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ @@ -203,6 +205,14 @@ public: Dictionary get_face_trackers() const; Ref<XRFaceTracker> get_face_tracker(const StringName &p_tracker_name) const; + /* + Body trackers are objects that expose the tracked joints of a body. + */ + void add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_face_tracker); + void remove_body_tracker(const StringName &p_tracker_name); + Dictionary get_body_trackers() const; + Ref<XRBodyTracker> get_body_tracker(const StringName &p_tracker_name) const; + // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process(); diff --git a/tests/core/string/test_node_path.h b/tests/core/string/test_node_path.h index 031a33c570..bdbc578e85 100644 --- a/tests/core/string/test_node_path.h +++ b/tests/core/string/test_node_path.h @@ -167,6 +167,59 @@ TEST_CASE("[NodePath] Empty path") { node_path_empty.is_empty(), "The node path should be considered empty."); } + +TEST_CASE("[NodePath] Slice") { + const NodePath node_path_relative = NodePath("Parent/Child:prop"); + const NodePath node_path_absolute = NodePath("/root/Parent/Child:prop"); + CHECK_MESSAGE( + node_path_relative.slice(0, 2) == NodePath("Parent/Child"), + "The slice lower bound should be inclusive and the slice upper bound should be exclusive."); + CHECK_MESSAGE( + node_path_relative.slice(3) == NodePath(":prop"), + "Slicing on the length of the path should return the last entry."); + CHECK_MESSAGE( + node_path_relative.slice(1, 3) == NodePath("Child:prop"), + "Slicing should include names and subnames."); + CHECK_MESSAGE( + node_path_relative.slice(-1) == NodePath(":prop"), + "Slicing on -1 should return the last entry."); + CHECK_MESSAGE( + node_path_relative.slice(0, -1) == NodePath("Parent/Child"), + "Slicing up to -1 should include the second-to-last entry."); + CHECK_MESSAGE( + node_path_relative.slice(-2, -1) == NodePath("Child"), + "Slicing from negative to negative should treat lower bound as inclusive and upper bound as exclusive."); + CHECK_MESSAGE( + node_path_relative.slice(0, 10) == NodePath("Parent/Child:prop"), + "Slicing past the length of the path should work like slicing up to the last entry."); + CHECK_MESSAGE( + node_path_relative.slice(-10, 2) == NodePath("Parent/Child"), + "Slicing negatively past the length of the path should work like slicing from the first entry."); + CHECK_MESSAGE( + node_path_relative.slice(1, 1) == NodePath(""), + "Slicing with a lower bound equal to upper bound should return empty path."); + + CHECK_MESSAGE( + node_path_absolute.slice(0, 2) == NodePath("/root/Parent"), + "Slice from beginning of an absolute path should be an absolute path."); + CHECK_MESSAGE( + node_path_absolute.slice(1, 4) == NodePath("Parent/Child:prop"), + "Slice of an absolute path that does not start at the beginning should be a relative path."); + CHECK_MESSAGE( + node_path_absolute.slice(3, 4) == NodePath(":prop"), + "Slice of an absolute path that does not start at the beginning should be a relative path."); + + CHECK_MESSAGE( + NodePath("").slice(0, 1) == NodePath(""), + "Slice of an empty path should be an empty path."); + CHECK_MESSAGE( + NodePath("").slice(-1, 2) == NodePath(""), + "Slice of an empty path should be an empty path."); + CHECK_MESSAGE( + NodePath("/").slice(-1, 2) == NodePath("/"), + "Slice of an empty absolute path should be an empty absolute path."); +} + } // namespace TestNodePath #endif // TEST_NODE_PATH_H diff --git a/tests/scene/test_viewport.h b/tests/scene/test_viewport.h index e15b01ae9f..66b0f438cc 100644 --- a/tests/scene/test_viewport.h +++ b/tests/scene/test_viewport.h @@ -31,8 +31,8 @@ #ifndef TEST_VIEWPORT_H #define TEST_VIEWPORT_H -#include "scene/2d/area_2d.h" -#include "scene/2d/collision_shape_2d.h" +#include "scene/2d/physics/area_2d.h" +#include "scene/2d/physics/collision_shape_2d.h" #include "scene/gui/control.h" #include "scene/gui/subviewport_container.h" #include "scene/main/canvas_layer.h" diff --git a/thirdparty/README.md b/thirdparty/README.md index 69a9d70756..4c276b3c00 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -724,7 +724,7 @@ with the provided patch. ## openxr - Upstream: https://github.com/KhronosGroup/OpenXR-SDK -- Version: 1.0.33 (dc1e23937fe45eabcce80f6588cf47449edb29d1, 2024) +- Version: 1.0.34 (288d3a7ebc1ad959f62d51da75baa3d27438c499, 2024) - License: Apache 2.0 Files extracted from upstream source: diff --git a/thirdparty/openxr/include/openxr/openxr.h b/thirdparty/openxr/include/openxr/openxr.h index 3e9d6599bb..c0c826b981 100644 --- a/thirdparty/openxr/include/openxr/openxr.h +++ b/thirdparty/openxr/include/openxr/openxr.h @@ -25,7 +25,7 @@ extern "C" { ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) // OpenXR current version number. -#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 33) +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 34) #define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) #define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) @@ -549,11 +549,19 @@ typedef enum XrStructureType { XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB = 1000238001, XR_TYPE_SPACE_USER_CREATE_INFO_FB = 1000241001, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META = 1000245000, + XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_META = 1000254000, + XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_GET_INFO_META = 1000254001, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META = 1000266000, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META = 1000266001, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META = 1000266002, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META = 1000266100, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META = 1000266101, + XR_TYPE_SPACE_TRIANGLE_MESH_GET_INFO_META = 1000269001, + XR_TYPE_SPACE_TRIANGLE_MESH_META = 1000269002, + XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES2_FB = 1000287013, + XR_TYPE_FACE_TRACKER_CREATE_INFO2_FB = 1000287014, + XR_TYPE_FACE_EXPRESSION_INFO2_FB = 1000287015, + XR_TYPE_FACE_EXPRESSION_WEIGHTS2_FB = 1000287016, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001, XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC = 1000317003, @@ -575,6 +583,8 @@ typedef enum XrStructureType { XR_TYPE_PLANE_DETECTOR_LOCATION_EXT = 1000429005, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT = 1000429006, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT = 1000429007, + XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT = 1000470000, + XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT = 1000470001, XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, @@ -672,6 +682,7 @@ typedef enum XrObjectType { XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META = 1000219000, XR_OBJECT_TYPE_SPACE_USER_FB = 1000241000, XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META = 1000266000, + XR_OBJECT_TYPE_FACE_TRACKER2_FB = 1000287012, XR_OBJECT_TYPE_PASSTHROUGH_HTC = 1000317000, XR_OBJECT_TYPE_PLANE_DETECTOR_EXT = 1000429000, XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF @@ -3616,7 +3627,7 @@ typedef struct XrHandTrackingCapsulesStateFB { #define XR_FB_spatial_entity 1 XR_DEFINE_ATOM(XrAsyncRequestIdFB) #define XR_UUID_SIZE_EXT 16 -#define XR_FB_spatial_entity_SPEC_VERSION 2 +#define XR_FB_spatial_entity_SPEC_VERSION 3 #define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity" typedef enum XrSpaceComponentTypeFB { @@ -3628,6 +3639,7 @@ typedef enum XrSpaceComponentTypeFB { XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5, XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB = 6, XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB = 7, + XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META = 1000269000, XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB = 0x7FFFFFFF } XrSpaceComponentTypeFB; // XrSystemSpatialEntityPropertiesFB extends XrSystemProperties @@ -4332,6 +4344,11 @@ XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO( #endif /* !XR_NO_PROTOTYPES */ +#define XR_VARJO_xr4_controller_interaction 1 +#define XR_VARJO_xr4_controller_interaction_SPEC_VERSION 1 +#define XR_VARJO_XR4_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_VARJO_xr4_controller_interaction" + + #define XR_ML_ml2_controller_interaction 1 #define XR_ML_ml2_controller_interaction_SPEC_VERSION 1 #define XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_ML_ml2_controller_interaction" @@ -5151,13 +5168,14 @@ typedef struct XrHapticAmplitudeEnvelopeVibrationFB { #define XR_FB_scene 1 -#define XR_FB_scene_SPEC_VERSION 3 +#define XR_FB_scene_SPEC_VERSION 4 #define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene" typedef XrFlags64 XrSemanticLabelsSupportFlagsFB; // Flag bits for XrSemanticLabelsSupportFlagsFB static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB = 0x00000001; static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB = 0x00000002; +static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_INVISIBLE_WALL_FACE_BIT_FB = 0x00000004; typedef struct XrExtent3DfFB { float width; @@ -5612,6 +5630,7 @@ static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NOR static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB = 0x00000002; static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB = 0x00000004; static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB = 0x00000008; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_AUTO_LAYER_FILTER_BIT_META = 0x00000020; // XrCompositionLayerSettingsFB extends XrCompositionLayerBaseHeader typedef struct XrCompositionLayerSettingsFB { @@ -6115,7 +6134,7 @@ XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpaceUserFB( #define XR_META_headset_id 1 -#define XR_META_headset_id_SPEC_VERSION 1 +#define XR_META_headset_id_SPEC_VERSION 2 #define XR_META_HEADSET_ID_EXTENSION_NAME "XR_META_headset_id" // XrSystemHeadsetIdPropertiesMETA extends XrSystemProperties typedef struct XrSystemHeadsetIdPropertiesMETA { @@ -6126,6 +6145,35 @@ typedef struct XrSystemHeadsetIdPropertiesMETA { +#define XR_META_recommended_layer_resolution 1 +#define XR_META_recommended_layer_resolution_SPEC_VERSION 1 +#define XR_META_RECOMMENDED_LAYER_RESOLUTION_EXTENSION_NAME "XR_META_recommended_layer_resolution" +typedef struct XrRecommendedLayerResolutionMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrExtent2Di recommendedImageDimensions; + XrBool32 isValid; +} XrRecommendedLayerResolutionMETA; + +typedef struct XrRecommendedLayerResolutionGetInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const XrCompositionLayerBaseHeader* layer; + XrTime predictedDisplayTime; +} XrRecommendedLayerResolutionGetInfoMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrGetRecommendedLayerResolutionMETA)(XrSession session, const XrRecommendedLayerResolutionGetInfoMETA* info, XrRecommendedLayerResolutionMETA* resolution); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetRecommendedLayerResolutionMETA( + XrSession session, + const XrRecommendedLayerResolutionGetInfoMETA* info, + XrRecommendedLayerResolutionMETA* resolution); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_META_passthrough_color_lut 1 XR_DEFINE_HANDLE(XrPassthroughColorLutMETA) #define XR_META_passthrough_color_lut_SPEC_VERSION 1 @@ -6200,11 +6248,201 @@ XRAPI_ATTR XrResult XRAPI_CALL xrUpdatePassthroughColorLutMETA( #endif /* !XR_NO_PROTOTYPES */ +#define XR_META_spatial_entity_mesh 1 +#define XR_META_spatial_entity_mesh_SPEC_VERSION 1 +#define XR_META_SPATIAL_ENTITY_MESH_EXTENSION_NAME "XR_META_spatial_entity_mesh" +typedef struct XrSpaceTriangleMeshGetInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceTriangleMeshGetInfoMETA; + +typedef struct XrSpaceTriangleMeshMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSpaceTriangleMeshMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceTriangleMeshMETA)(XrSpace space, const XrSpaceTriangleMeshGetInfoMETA* getInfo, XrSpaceTriangleMeshMETA* triangleMeshOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceTriangleMeshMETA( + XrSpace space, + const XrSpaceTriangleMeshGetInfoMETA* getInfo, + XrSpaceTriangleMeshMETA* triangleMeshOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_META_automatic_layer_filter 1 +#define XR_META_automatic_layer_filter_SPEC_VERSION 1 +#define XR_META_AUTOMATIC_LAYER_FILTER_EXTENSION_NAME "XR_META_automatic_layer_filter" + + #define XR_META_touch_controller_plus 1 #define XR_META_touch_controller_plus_SPEC_VERSION 1 #define XR_META_TOUCH_CONTROLLER_PLUS_EXTENSION_NAME "XR_META_touch_controller_plus" +#define XR_FB_face_tracking2 1 +XR_DEFINE_HANDLE(XrFaceTracker2FB) +#define XR_FB_face_tracking2_SPEC_VERSION 1 +#define XR_FB_FACE_TRACKING2_EXTENSION_NAME "XR_FB_face_tracking2" + +typedef enum XrFaceExpression2FB { + XR_FACE_EXPRESSION2_BROW_LOWERER_L_FB = 0, + XR_FACE_EXPRESSION2_BROW_LOWERER_R_FB = 1, + XR_FACE_EXPRESSION2_CHEEK_PUFF_L_FB = 2, + XR_FACE_EXPRESSION2_CHEEK_PUFF_R_FB = 3, + XR_FACE_EXPRESSION2_CHEEK_RAISER_L_FB = 4, + XR_FACE_EXPRESSION2_CHEEK_RAISER_R_FB = 5, + XR_FACE_EXPRESSION2_CHEEK_SUCK_L_FB = 6, + XR_FACE_EXPRESSION2_CHEEK_SUCK_R_FB = 7, + XR_FACE_EXPRESSION2_CHIN_RAISER_B_FB = 8, + XR_FACE_EXPRESSION2_CHIN_RAISER_T_FB = 9, + XR_FACE_EXPRESSION2_DIMPLER_L_FB = 10, + XR_FACE_EXPRESSION2_DIMPLER_R_FB = 11, + XR_FACE_EXPRESSION2_EYES_CLOSED_L_FB = 12, + XR_FACE_EXPRESSION2_EYES_CLOSED_R_FB = 13, + XR_FACE_EXPRESSION2_EYES_LOOK_DOWN_L_FB = 14, + XR_FACE_EXPRESSION2_EYES_LOOK_DOWN_R_FB = 15, + XR_FACE_EXPRESSION2_EYES_LOOK_LEFT_L_FB = 16, + XR_FACE_EXPRESSION2_EYES_LOOK_LEFT_R_FB = 17, + XR_FACE_EXPRESSION2_EYES_LOOK_RIGHT_L_FB = 18, + XR_FACE_EXPRESSION2_EYES_LOOK_RIGHT_R_FB = 19, + XR_FACE_EXPRESSION2_EYES_LOOK_UP_L_FB = 20, + XR_FACE_EXPRESSION2_EYES_LOOK_UP_R_FB = 21, + XR_FACE_EXPRESSION2_INNER_BROW_RAISER_L_FB = 22, + XR_FACE_EXPRESSION2_INNER_BROW_RAISER_R_FB = 23, + XR_FACE_EXPRESSION2_JAW_DROP_FB = 24, + XR_FACE_EXPRESSION2_JAW_SIDEWAYS_LEFT_FB = 25, + XR_FACE_EXPRESSION2_JAW_SIDEWAYS_RIGHT_FB = 26, + XR_FACE_EXPRESSION2_JAW_THRUST_FB = 27, + XR_FACE_EXPRESSION2_LID_TIGHTENER_L_FB = 28, + XR_FACE_EXPRESSION2_LID_TIGHTENER_R_FB = 29, + XR_FACE_EXPRESSION2_LIP_CORNER_DEPRESSOR_L_FB = 30, + XR_FACE_EXPRESSION2_LIP_CORNER_DEPRESSOR_R_FB = 31, + XR_FACE_EXPRESSION2_LIP_CORNER_PULLER_L_FB = 32, + XR_FACE_EXPRESSION2_LIP_CORNER_PULLER_R_FB = 33, + XR_FACE_EXPRESSION2_LIP_FUNNELER_LB_FB = 34, + XR_FACE_EXPRESSION2_LIP_FUNNELER_LT_FB = 35, + XR_FACE_EXPRESSION2_LIP_FUNNELER_RB_FB = 36, + XR_FACE_EXPRESSION2_LIP_FUNNELER_RT_FB = 37, + XR_FACE_EXPRESSION2_LIP_PRESSOR_L_FB = 38, + XR_FACE_EXPRESSION2_LIP_PRESSOR_R_FB = 39, + XR_FACE_EXPRESSION2_LIP_PUCKER_L_FB = 40, + XR_FACE_EXPRESSION2_LIP_PUCKER_R_FB = 41, + XR_FACE_EXPRESSION2_LIP_STRETCHER_L_FB = 42, + XR_FACE_EXPRESSION2_LIP_STRETCHER_R_FB = 43, + XR_FACE_EXPRESSION2_LIP_SUCK_LB_FB = 44, + XR_FACE_EXPRESSION2_LIP_SUCK_LT_FB = 45, + XR_FACE_EXPRESSION2_LIP_SUCK_RB_FB = 46, + XR_FACE_EXPRESSION2_LIP_SUCK_RT_FB = 47, + XR_FACE_EXPRESSION2_LIP_TIGHTENER_L_FB = 48, + XR_FACE_EXPRESSION2_LIP_TIGHTENER_R_FB = 49, + XR_FACE_EXPRESSION2_LIPS_TOWARD_FB = 50, + XR_FACE_EXPRESSION2_LOWER_LIP_DEPRESSOR_L_FB = 51, + XR_FACE_EXPRESSION2_LOWER_LIP_DEPRESSOR_R_FB = 52, + XR_FACE_EXPRESSION2_MOUTH_LEFT_FB = 53, + XR_FACE_EXPRESSION2_MOUTH_RIGHT_FB = 54, + XR_FACE_EXPRESSION2_NOSE_WRINKLER_L_FB = 55, + XR_FACE_EXPRESSION2_NOSE_WRINKLER_R_FB = 56, + XR_FACE_EXPRESSION2_OUTER_BROW_RAISER_L_FB = 57, + XR_FACE_EXPRESSION2_OUTER_BROW_RAISER_R_FB = 58, + XR_FACE_EXPRESSION2_UPPER_LID_RAISER_L_FB = 59, + XR_FACE_EXPRESSION2_UPPER_LID_RAISER_R_FB = 60, + XR_FACE_EXPRESSION2_UPPER_LIP_RAISER_L_FB = 61, + XR_FACE_EXPRESSION2_UPPER_LIP_RAISER_R_FB = 62, + XR_FACE_EXPRESSION2_TONGUE_TIP_INTERDENTAL_FB = 63, + XR_FACE_EXPRESSION2_TONGUE_TIP_ALVEOLAR_FB = 64, + XR_FACE_EXPRESSION2_TONGUE_FRONT_DORSAL_PALATE_FB = 65, + XR_FACE_EXPRESSION2_TONGUE_MID_DORSAL_PALATE_FB = 66, + XR_FACE_EXPRESSION2_TONGUE_BACK_DORSAL_VELAR_FB = 67, + XR_FACE_EXPRESSION2_TONGUE_OUT_FB = 68, + XR_FACE_EXPRESSION2_TONGUE_RETREAT_FB = 69, + XR_FACE_EXPRESSION2_COUNT_FB = 70, + XR_FACE_EXPRESSION_2FB_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceExpression2FB; + +typedef enum XrFaceExpressionSet2FB { + XR_FACE_EXPRESSION_SET2_DEFAULT_FB = 0, + XR_FACE_EXPRESSION_SET_2FB_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceExpressionSet2FB; + +typedef enum XrFaceTrackingDataSource2FB { + XR_FACE_TRACKING_DATA_SOURCE2_VISUAL_FB = 0, + XR_FACE_TRACKING_DATA_SOURCE2_AUDIO_FB = 1, + XR_FACE_TRACKING_DATA_SOURCE_2FB_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceTrackingDataSource2FB; + +typedef enum XrFaceConfidence2FB { + XR_FACE_CONFIDENCE2_LOWER_FACE_FB = 0, + XR_FACE_CONFIDENCE2_UPPER_FACE_FB = 1, + XR_FACE_CONFIDENCE2_COUNT_FB = 2, + XR_FACE_CONFIDENCE_2FB_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceConfidence2FB; +// XrSystemFaceTrackingProperties2FB extends XrSystemProperties +typedef struct XrSystemFaceTrackingProperties2FB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsVisualFaceTracking; + XrBool32 supportsAudioFaceTracking; +} XrSystemFaceTrackingProperties2FB; + +typedef struct XrFaceTrackerCreateInfo2FB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFaceExpressionSet2FB faceExpressionSet; + uint32_t requestedDataSourceCount; + XrFaceTrackingDataSource2FB* requestedDataSources; +} XrFaceTrackerCreateInfo2FB; + +typedef struct XrFaceExpressionInfo2FB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime time; +} XrFaceExpressionInfo2FB; + +typedef struct XrFaceExpressionWeights2FB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t weightCount; + float* weights; + uint32_t confidenceCount; + float* confidences; + XrBool32 isValid; + XrBool32 isEyeFollowingBlendshapesValid; + XrFaceTrackingDataSource2FB dataSource; + XrTime time; +} XrFaceExpressionWeights2FB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFaceTracker2FB)(XrSession session, const XrFaceTrackerCreateInfo2FB* createInfo, XrFaceTracker2FB* faceTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFaceTracker2FB)(XrFaceTracker2FB faceTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFaceExpressionWeights2FB)(XrFaceTracker2FB faceTracker, const XrFaceExpressionInfo2FB* expressionInfo, XrFaceExpressionWeights2FB* expressionWeights); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFaceTracker2FB( + XrSession session, + const XrFaceTrackerCreateInfo2FB* createInfo, + XrFaceTracker2FB* faceTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFaceTracker2FB( + XrFaceTracker2FB faceTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFaceExpressionWeights2FB( + XrFaceTracker2FB faceTracker, + const XrFaceExpressionInfo2FB* expressionInfo, + XrFaceExpressionWeights2FB* expressionWeights); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + #define XR_EXT_uuid 1 #define XR_EXT_uuid_SPEC_VERSION 1 #define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" @@ -6667,6 +6905,25 @@ XRAPI_ATTR XrResult XRAPI_CALL xrGetPlanePolygonBufferEXT( #define XR_OPPO_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_OPPO_controller_interaction" +#define XR_EXT_user_presence 1 +#define XR_EXT_user_presence_SPEC_VERSION 1 +#define XR_EXT_USER_PRESENCE_EXTENSION_NAME "XR_EXT_user_presence" +typedef struct XrEventDataUserPresenceChangedEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrBool32 isUserPresent; +} XrEventDataUserPresenceChangedEXT; + +// XrSystemUserPresencePropertiesEXT extends XrSystemProperties +typedef struct XrSystemUserPresencePropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsUserPresence; +} XrSystemUserPresencePropertiesEXT; + + + #define XR_ML_user_calibration 1 #define XR_ML_user_calibration_SPEC_VERSION 1 #define XR_ML_USER_CALIBRATION_EXTENSION_NAME "XR_ML_user_calibration" diff --git a/thirdparty/openxr/include/openxr/openxr_reflection.h b/thirdparty/openxr/include/openxr/openxr_reflection.h index f6d66363bf..b449c7099b 100644 --- a/thirdparty/openxr/include/openxr/openxr_reflection.h +++ b/thirdparty/openxr/include/openxr/openxr_reflection.h @@ -444,11 +444,19 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB, 1000238001) \ _(XR_TYPE_SPACE_USER_CREATE_INFO_FB, 1000241001) \ _(XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META, 1000245000) \ + _(XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_META, 1000254000) \ + _(XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_GET_INFO_META, 1000254001) \ _(XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META, 1000266000) \ _(XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META, 1000266001) \ _(XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META, 1000266002) \ _(XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META, 1000266100) \ _(XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META, 1000266101) \ + _(XR_TYPE_SPACE_TRIANGLE_MESH_GET_INFO_META, 1000269001) \ + _(XR_TYPE_SPACE_TRIANGLE_MESH_META, 1000269002) \ + _(XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES2_FB, 1000287013) \ + _(XR_TYPE_FACE_TRACKER_CREATE_INFO2_FB, 1000287014) \ + _(XR_TYPE_FACE_EXPRESSION_INFO2_FB, 1000287015) \ + _(XR_TYPE_FACE_EXPRESSION_WEIGHTS2_FB, 1000287016) \ _(XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, 1000317001) \ _(XR_TYPE_PASSTHROUGH_COLOR_HTC, 1000317002) \ _(XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC, 1000317003) \ @@ -470,6 +478,8 @@ XR_ENUM_STR(XrResult); _(XR_TYPE_PLANE_DETECTOR_LOCATION_EXT, 1000429005) \ _(XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT, 1000429006) \ _(XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT, 1000429007) \ + _(XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT, 1000470000) \ + _(XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT, 1000470001) \ _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) #define XR_LIST_ENUM_XrFormFactor(_) \ @@ -555,6 +565,7 @@ XR_ENUM_STR(XrResult); _(XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META, 1000219000) \ _(XR_OBJECT_TYPE_SPACE_USER_FB, 1000241000) \ _(XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META, 1000266000) \ + _(XR_OBJECT_TYPE_FACE_TRACKER2_FB, 1000287012) \ _(XR_OBJECT_TYPE_PASSTHROUGH_HTC, 1000317000) \ _(XR_OBJECT_TYPE_PLANE_DETECTOR_EXT, 1000429000) \ _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) @@ -891,6 +902,7 @@ XR_ENUM_STR(XrResult); _(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \ _(XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB, 6) \ _(XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB, 7) \ + _(XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META, 1000269000) \ _(XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB, 0x7FFFFFFF) #define XR_LIST_ENUM_XrFoveationLevelFB(_) \ @@ -1209,6 +1221,95 @@ XR_ENUM_STR(XrResult); _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGBA_META, 2) \ _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_MAX_ENUM_META, 0x7FFFFFFF) +#define XR_LIST_ENUM_XrFaceExpression2FB(_) \ + _(XR_FACE_EXPRESSION2_BROW_LOWERER_L_FB, 0) \ + _(XR_FACE_EXPRESSION2_BROW_LOWERER_R_FB, 1) \ + _(XR_FACE_EXPRESSION2_CHEEK_PUFF_L_FB, 2) \ + _(XR_FACE_EXPRESSION2_CHEEK_PUFF_R_FB, 3) \ + _(XR_FACE_EXPRESSION2_CHEEK_RAISER_L_FB, 4) \ + _(XR_FACE_EXPRESSION2_CHEEK_RAISER_R_FB, 5) \ + _(XR_FACE_EXPRESSION2_CHEEK_SUCK_L_FB, 6) \ + _(XR_FACE_EXPRESSION2_CHEEK_SUCK_R_FB, 7) \ + _(XR_FACE_EXPRESSION2_CHIN_RAISER_B_FB, 8) \ + _(XR_FACE_EXPRESSION2_CHIN_RAISER_T_FB, 9) \ + _(XR_FACE_EXPRESSION2_DIMPLER_L_FB, 10) \ + _(XR_FACE_EXPRESSION2_DIMPLER_R_FB, 11) \ + _(XR_FACE_EXPRESSION2_EYES_CLOSED_L_FB, 12) \ + _(XR_FACE_EXPRESSION2_EYES_CLOSED_R_FB, 13) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_DOWN_L_FB, 14) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_DOWN_R_FB, 15) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_LEFT_L_FB, 16) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_LEFT_R_FB, 17) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_RIGHT_L_FB, 18) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_RIGHT_R_FB, 19) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_UP_L_FB, 20) \ + _(XR_FACE_EXPRESSION2_EYES_LOOK_UP_R_FB, 21) \ + _(XR_FACE_EXPRESSION2_INNER_BROW_RAISER_L_FB, 22) \ + _(XR_FACE_EXPRESSION2_INNER_BROW_RAISER_R_FB, 23) \ + _(XR_FACE_EXPRESSION2_JAW_DROP_FB, 24) \ + _(XR_FACE_EXPRESSION2_JAW_SIDEWAYS_LEFT_FB, 25) \ + _(XR_FACE_EXPRESSION2_JAW_SIDEWAYS_RIGHT_FB, 26) \ + _(XR_FACE_EXPRESSION2_JAW_THRUST_FB, 27) \ + _(XR_FACE_EXPRESSION2_LID_TIGHTENER_L_FB, 28) \ + _(XR_FACE_EXPRESSION2_LID_TIGHTENER_R_FB, 29) \ + _(XR_FACE_EXPRESSION2_LIP_CORNER_DEPRESSOR_L_FB, 30) \ + _(XR_FACE_EXPRESSION2_LIP_CORNER_DEPRESSOR_R_FB, 31) \ + _(XR_FACE_EXPRESSION2_LIP_CORNER_PULLER_L_FB, 32) \ + _(XR_FACE_EXPRESSION2_LIP_CORNER_PULLER_R_FB, 33) \ + _(XR_FACE_EXPRESSION2_LIP_FUNNELER_LB_FB, 34) \ + _(XR_FACE_EXPRESSION2_LIP_FUNNELER_LT_FB, 35) \ + _(XR_FACE_EXPRESSION2_LIP_FUNNELER_RB_FB, 36) \ + _(XR_FACE_EXPRESSION2_LIP_FUNNELER_RT_FB, 37) \ + _(XR_FACE_EXPRESSION2_LIP_PRESSOR_L_FB, 38) \ + _(XR_FACE_EXPRESSION2_LIP_PRESSOR_R_FB, 39) \ + _(XR_FACE_EXPRESSION2_LIP_PUCKER_L_FB, 40) \ + _(XR_FACE_EXPRESSION2_LIP_PUCKER_R_FB, 41) \ + _(XR_FACE_EXPRESSION2_LIP_STRETCHER_L_FB, 42) \ + _(XR_FACE_EXPRESSION2_LIP_STRETCHER_R_FB, 43) \ + _(XR_FACE_EXPRESSION2_LIP_SUCK_LB_FB, 44) \ + _(XR_FACE_EXPRESSION2_LIP_SUCK_LT_FB, 45) \ + _(XR_FACE_EXPRESSION2_LIP_SUCK_RB_FB, 46) \ + _(XR_FACE_EXPRESSION2_LIP_SUCK_RT_FB, 47) \ + _(XR_FACE_EXPRESSION2_LIP_TIGHTENER_L_FB, 48) \ + _(XR_FACE_EXPRESSION2_LIP_TIGHTENER_R_FB, 49) \ + _(XR_FACE_EXPRESSION2_LIPS_TOWARD_FB, 50) \ + _(XR_FACE_EXPRESSION2_LOWER_LIP_DEPRESSOR_L_FB, 51) \ + _(XR_FACE_EXPRESSION2_LOWER_LIP_DEPRESSOR_R_FB, 52) \ + _(XR_FACE_EXPRESSION2_MOUTH_LEFT_FB, 53) \ + _(XR_FACE_EXPRESSION2_MOUTH_RIGHT_FB, 54) \ + _(XR_FACE_EXPRESSION2_NOSE_WRINKLER_L_FB, 55) \ + _(XR_FACE_EXPRESSION2_NOSE_WRINKLER_R_FB, 56) \ + _(XR_FACE_EXPRESSION2_OUTER_BROW_RAISER_L_FB, 57) \ + _(XR_FACE_EXPRESSION2_OUTER_BROW_RAISER_R_FB, 58) \ + _(XR_FACE_EXPRESSION2_UPPER_LID_RAISER_L_FB, 59) \ + _(XR_FACE_EXPRESSION2_UPPER_LID_RAISER_R_FB, 60) \ + _(XR_FACE_EXPRESSION2_UPPER_LIP_RAISER_L_FB, 61) \ + _(XR_FACE_EXPRESSION2_UPPER_LIP_RAISER_R_FB, 62) \ + _(XR_FACE_EXPRESSION2_TONGUE_TIP_INTERDENTAL_FB, 63) \ + _(XR_FACE_EXPRESSION2_TONGUE_TIP_ALVEOLAR_FB, 64) \ + _(XR_FACE_EXPRESSION2_TONGUE_FRONT_DORSAL_PALATE_FB, 65) \ + _(XR_FACE_EXPRESSION2_TONGUE_MID_DORSAL_PALATE_FB, 66) \ + _(XR_FACE_EXPRESSION2_TONGUE_BACK_DORSAL_VELAR_FB, 67) \ + _(XR_FACE_EXPRESSION2_TONGUE_OUT_FB, 68) \ + _(XR_FACE_EXPRESSION2_TONGUE_RETREAT_FB, 69) \ + _(XR_FACE_EXPRESSION2_COUNT_FB, 70) \ + _(XR_FACE_EXPRESSION_2FB_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceExpressionSet2FB(_) \ + _(XR_FACE_EXPRESSION_SET2_DEFAULT_FB, 0) \ + _(XR_FACE_EXPRESSION_SET_2FB_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceTrackingDataSource2FB(_) \ + _(XR_FACE_TRACKING_DATA_SOURCE2_VISUAL_FB, 0) \ + _(XR_FACE_TRACKING_DATA_SOURCE2_AUDIO_FB, 1) \ + _(XR_FACE_TRACKING_DATA_SOURCE_2FB_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceConfidence2FB(_) \ + _(XR_FACE_CONFIDENCE2_LOWER_FACE_FB, 0) \ + _(XR_FACE_CONFIDENCE2_UPPER_FACE_FB, 1) \ + _(XR_FACE_CONFIDENCE2_COUNT_FB, 2) \ + _(XR_FACE_CONFIDENCE_2FB_MAX_ENUM_FB, 0x7FFFFFFF) + #define XR_LIST_ENUM_XrTrackingOptimizationSettingsDomainQCOM(_) \ _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_ALL_QCOM, 1) \ _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_MAX_ENUM_QCOM, 0x7FFFFFFF) @@ -1437,6 +1538,7 @@ XR_ENUM_STR(XrResult); #define XR_LIST_BITS_XrSemanticLabelsSupportFlagsFB(_) \ _(XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB, 0x00000001) \ _(XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB, 0x00000002) \ + _(XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_INVISIBLE_WALL_FACE_BIT_FB, 0x00000004) \ #define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ @@ -1451,6 +1553,7 @@ XR_ENUM_STR(XrResult); _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \ _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \ _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \ + _(XR_COMPOSITION_LAYER_SETTINGS_AUTO_LAYER_FILTER_BIT_META, 0x00000020) \ #define XR_LIST_BITS_XrPassthroughPreferenceFlagsMETA(_) \ _(XR_PASSTHROUGH_PREFERENCE_DEFAULT_TO_ACTIVE_BIT_META, 0x00000001) \ @@ -4141,6 +4244,20 @@ XR_ENUM_STR(XrResult); _(next) \ _(id) \ +/// Calls your macro with the name of each member of XrRecommendedLayerResolutionMETA, in order. +#define XR_LIST_STRUCT_XrRecommendedLayerResolutionMETA(_) \ + _(type) \ + _(next) \ + _(recommendedImageDimensions) \ + _(isValid) \ + +/// Calls your macro with the name of each member of XrRecommendedLayerResolutionGetInfoMETA, in order. +#define XR_LIST_STRUCT_XrRecommendedLayerResolutionGetInfoMETA(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(predictedDisplayTime) \ + /// Calls your macro with the name of each member of XrPassthroughColorLutDataMETA, in order. #define XR_LIST_STRUCT_XrPassthroughColorLutDataMETA(_) \ _(bufferSize) \ @@ -4181,6 +4298,56 @@ XR_ENUM_STR(XrResult); _(next) \ _(maxColorLutResolution) \ +/// Calls your macro with the name of each member of XrSpaceTriangleMeshGetInfoMETA, in order. +#define XR_LIST_STRUCT_XrSpaceTriangleMeshGetInfoMETA(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSpaceTriangleMeshMETA, in order. +#define XR_LIST_STRUCT_XrSpaceTriangleMeshMETA(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrSystemFaceTrackingProperties2FB, in order. +#define XR_LIST_STRUCT_XrSystemFaceTrackingProperties2FB(_) \ + _(type) \ + _(next) \ + _(supportsVisualFaceTracking) \ + _(supportsAudioFaceTracking) \ + +/// Calls your macro with the name of each member of XrFaceTrackerCreateInfo2FB, in order. +#define XR_LIST_STRUCT_XrFaceTrackerCreateInfo2FB(_) \ + _(type) \ + _(next) \ + _(faceExpressionSet) \ + _(requestedDataSourceCount) \ + _(requestedDataSources) \ + +/// Calls your macro with the name of each member of XrFaceExpressionInfo2FB, in order. +#define XR_LIST_STRUCT_XrFaceExpressionInfo2FB(_) \ + _(type) \ + _(next) \ + _(time) \ + +/// Calls your macro with the name of each member of XrFaceExpressionWeights2FB, in order. +#define XR_LIST_STRUCT_XrFaceExpressionWeights2FB(_) \ + _(type) \ + _(next) \ + _(weightCount) \ + _(weights) \ + _(confidenceCount) \ + _(confidences) \ + _(isValid) \ + _(isEyeFollowingBlendshapesValid) \ + _(dataSource) \ + _(time) \ + /// Calls your macro with the name of each member of XrPassthroughCreateInfoHTC, in order. #define XR_LIST_STRUCT_XrPassthroughCreateInfoHTC(_) \ _(type) \ @@ -4372,6 +4539,19 @@ XR_ENUM_STR(XrResult); _(vertexCountOutput) \ _(vertices) \ +/// Calls your macro with the name of each member of XrEventDataUserPresenceChangedEXT, in order. +#define XR_LIST_STRUCT_XrEventDataUserPresenceChangedEXT(_) \ + _(type) \ + _(next) \ + _(session) \ + _(isUserPresent) \ + +/// Calls your macro with the name of each member of XrSystemUserPresencePropertiesEXT, in order. +#define XR_LIST_STRUCT_XrSystemUserPresencePropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsUserPresence) \ + /// Calls your macro with the name of each member of XrEventDataHeadsetFitChangedML, in order. #define XR_LIST_STRUCT_XrEventDataHeadsetFitChangedML(_) \ _(type) \ @@ -4680,11 +4860,19 @@ XR_ENUM_STR(XrResult); _(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \ _(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \ _(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \ + _(XrRecommendedLayerResolutionMETA, XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_META) \ + _(XrRecommendedLayerResolutionGetInfoMETA, XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_GET_INFO_META) \ _(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \ _(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \ _(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \ _(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \ _(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \ + _(XrSpaceTriangleMeshGetInfoMETA, XR_TYPE_SPACE_TRIANGLE_MESH_GET_INFO_META) \ + _(XrSpaceTriangleMeshMETA, XR_TYPE_SPACE_TRIANGLE_MESH_META) \ + _(XrSystemFaceTrackingProperties2FB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES2_FB) \ + _(XrFaceTrackerCreateInfo2FB, XR_TYPE_FACE_TRACKER_CREATE_INFO2_FB) \ + _(XrFaceExpressionInfo2FB, XR_TYPE_FACE_EXPRESSION_INFO2_FB) \ + _(XrFaceExpressionWeights2FB, XR_TYPE_FACE_EXPRESSION_WEIGHTS2_FB) \ _(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \ _(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \ _(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \ @@ -4706,6 +4894,8 @@ XR_ENUM_STR(XrResult); _(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \ _(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \ _(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \ + _(XrEventDataUserPresenceChangedEXT, XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT) \ + _(XrSystemUserPresencePropertiesEXT, XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT) \ _(XrEventDataHeadsetFitChangedML, XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML) \ _(XrEventDataEyeCalibrationChangedML, XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML) \ _(XrUserCalibrationEnableEventsInfoML, XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML) \ @@ -4960,6 +5150,7 @@ XR_ENUM_STR(XrResult); _(XR_VARJO_environment_depth_estimation, 124) \ _(XR_VARJO_marker_tracking, 125) \ _(XR_VARJO_view_offset, 126) \ + _(XR_VARJO_xr4_controller_interaction, 130) \ _(XR_ML_ml2_controller_interaction, 135) \ _(XR_ML_frame_end_info, 136) \ _(XR_ML_global_dimmer, 137) \ @@ -5003,8 +5194,12 @@ XR_ENUM_STR(XrResult); _(XR_FB_spatial_entity_storage_batch, 239) \ _(XR_FB_spatial_entity_user, 242) \ _(XR_META_headset_id, 246) \ + _(XR_META_recommended_layer_resolution, 255) \ _(XR_META_passthrough_color_lut, 267) \ + _(XR_META_spatial_entity_mesh, 270) \ + _(XR_META_automatic_layer_filter, 272) \ _(XR_META_touch_controller_plus, 280) \ + _(XR_FB_face_tracking2, 288) \ _(XR_EXT_uuid, 300) \ _(XR_EXT_hand_interaction, 303) \ _(XR_QCOM_tracking_optimization_settings, 307) \ @@ -5018,9 +5213,830 @@ XR_ENUM_STR(XrResult); _(XR_EXT_hand_tracking_data_source, 429) \ _(XR_EXT_plane_detection, 430) \ _(XR_OPPO_controller_interaction, 454) \ + _(XR_EXT_user_presence, 471) \ _(XR_ML_user_calibration, 473) \ _(XR_YVR_controller_interaction, 498) \ + +/// For every function defined by XR_VERSION_1_0 in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_VERSION_1_0(_) \ + _(GetInstanceProcAddr, VERSION_1_0) \ + _(EnumerateApiLayerProperties, VERSION_1_0) \ + _(EnumerateInstanceExtensionProperties, VERSION_1_0) \ + _(CreateInstance, VERSION_1_0) \ + _(DestroyInstance, VERSION_1_0) \ + _(GetInstanceProperties, VERSION_1_0) \ + _(PollEvent, VERSION_1_0) \ + _(ResultToString, VERSION_1_0) \ + _(StructureTypeToString, VERSION_1_0) \ + _(GetSystem, VERSION_1_0) \ + _(GetSystemProperties, VERSION_1_0) \ + _(EnumerateEnvironmentBlendModes, VERSION_1_0) \ + _(CreateSession, VERSION_1_0) \ + _(DestroySession, VERSION_1_0) \ + _(EnumerateReferenceSpaces, VERSION_1_0) \ + _(CreateReferenceSpace, VERSION_1_0) \ + _(GetReferenceSpaceBoundsRect, VERSION_1_0) \ + _(CreateActionSpace, VERSION_1_0) \ + _(LocateSpace, VERSION_1_0) \ + _(DestroySpace, VERSION_1_0) \ + _(EnumerateViewConfigurations, VERSION_1_0) \ + _(GetViewConfigurationProperties, VERSION_1_0) \ + _(EnumerateViewConfigurationViews, VERSION_1_0) \ + _(EnumerateSwapchainFormats, VERSION_1_0) \ + _(CreateSwapchain, VERSION_1_0) \ + _(DestroySwapchain, VERSION_1_0) \ + _(EnumerateSwapchainImages, VERSION_1_0) \ + _(AcquireSwapchainImage, VERSION_1_0) \ + _(WaitSwapchainImage, VERSION_1_0) \ + _(ReleaseSwapchainImage, VERSION_1_0) \ + _(BeginSession, VERSION_1_0) \ + _(EndSession, VERSION_1_0) \ + _(RequestExitSession, VERSION_1_0) \ + _(WaitFrame, VERSION_1_0) \ + _(BeginFrame, VERSION_1_0) \ + _(EndFrame, VERSION_1_0) \ + _(LocateViews, VERSION_1_0) \ + _(StringToPath, VERSION_1_0) \ + _(PathToString, VERSION_1_0) \ + _(CreateActionSet, VERSION_1_0) \ + _(DestroyActionSet, VERSION_1_0) \ + _(CreateAction, VERSION_1_0) \ + _(DestroyAction, VERSION_1_0) \ + _(SuggestInteractionProfileBindings, VERSION_1_0) \ + _(AttachSessionActionSets, VERSION_1_0) \ + _(GetCurrentInteractionProfile, VERSION_1_0) \ + _(GetActionStateBoolean, VERSION_1_0) \ + _(GetActionStateFloat, VERSION_1_0) \ + _(GetActionStateVector2f, VERSION_1_0) \ + _(GetActionStatePose, VERSION_1_0) \ + _(SyncActions, VERSION_1_0) \ + _(EnumerateBoundSourcesForAction, VERSION_1_0) \ + _(GetInputSourceLocalizedName, VERSION_1_0) \ + _(ApplyHapticFeedback, VERSION_1_0) \ + _(StopHapticFeedback, VERSION_1_0) \ + + +/// For every function defined by XR_LOADER_VERSION_1_0 in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_LOADER_VERSION_1_0(_) \ + _(CreateApiLayerInstance, LOADER_VERSION_1_0) \ + _(NegotiateLoaderRuntimeInterface, LOADER_VERSION_1_0) \ + _(NegotiateLoaderApiLayerInterface, LOADER_VERSION_1_0) \ + + +/// For every function defined by XR_KHR_android_thread_settings in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_android_thread_settings(_) \ + _(SetAndroidApplicationThreadKHR, KHR_android_thread_settings) \ + + +/// For every function defined by XR_KHR_android_surface_swapchain in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_android_surface_swapchain(_) \ + _(CreateSwapchainAndroidSurfaceKHR, KHR_android_surface_swapchain) \ + + +/// For every function defined by XR_KHR_opengl_enable in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_opengl_enable(_) \ + _(GetOpenGLGraphicsRequirementsKHR, KHR_opengl_enable) \ + + +/// For every function defined by XR_KHR_opengl_es_enable in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_opengl_es_enable(_) \ + _(GetOpenGLESGraphicsRequirementsKHR, KHR_opengl_es_enable) \ + + +/// For every function defined by XR_KHR_vulkan_enable in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_vulkan_enable(_) \ + _(GetVulkanInstanceExtensionsKHR, KHR_vulkan_enable) \ + _(GetVulkanDeviceExtensionsKHR, KHR_vulkan_enable) \ + _(GetVulkanGraphicsDeviceKHR, KHR_vulkan_enable) \ + _(GetVulkanGraphicsRequirementsKHR, KHR_vulkan_enable) \ + + +/// For every function defined by XR_KHR_D3D11_enable in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_D3D11_enable(_) \ + _(GetD3D11GraphicsRequirementsKHR, KHR_D3D11_enable) \ + + +/// For every function defined by XR_KHR_D3D12_enable in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_D3D12_enable(_) \ + _(GetD3D12GraphicsRequirementsKHR, KHR_D3D12_enable) \ + + +/// For every function defined by XR_KHR_visibility_mask in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_visibility_mask(_) \ + _(GetVisibilityMaskKHR, KHR_visibility_mask) \ + + +/// For every function defined by XR_KHR_win32_convert_performance_counter_time in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_win32_convert_performance_counter_time(_) \ + _(ConvertWin32PerformanceCounterToTimeKHR, KHR_win32_convert_performance_counter_time) \ + _(ConvertTimeToWin32PerformanceCounterKHR, KHR_win32_convert_performance_counter_time) \ + + +/// For every function defined by XR_KHR_convert_timespec_time in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_convert_timespec_time(_) \ + _(ConvertTimespecTimeToTimeKHR, KHR_convert_timespec_time) \ + _(ConvertTimeToTimespecTimeKHR, KHR_convert_timespec_time) \ + + +/// For every function defined by XR_KHR_loader_init in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_loader_init(_) \ + _(InitializeLoaderKHR, KHR_loader_init) \ + + +/// For every function defined by XR_KHR_vulkan_enable2 in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_KHR_vulkan_enable2(_) \ + _(CreateVulkanInstanceKHR, KHR_vulkan_enable2) \ + _(CreateVulkanDeviceKHR, KHR_vulkan_enable2) \ + _(GetVulkanGraphicsDevice2KHR, KHR_vulkan_enable2) \ + + +/// For every function defined by XR_EXT_performance_settings in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_performance_settings(_) \ + _(PerfSettingsSetPerformanceLevelEXT, EXT_performance_settings) \ + + +/// For every function defined by XR_EXT_thermal_query in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_thermal_query(_) \ + _(ThermalGetTemperatureTrendEXT, EXT_thermal_query) \ + + +/// For every function defined by XR_EXT_debug_utils in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_debug_utils(_) \ + _(SetDebugUtilsObjectNameEXT, EXT_debug_utils) \ + _(CreateDebugUtilsMessengerEXT, EXT_debug_utils) \ + _(DestroyDebugUtilsMessengerEXT, EXT_debug_utils) \ + _(SubmitDebugUtilsMessageEXT, EXT_debug_utils) \ + _(SessionBeginDebugUtilsLabelRegionEXT, EXT_debug_utils) \ + _(SessionEndDebugUtilsLabelRegionEXT, EXT_debug_utils) \ + _(SessionInsertDebugUtilsLabelEXT, EXT_debug_utils) \ + + +/// For every function defined by XR_MSFT_spatial_anchor in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_spatial_anchor(_) \ + _(CreateSpatialAnchorMSFT, MSFT_spatial_anchor) \ + _(CreateSpatialAnchorSpaceMSFT, MSFT_spatial_anchor) \ + _(DestroySpatialAnchorMSFT, MSFT_spatial_anchor) \ + + +/// For every function defined by XR_EXT_conformance_automation in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_conformance_automation(_) \ + _(SetInputDeviceActiveEXT, EXT_conformance_automation) \ + _(SetInputDeviceStateBoolEXT, EXT_conformance_automation) \ + _(SetInputDeviceStateFloatEXT, EXT_conformance_automation) \ + _(SetInputDeviceStateVector2fEXT, EXT_conformance_automation) \ + _(SetInputDeviceLocationEXT, EXT_conformance_automation) \ + + +/// For every function defined by XR_MSFT_spatial_graph_bridge in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_spatial_graph_bridge(_) \ + _(CreateSpatialGraphNodeSpaceMSFT, MSFT_spatial_graph_bridge) \ + _(TryCreateSpatialGraphStaticNodeBindingMSFT, MSFT_spatial_graph_bridge) \ + _(DestroySpatialGraphNodeBindingMSFT, MSFT_spatial_graph_bridge) \ + _(GetSpatialGraphNodeBindingPropertiesMSFT, MSFT_spatial_graph_bridge) \ + + +/// For every function defined by XR_EXT_hand_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_hand_tracking(_) \ + _(CreateHandTrackerEXT, EXT_hand_tracking) \ + _(DestroyHandTrackerEXT, EXT_hand_tracking) \ + _(LocateHandJointsEXT, EXT_hand_tracking) \ + + +/// For every function defined by XR_MSFT_hand_tracking_mesh in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_hand_tracking_mesh(_) \ + _(CreateHandMeshSpaceMSFT, MSFT_hand_tracking_mesh) \ + _(UpdateHandMeshMSFT, MSFT_hand_tracking_mesh) \ + + +/// For every function defined by XR_MSFT_controller_model in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_controller_model(_) \ + _(GetControllerModelKeyMSFT, MSFT_controller_model) \ + _(LoadControllerModelMSFT, MSFT_controller_model) \ + _(GetControllerModelPropertiesMSFT, MSFT_controller_model) \ + _(GetControllerModelStateMSFT, MSFT_controller_model) \ + + +/// For every function defined by XR_MSFT_perception_anchor_interop in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_perception_anchor_interop(_) \ + _(CreateSpatialAnchorFromPerceptionAnchorMSFT, MSFT_perception_anchor_interop) \ + _(TryGetPerceptionAnchorFromSpatialAnchorMSFT, MSFT_perception_anchor_interop) \ + + +/// For every function defined by XR_MSFT_composition_layer_reprojection in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_composition_layer_reprojection(_) \ + _(EnumerateReprojectionModesMSFT, MSFT_composition_layer_reprojection) \ + + +/// For every function defined by XR_FB_swapchain_update_state in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_swapchain_update_state(_) \ + _(UpdateSwapchainFB, FB_swapchain_update_state) \ + _(GetSwapchainStateFB, FB_swapchain_update_state) \ + + +/// For every function defined by XR_FB_body_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_body_tracking(_) \ + _(CreateBodyTrackerFB, FB_body_tracking) \ + _(DestroyBodyTrackerFB, FB_body_tracking) \ + _(LocateBodyJointsFB, FB_body_tracking) \ + _(GetBodySkeletonFB, FB_body_tracking) \ + + +/// For every function defined by XR_MSFT_scene_understanding in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_scene_understanding(_) \ + _(EnumerateSceneComputeFeaturesMSFT, MSFT_scene_understanding) \ + _(CreateSceneObserverMSFT, MSFT_scene_understanding) \ + _(DestroySceneObserverMSFT, MSFT_scene_understanding) \ + _(CreateSceneMSFT, MSFT_scene_understanding) \ + _(DestroySceneMSFT, MSFT_scene_understanding) \ + _(ComputeNewSceneMSFT, MSFT_scene_understanding) \ + _(GetSceneComputeStateMSFT, MSFT_scene_understanding) \ + _(GetSceneComponentsMSFT, MSFT_scene_understanding) \ + _(LocateSceneComponentsMSFT, MSFT_scene_understanding) \ + _(GetSceneMeshBuffersMSFT, MSFT_scene_understanding) \ + + +/// For every function defined by XR_MSFT_scene_understanding_serialization in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_scene_understanding_serialization(_) \ + _(DeserializeSceneMSFT, MSFT_scene_understanding_serialization) \ + _(GetSerializedSceneFragmentDataMSFT, MSFT_scene_understanding_serialization) \ + + +/// For every function defined by XR_FB_display_refresh_rate in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_display_refresh_rate(_) \ + _(EnumerateDisplayRefreshRatesFB, FB_display_refresh_rate) \ + _(GetDisplayRefreshRateFB, FB_display_refresh_rate) \ + _(RequestDisplayRefreshRateFB, FB_display_refresh_rate) \ + + +/// For every function defined by XR_HTCX_vive_tracker_interaction in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_HTCX_vive_tracker_interaction(_) \ + _(EnumerateViveTrackerPathsHTCX, HTCX_vive_tracker_interaction) \ + + +/// For every function defined by XR_HTC_facial_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_HTC_facial_tracking(_) \ + _(CreateFacialTrackerHTC, HTC_facial_tracking) \ + _(DestroyFacialTrackerHTC, HTC_facial_tracking) \ + _(GetFacialExpressionsHTC, HTC_facial_tracking) \ + + +/// For every function defined by XR_FB_color_space in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_color_space(_) \ + _(EnumerateColorSpacesFB, FB_color_space) \ + _(SetColorSpaceFB, FB_color_space) \ + + +/// For every function defined by XR_FB_hand_tracking_mesh in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_hand_tracking_mesh(_) \ + _(GetHandMeshFB, FB_hand_tracking_mesh) \ + + +/// For every function defined by XR_FB_spatial_entity in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity(_) \ + _(CreateSpatialAnchorFB, FB_spatial_entity) \ + _(GetSpaceUuidFB, FB_spatial_entity) \ + _(EnumerateSpaceSupportedComponentsFB, FB_spatial_entity) \ + _(SetSpaceComponentStatusFB, FB_spatial_entity) \ + _(GetSpaceComponentStatusFB, FB_spatial_entity) \ + + +/// For every function defined by XR_FB_foveation in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_foveation(_) \ + _(CreateFoveationProfileFB, FB_foveation) \ + _(DestroyFoveationProfileFB, FB_foveation) \ + + +/// For every function defined by XR_FB_keyboard_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_keyboard_tracking(_) \ + _(QuerySystemTrackedKeyboardFB, FB_keyboard_tracking) \ + _(CreateKeyboardSpaceFB, FB_keyboard_tracking) \ + + +/// For every function defined by XR_FB_triangle_mesh in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_triangle_mesh(_) \ + _(CreateTriangleMeshFB, FB_triangle_mesh) \ + _(DestroyTriangleMeshFB, FB_triangle_mesh) \ + _(TriangleMeshGetVertexBufferFB, FB_triangle_mesh) \ + _(TriangleMeshGetIndexBufferFB, FB_triangle_mesh) \ + _(TriangleMeshBeginUpdateFB, FB_triangle_mesh) \ + _(TriangleMeshEndUpdateFB, FB_triangle_mesh) \ + _(TriangleMeshBeginVertexBufferUpdateFB, FB_triangle_mesh) \ + _(TriangleMeshEndVertexBufferUpdateFB, FB_triangle_mesh) \ + + +/// For every function defined by XR_FB_passthrough in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_passthrough(_) \ + _(CreatePassthroughFB, FB_passthrough) \ + _(DestroyPassthroughFB, FB_passthrough) \ + _(PassthroughStartFB, FB_passthrough) \ + _(PassthroughPauseFB, FB_passthrough) \ + _(CreatePassthroughLayerFB, FB_passthrough) \ + _(DestroyPassthroughLayerFB, FB_passthrough) \ + _(PassthroughLayerPauseFB, FB_passthrough) \ + _(PassthroughLayerResumeFB, FB_passthrough) \ + _(PassthroughLayerSetStyleFB, FB_passthrough) \ + _(CreateGeometryInstanceFB, FB_passthrough) \ + _(DestroyGeometryInstanceFB, FB_passthrough) \ + _(GeometryInstanceSetTransformFB, FB_passthrough) \ + + +/// For every function defined by XR_FB_render_model in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_render_model(_) \ + _(EnumerateRenderModelPathsFB, FB_render_model) \ + _(GetRenderModelPropertiesFB, FB_render_model) \ + _(LoadRenderModelFB, FB_render_model) \ + + +/// For every function defined by XR_VARJO_environment_depth_estimation in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_VARJO_environment_depth_estimation(_) \ + _(SetEnvironmentDepthEstimationVARJO, VARJO_environment_depth_estimation) \ + + +/// For every function defined by XR_VARJO_marker_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_VARJO_marker_tracking(_) \ + _(SetMarkerTrackingVARJO, VARJO_marker_tracking) \ + _(SetMarkerTrackingTimeoutVARJO, VARJO_marker_tracking) \ + _(SetMarkerTrackingPredictionVARJO, VARJO_marker_tracking) \ + _(GetMarkerSizeVARJO, VARJO_marker_tracking) \ + _(CreateMarkerSpaceVARJO, VARJO_marker_tracking) \ + + +/// For every function defined by XR_VARJO_view_offset in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_VARJO_view_offset(_) \ + _(SetViewOffsetVARJO, VARJO_view_offset) \ + + +/// For every function defined by XR_ML_compat in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_ML_compat(_) \ + _(CreateSpaceFromCoordinateFrameUIDML, ML_compat) \ + + +/// For every function defined by XR_ML_marker_understanding in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_ML_marker_understanding(_) \ + _(CreateMarkerDetectorML, ML_marker_understanding) \ + _(DestroyMarkerDetectorML, ML_marker_understanding) \ + _(SnapshotMarkerDetectorML, ML_marker_understanding) \ + _(GetMarkerDetectorStateML, ML_marker_understanding) \ + _(GetMarkersML, ML_marker_understanding) \ + _(GetMarkerReprojectionErrorML, ML_marker_understanding) \ + _(GetMarkerLengthML, ML_marker_understanding) \ + _(GetMarkerNumberML, ML_marker_understanding) \ + _(GetMarkerStringML, ML_marker_understanding) \ + _(CreateMarkerSpaceML, ML_marker_understanding) \ + + +/// For every function defined by XR_ML_localization_map in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_ML_localization_map(_) \ + _(EnableLocalizationEventsML, ML_localization_map) \ + _(QueryLocalizationMapsML, ML_localization_map) \ + _(RequestMapLocalizationML, ML_localization_map) \ + _(ImportLocalizationMapML, ML_localization_map) \ + _(CreateExportedLocalizationMapML, ML_localization_map) \ + _(DestroyExportedLocalizationMapML, ML_localization_map) \ + _(GetExportedLocalizationMapDataML, ML_localization_map) \ + + +/// For every function defined by XR_MSFT_spatial_anchor_persistence in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_spatial_anchor_persistence(_) \ + _(CreateSpatialAnchorStoreConnectionMSFT, MSFT_spatial_anchor_persistence) \ + _(DestroySpatialAnchorStoreConnectionMSFT, MSFT_spatial_anchor_persistence) \ + _(PersistSpatialAnchorMSFT, MSFT_spatial_anchor_persistence) \ + _(EnumeratePersistedSpatialAnchorNamesMSFT, MSFT_spatial_anchor_persistence) \ + _(CreateSpatialAnchorFromPersistedNameMSFT, MSFT_spatial_anchor_persistence) \ + _(UnpersistSpatialAnchorMSFT, MSFT_spatial_anchor_persistence) \ + _(ClearSpatialAnchorStoreMSFT, MSFT_spatial_anchor_persistence) \ + + +/// For every function defined by XR_MSFT_scene_marker in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MSFT_scene_marker(_) \ + _(GetSceneMarkerRawDataMSFT, MSFT_scene_marker) \ + _(GetSceneMarkerDecodedStringMSFT, MSFT_scene_marker) \ + + +/// For every function defined by XR_FB_spatial_entity_query in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_query(_) \ + _(QuerySpacesFB, FB_spatial_entity_query) \ + _(RetrieveSpaceQueryResultsFB, FB_spatial_entity_query) \ + + +/// For every function defined by XR_FB_spatial_entity_storage in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_storage(_) \ + _(SaveSpaceFB, FB_spatial_entity_storage) \ + _(EraseSpaceFB, FB_spatial_entity_storage) \ + + +/// For every function defined by XR_OCULUS_audio_device_guid in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_OCULUS_audio_device_guid(_) \ + _(GetAudioOutputDeviceGuidOculus, OCULUS_audio_device_guid) \ + _(GetAudioInputDeviceGuidOculus, OCULUS_audio_device_guid) \ + + +/// For every function defined by XR_FB_spatial_entity_sharing in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_sharing(_) \ + _(ShareSpacesFB, FB_spatial_entity_sharing) \ + + +/// For every function defined by XR_FB_scene in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_scene(_) \ + _(GetSpaceBoundingBox2DFB, FB_scene) \ + _(GetSpaceBoundingBox3DFB, FB_scene) \ + _(GetSpaceSemanticLabelsFB, FB_scene) \ + _(GetSpaceBoundary2DFB, FB_scene) \ + _(GetSpaceRoomLayoutFB, FB_scene) \ + + +/// For every function defined by XR_ALMALENCE_digital_lens_control in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_ALMALENCE_digital_lens_control(_) \ + _(SetDigitalLensControlALMALENCE, ALMALENCE_digital_lens_control) \ + + +/// For every function defined by XR_FB_scene_capture in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_scene_capture(_) \ + _(RequestSceneCaptureFB, FB_scene_capture) \ + + +/// For every function defined by XR_FB_spatial_entity_container in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_container(_) \ + _(GetSpaceContainerFB, FB_spatial_entity_container) \ + + +/// For every function defined by XR_META_foveation_eye_tracked in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_foveation_eye_tracked(_) \ + _(GetFoveationEyeTrackedStateMETA, META_foveation_eye_tracked) \ + + +/// For every function defined by XR_FB_face_tracking in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_face_tracking(_) \ + _(CreateFaceTrackerFB, FB_face_tracking) \ + _(DestroyFaceTrackerFB, FB_face_tracking) \ + _(GetFaceExpressionWeightsFB, FB_face_tracking) \ + + +/// For every function defined by XR_FB_eye_tracking_social in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_eye_tracking_social(_) \ + _(CreateEyeTrackerFB, FB_eye_tracking_social) \ + _(DestroyEyeTrackerFB, FB_eye_tracking_social) \ + _(GetEyeGazesFB, FB_eye_tracking_social) \ + + +/// For every function defined by XR_FB_passthrough_keyboard_hands in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_passthrough_keyboard_hands(_) \ + _(PassthroughLayerSetKeyboardHandsIntensityFB, FB_passthrough_keyboard_hands) \ + + +/// For every function defined by XR_FB_haptic_pcm in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_haptic_pcm(_) \ + _(GetDeviceSampleRateFB, FB_haptic_pcm) \ + + +/// For every function defined by XR_META_passthrough_preferences in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_passthrough_preferences(_) \ + _(GetPassthroughPreferencesMETA, META_passthrough_preferences) \ + + +/// For every function defined by XR_META_virtual_keyboard in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_virtual_keyboard(_) \ + _(CreateVirtualKeyboardMETA, META_virtual_keyboard) \ + _(DestroyVirtualKeyboardMETA, META_virtual_keyboard) \ + _(CreateVirtualKeyboardSpaceMETA, META_virtual_keyboard) \ + _(SuggestVirtualKeyboardLocationMETA, META_virtual_keyboard) \ + _(GetVirtualKeyboardScaleMETA, META_virtual_keyboard) \ + _(SetVirtualKeyboardModelVisibilityMETA, META_virtual_keyboard) \ + _(GetVirtualKeyboardModelAnimationStatesMETA, META_virtual_keyboard) \ + _(GetVirtualKeyboardDirtyTexturesMETA, META_virtual_keyboard) \ + _(GetVirtualKeyboardTextureDataMETA, META_virtual_keyboard) \ + _(SendVirtualKeyboardInputMETA, META_virtual_keyboard) \ + _(ChangeVirtualKeyboardTextContextMETA, META_virtual_keyboard) \ + + +/// For every function defined by XR_OCULUS_external_camera in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_OCULUS_external_camera(_) \ + _(EnumerateExternalCamerasOCULUS, OCULUS_external_camera) \ + + +/// For every function defined by XR_META_performance_metrics in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_performance_metrics(_) \ + _(EnumeratePerformanceMetricsCounterPathsMETA, META_performance_metrics) \ + _(SetPerformanceMetricsStateMETA, META_performance_metrics) \ + _(GetPerformanceMetricsStateMETA, META_performance_metrics) \ + _(QueryPerformanceMetricsCounterMETA, META_performance_metrics) \ + + +/// For every function defined by XR_FB_spatial_entity_storage_batch in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_storage_batch(_) \ + _(SaveSpaceListFB, FB_spatial_entity_storage_batch) \ + + +/// For every function defined by XR_FB_spatial_entity_user in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_spatial_entity_user(_) \ + _(CreateSpaceUserFB, FB_spatial_entity_user) \ + _(GetSpaceUserIdFB, FB_spatial_entity_user) \ + _(DestroySpaceUserFB, FB_spatial_entity_user) \ + + +/// For every function defined by XR_META_recommended_layer_resolution in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_recommended_layer_resolution(_) \ + _(GetRecommendedLayerResolutionMETA, META_recommended_layer_resolution) \ + + +/// For every function defined by XR_META_passthrough_color_lut in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_passthrough_color_lut(_) \ + _(CreatePassthroughColorLutMETA, META_passthrough_color_lut) \ + _(DestroyPassthroughColorLutMETA, META_passthrough_color_lut) \ + _(UpdatePassthroughColorLutMETA, META_passthrough_color_lut) \ + + +/// For every function defined by XR_META_spatial_entity_mesh in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_META_spatial_entity_mesh(_) \ + _(GetSpaceTriangleMeshMETA, META_spatial_entity_mesh) \ + + +/// For every function defined by XR_FB_face_tracking2 in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_FB_face_tracking2(_) \ + _(CreateFaceTracker2FB, FB_face_tracking2) \ + _(DestroyFaceTracker2FB, FB_face_tracking2) \ + _(GetFaceExpressionWeights2FB, FB_face_tracking2) \ + + +/// For every function defined by XR_QCOM_tracking_optimization_settings in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_QCOM_tracking_optimization_settings(_) \ + _(SetTrackingOptimizationSettingsHintQCOM, QCOM_tracking_optimization_settings) \ + + +/// For every function defined by XR_HTC_passthrough in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_HTC_passthrough(_) \ + _(CreatePassthroughHTC, HTC_passthrough) \ + _(DestroyPassthroughHTC, HTC_passthrough) \ + + +/// For every function defined by XR_HTC_foveation in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_HTC_foveation(_) \ + _(ApplyFoveationHTC, HTC_foveation) \ + + +/// For every function defined by XR_HTC_anchor in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_HTC_anchor(_) \ + _(CreateSpatialAnchorHTC, HTC_anchor) \ + _(GetSpatialAnchorNameHTC, HTC_anchor) \ + + +/// For every function defined by XR_MNDX_force_feedback_curl in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_MNDX_force_feedback_curl(_) \ + _(ApplyForceFeedbackCurlMNDX, MNDX_force_feedback_curl) \ + + +/// For every function defined by XR_EXT_plane_detection in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_EXT_plane_detection(_) \ + _(CreatePlaneDetectorEXT, EXT_plane_detection) \ + _(DestroyPlaneDetectorEXT, EXT_plane_detection) \ + _(BeginPlaneDetectionEXT, EXT_plane_detection) \ + _(GetPlaneDetectionStateEXT, EXT_plane_detection) \ + _(GetPlaneDetectionsEXT, EXT_plane_detection) \ + _(GetPlanePolygonBufferEXT, EXT_plane_detection) \ + + +/// For every function defined by XR_ML_user_calibration in this version of the spec, +/// calls your macro with the function name and extension name. +/// Trims the leading `xr` from the function name and the leading `XR_` from the feature name, +/// because it is easy to add back but impossible to remove with the preprocessor. +#define XR_LIST_FUNCTIONS_XR_ML_user_calibration(_) \ + _(EnableUserCalibrationEventsML, ML_user_calibration) \ + + + + #endif diff --git a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h index bcc1333e29..f973539cbb 100644 --- a/thirdparty/openxr/include/openxr/openxr_reflection_structs.h +++ b/thirdparty/openxr/include/openxr/openxr_reflection_structs.h @@ -308,11 +308,19 @@ This file contains expansion macros (X Macros) for OpenXR structures. _avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \ _avail(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \ _avail(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \ + _avail(XrRecommendedLayerResolutionMETA, XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_META) \ + _avail(XrRecommendedLayerResolutionGetInfoMETA, XR_TYPE_RECOMMENDED_LAYER_RESOLUTION_GET_INFO_META) \ _avail(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \ _avail(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \ _avail(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \ _avail(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \ _avail(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \ + _avail(XrSpaceTriangleMeshGetInfoMETA, XR_TYPE_SPACE_TRIANGLE_MESH_GET_INFO_META) \ + _avail(XrSpaceTriangleMeshMETA, XR_TYPE_SPACE_TRIANGLE_MESH_META) \ + _avail(XrSystemFaceTrackingProperties2FB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES2_FB) \ + _avail(XrFaceTrackerCreateInfo2FB, XR_TYPE_FACE_TRACKER_CREATE_INFO2_FB) \ + _avail(XrFaceExpressionInfo2FB, XR_TYPE_FACE_EXPRESSION_INFO2_FB) \ + _avail(XrFaceExpressionWeights2FB, XR_TYPE_FACE_EXPRESSION_WEIGHTS2_FB) \ _avail(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \ _avail(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \ _avail(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \ @@ -334,6 +342,8 @@ This file contains expansion macros (X Macros) for OpenXR structures. _avail(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \ _avail(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \ _avail(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \ + _avail(XrEventDataUserPresenceChangedEXT, XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT) \ + _avail(XrSystemUserPresencePropertiesEXT, XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT) \ _avail(XrEventDataHeadsetFitChangedML, XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML) \ _avail(XrEventDataEyeCalibrationChangedML, XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML) \ _avail(XrUserCalibrationEnableEventsInfoML, XR_TYPE_USER_CALIBRATION_ENABLE_EVENTS_INFO_ML) \ diff --git a/thirdparty/openxr/src/common/platform_utils.hpp b/thirdparty/openxr/src/common/platform_utils.hpp index c4d75bf259..35369a1477 100644 --- a/thirdparty/openxr/src/common/platform_utils.hpp +++ b/thirdparty/openxr/src/common/platform_utils.hpp @@ -323,6 +323,8 @@ static inline std::string PlatformUtilsGetSecureEnv(const char* name) { const std::string envValue = PlatformUtilsGetEnv(name); // Do not allow high integrity processes to act on data that can be controlled by medium integrity processes. + // Specifically, medium integrity processes can set environment variables which could then + // be read by high integrity processes. if (IsHighIntegrityLevel()) { if (!envValue.empty()) { LogPlatformUtilsError(std::string("!!! WARNING !!! Environment variable ") + name + diff --git a/thirdparty/openxr/src/loader/api_layer_interface.cpp b/thirdparty/openxr/src/loader/api_layer_interface.cpp index fb509de270..a93d45da37 100644 --- a/thirdparty/openxr/src/loader/api_layer_interface.cpp +++ b/thirdparty/openxr/src/loader/api_layer_interface.cpp @@ -72,10 +72,10 @@ XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_comm } // Find any implicit layers which we may need to report information for. - XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); if (XR_SUCCEEDED(result)) { // Find any explicit layers which we may need to report information for. - result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); + result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); } if (XR_FAILED(result)) { LoaderLogger::LogErrorMessage(openxr_command, @@ -126,10 +126,10 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op // If a layer name is supplied, only use the information out of that one layer if (nullptr != layer_name && 0 != strlen(layer_name)) { - XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); if (XR_SUCCEEDED(result)) { // Find any explicit layers which we may need to report information for. - result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); + result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files); if (XR_FAILED(result)) { LoaderLogger::LogErrorMessage( openxr_command, @@ -155,7 +155,7 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op } // Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables } else { - XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); + XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files); if (XR_SUCCEEDED(result)) { // Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers // since we know that they're going to be enabled. @@ -163,7 +163,8 @@ XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& op AddEnvironmentApiLayers(env_enabled_layers); if (!env_enabled_layers.empty()) { std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {}; - result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files); + result = + ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files); if (XR_SUCCEEDED(result)) { for (auto& exp_layer_man_file : exp_layer_man_files) { for (std::string& enabled_layer : env_enabled_layers) { @@ -197,8 +198,8 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {}; // Find any implicit layers. - XrResult result = - ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, enabled_layer_manifest_files_in_init_order); + XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, + enabled_layer_manifest_files_in_init_order); for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) { layers_already_found.insert(enabled_layer_manifest_file->LayerName()); @@ -208,7 +209,8 @@ XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uin std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {}; if (XR_SUCCEEDED(result)) { - result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, explicit_layer_manifest_files); + result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, + explicit_layer_manifest_files); } bool found_all_layers = true; diff --git a/thirdparty/openxr/src/loader/loader_init_data.cpp b/thirdparty/openxr/src/loader/loader_init_data.cpp index 11d3c4e77b..3ba6d26713 100644 --- a/thirdparty/openxr/src/loader/loader_init_data.cpp +++ b/thirdparty/openxr/src/loader/loader_init_data.cpp @@ -11,9 +11,9 @@ #ifdef XR_KHR_LOADER_INIT_SUPPORT -#ifdef XR_USE_PLATFORM_ANDROID // Check and copy the Android-specific init data. XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) { +#if defined(XR_USE_PLATFORM_ANDROID) if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) { return XR_ERROR_VALIDATION_FAILURE; } @@ -40,11 +40,13 @@ XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) { const auto applicationContext = context.call<jni::Object>("getApplicationContext()Landroid/content/Context;"); const auto applicationInfo = context.call<jni::Object>("getApplicationInfo()Landroid/content/pm/ApplicationInfo;"); _native_library_path = applicationInfo.get<std::string>("nativeLibraryDir"); +#else +#error "Platform specific XR_KHR_loader_init structure is not defined for this platform." +#endif // XR_USE_PLATFORM_ANDROID _initialized = true; return XR_SUCCESS; } -#endif // XR_USE_PLATFORM_ANDROID XrResult InitializeLoaderInitData(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) { return LoaderInitData::instance().initialize(loaderInitInfo); diff --git a/thirdparty/openxr/src/loader/loader_init_data.hpp b/thirdparty/openxr/src/loader/loader_init_data.hpp index fe6bc134d3..e3a27fc403 100644 --- a/thirdparty/openxr/src/loader/loader_init_data.hpp +++ b/thirdparty/openxr/src/loader/loader_init_data.hpp @@ -33,7 +33,7 @@ class LoaderInitData { return obj; } -#ifdef XR_USE_PLATFORM_ANDROID +#if defined(XR_USE_PLATFORM_ANDROID) /*! * Type alias for the platform-specific structure type. */ diff --git a/thirdparty/openxr/src/loader/manifest_file.cpp b/thirdparty/openxr/src/loader/manifest_file.cpp index f9699ece40..4e3e5b4947 100644 --- a/thirdparty/openxr/src/loader/manifest_file.cpp +++ b/thirdparty/openxr/src/loader/manifest_file.cpp @@ -600,14 +600,8 @@ void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std: // If the library_path variable has no directory symbol, it's just a file name and should be accessible on the // global library path. if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) { - // If the library_path is an absolute path, just use that if it exists - if (FileSysUtilsIsAbsolutePath(lib_path)) { - if (!FileSysUtilsPathExists(lib_path)) { - error_ss << filename << " library " << lib_path << " does not appear to exist"; - LoaderLogger::LogErrorMessage("", error_ss.str()); - return; - } - } else { + // If the library_path is an absolute path, just use that as-is. + if (!FileSysUtilsIsAbsolutePath(lib_path)) { // Otherwise, treat the library path as a relative path based on the JSON file. std::string canonical_path; std::string combined_path; @@ -618,8 +612,8 @@ void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std: canonical_path = filename; } if (!FileSysUtilsGetParentPath(canonical_path, file_parent) || - !FileSysUtilsCombinePaths(file_parent, lib_path, combined_path) || !FileSysUtilsPathExists(combined_path)) { - error_ss << filename << " library " << combined_path << " does not appear to exist"; + !FileSysUtilsCombinePaths(file_parent, lib_path, combined_path)) { + error_ss << filename << " filesystem operations failed for path " << canonical_path; LoaderLogger::LogErrorMessage("", error_ss.str()); return; } @@ -636,53 +630,58 @@ void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std: } // Find all manifest files in the appropriate search paths/registries for the given type. -XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { +XrResult RuntimeManifestFile::FindManifestFiles(const std::string &openxr_command, + std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) { XrResult result = XR_SUCCESS; std::string filename = PlatformUtilsGetSecureEnv(OPENXR_RUNTIME_JSON_ENV_VAR); if (!filename.empty()) { LoaderLogger::LogInfoMessage( - "", "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file " + filename); + openxr_command, + "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file " + filename); } else { #ifdef XR_OS_WINDOWS std::vector<std::string> filenames; ReadRuntimeDataFilesInRegistry("", "ActiveRuntime", filenames); if (filenames.size() == 0) { LoaderLogger::LogErrorMessage( - "", "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry"); + openxr_command, "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry"); return XR_ERROR_RUNTIME_UNAVAILABLE; } if (filenames.size() > 1) { LoaderLogger::LogWarningMessage( - "", "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry"); + openxr_command, "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry"); } filename = filenames[0]; - LoaderLogger::LogInfoMessage("", + LoaderLogger::LogInfoMessage(openxr_command, "RuntimeManifestFile::FindManifestFiles - using registry-specified runtime file " + filename); #elif defined(XR_OS_LINUX) if (!FindXDGConfigFile("openxr/", XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) { LoaderLogger::LogErrorMessage( - "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); + openxr_command, + "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); return XR_ERROR_RUNTIME_UNAVAILABLE; } -#else +#else // !defined(XR_OS_WINDOWS) && !defined(XR_OS_LINUX) -#if defined(XR_USE_PLATFORM_ANDROID) +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) Json::Value virtualManifest; result = GetPlatformRuntimeVirtualManifest(virtualManifest); if (XR_SUCCESS == result) { RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files); return result; } -#endif // defined(XR_USE_PLATFORM_ANDROID) +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) { LoaderLogger::LogErrorMessage( - "", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); + openxr_command, + "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment"); return XR_ERROR_RUNTIME_UNAVAILABLE; } result = XR_SUCCESS; - LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename); -#endif + LoaderLogger::LogInfoMessage(openxr_command, + "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename); +#endif // !defined(XR_OS_WINDOWS) && !defined(XR_OS_LINUX) } RuntimeManifestFile::CreateIfValid(filename, manifest_files); @@ -698,9 +697,17 @@ ApiLayerManifestFile::ApiLayerManifestFile(ManifestFileType type, const std::str _description(description), _implementation_version(implementation_version) {} -#ifdef XR_USE_PLATFORM_ANDROID -void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) +void ApiLayerManifestFile::AddManifestFilesAndroid(const std::string &openxr_command, ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) { + if (!LoaderInitData::instance().initialized()) { + // This will happen for applications that do not call xrInitializeLoaderKHR + LoaderLogger::LogWarningMessage( + openxr_command, + "ApiLayerManifestFile::AddManifestFilesAndroid unable to add manifest files LoaderInitData not initialized."); + return; + } + AAssetManager *assetManager = (AAssetManager *)Android_Get_Asset_Manager(); std::vector<std::string> filenames; { @@ -736,7 +743,7 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, UniqueAsset asset{AAssetManager_open(assetManager, filename.c_str(), AASSET_MODE_BUFFER)}; if (!asset) { LoaderLogger::LogWarningMessage( - "", "ApiLayerManifestFile::AddManifestFilesAndroid unable to open asset " + filename + ", skipping"); + openxr_command, "ApiLayerManifestFile::AddManifestFilesAndroid unable to open asset " + filename + ", skipping"); continue; } @@ -744,7 +751,7 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, const char *buf = reinterpret_cast<const char *>(AAsset_getBuffer(asset.get())); if (!buf) { LoaderLogger::LogWarningMessage( - "", "ApiLayerManifestFile::AddManifestFilesAndroid unable to access asset" + filename + ", skipping"); + openxr_command, "ApiLayerManifestFile::AddManifestFilesAndroid unable to access asset" + filename + ", skipping"); continue; } @@ -754,7 +761,7 @@ void ApiLayerManifestFile::AddManifestFilesAndroid(ManifestFileType type, &ApiLayerManifestFile::LocateLibraryInAssets, manifest_files); } } -#endif // XR_USE_PLATFORM_ANDROID +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename, std::istream &json_stream, LibraryLocator locate_library, @@ -898,7 +905,7 @@ bool ApiLayerManifestFile::LocateLibraryRelativeToJson( return true; } -#ifdef XR_USE_PLATFORM_ANDROID +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) bool ApiLayerManifestFile::LocateLibraryInAssets(const std::string & /* json_filename */, const std::string &library_path, std::string &out_combined_path) { std::string combined_path; @@ -910,7 +917,7 @@ bool ApiLayerManifestFile::LocateLibraryInAssets(const std::string & /* json_fil out_combined_path = combined_path; return true; } -#endif +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &props) const { props.layerVersion = _implementation_version; @@ -926,7 +933,7 @@ void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &prop } // Find all layer manifest files in the appropriate search paths/registries for the given type. -XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, +XrResult ApiLayerManifestFile::FindManifestFiles(const std::string &openxr_command, ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) { std::string relative_path; std::string override_env_var; @@ -953,7 +960,8 @@ XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, #endif break; default: - LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested"); + LoaderLogger::LogErrorMessage(openxr_command, + "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested"); return XR_ERROR_FILE_ACCESS_ERROR; } @@ -972,9 +980,9 @@ XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type, ApiLayerManifestFile::CreateIfValid(type, cur_file, manifest_files); } -#ifdef XR_USE_PLATFORM_ANDROID - ApiLayerManifestFile::AddManifestFilesAndroid(type, manifest_files); -#endif // XR_USE_PLATFORM_ANDROID +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) + ApiLayerManifestFile::AddManifestFilesAndroid(openxr_command, type, manifest_files); +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) return XR_SUCCESS; } diff --git a/thirdparty/openxr/src/loader/manifest_file.hpp b/thirdparty/openxr/src/loader/manifest_file.hpp index 52fe3134b0..801614ad1e 100644 --- a/thirdparty/openxr/src/loader/manifest_file.hpp +++ b/thirdparty/openxr/src/loader/manifest_file.hpp @@ -71,7 +71,8 @@ class ManifestFile { class RuntimeManifestFile : public ManifestFile { public: // Factory method - static XrResult FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files); + static XrResult FindManifestFiles(const std::string &openxr_command, + std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files); private: RuntimeManifestFile(const std::string &filename, const std::string &library_path); @@ -87,7 +88,8 @@ using LibraryLocator = bool (*)(const std::string &json_filename, const std::str class ApiLayerManifestFile : public ManifestFile { public: // Factory method - static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); + static XrResult FindManifestFiles(const std::string &openxr_command, ManifestFileType type, + std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); const std::string &LayerName() const { return _layer_name; } void PopulateApiLayerProperties(XrApiLayerProperties &props) const; @@ -104,11 +106,13 @@ class ApiLayerManifestFile : public ManifestFile { /// @return false if we could not find the library. static bool LocateLibraryRelativeToJson(const std::string &json_filename, const std::string &library_path, std::string &out_combined_path); -#ifdef XR_USE_PLATFORM_ANDROID + +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) static bool LocateLibraryInAssets(const std::string &json_filename, const std::string &library_path, std::string &out_combined_path); - static void AddManifestFilesAndroid(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); -#endif + static void AddManifestFilesAndroid(const std::string &openxr_command, ManifestFileType type, + std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files); +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) JsonVersion _api_version; std::string _layer_name; diff --git a/thirdparty/openxr/src/loader/runtime_interface.cpp b/thirdparty/openxr/src/loader/runtime_interface.cpp index 7812aca987..a0296c738c 100644 --- a/thirdparty/openxr/src/loader/runtime_interface.cpp +++ b/thirdparty/openxr/src/loader/runtime_interface.cpp @@ -34,7 +34,7 @@ #include <openxr/openxr_platform.h> #endif // XR_USE_PLATFORM_ANDROID -#ifdef XR_USE_PLATFORM_ANDROID +#if defined(XR_KHR_LOADER_INIT_SUPPORT) && defined(XR_USE_PLATFORM_ANDROID) XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { using wrap::android::content::Context; auto& initData = LoaderInitData::instance(); @@ -52,7 +52,7 @@ XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) { out_manifest = virtualManifest; return XR_SUCCESS; } -#endif // XR_USE_PLATFORM_ANDROID +#endif // defined(XR_USE_PLATFORM_ANDROID) && defined(XR_KHR_LOADER_INIT_SUPPORT) XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr<RuntimeManifestFile>& manifest_file) { @@ -227,7 +227,6 @@ XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) { return XR_SUCCESS; } #ifdef XR_KHR_LOADER_INIT_SUPPORT - if (!LoaderInitData::instance().initialized()) { LoaderLogger::LogErrorMessage( openxr_command, "RuntimeInterface::LoadRuntime cannot run because xrInitializeLoaderKHR was not successfully called."); @@ -238,7 +237,7 @@ XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) { std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {}; // Find the available runtimes which we may need to report information for. - XrResult last_error = RuntimeManifestFile::FindManifestFiles(runtime_manifest_files); + XrResult last_error = RuntimeManifestFile::FindManifestFiles(openxr_command, runtime_manifest_files); if (XR_FAILED(last_error)) { LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error"); } else { |