diff options
24 files changed, 716 insertions, 240 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e59419ac08..5c0c0b6917 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,8 +23,6 @@ repos: - id: black files: (\.py$|SConstruct|SCsub) types_or: [text] - args: - - --line-length=120 - repo: https://github.com/pre-commit/mirrors-mypy rev: v0.971 @@ -32,7 +30,6 @@ repos: - id: mypy files: \.py$ types_or: [text] - args: [--config-file=./misc/scripts/mypy.ini] - repo: https://github.com/codespell-project/codespell rev: v2.2.6 diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp index 1ffe76495d..9bf625cc15 100644 --- a/core/core_string_names.cpp +++ b/core/core_string_names.cpp @@ -42,10 +42,8 @@ CoreStringNames::CoreStringNames() : _iter_get(StaticCString::create("_iter_get")), get_rid(StaticCString::create("get_rid")), _to_string(StaticCString::create("_to_string")), -#ifdef TOOLS_ENABLED - _sections_unfolded(StaticCString::create("_sections_unfolded")), -#endif _custom_features(StaticCString::create("_custom_features")), + x(StaticCString::create("x")), y(StaticCString::create("y")), z(StaticCString::create("z")), @@ -68,11 +66,10 @@ CoreStringNames::CoreStringNames() : g8(StaticCString::create("g8")), b8(StaticCString::create("b8")), a8(StaticCString::create("a8")), + call(StaticCString::create("call")), call_deferred(StaticCString::create("call_deferred")), bind(StaticCString::create("bind")), - unbind(StaticCString::create("unbind")), - emit(StaticCString::create("emit")), notification(StaticCString::create("notification")), property_list_changed(StaticCString::create("property_list_changed")) { } diff --git a/core/core_string_names.h b/core/core_string_names.h index d7ddc39f5e..d4ba9110c3 100644 --- a/core/core_string_names.h +++ b/core/core_string_names.h @@ -59,9 +59,6 @@ public: StringName _iter_get; StringName get_rid; StringName _to_string; -#ifdef TOOLS_ENABLED - StringName _sections_unfolded; -#endif StringName _custom_features; StringName x; @@ -90,8 +87,6 @@ public: StringName call; StringName call_deferred; StringName bind; - StringName unbind; - StringName emit; StringName notification; StringName property_list_changed; }; diff --git a/core/variant/variant.h b/core/variant/variant.h index 6494313722..f352af24da 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -165,10 +165,12 @@ private: friend struct _VariantCall; friend class VariantInternal; - // Variant takes 20 bytes when real_t is float, and 36 if double - // it only allocates extra memory for aabb/matrix. + // Variant takes 24 bytes when real_t is float, and 40 bytes if double. + // It only allocates extra memory for AABB/Transform2D (24, 48 if double), + // Basis/Transform3D (48, 96 if double), Projection (64, 128 if double), + // and PackedArray/Array/Dictionary (platform-dependent). - Type type; + Type type = NIL; struct ObjData { ObjectID id; diff --git a/editor/plugins/navigation_obstacle_2d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_2d_editor_plugin.cpp index 0cbc711982..a0ef3f9a20 100644 --- a/editor/plugins/navigation_obstacle_2d_editor_plugin.cpp +++ b/editor/plugins/navigation_obstacle_2d_editor_plugin.cpp @@ -41,6 +41,14 @@ void NavigationObstacle2DEditor::_set_node(Node *p_polygon) { node = Object::cast_to<NavigationObstacle2D>(p_polygon); } +Variant NavigationObstacle2DEditor::_get_polygon(int p_idx) const { + return node->get_vertices(); +} + +void NavigationObstacle2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { + node->set_vertices(p_polygon); +} + void NavigationObstacle2DEditor::_action_add_polygon(const Variant &p_polygon) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->add_do_method(node, "set_vertices", p_polygon); diff --git a/editor/plugins/navigation_obstacle_2d_editor_plugin.h b/editor/plugins/navigation_obstacle_2d_editor_plugin.h index 5a2206b8df..ae5b3a056a 100644 --- a/editor/plugins/navigation_obstacle_2d_editor_plugin.h +++ b/editor/plugins/navigation_obstacle_2d_editor_plugin.h @@ -43,6 +43,9 @@ protected: virtual Node2D *_get_node() const override; virtual void _set_node(Node *p_polygon) override; + virtual Variant _get_polygon(int p_idx) const override; + virtual void _set_polygon(int p_idx, const Variant &p_polygon) const override; + virtual void _action_add_polygon(const Variant &p_polygon) override; virtual void _action_remove_polygon(int p_idx) override; virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) override; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index c2d6acd140..53145c3450 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -2907,6 +2907,13 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro } } + // HACK: Remember size of anchored control. + Control *old_control = Object::cast_to<Control>(oldnode); + Size2 size; + if (old_control) { + size = old_control->get_size(); + } + String newname = oldnode->get_name(); List<Node *> to_erase; @@ -2917,6 +2924,12 @@ void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_pro } oldnode->replace_by(newnode, true); + // Re-apply size of anchored control. + Control *new_control = Object::cast_to<Control>(newnode); + if (old_control && new_control) { + new_control->set_size(size); + } + //small hack to make collisionshapes and other kind of nodes to work for (int i = 0; i < newnode->get_child_count(); i++) { Node *c = newnode->get_child(i); diff --git a/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy b/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000..a5257b74a4 --- /dev/null +++ b/misc/dist/macos_template.app/Contents/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + $priv_tracking + $priv_collection +</dict> +</plist> diff --git a/misc/scripts/mypy.ini b/misc/scripts/mypy.ini deleted file mode 100644 index 45f048f118..0000000000 --- a/misc/scripts/mypy.ini +++ /dev/null @@ -1,13 +0,0 @@ -[mypy] -ignore_missing_imports = True -disallow_any_generics = True -no_implicit_optional = True -pretty = True -show_column_numbers = True -warn_redundant_casts = True -warn_return_any = True -warn_unreachable = True - -namespace_packages = True -explicit_package_bases = True -exclude = (?x)(^thirdparty) diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 316281209a..d74d316704 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -276,8 +276,8 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C id_ctx_plural.resize(3); bool extract_id_ctx_plural = true; - if (function_name == tr_func) { - // Extract from tr(id, ctx). + if (function_name == tr_func || function_name == atr_func) { + // Extract from `tr(id, ctx)` or `atr(id, ctx)`. for (int i = 0; i < p_call->arguments.size(); i++) { if (_is_constant_string(p_call->arguments[i])) { id_ctx_plural.write[i] = p_call->arguments[i]->reduced_value; @@ -289,8 +289,8 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C if (extract_id_ctx_plural) { ids_ctx_plural->push_back(id_ctx_plural); } - } else if (function_name == trn_func) { - // Extract from tr_n(id, plural, n, ctx). + } else if (function_name == trn_func || function_name == atrn_func) { + // Extract from `tr_n(id, plural, n, ctx)` or `atr_n(id, plural, n, ctx)`. Vector<int> indices; indices.push_back(0); indices.push_back(3); diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index fe876134c2..61ff81ed66 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -45,6 +45,8 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug // List of patterns used for extracting translation strings. StringName tr_func = "tr"; StringName trn_func = "tr_n"; + StringName atr_func = "atr"; + StringName atrn_func = "atr_n"; HashSet<StringName> assignment_patterns; HashSet<StringName> first_arg_patterns; HashSet<StringName> second_arg_patterns; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 9174b65b1b..daf0247540 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1007,7 +1007,8 @@ int DisplayServerX11::get_screen_count() const { if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) { XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); XFree(xsi); - } else { + } + if (count == 0) { count = XScreenCount(x11_display); } @@ -1068,25 +1069,29 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { ERR_FAIL_COND_V(p_screen < 0, rect); // Using Xinerama Extension. + bool found = false; int event_base, error_base; if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) { int count; XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); - - // Check if screen is valid. - if (p_screen < count) { - rect.position.x = xsi[p_screen].x_org; - rect.position.y = xsi[p_screen].y_org; - rect.size.width = xsi[p_screen].width; - rect.size.height = xsi[p_screen].height; - } else { - ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ")."); - } - if (xsi) { + if (count > 0) { + // Check if screen is valid. + if (p_screen < count) { + rect.position.x = xsi[p_screen].x_org; + rect.position.y = xsi[p_screen].y_org; + rect.size.width = xsi[p_screen].width; + rect.size.height = xsi[p_screen].height; + found = true; + } else { + ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count)); + } + } XFree(xsi); } - } else { + } + + if (!found) { int count = XScreenCount(x11_display); if (p_screen < count) { Window root = XRootWindow(x11_display, p_screen); @@ -1097,7 +1102,7 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { rect.size.width = xwa.width; rect.size.height = xwa.height; } else { - ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ")."); + ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count)); } } @@ -1503,25 +1508,33 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const { XImage *image = nullptr; + bool found = false; int event_base, error_base; if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) { int xin_count; XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &xin_count); - if (p_screen < xin_count) { - int x_count = XScreenCount(x11_display); - for (int i = 0; i < x_count; i++) { - Window root = XRootWindow(x11_display, i); - XWindowAttributes root_attrs; - XGetWindowAttributes(x11_display, root, &root_attrs); - if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) { - image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap); - break; + if (xsi) { + if (xin_count > 0) { + if (p_screen < xin_count) { + int x_count = XScreenCount(x11_display); + for (int i = 0; i < x_count; i++) { + Window root = XRootWindow(x11_display, i); + XWindowAttributes root_attrs; + XGetWindowAttributes(x11_display, root, &root_attrs); + if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) { + found = true; + image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap); + break; + } + } + } else { + ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, xin_count)); } } - } else { - ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(xin_count) + ")."); + XFree(xsi); } - } else { + } + if (!found) { int x_count = XScreenCount(x11_display); if (p_screen < x_count) { Window root = XRootWindow(x11_display, p_screen); @@ -1531,7 +1544,7 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const { image = XGetImage(x11_display, root, root_attrs.x, root_attrs.y, root_attrs.width, root_attrs.height, AllPlanes, ZPixmap); } else { - ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(x_count) + ")."); + ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, x_count)); } } diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml index 7355042a48..92ade4b77a 100644 --- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml +++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml @@ -211,6 +211,426 @@ <member name="privacy/camera_usage_description_localized" type="Dictionary" setter="" getter=""> A message displayed when requesting access to the device's camera (localized). </member> + <member name="privacy/collected_data/advertising_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects advertising data. + </member> + <member name="privacy/collected_data/advertising_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects advertising data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/advertising_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links advertising data to the user's identity. + </member> + <member name="privacy/collected_data/advertising_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses advertising data for tracking. + </member> + <member name="privacy/collected_data/audio_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects audio data data. + </member> + <member name="privacy/collected_data/audio_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/audio_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links audio data data to the user's identity. + </member> + <member name="privacy/collected_data/audio_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses audio data data for tracking. + </member> + <member name="privacy/collected_data/browsing_history/collected" type="bool" setter="" getter=""> + Indicates whether your app collects browsing history. + </member> + <member name="privacy/collected_data/browsing_history/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects browsing history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/browsing_history/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links browsing history to the user's identity. + </member> + <member name="privacy/collected_data/browsing_history/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses browsing history for tracking. + </member> + <member name="privacy/collected_data/coarse_location/collected" type="bool" setter="" getter=""> + Indicates whether your app collects coarse location data. + </member> + <member name="privacy/collected_data/coarse_location/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects coarse location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/coarse_location/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links coarse location data to the user's identity. + </member> + <member name="privacy/collected_data/coarse_location/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses coarse location data for tracking. + </member> + <member name="privacy/collected_data/contacts/collected" type="bool" setter="" getter=""> + Indicates whether your app collects contacts. + </member> + <member name="privacy/collected_data/contacts/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects contacts. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/contacts/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links contacts to the user's identity. + </member> + <member name="privacy/collected_data/contacts/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses contacts for tracking. + </member> + <member name="privacy/collected_data/crash_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects crash data. + </member> + <member name="privacy/collected_data/crash_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects crash data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/crash_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links crash data to the user's identity. + </member> + <member name="privacy/collected_data/crash_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses crash data for tracking. + </member> + <member name="privacy/collected_data/credit_info/collected" type="bool" setter="" getter=""> + Indicates whether your app collects credit information. + </member> + <member name="privacy/collected_data/credit_info/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects credit information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/credit_info/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links credit information to the user's identity. + </member> + <member name="privacy/collected_data/credit_info/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses credit information for tracking. + </member> + <member name="privacy/collected_data/customer_support/collected" type="bool" setter="" getter=""> + Indicates whether your app collects customer support data. + </member> + <member name="privacy/collected_data/customer_support/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects customer support data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/customer_support/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links customer support data to the user's identity. + </member> + <member name="privacy/collected_data/customer_support/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses customer support data for tracking. + </member> + <member name="privacy/collected_data/device_id/collected" type="bool" setter="" getter=""> + Indicates whether your app collects device IDs. + </member> + <member name="privacy/collected_data/device_id/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects device IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/device_id/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links device IDs to the user's identity. + </member> + <member name="privacy/collected_data/device_id/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses device IDs for tracking. + </member> + <member name="privacy/collected_data/email_address/collected" type="bool" setter="" getter=""> + Indicates whether your app collects email address. + </member> + <member name="privacy/collected_data/email_address/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects email address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/email_address/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links email address to the user's identity. + </member> + <member name="privacy/collected_data/email_address/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses email address for tracking. + </member> + <member name="privacy/collected_data/emails_or_text_messages/collected" type="bool" setter="" getter=""> + Indicates whether your app collects emails or text messages. + </member> + <member name="privacy/collected_data/emails_or_text_messages/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects emails or text messages. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/emails_or_text_messages/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links emails or text messages to the user's identity. + </member> + <member name="privacy/collected_data/emails_or_text_messages/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses emails or text messages for tracking. + </member> + <member name="privacy/collected_data/environment_scanning/collected" type="bool" setter="" getter=""> + Indicates whether your app collects environment scanning data. + </member> + <member name="privacy/collected_data/environment_scanning/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects environment scanning data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/environment_scanning/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links environment scanning data to the user's identity. + </member> + <member name="privacy/collected_data/environment_scanning/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses environment scanning data for tracking. + </member> + <member name="privacy/collected_data/fitness/collected" type="bool" setter="" getter=""> + Indicates whether your app collects fitness and exercise data. + </member> + <member name="privacy/collected_data/fitness/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects fitness and exercise data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/fitness/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links fitness and exercise data to the user's identity. + </member> + <member name="privacy/collected_data/fitness/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses fitness and exercise data for tracking. + </member> + <member name="privacy/collected_data/gameplay_content/collected" type="bool" setter="" getter=""> + Indicates whether your app collects gameplay content. + </member> + <member name="privacy/collected_data/gameplay_content/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects gameplay content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/gameplay_content/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links gameplay content to the user's identity. + </member> + <member name="privacy/collected_data/gameplay_content/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses gameplay content for tracking. + </member> + <member name="privacy/collected_data/hands/collected" type="bool" setter="" getter=""> + Indicates whether your app collects user's hand structure and hand movements. + </member> + <member name="privacy/collected_data/hands/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects user's hand structure and hand movements. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/hands/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links user's hand structure and hand movements to the user's identity. + </member> + <member name="privacy/collected_data/hands/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses user's hand structure and hand movements for tracking. + </member> + <member name="privacy/collected_data/head/collected" type="bool" setter="" getter=""> + Indicates whether your app collects user's head movement. + </member> + <member name="privacy/collected_data/head/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects user's head movement. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/head/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links user's head movement to the user's identity. + </member> + <member name="privacy/collected_data/head/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses user's head movement for tracking. + </member> + <member name="privacy/collected_data/health/collected" type="bool" setter="" getter=""> + Indicates whether your app collects health and medical data. + </member> + <member name="privacy/collected_data/health/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects health and medical data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/health/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links health and medical data to the user's identity. + </member> + <member name="privacy/collected_data/health/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses health and medical data for tracking. + </member> + <member name="privacy/collected_data/name/collected" type="bool" setter="" getter=""> + Indicates whether your app collects user's name. + </member> + <member name="privacy/collected_data/name/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects user's name. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/name/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links user's name to the user's identity. + </member> + <member name="privacy/collected_data/name/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses user's name for tracking. + </member> + <member name="privacy/collected_data/other_contact_info/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other contact information. + </member> + <member name="privacy/collected_data/other_contact_info/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other contact information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_contact_info/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other contact information to the user's identity. + </member> + <member name="privacy/collected_data/other_contact_info/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other contact information for tracking. + </member> + <member name="privacy/collected_data/other_data_types/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other data. + </member> + <member name="privacy/collected_data/other_data_types/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_data_types/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other data to the user's identity. + </member> + <member name="privacy/collected_data/other_data_types/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other data for tracking. + </member> + <member name="privacy/collected_data/other_diagnostic_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other diagnostic data. + </member> + <member name="privacy/collected_data/other_diagnostic_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other diagnostic data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_diagnostic_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other diagnostic data to the user's identity. + </member> + <member name="privacy/collected_data/other_diagnostic_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other diagnostic data for tracking. + </member> + <member name="privacy/collected_data/other_financial_info/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other financial information. + </member> + <member name="privacy/collected_data/other_financial_info/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other financial information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_financial_info/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other financial information to the user's identity. + </member> + <member name="privacy/collected_data/other_financial_info/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other financial information for tracking. + </member> + <member name="privacy/collected_data/other_usage_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other usage data. + </member> + <member name="privacy/collected_data/other_usage_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other usage data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_usage_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other usage data to the user's identity. + </member> + <member name="privacy/collected_data/other_usage_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other usage data for tracking. + </member> + <member name="privacy/collected_data/other_user_content/collected" type="bool" setter="" getter=""> + Indicates whether your app collects any other user generated content. + </member> + <member name="privacy/collected_data/other_user_content/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects any other user generated content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/other_user_content/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links any other user generated content to the user's identity. + </member> + <member name="privacy/collected_data/other_user_content/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses any other user generated content for tracking. + </member> + <member name="privacy/collected_data/payment_info/collected" type="bool" setter="" getter=""> + Indicates whether your app collects payment information. + </member> + <member name="privacy/collected_data/payment_info/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects payment information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/payment_info/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links payment information to the user's identity. + </member> + <member name="privacy/collected_data/payment_info/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses payment information for tracking. + </member> + <member name="privacy/collected_data/performance_data/collected" type="bool" setter="" getter=""> + Indicates whether your app collects performance data. + </member> + <member name="privacy/collected_data/performance_data/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects performance data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/performance_data/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links performance data to the user's identity. + </member> + <member name="privacy/collected_data/performance_data/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses performance data for tracking. + </member> + <member name="privacy/collected_data/phone_number/collected" type="bool" setter="" getter=""> + Indicates whether your app collects phone number. + </member> + <member name="privacy/collected_data/phone_number/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects phone number. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/phone_number/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links phone number to the user's identity. + </member> + <member name="privacy/collected_data/phone_number/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses phone number for tracking. + </member> + <member name="privacy/collected_data/photos_or_videos/collected" type="bool" setter="" getter=""> + Indicates whether your app collects photos or videos. + </member> + <member name="privacy/collected_data/photos_or_videos/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects photos or videos. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/photos_or_videos/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links photos or videos to the user's identity. + </member> + <member name="privacy/collected_data/photos_or_videos/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses photos or videos for tracking. + </member> + <member name="privacy/collected_data/physical_address/collected" type="bool" setter="" getter=""> + Indicates whether your app collects physical address. + </member> + <member name="privacy/collected_data/physical_address/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects physical address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/physical_address/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links physical address to the user's identity. + </member> + <member name="privacy/collected_data/physical_address/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses physical address for tracking. + </member> + <member name="privacy/collected_data/precise_location/collected" type="bool" setter="" getter=""> + Indicates whether your app collects precise location data. + </member> + <member name="privacy/collected_data/precise_location/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects precise location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/precise_location/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links precise location data to the user's identity. + </member> + <member name="privacy/collected_data/precise_location/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses precise location data for tracking. + </member> + <member name="privacy/collected_data/product_interaction/collected" type="bool" setter="" getter=""> + Indicates whether your app collects product interaction data. + </member> + <member name="privacy/collected_data/product_interaction/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects product interaction data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/product_interaction/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links product interaction data to the user's identity. + </member> + <member name="privacy/collected_data/product_interaction/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses product interaction data for tracking. + </member> + <member name="privacy/collected_data/purchase_history/collected" type="bool" setter="" getter=""> + Indicates whether your app collects purchase history. + </member> + <member name="privacy/collected_data/purchase_history/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects purchase history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/purchase_history/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links purchase history to the user's identity. + </member> + <member name="privacy/collected_data/purchase_history/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses purchase history for tracking. + </member> + <member name="privacy/collected_data/search_hhistory/collected" type="bool" setter="" getter=""> + Indicates whether your app collects search history. + </member> + <member name="privacy/collected_data/search_hhistory/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects search history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/search_hhistory/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links search history to the user's identity. + </member> + <member name="privacy/collected_data/search_hhistory/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses search history for tracking. + </member> + <member name="privacy/collected_data/sensitive_info/collected" type="bool" setter="" getter=""> + Indicates whether your app collects sensitive user information. + </member> + <member name="privacy/collected_data/sensitive_info/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects sensitive user information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/sensitive_info/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links sensitive user information to the user's identity. + </member> + <member name="privacy/collected_data/sensitive_info/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses sensitive user information for tracking. + </member> + <member name="privacy/collected_data/user_id/collected" type="bool" setter="" getter=""> + Indicates whether your app collects user IDs. + </member> + <member name="privacy/collected_data/user_id/collection_purposes" type="int" setter="" getter=""> + The reasons your app collects user IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + </member> + <member name="privacy/collected_data/user_id/linked_to_user" type="bool" setter="" getter=""> + Indicates whether your app links user IDs to the user's identity. + </member> + <member name="privacy/collected_data/user_id/used_for_tracking" type="bool" setter="" getter=""> + Indicates whether your app uses user IDs for tracking. + </member> <member name="privacy/desktop_folder_usage_description" type="String" setter="" getter=""> A message displayed when requesting access to the user's "Desktop" folder (in English). </member> @@ -259,6 +679,12 @@ <member name="privacy/removable_volumes_usage_description_localized" type="Dictionary" setter="" getter=""> A message displayed when requesting access to the user's removable drives (localized). </member> + <member name="privacy/tracking_domains" type="PackedStringArray" setter="" getter=""> + The list of internet domains your app connects to that engage in tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + </member> + <member name="privacy/tracking_enabled" type="bool" setter="" getter=""> + Indicates whether your app uses data for tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + </member> <member name="ssh_remote_deploy/cleanup_script" type="String" setter="" getter=""> Script code to execute on the remote host when app is finished. The following variables can be used in the script: diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 96d64ef209..9c9d8fc1a4 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -325,6 +325,11 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP } } break; } + + bool advanced_options_enabled = p_preset->are_advanced_options_enabled(); + if (p_option.begins_with("privacy")) { + return advanced_options_enabled; + } } // These entitlements are required to run managed code, and are always enabled in Mono builds. @@ -373,6 +378,58 @@ List<String> EditorExportPlatformMacOS::get_binary_extensions(const Ref<EditorEx return list; } +struct DataCollectionInfo { + String prop_name; + String type_name; +}; + +static const DataCollectionInfo data_collect_type_info[] = { + { "name", "NSPrivacyCollectedDataTypeName" }, + { "email_address", "NSPrivacyCollectedDataTypeEmailAddress" }, + { "phone_number", "NSPrivacyCollectedDataTypePhoneNumber" }, + { "physical_address", "NSPrivacyCollectedDataTypePhysicalAddress" }, + { "other_contact_info", "NSPrivacyCollectedDataTypeOtherUserContactInfo" }, + { "health", "NSPrivacyCollectedDataTypeHealth" }, + { "fitness", "NSPrivacyCollectedDataTypeFitness" }, + { "payment_info", "NSPrivacyCollectedDataTypePaymentInfo" }, + { "credit_info", "NSPrivacyCollectedDataTypeCreditInfo" }, + { "other_financial_info", "NSPrivacyCollectedDataTypeOtherFinancialInfo" }, + { "precise_location", "NSPrivacyCollectedDataTypePreciseLocation" }, + { "coarse_location", "NSPrivacyCollectedDataTypeCoarseLocation" }, + { "sensitive_info", "NSPrivacyCollectedDataTypeSensitiveInfo" }, + { "contacts", "NSPrivacyCollectedDataTypeContacts" }, + { "emails_or_text_messages", "NSPrivacyCollectedDataTypeEmailsOrTextMessages" }, + { "photos_or_videos", "NSPrivacyCollectedDataTypePhotosorVideos" }, + { "audio_data", "NSPrivacyCollectedDataTypeAudioData" }, + { "gameplay_content", "NSPrivacyCollectedDataTypeGameplayContent" }, + { "customer_support", "NSPrivacyCollectedDataTypeCustomerSupport" }, + { "other_user_content", "NSPrivacyCollectedDataTypeOtherUserContent" }, + { "browsing_history", "NSPrivacyCollectedDataTypeBrowsingHistory" }, + { "search_hhistory", "NSPrivacyCollectedDataTypeSearchHistory" }, + { "user_id", "NSPrivacyCollectedDataTypeUserID" }, + { "device_id", "NSPrivacyCollectedDataTypeDeviceID" }, + { "purchase_history", "NSPrivacyCollectedDataTypePurchaseHistory" }, + { "product_interaction", "NSPrivacyCollectedDataTypeProductInteraction" }, + { "advertising_data", "NSPrivacyCollectedDataTypeAdvertisingData" }, + { "other_usage_data", "NSPrivacyCollectedDataTypeOtherUsageData" }, + { "crash_data", "NSPrivacyCollectedDataTypeCrashData" }, + { "performance_data", "NSPrivacyCollectedDataTypePerformanceData" }, + { "other_diagnostic_data", "NSPrivacyCollectedDataTypeOtherDiagnosticData" }, + { "environment_scanning", "NSPrivacyCollectedDataTypeEnvironmentScanning" }, + { "hands", "NSPrivacyCollectedDataTypeHands" }, + { "head", "NSPrivacyCollectedDataTypeHead" }, + { "other_data_types", "NSPrivacyCollectedDataTypeOtherDataTypes" }, +}; + +static const DataCollectionInfo data_collect_purpose_info[] = { + { "Analytics", "NSPrivacyCollectedDataTypePurposeAnalytics" }, + { "App Functionality", "NSPrivacyCollectedDataTypePurposeAppFunctionality" }, + { "Developer Advertising", "NSPrivacyCollectedDataTypePurposeDeveloperAdvertising" }, + { "Third-party Advertising", "NSPrivacyCollectedDataTypePurposeThirdPartyAdvertising" }, + { "Product Personalization", "NSPrivacyCollectedDataTypePurposeProductPersonalization" }, + { "Other", "NSPrivacyCollectedDataTypePurposeOther" }, +}; + void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options) const { #ifdef MACOS_ENABLED r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "export/distribution_type", PROPERTY_HINT_ENUM, "Testing,Distribution,App Store"), 1, true)); @@ -484,6 +541,25 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "", false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "privacy/tracking_enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "privacy/tracking_domains"), Vector<String>())); + + { + String hint; + for (uint64_t i = 0; i < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++i) { + if (i != 0) { + hint += ","; + } + hint += vformat("%s:%d", data_collect_purpose_info[i].prop_name, (1 << i)); + } + for (uint64_t i = 0; i < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++i) { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/collected", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[i].prop_name), PROPERTY_HINT_FLAGS, hint), 0)); + } + } + String run_script = "#!/usr/bin/env bash\n" "unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"\n" "open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}"; @@ -644,6 +720,85 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<EditorExportPreset> &p_pres p_data = data; } +void EditorExportPlatformMacOS::_fix_privacy_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist) { + String str; + String strnew; + str.parse_utf8((const char *)plist.ptr(), plist.size()); + Vector<String> lines = str.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (lines[i].find("$priv_collection") != -1) { + bool section_opened = false; + for (uint64_t j = 0; j < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++j) { + bool data_collected = p_preset->get(vformat("privacy/collected_data/%s/collected", data_collect_type_info[j].prop_name)); + bool linked = p_preset->get(vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[j].prop_name)); + bool tracking = p_preset->get(vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[j].prop_name)); + int purposes = p_preset->get(vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[j].prop_name)); + if (data_collected) { + if (!section_opened) { + section_opened = true; + strnew += "\t<key>NSPrivacyCollectedDataTypes</key>\n"; + strnew += "\t<array>\n"; + } + strnew += "\t\t<dict>\n"; + strnew += "\t\t\t<key>NSPrivacyCollectedDataType</key>\n"; + strnew += vformat("\t\t\t<string>%s</string>\n", data_collect_type_info[j].type_name); + strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypeLinked</key>\n"; + if (linked) { + strnew += "\t\t\t\t<true/>\n"; + } else { + strnew += "\t\t\t\t<false/>\n"; + } + strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypeTracking</key>\n"; + if (tracking) { + strnew += "\t\t\t\t<true/>\n"; + } else { + strnew += "\t\t\t\t<false/>\n"; + } + if (purposes != 0) { + strnew += "\t\t\t\t<key>NSPrivacyCollectedDataTypePurposes</key>\n"; + strnew += "\t\t\t\t<array>\n"; + for (uint64_t k = 0; k < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++k) { + if (purposes & (1 << k)) { + strnew += vformat("\t\t\t\t\t<string>%s</string>\n", data_collect_purpose_info[k].type_name); + } + } + strnew += "\t\t\t\t</array>\n"; + } + strnew += "\t\t\t</dict>\n"; + } + } + if (section_opened) { + strnew += "\t</array>\n"; + } + } else if (lines[i].find("$priv_tracking") != -1) { + bool tracking = p_preset->get("privacy/tracking_enabled"); + strnew += "\t<key>NSPrivacyTracking</key>\n"; + if (tracking) { + strnew += "\t<true/>\n"; + } else { + strnew += "\t<false/>\n"; + } + Vector<String> tracking_domains = p_preset->get("privacy/tracking_domains"); + if (!tracking_domains.is_empty()) { + strnew += "\t<key>NSPrivacyTrackingDomains</key>\n"; + strnew += "\t<array>\n"; + for (const String &E : tracking_domains) { + strnew += "\t\t<string>" + E + "</string>\n"; + } + strnew += "\t</array>\n"; + } + } else { + strnew += lines[i] + "\n"; + } + } + + CharString cs = strnew.utf8(); + plist.resize(cs.size() - 1); + for (int i = 0; i < cs.size() - 1; i++) { + plist.write[i] = cs[i]; + } +} + void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { String str; String strnew; @@ -1674,6 +1829,10 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p _fix_plist(p_preset, data, pkg_name); } + if (file == "Contents/Resources/PrivacyInfo.xcprivacy") { + _fix_privacy_manifest(p_preset, data); + } + if (file.begins_with("Contents/MacOS/godot_")) { if (file != "Contents/MacOS/" + binary_to_use) { ret = unzGoToNextFile(src_pkg_zip); diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index 2d615abede..6134d756b9 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -85,6 +85,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { OS::ProcessID ssh_pid = 0; int menu_options = 0; + void _fix_privacy_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist); void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); void _make_icon(const Ref<EditorExportPreset> &p_preset, const Ref<Image> &p_icon, Vector<uint8_t> &p_data); diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..f1ea10fbae --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.mypy] +ignore_missing_imports = true +disallow_any_generics = true +no_implicit_optional = true +pretty = true +show_column_numbers = true +warn_redundant_casts = true +warn_return_any = true +warn_unreachable = true +namespace_packages = true +explicit_package_bases = true +exclude = ["thirdparty/"] + +[tool.black] +line-length = 120 +extend-exclude = ".*thirdparty/.*" diff --git a/scene/2d/physics/joints/joint_2d.cpp b/scene/2d/physics/joints/joint_2d.cpp index 6ed64960e8..a32bcbae78 100644 --- a/scene/2d/physics/joints/joint_2d.cpp +++ b/scene/2d/physics/joints/joint_2d.cpp @@ -116,8 +116,12 @@ void Joint2D::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); - body_a->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree)); - body_b->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree)); + if (!body_a->is_connected(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree))) { + body_a->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree)); + } + if (!body_b->is_connected(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree))) { + body_b->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint2D::_body_exit_tree)); + } PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index b5fa48c9c1..2e08afb30d 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -192,7 +192,7 @@ void Node3D::_notification(int p_what) { ERR_FAIL_NULL(data.viewport); if (get_script_instance()) { - get_script_instance()->call(SceneStringName(_enter_world)); + get_script_instance()->call(SNAME("_enter_world")); } #ifdef TOOLS_ENABLED @@ -210,7 +210,7 @@ void Node3D::_notification(int p_what) { #endif if (get_script_instance()) { - get_script_instance()->call(SceneStringName(_exit_world)); + get_script_instance()->call(SNAME("_exit_world")); } data.viewport = nullptr; @@ -582,7 +582,7 @@ void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transfor } if (is_part_of_edited_scene()) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringName(_spatial_editor_group), SceneStringName(_set_subgizmo_selection), this, p_gizmo, p_id, p_transform); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringName(_spatial_editor_group), SNAME("_set_subgizmo_selection"), this, p_gizmo, p_id, p_transform); } #endif } @@ -599,7 +599,7 @@ void Node3D::clear_subgizmo_selection() { } if (is_part_of_edited_scene()) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringName(_spatial_editor_group), SceneStringName(_clear_subgizmo_selection), this); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringName(_spatial_editor_group), SNAME("_clear_subgizmo_selection"), this); } #endif } diff --git a/scene/3d/physics/joints/joint_3d.cpp b/scene/3d/physics/joints/joint_3d.cpp index 8feec9e0e7..47c89f37e2 100644 --- a/scene/3d/physics/joints/joint_3d.cpp +++ b/scene/3d/physics/joints/joint_3d.cpp @@ -106,12 +106,16 @@ void Joint3D::_update_joint(bool p_only_free) { if (body_a) { ba = body_a->get_rid(); - body_a->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree)); + if (!body_a->is_connected(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree))) { + body_a->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree)); + } } if (body_b) { bb = body_b->get_rid(); - body_b->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree)); + if (!body_b->is_connected(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree))) { + body_b->connect(SceneStringName(tree_exiting), callable_mp(this, &Joint3D::_body_exit_tree)); + } } PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index f129a6c810..f14ae3a285 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -276,12 +276,12 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) return true; } #ifndef DISABLE_DEPRECATED - if (p_name == SceneStringName(use_in_baked_light) && bool(p_value)) { + if (p_name == SNAME("use_in_baked_light") && bool(p_value)) { set_gi_mode(GI_MODE_STATIC); return true; } - if (p_name == SceneStringName(use_dynamic_gi) && bool(p_value)) { + if (p_name == SNAME("use_dynamic_gi") && bool(p_value)) { set_gi_mode(GI_MODE_DYNAMIC); return true; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 1cd36c2632..884fc6de07 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1736,12 +1736,10 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { StringName name = p_path.get_name(i); Node *next = nullptr; - if (name == SceneStringName(dot)) { // . - + if (name == SNAME(".")) { next = current; - } else if (name == SceneStringName(doubledot)) { // .. - + } else if (name == SNAME("..")) { if (current == nullptr || !current->data.parent) { return nullptr; } diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index 64b4f5f66e..01d26a8bed 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -991,13 +991,15 @@ void ParticleProcessMaterial::_update_shader() { code += " \n"; if (collision_mode == COLLISION_RIGID) { code += " if (COLLIDED) {\n"; - code += " if (length(VELOCITY) > 3.0) {\n"; - code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n"; - code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; - code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n"; - code += " } else {\n"; - code += " VELOCITY = vec3(0.0);\n"; - code += " }\n"; + code += " float collision_response = dot(COLLISION_NORMAL, VELOCITY);\n"; + code += " float slide_to_bounce_trigger = step(2.0/clamp(collision_bounce + 1.0, 1.0, 2.0), abs(collision_response));\n"; + code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n"; + code += " // Remove all components of VELOCITY that is not tangent to COLLISION_NORMAL\n"; + code += " VELOCITY -= COLLISION_NORMAL * collision_response;\n"; + code += " // Apply friction only to VELOCITY across the surface (Effectively decouples friction and bounce behavior).\n"; + code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n"; + code += " // Add bounce velocity to VELOCITY\n"; + code += " VELOCITY -= COLLISION_NORMAL * collision_response * (collision_bounce * slide_to_bounce_trigger);\n"; code += " }\n"; } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) { code += " if (COLLIDED) {\n"; diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 4990b0cede..2ee27c95e1 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -33,20 +33,12 @@ SceneStringNames *SceneStringNames::singleton = nullptr; SceneStringNames::SceneStringNames() { - _estimate_cost = StaticCString::create("_estimate_cost"); - _compute_cost = StaticCString::create("_compute_cost"); - resized = StaticCString::create("resized"); - dot = StaticCString::create("."); - doubledot = StaticCString::create(".."); draw = StaticCString::create("draw"); - _draw = StaticCString::create("_draw"); hidden = StaticCString::create("hidden"); visibility_changed = StaticCString::create("visibility_changed"); input_event = StaticCString::create("input_event"); shader = StaticCString::create("shader"); - shader_unshaded = StaticCString::create("shader/unshaded"); - shading_mode = StaticCString::create("shader/shading_mode"); tree_entered = StaticCString::create("tree_entered"); tree_exiting = StaticCString::create("tree_exiting"); tree_exited = StaticCString::create("tree_exited"); @@ -86,98 +78,33 @@ SceneStringNames::SceneStringNames() { area_shape_entered = StaticCString::create("area_shape_entered"); area_shape_exited = StaticCString::create("area_shape_exited"); - _body_inout = StaticCString::create("_body_inout"); - _area_inout = StaticCString::create("_area_inout"); - - idle = StaticCString::create("idle"); - iteration = StaticCString::create("iteration"); update = StaticCString::create("update"); updated = StaticCString::create("updated"); - _physics_process = StaticCString::create("_physics_process"); - _process = StaticCString::create("_process"); - - _enter_tree = StaticCString::create("_enter_tree"); - _exit_tree = StaticCString::create("_exit_tree"); - _enter_world = StaticCString::create("_enter_world"); - _exit_world = StaticCString::create("_exit_world"); _ready = StaticCString::create("_ready"); - _update_scroll = StaticCString::create("_update_scroll"); - _update_xform = StaticCString::create("_update_xform"); - - _structured_text_parser = StaticCString::create("_structured_text_parser"); - - _proxgroup_add = StaticCString::create("_proxgroup_add"); - _proxgroup_remove = StaticCString::create("_proxgroup_remove"); - - grouped = StaticCString::create("grouped"); - ungrouped = StaticCString::create("ungrouped"); - screen_entered = StaticCString::create("screen_entered"); screen_exited = StaticCString::create("screen_exited"); - viewport_entered = StaticCString::create("viewport_entered"); - viewport_exited = StaticCString::create("viewport_exited"); - - camera_entered = StaticCString::create("camera_entered"); - camera_exited = StaticCString::create("camera_exited"); - - _input = StaticCString::create("_input"); - _input_event = StaticCString::create("_input_event"); - gui_input = StaticCString::create("gui_input"); - _gui_input = StaticCString::create("_gui_input"); - - _unhandled_input = StaticCString::create("_unhandled_input"); - _unhandled_key_input = StaticCString::create("_unhandled_key_input"); - - _shader_changed = StaticCString::create("_shader_changed"); _spatial_editor_group = StaticCString::create("_spatial_editor_group"); _request_gizmo = StaticCString::create("_request_gizmo"); - _set_subgizmo_selection = StaticCString::create("_set_subgizmo_selection"); - _clear_subgizmo_selection = StaticCString::create("_clear_subgizmo_selection"); offset = StaticCString::create("offset"); - unit_offset = StaticCString::create("unit_offset"); rotation_mode = StaticCString::create("rotation_mode"); rotate = StaticCString::create("rotate"); h_offset = StaticCString::create("h_offset"); v_offset = StaticCString::create("v_offset"); - _update_remote = StaticCString::create("_update_remote"); - _update_pairs = StaticCString::create("_update_pairs"); - - _get_minimum_size = StaticCString::create("_get_minimum_size"); - area_entered = StaticCString::create("area_entered"); area_exited = StaticCString::create("area_exited"); - _has_point = StaticCString::create("_has_point"); - line_separation = StaticCString::create("line_separation"); - _get_drag_data = StaticCString::create("_get_drag_data"); - _drop_data = StaticCString::create("_drop_data"); - _can_drop_data = StaticCString::create("_can_drop_data"); - - baked_light_changed = StaticCString::create("baked_light_changed"); - _baked_light_changed = StaticCString::create("_baked_light_changed"); - - _mouse_enter = StaticCString::create("_mouse_enter"); - _mouse_exit = StaticCString::create("_mouse_exit"); - _mouse_shape_enter = StaticCString::create("_mouse_shape_enter"); - _mouse_shape_exit = StaticCString::create("_mouse_shape_exit"); - - _pressed = StaticCString::create("_pressed"); - _toggled = StaticCString::create("_toggled"); - frame_changed = StaticCString::create("frame_changed"); texture_changed = StaticCString::create("texture_changed"); - playback_speed = StaticCString::create("playback/speed"); - playback_active = StaticCString::create("playback/active"); autoplay = StaticCString::create("autoplay"); blend_times = StaticCString::create("blend_times"); speed = StaticCString::create("speed"); @@ -193,11 +120,7 @@ SceneStringNames::SceneStringNames() { default_ = StaticCString::create("default"); - _window_group = StaticCString::create("_window_group"); - _window_input = StaticCString::create("_window_input"); window_input = StaticCString::create("window_input"); - _window_unhandled_input = StaticCString::create("_window_unhandled_input"); - _get_contents_minimum_size = StaticCString::create("_get_contents_minimum_size"); theme_changed = StaticCString::create("theme_changed"); parameters_base_path = "parameters/"; @@ -206,9 +129,4 @@ SceneStringNames::SceneStringNames() { shader_overrides_group_active = StaticCString::create("_shader_overrides_group_active_"); pressed = StaticCString::create("pressed"); - -#ifndef DISABLE_DEPRECATED - use_in_baked_light = StaticCString::create("use_in_baked_light"); - use_dynamic_gi = StaticCString::create("use_dynamic_gi"); -#endif } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 9544ce9b98..7ed86cde46 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -51,23 +51,14 @@ class SceneStringNames { public: _FORCE_INLINE_ static SceneStringNames *get_singleton() { return singleton; } - StringName _estimate_cost; - StringName _compute_cost; - StringName resized; - StringName dot; - StringName doubledot; StringName draw; StringName hidden; StringName visibility_changed; StringName input_event; - StringName _input_event; StringName gui_input; - StringName _gui_input; StringName item_rect_changed; StringName shader; - StringName shader_unshaded; - StringName shading_mode; StringName tree_entered; StringName tree_exiting; StringName tree_exited; @@ -75,8 +66,6 @@ public: StringName size_flags_changed; StringName minimum_size_changed; StringName sleeping_state_changed; - StringName idle; - StringName iteration; StringName update; StringName updated; @@ -111,82 +100,26 @@ public: StringName area_shape_entered; StringName area_shape_exited; - StringName _body_inout; - StringName _area_inout; - - StringName _physics_process; - StringName _process; - StringName _enter_world; - StringName _exit_world; - StringName _enter_tree; - StringName _exit_tree; - StringName _draw; - StringName _input; StringName _ready; - StringName _unhandled_input; - StringName _unhandled_key_input; - - StringName _pressed; - StringName _toggled; - - StringName _update_scroll; - StringName _update_xform; - - StringName _structured_text_parser; - - StringName _proxgroup_add; - StringName _proxgroup_remove; - - StringName grouped; - StringName ungrouped; - - StringName _has_point; - StringName _get_drag_data; - StringName _can_drop_data; - StringName _drop_data; StringName screen_entered; StringName screen_exited; - StringName viewport_entered; - StringName viewport_exited; - StringName camera_entered; - StringName camera_exited; - - StringName _shader_changed; StringName _spatial_editor_group; StringName _request_gizmo; - StringName _set_subgizmo_selection; - StringName _clear_subgizmo_selection; StringName offset; - StringName unit_offset; StringName rotation_mode; StringName rotate; StringName v_offset; StringName h_offset; - StringName _update_remote; - StringName _update_pairs; - StringName area_entered; StringName area_exited; - StringName _get_minimum_size; - - StringName baked_light_changed; - StringName _baked_light_changed; - - StringName _mouse_enter; - StringName _mouse_exit; - StringName _mouse_shape_enter; - StringName _mouse_shape_exit; - StringName frame_changed; StringName texture_changed; - StringName playback_speed; - StringName playback_active; StringName autoplay; StringName blend_times; StringName speed; @@ -202,23 +135,13 @@ public: StringName Master; StringName parameters_base_path; - - StringName _window_group; - StringName _window_input; - StringName _window_unhandled_input; StringName window_input; - StringName _get_contents_minimum_size; StringName theme_changed; StringName shader_overrides_group; StringName shader_overrides_group_active; StringName pressed; - -#ifndef DISABLE_DEPRECATED - StringName use_in_baked_light; - StringName use_dynamic_gi; -#endif }; #define SceneStringName(m_name) SceneStringNames::get_singleton()->m_name |
