diff options
58 files changed, 1901 insertions, 1418 deletions
diff --git a/SConstruct b/SConstruct index 0fd9326e1c..17184c2e36 100644 --- a/SConstruct +++ b/SConstruct @@ -337,21 +337,27 @@ for path in module_search_paths: # Add module options. for name, path in modules_detected.items(): + sys.path.insert(0, path) + import config + if env_base["modules_enabled_by_default"]: enabled = True - - sys.path.insert(0, path) - import config - try: enabled = config.is_enabled() except AttributeError: pass - sys.path.remove(path) - sys.modules.pop("config") else: enabled = False + # Add module-specific options. + try: + for opt in config.get_opts(selected_platform): + opts.Add(opt) + except AttributeError: + pass + + sys.path.remove(path) + sys.modules.pop("config") opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled)) methods.write_modules(modules_detected) diff --git a/core/io/dir_access.h b/core/io/dir_access.h index 22017efaa3..d5318dfb45 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -108,6 +108,8 @@ public: if (da->remove(p_path) != OK) { ERR_FAIL_MSG("Cannot remove file or directory: " + p_path); } + } else { + ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path); } } diff --git a/core/object/object.cpp b/core/object/object.cpp index 75dbe8872f..0fcd1c0e40 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -472,7 +472,6 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const { if (script_instance && p_reversed) { - p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); } @@ -503,7 +502,6 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons } if (script_instance && !p_reversed) { - p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); } diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 226fd8b791..b06c2e8896 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -101,6 +101,31 @@ Dictionary Script::_get_script_constant_map() { return ret; } +#ifdef TOOLS_ENABLED + +PropertyInfo Script::get_class_category() const { + String path = get_path(); + String name; + + if (is_built_in()) { + if (get_name().is_empty()) { + name = TTR("Built-in script"); + } else { + name = vformat("%s (%s)", get_name(), TTR("Built-in")); + } + } else { + if (get_name().is_empty()) { + name = path.get_file(); + } else { + name = get_name(); + } + } + + return PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY); +} + +#endif // TOOLS_ENABLED + void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate); //ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create); diff --git a/core/object/script_language.h b/core/object/script_language.h index c9f8a4f828..f5f052b600 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -132,6 +132,7 @@ public: #ifdef TOOLS_ENABLED virtual Vector<DocData::ClassDoc> get_documentation() const = 0; + virtual PropertyInfo get_class_category() const; #endif // TOOLS_ENABLED virtual bool has_method(const StringName &p_method) const = 0; diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 10eacfd9f7..2869f4ad98 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -663,6 +663,14 @@ public: if (native_info->get_property_list_func) { uint32_t pcount; const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount); + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_script(); + if (script->is_valid() && pcount > 0) { + p_list->push_back(script->get_class_category()); + } +#endif // TOOLS_ENABLED + for (uint32_t i = 0; i < pcount; i++) { p_list->push_back(PropertyInfo(pinfo[i])); } diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 669e18b5f7..6cca7955ae 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -341,6 +341,8 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D); register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB); register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<Plane, Transform3D, Plane>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PLANE); + register_op<OperatorEvaluatorXFormInv<Plane, Plane, Transform3D>>(Variant::OP_MULTIPLY, Variant::PLANE, Variant::TRANSFORM3D); register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY); register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D); diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 5595abc02a..643351efc0 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -144,7 +144,7 @@ # This code block is part of a script that inherits from Node3D. # `control` is a reference to a node inheriting from Control. control.visible = not get_viewport().get_camera_3d().is_position_behind(global_transform.origin) - control.rect_position = get_viewport().get_camera_3d().unproject_position(global_transform.origin) + control.position = get_viewport().get_camera_3d().unproject_position(global_transform.origin) [/codeblock] </description> </method> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index fea4085019..ade7bc1256 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -151,6 +151,7 @@ <argument index="0" name="name" type="String" /> <argument index="1" name="actions_list" type="Array" /> <description> + Overrides the built-in editor action [code]name[/code] with the input actions defined in [code]actions_list[/code]. </description> </method> <method name="set_favorites"> @@ -196,450 +197,726 @@ </methods> <members> <member name="debugger/profiler_frame_history_size" type="int" setter="" getter=""> + The size of the profiler's frame history. The default value (3600) allows seeing up to 60 seconds of profiling if the project renders at a constant 60 FPS. Higher values allow viewing longer periods of profiling in the graphs, especially when the project is running at high framerates. </member> <member name="docks/filesystem/always_show_folders" type="bool" setter="" getter=""> + If [code]true[/code], displays folders in the FileSystem dock's bottom pane when split mode is enabled. If [code]false[/code], only files will be displayed in the bottom pane. Split mode can be toggled by pressing the icon next to the [code]res://[/code] folder path. + [b]Note:[/b] This setting has no effect when split mode is disabled (which is the default). </member> <member name="docks/filesystem/textfile_extensions" type="String" setter="" getter=""> + List of file extensions to consider as editable text files in the FileSystem dock (by double-clicking on the files). </member> <member name="docks/filesystem/thumbnail_size" type="int" setter="" getter=""> + The thumbnail size to use in the FileSystem dock (in pixels). See also [member filesystem/file_dialog/thumbnail_size]. </member> <member name="docks/property_editor/auto_refresh_interval" type="float" setter="" getter=""> + The refresh interval to use for the inspector dock's properties. The effect of this setting is mainly noticeable when adjusting gizmos in the 2D/3D editor and looking at the inspector at the same time. Lower values make the inspector more often, but take up more CPU time. </member> <member name="docks/property_editor/subresource_hue_tint" type="float" setter="" getter=""> + The tint intensity to use for the subresources background in the inspector dock. The tint is used to distinguish between different subresources in the inspector. Higher values result in a more noticeable background color difference. </member> <member name="docks/scene_tree/auto_expand_to_selected" type="bool" setter="" getter=""> + If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected. </member> <member name="docks/scene_tree/start_create_dialog_fully_expanded" type="bool" setter="" getter=""> + If [code]true[/code], the Create dialog (Create New Node/Create New Resource) will start with all its sections expanded. Otherwise, sections will be collapsed until the user starts searching (which will automatically expand sections as needed). </member> <member name="editors/2d/bone_color1" type="Color" setter="" getter=""> + The "start" stop of the color gradient to use for bones in the 2D skeleton editor. </member> <member name="editors/2d/bone_color2" type="Color" setter="" getter=""> + The "end" stop of the color gradient to use for bones in the 2D skeleton editor. </member> <member name="editors/2d/bone_ik_color" type="Color" setter="" getter=""> + The color to use for inverse kinematics-enabled bones in the 2D skeleton editor. </member> <member name="editors/2d/bone_outline_color" type="Color" setter="" getter=""> + The outline color to use for non-selected bones in the 2D skeleton editor. See also [member editors/2d/bone_selected_color]. </member> <member name="editors/2d/bone_outline_size" type="int" setter="" getter=""> + The outline size in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_width]. </member> <member name="editors/2d/bone_selected_color" type="Color" setter="" getter=""> + The color to use for selected bones in the 2D skeleton editor. See also [member editors/2d/bone_outline_color]. </member> <member name="editors/2d/bone_width" type="int" setter="" getter=""> + The bone width in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_outline_size]. </member> <member name="editors/2d/constrain_editor_view" type="bool" setter="" getter=""> + If [code]true[/code], prevents the 2D editor viewport from leaving the scene. Limits are calculated dynamically based on nodes present in the current scene. If [code]false[/code], the 2D editor viewport will be able to move freely, but you risk getting lost when zooming out too far. You can refocus on the scene by selecting a node then pressing [kbd]F[/kbd]. </member> <member name="editors/2d/grid_color" type="Color" setter="" getter=""> + The grid color to use in the 2D editor. </member> <member name="editors/2d/guides_color" type="Color" setter="" getter=""> + The guides color to use in the 2D editor. Guides can be created by dragging the mouse cursor from the rulers. </member> <member name="editors/2d/smart_snapping_line_color" type="Color" setter="" getter=""> + The color to use when drawing smart snapping lines in the 2D editor. The smart snapping lines will automatically display when moving 2D nodes if smart snapping is enabled in the Snapping Options menu at the top of the 2D editor viewport. </member> <member name="editors/2d/viewport_border_color" type="Color" setter="" getter=""> + The color of the viewport border in the 2D editor. This border represents the viewport's size at the base resolution defined in the Project Settings. Objects placed outside this border will not be visible unless a [Camera2D] node is used, or unless the window is resized and the stretch mode is set to [code]disabled[/code]. </member> <member name="editors/3d/default_fov" type="float" setter="" getter=""> + The default camera field of view to use in the 3D editor (in degrees). The camera field of view can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera field of view adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor. </member> <member name="editors/3d/default_z_far" type="float" setter="" getter=""> + The default camera far clip distance to use in the 3D editor (in degrees). Higher values make it possible to view objects placed further away from the camera, at the cost of lower precision in the depth buffer (which can result in visible Z-fighting in the distance). The camera far clip distance can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera far clip distance adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor. </member> <member name="editors/3d/default_z_near" type="float" setter="" getter=""> + The default camera near clip distance to use in the 3D editor (in degrees). Lower values make it possible to view objects placed closer to the camera, at the cost of lower precision in the depth buffer (which can result in visible Z-fighting in the distance). The camera near clip distance can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera near clip distance adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor. </member> <member name="editors/3d/freelook/freelook_activation_modifier" type="int" setter="" getter=""> + The modifier key to use to enable freelook in the 3D editor (on top of pressing the right mouse button). + [b]Note:[/b] Regardless of this setting, the freelook toggle keyboard shortcut ([kbd]Shift + F[/kbd] by default) is always available. + [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed. </member> <member name="editors/3d/freelook/freelook_base_speed" type="float" setter="" getter=""> + The base 3D freelook speed in units per second. This can be adjusted by using the mouse wheel while in freelook mode, or by holding down the "fast" or "slow" modifier keys ([kbd]Shift[/kbd] and [kbd]Alt[/kbd] by default, respectively). </member> <member name="editors/3d/freelook/freelook_inertia" type="float" setter="" getter=""> + The inertia of the 3D freelook camera. Higher values make the camera start and stop slower, which looks smoother but adds latency. </member> <member name="editors/3d/freelook/freelook_navigation_scheme" type="int" setter="" getter=""> + The navigation scheme to use when freelook is enabled in the 3D editor. Some of the navigation schemes below may be more convenient when designing specific levels in the 3D editor. + - [b]Default:[/b] The "Freelook Forward", "Freelook Backward", "Freelook Up" and "Freelook Down" keys will move relative to the camera, taking its pitch angle into account for the movement. + - [b]Partially Axis-Locked:[/b] The "Freelook Forward" and "Freelook Backward" keys will move relative to the camera, taking its pitch angle into account for the movement. The "Freelook Up" and "Freelook Down" keys will move in an "absolute" manner, [i]not[/i] taking the camera's pitch angle into account for the movement. + - [b]Fully Axis-Locked:[/b] The "Freelook Forward", "Freelook Backward", "Freelook Up" and "Freelook Down" keys will move in an "absolute" manner, [i]not[/i] taking the camera's pitch angle into account for the movement. + See also [member editors/3d/navigation/navigation_scheme]. </member> <member name="editors/3d/freelook/freelook_sensitivity" type="float" setter="" getter=""> + The mouse sensitivity to use while freelook mode is active in the 3D editor. See also [member editors/3d/navigation_feel/orbit_sensitivity]. </member> <member name="editors/3d/freelook/freelook_speed_zoom_link" type="bool" setter="" getter=""> + If [code]true[/code], freelook speed is linked to the zoom value used in the camera orbit mode in the 3D editor. </member> <member name="editors/3d/grid_division_level_bias" type="float" setter="" getter=""> + The grid division bias to use in the 3D editor. Negative values will cause small grid divisions to appear earlier, whereas positive values will cause small grid divisions to appear later. </member> <member name="editors/3d/grid_division_level_max" type="int" setter="" getter=""> + The smallest grid division to use in the 3D editor, specified as a power of 2. The grid will not be able to get larger than [code]1 ^ grid_division_level_max[/code] units. By default, this means grid divisions cannot get smaller than 100 units each, no matter how far away the camera is from the grid. </member> <member name="editors/3d/grid_division_level_min" type="int" setter="" getter=""> + The smallest grid division to use in the 3D editor, specified as a power of 2. The grid will not be able to get smaller than [code]1 ^ grid_division_level_min[/code] units. By default, this means grid divisions cannot get smaller than 1 unit each, no matter how close the camera is from the grid. </member> <member name="editors/3d/grid_size" type="int" setter="" getter=""> + The grid size in units. Higher values prevent the grid from appearing "cut off" at certain angles, but make the grid more demanding to render. Depending on the camera's position, the grid may not be fully visible since a shader is used to fade it progressively. </member> <member name="editors/3d/grid_xy_plane" type="bool" setter="" getter=""> + If [code]true[/code], render the grid on an XY plane. This can be useful for 3D side-scrolling games. </member> <member name="editors/3d/grid_xz_plane" type="bool" setter="" getter=""> + If [code]true[/code], render the grid on an XZ plane. </member> <member name="editors/3d/grid_yz_plane" type="bool" setter="" getter=""> + If [code]true[/code], render the grid on an YZ plane. This can be useful for 3D side-scrolling games. </member> <member name="editors/3d/navigation/emulate_3_button_mouse" type="bool" setter="" getter=""> + If [code]true[/code], enables 3-button mouse emulation mode. This is useful on laptops when using a trackpad. + When 3-button mouse emulation mode is enabled, the pan, zoom and orbit modifiers can always be used in the 3D editor viewport, even when not holding down any mouse button. + [b]Note:[/b] No matter the orbit modifier configured in [member editors/3d/navigation/orbit_modifier], [kbd]Alt[/kbd] will always remain usable for orbiting in this mode to improve usability with graphics tablets. </member> <member name="editors/3d/navigation/emulate_numpad" type="bool" setter="" getter=""> + If [code]true[/code], allows using the top row [kbd]0[/kbd]-[kbd]9[/kbd] keys to function as their equivalent numpad keys for 3D editor navigation. This should be enabled on keyboards that have no numeric keypad available. </member> <member name="editors/3d/navigation/invert_x_axis" type="bool" setter="" getter=""> + If [code]true[/code], invert the horizontal mouse axis when panning or orbiting in the 3D editor. This setting does [i]not[/i] apply to freelook mode. </member> <member name="editors/3d/navigation/invert_y_axis" type="bool" setter="" getter=""> + If [code]true[/code], invert the vertical mouse axis when panning, orbiting, or using freelook mode in the 3D editor. </member> <member name="editors/3d/navigation/navigation_scheme" type="int" setter="" getter=""> + The navigation scheme to use in the 3D editor. Changing this setting will affect the mouse buttons that must be held down to perform certain operations in the 3D editor viewport. + - [b]Godot[/b] Middle mouse button to orbit, [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Mouse wheel[/kbd] to zoom. + - [b]Maya:[/b] [kbd]Alt + Left mouse buttton[/kbd] to orbit. [kbd]Middle mouse button[/kbd] to pan, [kbd]Shift + Middle mouse button[/kbd] to pan 10 times faster. [kbd]Mouse wheel[/kbd] to zoom. + - [b]Modo:[/b] [kbd]Alt + Left mouse buttton[/kbd] to orbit. [kbd]Alt + Shift + Left mouse button[/kbd] to pan. [kbd]Ctrl + Alt + Left mouse button[/kbd] to zoom. + See also [member editors/3d/freelook/freelook_navigation_scheme]. + [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed. </member> <member name="editors/3d/navigation/orbit_modifier" type="int" setter="" getter=""> + The modifier key that must be held to orbit in the 3D editor. + [b]Note:[/b] If [member editors/3d/navigation/emulate_3_button_mouse] is [code]true[/code], [kbd]Alt[/kbd] will always remain usable for orbiting to improve usability with graphics tablets. + [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed. </member> <member name="editors/3d/navigation/pan_modifier" type="int" setter="" getter=""> + The modifier key that must be held to pan in the 3D editor. + [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed. </member> <member name="editors/3d/navigation/warped_mouse_panning" type="bool" setter="" getter=""> + If [code]true[/code], warps the mouse around the 3D viewport while panning in the 3D editor. This makes it possible to pan over a large area without having to exit panning then mouse the mouse back constantly. </member> <member name="editors/3d/navigation/zoom_modifier" type="int" setter="" getter=""> + The modifier key that must be held to zoom in the 3D editor. + [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed. </member> <member name="editors/3d/navigation/zoom_style" type="int" setter="" getter=""> + The mouse cursor movement direction to use when zooming by moving the mouse. This does not affect zooming with the mouse wheel. </member> <member name="editors/3d/navigation_feel/orbit_inertia" type="float" setter="" getter=""> + The inertia to use when orbiting in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency. </member> <member name="editors/3d/navigation_feel/orbit_sensitivity" type="float" setter="" getter=""> + The mouse sensitivity to use when orbiting in the 3D editor. See also [member editors/3d/freelook/freelook_sensitivity]. </member> <member name="editors/3d/navigation_feel/translation_inertia" type="float" setter="" getter=""> + The inertia to use when panning in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency. </member> <member name="editors/3d/navigation_feel/zoom_inertia" type="float" setter="" getter=""> + The inertia to use when zooming in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency. </member> <member name="editors/3d/primary_grid_color" type="Color" setter="" getter=""> + The color to use for the primary 3D grid. The color's alpha channel affects the grid's opacity. </member> <member name="editors/3d/primary_grid_steps" type="int" setter="" getter=""> + If set above 0, where a primary grid line should be drawn. By default, primary lines are configured to be more visible than secondary lines. This helps with measurements in the 3D editor. See also [member editors/3d/primary_grid_color] and [member editors/3d/secondary_grid_color]. </member> <member name="editors/3d/secondary_grid_color" type="Color" setter="" getter=""> + The color to use for the secondary 3D grid. This is generally a less visible color than [member editors/3d/primary_grid_color]. The color's alpha channel affects the grid's opacity. </member> <member name="editors/3d/selection_box_color" type="Color" setter="" getter=""> + The color to use for the selection box that surrounds selected nodes in the 3D editor viewport. The color's alpha channel influences the selection box's opacity. </member> <member name="editors/3d_gizmos/gizmo_colors/instantiated" type="Color" setter="" getter=""> + The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instanced scene file (from the perspective of the current scene). </member> <member name="editors/3d_gizmos/gizmo_colors/joint" type="Color" setter="" getter=""> + The 3D editor gizmo color for [Joint3D]s and [PhysicalBone3D]s. </member> <member name="editors/3d_gizmos/gizmo_colors/shape" type="Color" setter="" getter=""> + The 3D editor gizmo color for [CollisionShape3D]s, [VehicleWheel3D]s, [RayCast3D]s and [SpringArm3D]s. </member> <member name="editors/animation/autorename_animation_tracks" type="bool" setter="" getter=""> + If [code]true[/code], automatically updates animation tracks' target paths when renaming or reparenting nodes in the Scene tree dock. </member> <member name="editors/animation/confirm_insert_track" type="bool" setter="" getter=""> + If [code]true[/code], display a confirmation dialog when adding a new track to an animation by pressing the "key" icon next to a property. </member> <member name="editors/animation/default_create_bezier_tracks" type="bool" setter="" getter=""> + If [code]true[/code], create a Bezier track instead of a standard track when pressing the "key" icon next to a property. Bezier tracks provide more control over animation curves, but are more difficult to adjust quickly. </member> <member name="editors/animation/default_create_reset_tracks" type="bool" setter="" getter=""> + If [code]true[/code], create a [code]RESET[/code] track when creating a new animation track. This track can be used to restore the animation to a "default" state. </member> <member name="editors/animation/onion_layers_future_color" type="Color" setter="" getter=""> + The modulate color to use for "future" frames displayed in the animation editor's onion skinning feature. </member> <member name="editors/animation/onion_layers_past_color" type="Color" setter="" getter=""> + The modulate color to use for "past" frames displayed in the animation editor's onion skinning feature. </member> <member name="editors/grid_map/pick_distance" type="float" setter="" getter=""> + The maximum distance at which tiles can be placed on a GridMap, relative to the camera position (in 3D units). </member> <member name="editors/panning/2d_editor_pan_speed" type="int" setter="" getter=""> + The panning speed when using the mouse wheel or touchscreen events in the 2D editor. This setting does not apply to panning by holding down the middle or right mouse buttons. </member> <member name="editors/panning/2d_editor_panning_scheme" type="int" setter="" getter=""> + Controls whether the mouse wheel scroll zooms or pans in the 2D editor. See also [member editors/panning/sub_editors_panning_scheme] and [member editors/panning/animation_editors_panning_scheme]. </member> <member name="editors/panning/animation_editors_panning_scheme" type="int" setter="" getter=""> + Controls whether the mouse wheel scroll zooms or pans in the animation track and Bezier editors. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/sub_editors_panning_scheme] (which controls the animation blend tree editor's pan behavior). </member> <member name="editors/panning/simple_panning" type="bool" setter="" getter=""> + If [code]true[/code], allows panning by holding down [kbd]Space[/kbd] in the 2D editor viewport (in addition to panning with the middle or right mouse buttons). If [code]false[/code], the left mouse button must be held down while holding down [kbd]Space[/kbd] to pan in the 2D editor viewport. </member> <member name="editors/panning/sub_editors_panning_scheme" type="int" setter="" getter=""> + Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor, visual shader editor and visual script editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme]. </member> <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 then mouse the mouse back constantly. </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> <member name="editors/polygon_editor/show_previous_outline" type="bool" setter="" getter=""> + If [code]true[/code], displays the polygon's previous shape in the 2D polygon editors with an opaque gray outline. This outline is displayed while dragging a point until the left mouse button is released. </member> <member name="editors/tiles_editor/display_grid" type="bool" setter="" getter=""> + If [code]true[/code], displays a grid while the TileMap editor is active. See also [member editors/tiles_editor/grid_color]. </member> <member name="editors/tiles_editor/grid_color" type="Color" setter="" getter=""> + The color to use for the TileMap editor's grid. + [b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code]. </member> <member name="editors/visual_editors/lines_curvature" type="float" setter="" getter=""> + The curvature to use for connection lines in the visual script and visual shader editors. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines. </member> <member name="editors/visual_editors/minimap_opacity" type="float" setter="" getter=""> + The opacity of the minimap displayed in the bottom-right corner of the visual script and visual shader editors. </member> <member name="editors/visual_editors/visual_shader/port_preview_size" type="int" setter="" getter=""> + The size to use for port previews in the visual shader uniforms (toggled by clicking the "eye" icon next to an output). The value is defined in pixels at 100% zoom, and will scale with zoom automatically. </member> <member name="filesystem/directories/autoscan_project_path" type="String" setter="" getter=""> + The folder where projects should be scanned for (recursively), in a way similar to the project manager's [b]Scan[/b]button. This can be set to the same value as [member filesystem/directories/default_project_path] for convenience. + [b]Note:[/b] Setting this path to a folder with very large amounts of files/folders can slow down the project manager startup significantly. To keep the project manager quick to start up, it is recommended to set this value to a folder as "specific" as possible. </member> <member name="filesystem/directories/default_project_path" type="String" setter="" getter=""> + The folder where new projects should be created by default when clicking the project manager's [b]New Project[/b] button. This can be set to the same value as [member filesystem/directories/autoscan_project_path] for convenience. </member> <member name="filesystem/file_dialog/display_mode" type="int" setter="" getter=""> + The display mode to use in the editor's file dialogs. + - [b]Thumbnails[/b] takes more space, but displays dynamic resource thumbnails, making resources easier to preview without having to open them. + - [b]List[/b] is more compact but doesn't display dynamic resource thumbnails. Instead, it displays static icons based on the file extension. </member> <member name="filesystem/file_dialog/show_hidden_files" type="bool" setter="" getter=""> + If [code]true[/code], display hidden files in the editor's file dialogs. Files that have names starting with [code].[/code] are considered hidden (e.g. [code].hidden_file[/code]). </member> <member name="filesystem/file_dialog/thumbnail_size" type="int" setter="" getter=""> + The thumbnail size to use in the editor's file dialogs (in pixels). See also [member docks/filesystem/thumbnail_size]. </member> <member name="filesystem/on_save/compress_binary_resources" type="bool" setter="" getter=""> + If [code]true[/code], uses lossless compression for binary resources. </member> <member name="filesystem/on_save/safe_save_on_backup_then_rename" type="bool" setter="" getter=""> + If [code]true[/code], when saving a file, the editor will rename the old file to a different name, save a new file, then only remove the old file once the new file has been saved. This makes loss of data less likely to happen if the editor or operating system exits unexpectedly while saving (e.g. due to a crash or power outage). + [b]Note:[/b] On Windows, this feature can interact negatively with certain antivirus programs. In this case, you may have to set this to [code]false[/code] to prevent file locking issues. </member> <member name="interface/editor/automatically_open_screenshots" type="bool" setter="" getter=""> + If [code]true[/code], automatically opens screenshots with the default program associated to [code].png[/code] files after a screenshot is taken using the [b]Editor > Take Screenshot[/b] action. </member> <member name="interface/editor/code_font" type="String" setter="" getter=""> + The font to use for the script editor. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file. </member> <member name="interface/editor/code_font_contextual_ligatures" type="int" setter="" getter=""> + The font ligatures to enable for the currently configured code font. Not all fonts include support for ligatures. + [b]Note:[/b] The default editor code font (Hack) does not have contextual ligatures in its font file. </member> <member name="interface/editor/code_font_custom_opentype_features" type="String" setter="" getter=""> + List of custom OpenType features to use, if supported by the currently configured code font. Not all fonts include support for custom OpenType features. The string should follow the OpenType specification. + [b]Note:[/b] The default editor code font (Hack) does not have custom OpenType features in its font file. </member> <member name="interface/editor/code_font_custom_variations" type="String" setter="" getter=""> + List of alternative characters to use, if supported by the currently configured code font. Not all fonts include support for custom variations. The string should follow the OpenType specification. + [b]Note:[/b] The default editor code font (Hack) does not have alternate characters in its font file. </member> <member name="interface/editor/code_font_size" type="int" setter="" getter=""> + The size of the font in the script editor. This setting does not impact the font size of the Output panel (see [member run/output/font_size]). </member> <member name="interface/editor/custom_display_scale" type="float" setter="" getter=""> + The custom editor scale factor to use. This can be used for displays with very high DPI where a scale factor of 200% is not sufficient. + [b]Note:[/b] Only effective if [member interface/editor/display_scale] is set to [b]Custom[/b]. </member> <member name="interface/editor/debug/enable_pseudolocalization" type="bool" setter="" getter=""> + If [code]true[/code], lengthens the editor's localizable strings and replaces their characters with accented variants. This allows spotting non-localizable strings easily, while also ensuring the UI layout doesn't break when strings are made longer (as many languages require strings to be longer). + This is a debugging feature and should only be enabled when working on the editor itself. </member> <member name="interface/editor/display_scale" type="int" setter="" getter=""> + The display scale factor to use for the editor interface. Higher values are more suited to hiDPI/Retina displays. + If set to [b]Auto[/b], the editor scale is automatically determined based on the screen resolution and reported display DPI. This heuristic is not always ideal, which means you can get better results by setting the editor scale manually. + If set to [b]Custom[/b], the scaling value in [member interface/editor/custom_display_scale] will be used. </member> <member name="interface/editor/editor_language" type="String" setter="" getter=""> + The language to use for the editor interface. + Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url] </member> <member name="interface/editor/font_antialiased" type="bool" setter="" getter=""> + If [code]true[/code], enables FreeType's font antialiasing on the editor fonts. Most fonts are not designed to look good with antialiasing disabled, so it's recommended to leave this enabled unless you're using a pixel art font. </member> <member name="interface/editor/font_hinting" type="int" setter="" getter=""> + The font hinting mode to use for the editor fonts. FreeType supports the following font hinting modes: + - [b]None:[/b] Don't use font hinting when rasterizing the font. This results in a smooth font, but it can look blurry. + - [b]Light:[/b] Use hinting on the X axis only. This is a compromise between font sharpness and smoothness. + - [b]Normal:[/b] Use hinting on both X and Y axes. This results in a sharp font, but it doesn't look very smooth. + If set to [b]Auto[/b], the font hinting mode will be set to match the current operating system in use. This means the [b]Light[/b] hinting mode will be used on Windows and Linux, and the [b]None[/b] hinting mode will be used on macOS. </member> <member name="interface/editor/font_subpixel_positioning" type="int" setter="" getter=""> + The subpixel positioning mode to use when rendering editor font glyphs. This affects both the main and code fonts. [b]Disabled[/b] is the fastest to render and uses the least memory. [b]Auto[/b] only uses subpixel positioning for small font sizes (where the benefit is the most noticeable). [b]One half of a pixel[/b] and [b]One quarter of a pixel[/b] force the same subpixel positioning mode for all editor fonts, regardless of their size (with [b]One quarter of a pixel[/b] being the highest-quality option). </member> <member name="interface/editor/low_processor_mode_sleep_usec" type="float" setter="" getter=""> + The amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops. However, higher values will result in a less responsive editor. The default value is set to allow for maximum smoothness on monitors up to 144 Hz. See also [member interface/editor/unfocused_low_processor_mode_sleep_usec]. </member> <member name="interface/editor/main_font" type="String" setter="" getter=""> + The font to use for the editor interface. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file. </member> <member name="interface/editor/main_font_bold" type="String" setter="" getter=""> + The font to use for bold text in the editor interface. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file. </member> <member name="interface/editor/main_font_size" type="int" setter="" getter=""> + The size of the font in the editor interface. </member> <member name="interface/editor/mouse_extra_buttons_navigate_history" type="bool" setter="" getter=""> + If [code]true[/code], the mouse's additional side buttons will be usable to navigate in the script editor's file history. Set this to [code]false[/code] if you're using the side buttons for other purposes (such as a push-to-talk button in a VoIP program). </member> <member name="interface/editor/save_each_scene_on_quit" type="bool" setter="" getter=""> + If [code]true[/code], the editor will save all scenes when confirming the [b]Save[/b] action when quitting the editor or quitting to the project list. If [code]false[/code], the editor will ask to save each scene individually. </member> <member name="interface/editor/separate_distraction_mode" type="bool" setter="" getter=""> + If [code]true[/code], the editor's Script tab will have a separate distraction mode setting from the 2D/3D/AssetLib tabs. If [code]false[/code], the distraction-free mode toggle is shared between all tabs. </member> <member name="interface/editor/show_internal_errors_in_toast_notifications" type="int" setter="" getter=""> + If enabled, displays internal engine errors in toast notifications (toggleable by clicking the "bell" icon at the bottom of the editor). No matter the value of this setting, non-internal engine errors will always be visible in toast notifications. + The default [b]Auto[/b] value will only enable this if the editor was compiled with the [code]dev=yes[/code] option (the default is [code]dev=no[/code]). </member> <member name="interface/editor/single_window_mode" type="bool" setter="" getter=""> + If [code]true[/code], embed modal windows such as docks inside the main editor window. When single-window mode is enabled, tooltips will also be embedded inside the main editor window, which means they can't be displayed outside of the editor window. </member> <member name="interface/editor/unfocused_low_processor_mode_sleep_usec" type="float" setter="" getter=""> + When the editor window is unfocused, the amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops (in addition to improving the running project's performance if the editor has to redraw continuously). However, higher values will result in a less responsive editor. The default value is set to limit the editor to 20 FPS when the editor window is unfocused. See also [member interface/editor/low_processor_mode_sleep_usec]. </member> <member name="interface/inspector/max_array_dictionary_items_per_page" type="int" setter="" getter=""> + The number of [Array] or [Dictionary] items to display on each "page" in the inspector. Higher values allow viewing more values per page, but take more time to load. This increased load time is noticeable when selecting nodes that have array or dictionary properties in the editor. </member> <member name="interface/inspector/show_low_level_opentype_features" type="bool" setter="" getter=""> + If [code]true[/code], display OpenType features marked as [code]hidden[/code] by the font file in the [Font] editor. </member> <member name="interface/scene_tabs/display_close_button" type="int" setter="" getter=""> + Controls when the Close (X) button is displayed on scene tabs at the top of the editor. </member> <member name="interface/scene_tabs/maximum_width" type="int" setter="" getter=""> + The maximum width of each scene tab at the top editor (in pixels). </member> <member name="interface/scene_tabs/show_script_button" type="bool" setter="" getter=""> + If [code]true[/code], show a button next to each scene tab that opens the scene's "dominant" script when clicked. The "dominant" script is the one that is at the highest level in the scene's hierarchy. </member> <member name="interface/scene_tabs/show_thumbnail_on_hover" type="bool" setter="" getter=""> + If [code]true[/code], display an automatically-generated thumbnail when hovering scene tabs with the mouse. Scene thumbnails are generated when saving the scene. </member> <member name="interface/theme/accent_color" type="Color" setter="" getter=""> + The color to use for "highlighted" user interface elements in the editor (pressed and hovered items). </member> <member name="interface/theme/additional_spacing" type="float" setter="" getter=""> + The spacing to add for buttons and list items in the editor (in pixels). Increasing this value is useful to improve usability on touch screens, at the cost of reducing the amount of usable screen real estate. </member> <member name="interface/theme/base_color" type="Color" setter="" getter=""> + The base color to use for user interface elements in the editor. Secondary colors (such as darker/lighter variants) are derived from this color. </member> <member name="interface/theme/border_size" type="int" setter="" getter=""> + The border size to use for interface elements (in pixels). </member> <member name="interface/theme/contrast" type="float" setter="" getter=""> + The contrast factor to use when deriving the editor theme's base color (see [member interface/theme/base_color]). When using a positive values, the derived colors will be [i]darker[/i] than the base color. This contrast factor can be set to a negative value, which will make the derived colors [i]brighter[/i] than the base color. Negative contrast rates often look better for light themes. </member> <member name="interface/theme/corner_radius" type="int" setter="" getter=""> + The corner radius to use for interface elements (in pixels). [code]0[/code] is square. </member> <member name="interface/theme/custom_theme" type="String" setter="" getter=""> + The custom theme resource to use for the editor. Must be a Godot theme resource in [code].tres[/code] or [code].res[/code] format. </member> <member name="interface/theme/icon_and_font_color" type="int" setter="" getter=""> + The icon and font color scheme to use in the editor. + - [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color]. + - [b]Dark[/b] makes fonts and icons light (suitable for dark themes). + - [b]Light[/b] makes fonts and icons dark (suitable for light themes). Icon colors are automatically converted by the editor following [url=https://github.com/godotengine/godot/blob/master/editor/editor_themes.cpp#L135]this set of rules[/url]. </member> <member name="interface/theme/icon_saturation" type="float" setter="" getter=""> + The saturation to use for editor icons. Higher values result in more vibrant colors. + [b]Note:[/b] The default editor icon saturation was increased by 30% in Godot 4.0 and later. To get Godot 3.x's icon saturation back, set [member interface/theme/icon_saturation] to [code]0.77[/code]. </member> <member name="interface/theme/preset" type="String" setter="" getter=""> + The editor theme preset to use. </member> <member name="interface/theme/relationship_line_opacity" type="float" setter="" getter=""> + The opacity to use when drawing relationship lines in the editor's [Tree]-based GUIs (such as the Scene tree dock). </member> <member name="network/debug/remote_host" type="String" setter="" getter=""> + The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]). </member> <member name="network/debug/remote_port" type="int" setter="" getter=""> + The port to listen to when starting the remote debugger. Godot will try to use port numbers above the configured number if the configured number is already taken by another application. </member> <member name="network/http_proxy/host" type="String" setter="" getter=""> + The host to use to contact the HTTP and HTTPS proxy in the editor (for the asset library and export template downloads). See also [member network/http_proxy/port]. + [b]Note:[/b] Godot currently doesn't automatically use system proxy settings, so you have to enter them manually here if needed. </member> <member name="network/http_proxy/port" type="int" setter="" getter=""> + The port number to use to contact the HTTP and HTTPS proxy in the editor (for the asset library and export template downloads). See also [member network/http_proxy/host]. + [b]Note:[/b] Godot currently doesn't automatically use system proxy settings, so you have to enter them manually here if needed. </member> <member name="network/ssl/editor_ssl_certificates" type="String" setter="" getter=""> + The SSL certificate bundle to use for HTTP requests made within the editor (e.g. from the AssetLib tab). If left empty, the [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]included Mozilla certificate bundle[/url] will be used. </member> <member name="project_manager/sorting_order" type="int" setter="" getter=""> + The sorting order to use in the project manager. When changing the sorting order in the project manager, this setting is set permanently in the editor settings. </member> <member name="run/auto_save/save_before_running" type="bool" setter="" getter=""> + If [code]true[/code], saves all scenes and scripts automatically before running the project. Setting this to [code]false[/code] prevents the editor from saving if there are no changes which can speed up the project startup slightly, but it makes it possible to run a project that has unsaved changes. (Unsaved changes will not be visible in the running project.) </member> <member name="run/output/always_clear_output_on_play" type="bool" setter="" getter=""> + If [code]true[/code], the editor will clear the Output panel when running the project. </member> <member name="run/output/always_close_output_on_stop" type="bool" setter="" getter=""> + If [code]true[/code], the editor will collapse the Output panel when stopping the project. </member> <member name="run/output/always_open_output_on_play" type="bool" setter="" getter=""> + If [code]true[/code], the editor will expand the Output panel when running the project. </member> <member name="run/output/font_size" type="int" setter="" getter=""> + The size of the font in the [b]Output[/b] panel at the bottom of the editor. This setting does not impact the font size of the script editor (see [member interface/editor/code_font_size]). </member> <member name="run/window_placement/rect" type="int" setter="" getter=""> + The window mode to use to display the project when starting the project from the editor. </member> <member name="run/window_placement/rect_custom_position" type="Vector2" setter="" getter=""> + The custom position to use when starting the project from the editor (in pixels from the top-left corner). Only effective if [member run/window_placement/rect] is set to [b]Custom Position[/b]. </member> <member name="run/window_placement/screen" type="int" setter="" getter=""> + The monitor to display the project on when starting the project from the editor. </member> <member name="text_editor/appearance/caret/caret_blink" type="bool" setter="" getter=""> + If [code]true[/code], makes the caret blink according to [member text_editor/appearance/caret/caret_blink_speed]. Disabling this setting can improve battery life on laptops if you spend long amounts of time in the script editor, since it will reduce the frequency at which the editor needs to be redrawn. </member> <member name="text_editor/appearance/caret/caret_blink_speed" type="float" setter="" getter=""> + The interval at which to blink the caret (in seconds). See also [member text_editor/appearance/caret/caret_blink]. </member> <member name="text_editor/appearance/caret/highlight_all_occurrences" type="bool" setter="" getter=""> + If [code]true[/code], highlights all occurrences of the currently selected text in the script editor. See also [member text_editor/theme/highlighting/word_highlighted_color]. </member> <member name="text_editor/appearance/caret/highlight_current_line" type="bool" setter="" getter=""> + If [code]true[/code], colors the background of the line the caret is currently on with [member text_editor/theme/highlighting/current_line_color]. </member> <member name="text_editor/appearance/caret/type" type="int" setter="" getter=""> + The shape of the caret to use in the script editor. [b]Line[/b] displays a vertical line to the left of the current character, whereas [b]Block[/b] displays a outline over the current character. </member> <member name="text_editor/appearance/guidelines/line_length_guideline_hard_column" type="int" setter="" getter=""> + The column at which to display a subtle line as a line length guideline for scripts. This should generally be greater than [member text_editor/appearance/guidelines/line_length_guideline_soft_column]. </member> <member name="text_editor/appearance/guidelines/line_length_guideline_soft_column" type="int" setter="" getter=""> + The column at which to display a [i]very[/i] subtle line as a line length guideline for scripts. This should generally be lower than [member text_editor/appearance/guidelines/line_length_guideline_hard_column]. </member> <member name="text_editor/appearance/guidelines/show_line_length_guidelines" type="bool" setter="" getter=""> + If [code]true[/code], displays line length guidelines to help you keep line lengths in check. See also [member text_editor/appearance/guidelines/line_length_guideline_soft_column] and [member text_editor/appearance/guidelines/line_length_guideline_hard_column]. </member> <member name="text_editor/appearance/gutters/highlight_type_safe_lines" type="bool" setter="" getter=""> + If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines will run faster in Godot 4.0 and later thanks to typed instructions. </member> <member name="text_editor/appearance/gutters/line_numbers_zero_padded" type="bool" setter="" getter=""> + If [code]true[/code], displays line numbers with zero padding (e.g. [code]007[/code] instead of [code]7[/code]). </member> <member name="text_editor/appearance/gutters/show_bookmark_gutter" type="bool" setter="" getter=""> + If [code]true[/code], displays a gutter at the left containing icons for bookmarks. </member> <member name="text_editor/appearance/gutters/show_info_gutter" type="bool" setter="" getter=""> + If [code]true[/code], displays a gutter at the left containing icons for methods with signal connections. </member> <member name="text_editor/appearance/gutters/show_line_numbers" type="bool" setter="" getter=""> + If [code]true[/code], displays line numbers in the gutter at the left. </member> <member name="text_editor/appearance/lines/code_folding" type="bool" setter="" getter=""> + If [code]true[/code], displays the folding arrows next to indented code sections and allows code folding. If [code]false[/code], hides the folding arrows next to indented code sections and disallows code folding. </member> <member name="text_editor/appearance/lines/word_wrap" type="int" setter="" getter=""> + If [code]true[/code], wraps long lines over multiple lines to avoid horizontal scrolling. This is a display-only feature; it does not actually insert line breaks in your scripts. </member> <member name="text_editor/appearance/minimap/minimap_width" type="int" setter="" getter=""> + The width of the minimap in the script editor (in pixels). </member> <member name="text_editor/appearance/minimap/show_minimap" type="bool" setter="" getter=""> + If [code]true[/code], draws an overview of the script near the scroll bar. The minimap can be left-clicked to scroll directly to a location in an "absolute" manner. </member> <member name="text_editor/appearance/whitespace/draw_spaces" type="bool" setter="" getter=""> + If [code]true[/code], draws space characters as centered points. </member> <member name="text_editor/appearance/whitespace/draw_tabs" type="bool" setter="" getter=""> + If [code]true[/code], draws tab characters as chevrons. </member> <member name="text_editor/appearance/whitespace/line_spacing" type="int" setter="" getter=""> + The space to add between lines (in pixels). Greater line spacing can help improve readability at the cost of displaying less lines on screen. </member> <member name="text_editor/behavior/files/auto_reload_scripts_on_external_change" type="bool" setter="" getter=""> + If [code]true[/code], automatically reloads scripts in the editor when they have been modified and saved by external editors. </member> <member name="text_editor/behavior/files/autosave_interval_secs" type="int" setter="" getter=""> + If set to a value greater than [code]0[/code], automatically saves the current script following the specified interval (in seconds). This can be used to prevent data loss if the editor crashes. </member> <member name="text_editor/behavior/files/convert_indent_on_save" type="bool" setter="" getter=""> + If [code]true[/code], converts indentation to match the script editor's indentation settings when saving a script. See also [member text_editor/behavior/indent/type]. </member> <member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter=""> + If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project. </member> <member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter=""> + If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy. </member> <member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter=""> + If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line. </member> <member name="text_editor/behavior/indent/size" type="int" setter="" getter=""> + When using tab indentation, determines the length of each tab. When using space indentation, determines how many spaces are inserted when pressing [kbd]Tab[/kbd] and when automatic indentation is performed. </member> <member name="text_editor/behavior/indent/type" type="int" setter="" getter=""> + The indentation style to use (tabs or spaces). + [b]Note:[/b] The [url=https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation. </member> <member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter=""> + If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor. </member> <member name="text_editor/behavior/navigation/move_caret_on_right_click" type="bool" setter="" getter=""> + If [code]true[/code], the caret will be moved when right-clicking somewhere in the script editor (like when left-clicking or middle-clicking). If [code]false[/code], the caret will only be moved when left-clicking or middle-clicking somewhere. </member> <member name="text_editor/behavior/navigation/scroll_past_end_of_file" type="bool" setter="" getter=""> + If [code]true[/code], allows scrolling past the end of the file. </member> <member name="text_editor/behavior/navigation/smooth_scrolling" type="bool" setter="" getter=""> + If [code]true[/code], allows scrolling in sub-line intervals and enables a smooth scrolling animation when using the mouse wheel to scroll. + [b]Note:[/b] [member text_editor/behavior/navigation/smooth_scrolling] currently behaves poorly in projects where [member ProjectSettings.physics/common/physics_ticks_per_second] has been increased significantly from its default value ([code]60[/code]). In this case, it is recommended to disable this setting. </member> <member name="text_editor/behavior/navigation/stay_in_script_editor_on_node_selected" type="bool" setter="" getter=""> + If [code]true[/code], prevents automatically switching between the Script and 2D/3D screens when selecting a node in the Scene tree dock. </member> <member name="text_editor/behavior/navigation/v_scroll_speed" type="int" setter="" getter=""> + The number of pixels to scroll with every mouse wheel increment. Higher values make the script scroll by faster when using the mouse wheel. + [b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster. </member> <member name="text_editor/completion/add_type_hints" type="bool" setter="" getter=""> + If [code]true[/code], adds static typing hints such as [code]-> void[/code] and [code]: int[/code] when performing method definition autocompletion. </member> <member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter=""> + If [code]true[/code], automatically completes braces when making use of code completion. </member> <member name="text_editor/completion/code_complete_delay" type="float" setter="" getter=""> + The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing. </member> <member name="text_editor/completion/complete_file_paths" type="bool" setter="" getter=""> + If [code]true[/code], provides autocompletion suggestions for file paths in methods such as [code]load()[/code] and [code]preload()[/code]. </member> <member name="text_editor/completion/idle_parse_delay" type="float" setter="" getter=""> + The delay in seconds after which the script editor should check for errors when the user stops typing. </member> <member name="text_editor/completion/put_callhint_tooltip_below_current_line" type="bool" setter="" getter=""> + If [code]true[/code], the code completion tooltip will appear below the current line unless there is no space on screen below the current line. If [code]false[/code], the code completion tooltip will appear above the current line. </member> <member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter=""> + If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]). </member> <member name="text_editor/help/class_reference_examples" type="int" setter="" getter=""> + Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help. </member> <member name="text_editor/help/help_font_size" type="int" setter="" getter=""> + The font size to use for the editor help (built-in class reference). </member> <member name="text_editor/help/help_source_font_size" type="int" setter="" getter=""> + The font size to use for code samples in the editor help (built-in class reference). </member> <member name="text_editor/help/help_title_font_size" type="int" setter="" getter=""> + The font size to use for headings in the editor help (built-in class reference). </member> <member name="text_editor/help/show_help_index" type="bool" setter="" getter=""> + If [code]true[/code], displays a table of contents at the left of the editor help (at the location where the members overview would appear when editing a script). </member> <member name="text_editor/script_list/show_members_overview" type="bool" setter="" getter=""> + If [code]true[/code], displays an overview of the current script's member variables and functions at the left of the script editor. See also [member text_editor/script_list/sort_members_outline_alphabetically]. </member> <member name="text_editor/script_list/sort_members_outline_alphabetically" type="bool" setter="" getter=""> + If [code]true[/code], sorts the members outline (located at the left of the script editor) using alphabetical order. If [code]false[/code], sorts the members outline depending on the order in which members are found in the script. + [b]Note:[/b] Only effective if [member text_editor/script_list/show_members_overview] is [code]true[/code]. </member> <member name="text_editor/theme/color_theme" type="String" setter="" getter=""> + The syntax theme to use in the script editor. + You can save your own syntax theme from your current settings by using [b]File > Theme > Save As...[/b] at the top of the script editor. The syntax theme will then be available locally in the list of color themes. + You can find additional syntax themes to install in the [url=https://github.com/godotengine/godot-syntax-themes]godot-syntax-themes[/url] repository. </member> <member name="text_editor/theme/highlighting/background_color" type="Color" setter="" getter=""> + The script editor's background color. If set to a translucent color, the editor theme's base color will be visible behind. </member> <member name="text_editor/theme/highlighting/base_type_color" type="Color" setter="" getter=""> + The script editor's base type color (used for types like [Vector2], [Vector3], ...). </member> <member name="text_editor/theme/highlighting/bookmark_color" type="Color" setter="" getter=""> + The script editor's bookmark icon color (displayed in the gutter). </member> <member name="text_editor/theme/highlighting/brace_mismatch_color" type="Color" setter="" getter=""> + The script editor's brace mismatch color. Used when the caret is currently on a mismatched brace, parenthesis or bracket character. </member> <member name="text_editor/theme/highlighting/breakpoint_color" type="Color" setter="" getter=""> + The script editor's breakpoint icon color (displayed in the gutter). </member> <member name="text_editor/theme/highlighting/caret_background_color" type="Color" setter="" getter=""> + The script editor's caret background color. + [b]Note:[/b] This setting has no effect as it's currently unused. </member> <member name="text_editor/theme/highlighting/caret_color" type="Color" setter="" getter=""> + The script editor's caret color. </member> <member name="text_editor/theme/highlighting/code_folding_color" type="Color" setter="" getter=""> + The script editor's color for the code folding icon (displayed in the gutter). </member> <member name="text_editor/theme/highlighting/comment_color" type="Color" setter="" getter=""> + The script editor's comment color. + [b]Note:[/b] In GDScript, unlike Python, multiline strings are not considered to be comments, and will use the string highlighting color instead. </member> <member name="text_editor/theme/highlighting/completion_background_color" type="Color" setter="" getter=""> + The script editor's autocompletion box background color. </member> <member name="text_editor/theme/highlighting/completion_existing_color" type="Color" setter="" getter=""> + The script editor's autocompletion box background color to highlight existing characters in the completion results. This should be a translucent color so that [member text_editor/theme/highlighting/completion_selected_color] can be seen behind. </member> <member name="text_editor/theme/highlighting/completion_font_color" type="Color" setter="" getter=""> + The script editor's autocompletion box text color. </member> <member name="text_editor/theme/highlighting/completion_scroll_color" type="Color" setter="" getter=""> + The script editor's autocompletion box scroll bar color. </member> <member name="text_editor/theme/highlighting/completion_scroll_hovered_color" type="Color" setter="" getter=""> + The script editor's autocompletion box scroll bar color when hovered or pressed with the mouse. </member> <member name="text_editor/theme/highlighting/completion_selected_color" type="Color" setter="" getter=""> + The script editor's autocompletion box background color for the currently selected line. </member> <member name="text_editor/theme/highlighting/control_flow_keyword_color" type="Color" setter="" getter=""> + The script editor's control flow keyword color (used for keywords like [code]if[/code], [code]for[/code], [code]return[/code], ...). </member> <member name="text_editor/theme/highlighting/current_line_color" type="Color" setter="" getter=""> + The script editor's background color for the line the caret is currently on. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/mark_color]. </member> <member name="text_editor/theme/highlighting/engine_type_color" type="Color" setter="" getter=""> + The script editor's engine type color ([Vector2], [Vector3], [Color], ...). </member> <member name="text_editor/theme/highlighting/executing_line_color" type="Color" setter="" getter=""> + The script editor's color for the debugger's executing line icon (displayed in the gutter). </member> <member name="text_editor/theme/highlighting/function_color" type="Color" setter="" getter=""> + The script editor's function call color. + [b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function declaration color configured in the syntax theme for function declarations (e.g. [code]func _ready():[/code]). </member> <member name="text_editor/theme/highlighting/keyword_color" type="Color" setter="" getter=""> + The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], some built-in methods, ...). </member> <member name="text_editor/theme/highlighting/line_length_guideline_color" type="Color" setter="" getter=""> + The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with an opacity twice as low. </member> <member name="text_editor/theme/highlighting/line_number_color" type="Color" setter="" getter=""> + The script editor's color for line numbers. See also [member text_editor/theme/highlighting/safe_line_number_color]. </member> <member name="text_editor/theme/highlighting/mark_color" type="Color" setter="" getter=""> + The script editor's background color for lines with errors. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color]. </member> <member name="text_editor/theme/highlighting/member_variable_color" type="Color" setter="" getter=""> + The script editor's color for member variables on objects (e.g. [code]self.some_property[/code]). + [b]Note:[/b] This color is not used for local variable declaration and access. </member> <member name="text_editor/theme/highlighting/number_color" type="Color" setter="" getter=""> + The script editor's color for numbers (integer and floating-point). </member> <member name="text_editor/theme/highlighting/safe_line_number_color" type="Color" setter="" getter=""> + The script editor's color for type-safe line numbers. See also [member text_editor/theme/highlighting/line_number_color]. + [b]Note:[/b] Only displayed if [member text_editor/appearance/gutters/highlight_type_safe_lines] is [code]true[/code]. </member> <member name="text_editor/theme/highlighting/search_result_border_color" type="Color" setter="" getter=""> + The script editor's color for the border of search results. This border helps bring further attention to the search result. Set this color's opacity to 0 to disable the border. </member> <member name="text_editor/theme/highlighting/search_result_color" type="Color" setter="" getter=""> + The script editor's background color for search results. </member> <member name="text_editor/theme/highlighting/selection_color" type="Color" setter="" getter=""> + The script editor's background color for the currently selected text. </member> <member name="text_editor/theme/highlighting/string_color" type="Color" setter="" getter=""> + The script editor's color for strings (single-line and multi-line). </member> <member name="text_editor/theme/highlighting/symbol_color" type="Color" setter="" getter=""> + The script editor's color for operators ([code]( ) [ ] { } + - * /[/code], ...). </member> <member name="text_editor/theme/highlighting/text_color" type="Color" setter="" getter=""> + The script editor's color for text not highlighted by any syntax highlighting rule. </member> <member name="text_editor/theme/highlighting/text_selected_color" type="Color" setter="" getter=""> + The script editor's background color for text. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color]. </member> <member name="text_editor/theme/highlighting/user_type_color" type="Color" setter="" getter=""> + The script editor's color for user-defined types (using [code]@class_name[/code]). </member> <member name="text_editor/theme/highlighting/word_highlighted_color" type="Color" setter="" getter=""> + The script editor's color for words highlighted by selecting them. Only visible if [member text_editor/appearance/caret/highlight_all_occurrences] is [code]true[/code]. </member> </members> <signals> diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml index 32eb71f1c7..df9d25902b 100644 --- a/doc/classes/Plane.xml +++ b/doc/classes/Plane.xml @@ -179,6 +179,13 @@ [b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable. </description> </operator> + <operator name="operator *"> + <return type="Plane" /> + <argument index="0" name="right" type="Transform3D" /> + <description> + Inversely transforms (multiplies) the [Plane] by the given [Transform3D] transformation matrix. + </description> + </operator> <operator name="operator =="> <return type="bool" /> <argument index="0" name="right" type="Plane" /> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 9f197dae02..35ad5f03ab 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -640,6 +640,7 @@ <description> Splits the string by a [code]delimiter[/code] string and returns an array of the substrings, starting from right. The splits in the returned array are sorted in the same order as the original string, from left to right. + If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split]. Example: [codeblocks] @@ -714,6 +715,7 @@ <argument index="2" name="maxsplit" type="int" default="0" /> <description> Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length. + If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split. If you need only one element from the array at a specific index, [method get_slice] is a more performant option. Example: @@ -742,6 +744,7 @@ <description> Splits the string in floats by using a delimiter string and returns an array of the substrings. For example, [code]"1,2.5,3"[/code] will return [code][1,2.5,3][/code] if split by [code]","[/code]. + If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. </description> </method> <method name="strip_edges" qualifiers="const"> diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index 9b673701ae..cefc74867c 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -216,6 +216,13 @@ </description> </operator> <operator name="operator *"> + <return type="Plane" /> + <argument index="0" name="right" type="Plane" /> + <description> + Transforms (multiplies) the [Plane] by the given [Transform3D] transformation matrix. + </description> + </operator> + <operator name="operator *"> <return type="Transform3D" /> <argument index="0" name="right" type="Transform3D" /> <description> diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 45e114b130..89daa2af64 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2004,6 +2004,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T } RID id = texture_owner.make_rid(texture); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { @@ -2133,6 +2136,9 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID texture.owner = p_with_texture; RID id = texture_owner.make_rid(texture); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif _add_dependency(id, p_with_texture); return id; @@ -2252,6 +2258,9 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat } RID id = texture_owner.make_rid(texture); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif return id; } @@ -2377,6 +2386,9 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p texture.owner = p_with_texture; RID id = texture_owner.make_rid(texture); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif _add_dependency(id, p_with_texture); return id; @@ -4082,7 +4094,11 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur framebuffer.size = p_size; framebuffer.view_count = 1; - return framebuffer_owner.make_rid(framebuffer); + RID id = framebuffer_owner.make_rid(framebuffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) { @@ -4162,6 +4178,9 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex framebuffer.view_count = p_view_count; RID id = framebuffer_owner.make_rid(framebuffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif for (int i = 0; i < p_texture_attachments.size(); i++) { if (p_texture_attachments[i].is_valid()) { @@ -4239,7 +4258,11 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) { VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler); ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + "."); - return sampler_owner.make_rid(sampler); + RID id = sampler_owner.make_rid(sampler); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } /**********************/ @@ -4268,7 +4291,11 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); } - return vertex_buffer_owner.make_rid(buffer); + RID id = vertex_buffer_owner.make_rid(buffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated @@ -4429,7 +4456,11 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff _buffer_update(&index_buffer, 0, r, data_size); _buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); } - return index_buffer_owner.make_rid(index_buffer); + RID id = index_buffer_owner.make_rid(index_buffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) { @@ -5526,7 +5557,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_ ERR_FAIL_V_MSG(RID(), error_text); } - return shader_owner.make_rid(shader); + RID id = shader_owner.make_rid(shader); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { @@ -5559,7 +5594,11 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve _buffer_update(&buffer, 0, r, data_size); _buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); } - return uniform_buffer_owner.make_rid(buffer); + RID id = uniform_buffer_owner.make_rid(buffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) { @@ -5630,7 +5669,11 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF } //allocate the view - return texture_buffer_owner.make_rid(texture_buffer); + RID id = texture_buffer_owner.make_rid(texture_buffer); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif + return id; } RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) { @@ -6209,6 +6252,9 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, uniform_set.shader_id = p_shader; RID id = uniform_set_owner.make_rid(uniform_set); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif //add dependencies _add_dependency(id, p_shader); for (uint32_t i = 0; i < uniform_count; i++) { @@ -6831,6 +6877,9 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma #endif //create ID to associate with this pipeline RID id = render_pipeline_owner.make_rid(pipeline); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif //now add all the dependencies _add_dependency(id, p_shader); return id; @@ -6920,6 +6969,9 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi //create ID to associate with this pipeline RID id = compute_pipeline_owner.make_rid(pipeline); +#ifdef DEV_ENABLED + set_resource_name(id, "RID:" + itos(id.get_id())); +#endif //now add all the dependencies _add_dependency(id, p_shader); return id; diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp index d093ab518e..0f0ab4a339 100644 --- a/editor/editor_build_profile.cpp +++ b/editor/editor_build_profile.cpp @@ -46,19 +46,68 @@ const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = { "disable_3d_physics", "disable_navigation", "openxr", + "rendering_device", // FIXME: there's no scons option to disable rendering device "opengl3", "vulkan", + "module_text_server_fb_enabled", + "module_text_server_adv_enabled", + "module_freetype_enabled", + "brotli", + "graphite", + "module_msdfgen_enabled" +}; + +const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = { + // This maps to SCons build options. + false, // 3D + false, // PHYSICS_2D + false, // PHYSICS_3D + false, // NAVIGATION + false, // XR + false, // RENDERING_DEVICE + false, // OPENGL + false, // VULKAN + true, // TEXT_SERVER_FALLBACK + false, // TEXT_SERVER_COMPLEX + false, // DYNAMIC_FONTS + false, // WOFF2_FONTS + false, // GRPAHITE_FONTS + false, // MSDFGEN }; const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = { // This maps to SCons build options. - true, - true, - true, - true, - false, - false, - false + true, // 3D + true, // PHYSICS_2D + true, // PHYSICS_3D + true, // NAVIGATION + false, // XR + false, // RENDERING_DEVICE + false, // OPENGL + false, // VULKAN + false, // TEXT_SERVER_FALLBACK + false, // TEXT_SERVER_COMPLEX + false, // DYNAMIC_FONTS + false, // WOFF2_FONTS + false, // GRPAHITE_FONTS + false, // MSDFGEN +}; + +const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = { + BUILD_OPTION_CATEGORY_GENERAL, // 3D + BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_2D + BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_3D + BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION + BUILD_OPTION_CATEGORY_GENERAL, // XR + BUILD_OPTION_CATEGORY_GENERAL, // RENDERING_DEVICE + BUILD_OPTION_CATEGORY_GENERAL, // OPENGL + BUILD_OPTION_CATEGORY_GENERAL, // VULKAN + BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK + BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_COMPLEX + BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS + BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS + BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRPAHITE_FONTS + BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN }; void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) { @@ -127,6 +176,12 @@ String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) { TTRC("RenderingDevice"), TTRC("OpenGL"), TTRC("Vulkan"), + TTRC("Text Server: Fallback"), + TTRC("Text Server: Advanced"), + TTRC("TTF, OTF, Type 1, WOFF1 Fonts"), + TTRC("WOFF2 Fonts"), + TTRC("SIL Graphite Fonts"), + TTRC("Multi-channel Signed Distance Field Font Rendering"), }; return TTRGET(build_option_names[p_build_option]); } @@ -143,11 +198,33 @@ String EditorBuildProfile::get_build_option_description(BuildOption p_build_opti TTRC("RenderingDevice based rendering (if disabled, the OpenGL back-end is required)."), TTRC("OpenGL back-end (if disabled, the RenderingDevice back-end is required)."), TTRC("Vulkan back-end of RenderingDevice."), + TTRC("Fallback implementation of Text Server\nSupports basic text layouts."), + TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."), + TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."), + TTRC("WOFF2 font format support using FreeType and Brotli libraries."), + TTRC("SIL Graphite smart font technology support (supported by Advanced Text Server only)."), + TTRC("Multi-channel signed distance field font rendering support using msdfgen library (pre-rendered MSDF fonts can be used even if this option disabled)."), }; return TTRGET(build_option_descriptions[p_build_option]); } +EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) { + ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL); + return build_option_category[p_build_option]; +} + +String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) { + ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String()); + + const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{ + TTRC("General Features:"), + TTRC("Text Rendering and Font Options:"), + }; + + return TTRGET(build_option_subcategories[p_build_option_category]); +} + Error EditorBuildProfile::save_to_file(const String &p_path) { Dictionary data; data["type"] = "build_profile"; @@ -160,8 +237,12 @@ Error EditorBuildProfile::save_to_file(const String &p_path) { Dictionary dis_build_options; for (int i = 0; i < BUILD_OPTION_MAX; i++) { - if (build_options_disabled[i]) { - dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i]; + if (build_options_disabled[i] != build_option_disabled_by_default[i]) { + if (build_options_disabled[i]) { + dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i]; + } else { + dis_build_options[build_option_identifiers[i]] = !build_option_disable_values[i]; + } } } @@ -211,7 +292,7 @@ Error EditorBuildProfile::load_from_file(const String &p_path) { } for (int i = 0; i < BUILD_OPTION_MAX; i++) { - build_options_disabled[i] = false; + build_options_disabled[i] = build_option_disabled_by_default[i]; } if (data.has("disabled_build_options")) { @@ -259,10 +340,24 @@ void EditorBuildProfile::_bind_methods() { BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE); BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL); BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN); + BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK); + BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED); + BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS); + BIND_ENUM_CONSTANT(BUILD_OPTION_WOFF2_FONTS); + BIND_ENUM_CONSTANT(BUILD_OPTION_GRPAHITE_FONTS); + BIND_ENUM_CONSTANT(BUILD_OPTION_MSDFGEN); BIND_ENUM_CONSTANT(BUILD_OPTION_MAX); + + BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL); + BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER); + BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX); } -EditorBuildProfile::EditorBuildProfile() {} +EditorBuildProfile::EditorBuildProfile() { + for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) { + build_options_disabled[i] = build_option_disabled_by_default[i]; + } +} ////////////////////////// @@ -633,11 +728,18 @@ void EditorBuildProfileManager::_update_edited_profile() { TreeItem *root = class_list->create_item(); - TreeItem *build_options = class_list->create_item(root); - build_options->set_text(0, TTR("General Features:")); + HashMap<EditorBuildProfile::BuildOptionCategory, TreeItem *> subcats; + for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_CATEGORY_MAX; i++) { + TreeItem *build_cat; + build_cat = class_list->create_item(root); + + build_cat->set_text(0, EditorBuildProfile::get_build_option_category_name(EditorBuildProfile::BuildOptionCategory(i))); + subcats[EditorBuildProfile::BuildOptionCategory(i)] = build_cat; + } + for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) { TreeItem *build_option; - build_option = class_list->create_item(build_options); + build_option = class_list->create_item(subcats[EditorBuildProfile::get_build_option_category(EditorBuildProfile::BuildOption(i))]); build_option->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); build_option->set_text(0, EditorBuildProfile::get_build_option_name(EditorBuildProfile::BuildOption(i))); diff --git a/editor/editor_build_profile.h b/editor/editor_build_profile.h index bb6494b8c9..606c415429 100644 --- a/editor/editor_build_profile.h +++ b/editor/editor_build_profile.h @@ -53,7 +53,19 @@ public: BUILD_OPTION_RENDERING_DEVICE, BUILD_OPTION_OPENGL, BUILD_OPTION_VULKAN, - BUILD_OPTION_MAX + BUILD_OPTION_TEXT_SERVER_FALLBACK, + BUILD_OPTION_TEXT_SERVER_ADVANCED, + BUILD_OPTION_DYNAMIC_FONTS, + BUILD_OPTION_WOFF2_FONTS, + BUILD_OPTION_GRPAHITE_FONTS, + BUILD_OPTION_MSDFGEN, + BUILD_OPTION_MAX, + }; + + enum BuildOptionCategory { + BUILD_OPTION_CATEGORY_GENERAL, + BUILD_OPTION_CATEGORY_TEXT_SERVER, + BUILD_OPTION_CATEGORY_MAX, }; private: @@ -65,7 +77,9 @@ private: bool build_options_disabled[BUILD_OPTION_MAX] = {}; static const char *build_option_identifiers[BUILD_OPTION_MAX]; + static const bool build_option_disabled_by_default[BUILD_OPTION_MAX]; static const bool build_option_disable_values[BUILD_OPTION_MAX]; + static const BuildOptionCategory build_option_category[BUILD_OPTION_MAX]; String _get_build_option_name(BuildOption p_build_option) { return get_build_option_name(p_build_option); } @@ -93,11 +107,15 @@ public: static String get_build_option_name(BuildOption p_build_option); static String get_build_option_description(BuildOption p_build_option); static bool get_build_option_disable_value(BuildOption p_build_option); + static BuildOptionCategory get_build_option_category(BuildOption p_build_option); + + static String get_build_option_category_name(BuildOptionCategory p_build_option_category); EditorBuildProfile(); }; VARIANT_ENUM_CAST(EditorBuildProfile::BuildOption) +VARIANT_ENUM_CAST(EditorBuildProfile::BuildOptionCategory) class EditorFileSystemDirectory; diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index ab6dec7eeb..f0bf9fd5b3 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -324,6 +324,11 @@ void EditorFeatureProfileManager::_notification(int p_what) { } _update_profile_list(current_profile); } break; + + case NOTIFICATION_THEME_CHANGED: { + // Make sure that the icons are correctly adjusted if the theme's lightness was switched. + _update_selected_profile(); + } break; } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index d11c659b98..3b37adb830 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2665,7 +2665,6 @@ void EditorInspector::update_tree() { List<PropertyInfo> plist; object->get_property_list(&plist, true); - _update_script_class_properties(*object, plist); HashMap<VBoxContainer *, HashMap<String, VBoxContainer *>> vbox_per_path; HashMap<String, EditorInspectorArray *> editor_inspector_array_per_prefix; @@ -2750,6 +2749,7 @@ void EditorInspector::update_tree() { category_vbox = nullptr; //reset String type = p.name; + String label = p.name; type_name = p.name; // Set the category icon. @@ -2757,11 +2757,16 @@ void EditorInspector::update_tree() { // If we have a category inside a script, search for the first script with a valid icon. Ref<Script> script = ResourceLoader::load(p.hint_string, "Script"); StringName base_type; + StringName name; if (script.is_valid()) { base_type = script->get_instance_base_type(); + name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); + if (name != StringName() && label != name) { + label = name; + } } while (script.is_valid()) { - StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); + name = EditorNode::get_editor_data().script_class_get_name(script->get_path()); String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name); if (name != StringName() && icon_path.length()) { category->icon = ResourceLoader::load(icon_path, "Texture"); @@ -2780,7 +2785,7 @@ void EditorInspector::update_tree() { } // Set the category label. - category->label = type; + category->label = label; if (use_doc_hints) { // Sets the category tooltip to show documentation. @@ -3926,93 +3931,6 @@ void EditorInspector::_feature_profile_changed() { update_tree(); } -void EditorInspector::_update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const { - Ref<Script> script = p_object.get_script(); - if (script.is_null()) { - return; - } - - List<Ref<Script>> classes; - - // NodeC -> NodeB -> NodeA - while (script.is_valid()) { - classes.push_front(script); - script = script->get_base_script(); - } - - if (classes.is_empty()) { - return; - } - - // Script Variables -> to insert: NodeC..B..A -> bottom (insert_here) - List<PropertyInfo>::Element *script_variables = nullptr; - List<PropertyInfo>::Element *bottom = nullptr; - List<PropertyInfo>::Element *insert_here = nullptr; - for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) { - PropertyInfo &pi = E->get(); - if (pi.name != "Script Variables") { - continue; - } - script_variables = E; - bottom = r_list.insert_after(script_variables, PropertyInfo()); - insert_here = bottom; - break; - } - - HashSet<StringName> added; - for (const Ref<Script> &s : classes) { - String path = s->get_path(); - String name = EditorNode::get_editor_data().script_class_get_name(path); - if (name.is_empty()) { - if (s->is_built_in()) { - if (s->get_name().is_empty()) { - name = TTR("Built-in script"); - } else { - name = vformat("%s (%s)", s->get_name(), TTR("Built-in")); - } - } else { - name = path.get_file(); - } - } - - List<PropertyInfo> props; - s->get_script_property_list(&props); - - // Script Variables -> NodeA -> bottom (insert_here) - List<PropertyInfo>::Element *category = r_list.insert_before(insert_here, PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY)); - - // Script Variables -> NodeA -> A props... -> bottom (insert_here) - for (List<PropertyInfo>::Element *P = props.front(); P; P = P->next()) { - PropertyInfo &pi = P->get(); - if (added.has(pi.name)) { - continue; - } - added.insert(pi.name); - - r_list.insert_before(insert_here, pi); - - List<PropertyInfo>::Element *prop_below = bottom->next(); - while (prop_below) { - if (prop_below->get() == pi) { - List<PropertyInfo>::Element *to_delete = prop_below; - prop_below = prop_below->next(); - r_list.erase(to_delete); - } else { - prop_below = prop_below->next(); - } - } - } - - // Script Variables -> NodeA (insert_here) -> A props... -> bottom - insert_here = category; - } - - if (script_variables) { - r_list.erase(script_variables); - r_list.erase(bottom); - } -} - void EditorInspector::set_restrict_to_basic_settings(bool p_restrict) { restrict_to_basic = p_restrict; update_tree(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 9b5e295854..551f6f6f86 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -536,7 +536,6 @@ class EditorInspector : public ScrollContainer { void _vscroll_changed(double); void _feature_profile_changed(); - void _update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const; bool _is_property_disabled_by_feature_profile(const StringName &p_property); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8caa38737c..e7946f56da 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -141,6 +141,7 @@ #include "editor/plugins/bone_map_editor_plugin.h" #include "editor/plugins/camera_3d_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" +#include "editor/plugins/cast_2d_editor_plugin.h" #include "editor/plugins/collision_polygon_2d_editor_plugin.h" #include "editor/plugins/collision_shape_2d_editor_plugin.h" #include "editor/plugins/control_editor_plugin.h" @@ -176,7 +177,6 @@ #include "editor/plugins/physical_bone_3d_editor_plugin.h" #include "editor/plugins/polygon_2d_editor_plugin.h" #include "editor/plugins/polygon_3d_editor_plugin.h" -#include "editor/plugins/ray_cast_2d_editor_plugin.h" #include "editor/plugins/resource_preloader_editor_plugin.h" #include "editor/plugins/root_motion_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" @@ -7192,7 +7192,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(NavigationPolygonEditorPlugin)); add_editor_plugin(memnew(Path2DEditorPlugin)); add_editor_plugin(memnew(Polygon2DEditorPlugin)); - add_editor_plugin(memnew(RayCast2DEditorPlugin)); + add_editor_plugin(memnew(Cast2DEditorPlugin)); add_editor_plugin(memnew(Skeleton2DEditorPlugin)); add_editor_plugin(memnew(Sprite2DEditorPlugin)); add_editor_plugin(memnew(TilesEditorPlugin)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 5298b818e7..c713fe3df0 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -133,6 +133,11 @@ void EditorPropertyMultilineText::_text_changed() { void EditorPropertyMultilineText::_open_big_text() { if (!big_text_dialog) { big_text = memnew(TextEdit); + if (expression) { + big_text->set_syntax_highlighter(text->get_syntax_highlighter()); + big_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts"))); + big_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts"))); + } big_text->connect("text_changed", callable_mp(this, &EditorPropertyMultilineText::_big_text_changed)); big_text->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY); big_text_dialog = memnew(AcceptDialog); @@ -162,12 +167,24 @@ void EditorPropertyMultilineText::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { Ref<Texture2D> df = get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons")); open_big_text->set_icon(df); - Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); - int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label")); - text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6)); - text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts")); - text->add_theme_font_size_override("font_size", get_theme_font_size("expression_size", "EditorFonts")); + Ref<Font> font; + int font_size; + if (expression) { + font = get_theme_font(SNAME("expression"), SNAME("EditorFonts")); + font_size = get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")); + + text->add_theme_font_override("font", font); + text->add_theme_font_size_override("font_size", font_size); + if (big_text) { + big_text->add_theme_font_override("font", font); + big_text->add_theme_font_size_override("font_size", font_size); + } + } else { + font = get_theme_font(SNAME("font"), SNAME("TextEdit")); + font_size = get_theme_font_size(SNAME("font_size"), SNAME("TextEdit")); + } + text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6)); } break; } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 6f8d33532f..ac85eb5e1b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4237,13 +4237,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, Control *ctrl = Object::cast_to<Control>(canvas_item); if (key_pos) { - te->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); + te->insert_node_value_key(ctrl, "position", ctrl->get_position(), p_on_existing); } if (key_rot) { - te->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing); + te->insert_node_value_key(ctrl, "rotation", ctrl->get_rotation(), p_on_existing); } if (key_scale) { - te->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); + te->insert_node_value_key(ctrl, "size", ctrl->get_size(), p_on_existing); } } } diff --git a/editor/plugins/ray_cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp index 6f247a37ef..18c38e7ab8 100644 --- a/editor/plugins/ray_cast_2d_editor_plugin.cpp +++ b/editor/plugins/cast_2d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* ray_cast_2d_editor_plugin.cpp */ +/* cast_2d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,30 +28,32 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "ray_cast_2d_editor_plugin.h" +#include "cast_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" +#include "scene/2d/ray_cast_2d.h" +#include "scene/2d/shape_cast_2d.h" -void RayCast2DEditor::_notification(int p_what) { +void Cast2DEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - get_tree()->connect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed)); + get_tree()->connect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed)); } break; case NOTIFICATION_EXIT_TREE: { - get_tree()->disconnect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed)); + get_tree()->disconnect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed)); } break; } } -void RayCast2DEditor::_node_removed(Node *p_node) { +void Cast2DEditor::_node_removed(Node *p_node) { if (p_node == node) { node = nullptr; } } -bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { +bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (!node || !node->is_visible_in_tree()) { return false; } @@ -60,10 +62,12 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { + Vector2 target_position = node->get("target_position"); + if (mb->is_pressed()) { - if (xform.xform(node->get_target_position()).distance_to(mb->get_position()) < 8) { + if (xform.xform(target_position).distance_to(mb->get_position()) < 8) { pressed = true; - original_target_position = node->get_target_position(); + original_target_position = target_position; return true; } else { @@ -73,9 +77,9 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { } } else if (pressed) { undo_redo->create_action(TTR("Set target_position")); - undo_redo->add_do_method(node, "set_target_position", node->get_target_position()); + undo_redo->add_do_property(node, "target_position", target_position); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(node, "set_target_position", original_target_position); + undo_redo->add_undo_property(node, "target_position", original_target_position); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); @@ -90,7 +94,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { Vector2 point = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position())); point = node->get_global_transform().affine_inverse().xform(point); - node->set_target_position(point); + node->set("target_position", point); canvas_item_editor->update_viewport(); node->notify_property_list_changed(); @@ -100,7 +104,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return false; } -void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { +void Cast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { if (!node || !node->is_visible_in_tree()) { return; } @@ -108,16 +112,16 @@ void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons")); - p_overlay->draw_texture(handle, gt.xform(node->get_target_position()) - handle->get_size() / 2); + p_overlay->draw_texture(handle, gt.xform((Vector2)node->get("target_position")) - handle->get_size() / 2); } -void RayCast2DEditor::edit(Node *p_node) { +void Cast2DEditor::edit(Node2D *p_node) { if (!canvas_item_editor) { canvas_item_editor = CanvasItemEditor::get_singleton(); } - if (p_node) { - node = Object::cast_to<RayCast2D>(p_node); + if (Object::cast_to<RayCast2D>(p_node) || Object::cast_to<ShapeCast2D>(p_node)) { + node = p_node; } else { node = nullptr; } @@ -125,27 +129,27 @@ void RayCast2DEditor::edit(Node *p_node) { canvas_item_editor->update_viewport(); } -RayCast2DEditor::RayCast2DEditor() { +Cast2DEditor::Cast2DEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); } /////////////////////// -void RayCast2DEditorPlugin::edit(Object *p_object) { - ray_cast_2d_editor->edit(Object::cast_to<RayCast2D>(p_object)); +void Cast2DEditorPlugin::edit(Object *p_object) { + cast_2d_editor->edit(Object::cast_to<Node2D>(p_object)); } -bool RayCast2DEditorPlugin::handles(Object *p_object) const { - return Object::cast_to<RayCast2D>(p_object) != nullptr; +bool Cast2DEditorPlugin::handles(Object *p_object) const { + return Object::cast_to<RayCast2D>(p_object) != nullptr || Object::cast_to<ShapeCast2D>(p_object) != nullptr; } -void RayCast2DEditorPlugin::make_visible(bool p_visible) { +void Cast2DEditorPlugin::make_visible(bool p_visible) { if (!p_visible) { edit(nullptr); } } -RayCast2DEditorPlugin::RayCast2DEditorPlugin() { - ray_cast_2d_editor = memnew(RayCast2DEditor); - EditorNode::get_singleton()->get_gui_base()->add_child(ray_cast_2d_editor); +Cast2DEditorPlugin::Cast2DEditorPlugin() { + cast_2d_editor = memnew(Cast2DEditor); + EditorNode::get_singleton()->get_gui_base()->add_child(cast_2d_editor); } diff --git a/editor/plugins/ray_cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h index 74628da0e4..d9c0cc4a06 100644 --- a/editor/plugins/ray_cast_2d_editor_plugin.h +++ b/editor/plugins/cast_2d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* ray_cast_2d_editor_plugin.h */ +/* cast_2d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RAY_CAST_2D_EDITOR_PLUGIN_H -#define RAY_CAST_2D_EDITOR_PLUGIN_H +#ifndef CAST_2D_EDITOR_PLUGIN_H +#define CAST_2D_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "scene/2d/ray_cast_2d.h" +#include "scene/2d/node_2d.h" class CanvasItemEditor; -class RayCast2DEditor : public Control { - GDCLASS(RayCast2DEditor, Control); +class Cast2DEditor : public Control { + GDCLASS(Cast2DEditor, Control); UndoRedo *undo_redo = nullptr; CanvasItemEditor *canvas_item_editor = nullptr; - RayCast2D *node; + Node2D *node; bool pressed = false; Point2 original_target_position; @@ -53,27 +53,27 @@ protected: public: bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); - void edit(Node *p_node); + void edit(Node2D *p_node); - RayCast2DEditor(); + Cast2DEditor(); }; -class RayCast2DEditorPlugin : public EditorPlugin { - GDCLASS(RayCast2DEditorPlugin, EditorPlugin); +class Cast2DEditorPlugin : public EditorPlugin { + GDCLASS(Cast2DEditorPlugin, EditorPlugin); - RayCast2DEditor *ray_cast_2d_editor = nullptr; + Cast2DEditor *cast_2d_editor = nullptr; public: - virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return ray_cast_2d_editor->forward_canvas_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { ray_cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } + virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return cast_2d_editor->forward_canvas_gui_input(p_event); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } - virtual String get_name() const override { return "RayCast2D"; } + virtual String get_name() const override { return "Cast2D"; } bool has_main_screen() const override { return false; } virtual void edit(Object *p_object) override; virtual bool handles(Object *p_object) const override; virtual void make_visible(bool visible) override; - RayCast2DEditorPlugin(); + Cast2DEditorPlugin(); }; -#endif // RAY_CAST_2D_EDITOR_PLUGIN_H +#endif // CAST_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index bbf5ffa462..c53ac59c11 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1853,10 +1853,12 @@ void ScriptEditor::_update_members_overview_visibility() { if (members_overview_enabled && se->show_members_overview()) { members_overview_alphabeta_sort_button->set_visible(true); + filter_methods->set_visible(true); members_overview->set_visible(true); overview_vbox->set_visible(true); } else { members_overview_alphabeta_sort_button->set_visible(false); + filter_methods->set_visible(false); members_overview->set_visible(false); overview_vbox->set_visible(false); } @@ -1911,6 +1913,7 @@ void ScriptEditor::_update_help_overview_visibility() { if (help_overview_enabled) { members_overview_alphabeta_sort_button->set_visible(false); + filter_methods->set_visible(false); help_overview->set_visible(true); overview_vbox->set_visible(true); filename->set_text(se->get_name()); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index b564195911..421e56f9a1 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -42,7 +42,8 @@ const int ERROR_CODE = 77; #include "core/templates/hash_map.h" #include "core/templates/list.h" -const int CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * 4; // 4 MB +const uint64_t CONVERSION_MAX_FILE_SIZE_MB = 4; +const uint64_t CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * CONVERSION_MAX_FILE_SIZE_MB; static const char *enum_renames[][2] = { //// constants @@ -255,6 +256,7 @@ static const char *gdscript_function_renames[][2] = { { "damped_spring_joint_create", "joint_make_damped_spring" }, // PhysicsServer2D { "damped_string_joint_get_param", "damped_spring_joint_get_param" }, // PhysicsServer2D { "damped_string_joint_set_param", "damped_spring_joint_set_param" }, // PhysicsServer2D + { "dectime", "move_toward" }, // GDScript, Math functions { "delete_char_at_cursor", "delete_char_at_caret" }, // LineEdit { "deselect_items", "deselect_all" }, // FileDialog { "disable_plugin", "_disable_plugin" }, // EditorPlugin @@ -427,6 +429,7 @@ static const char *gdscript_function_renames[][2] = { { "joint_create_slider", "joint_make_slider" }, // PhysicsServer3D { "line_intersects_line_2d", "line_intersects_line" }, // Geometry2D { "load_from_globals", "load_from_project_settings" }, // InputMap + { "load_interactive", "load_threaded_request" }, // ResourceLoader - load_threaded_request is alternative, but is used differently { "make_convex_from_brothers", "make_convex_from_siblings" }, // CollisionShape3D { "make_visible", "_make_visible" }, // EditorPlugin { "merge_polygons_2d", "merge_polygons" }, // Geometry2D @@ -484,6 +487,7 @@ static const char *gdscript_function_renames[][2] = { { "set_enabled_focus_mode", "set_focus_mode" }, // BaseButton { "set_endian_swap", "set_big_endian" }, // File { "set_expand_to_text_length", "set_expand_to_text_length_enabled" }, // LineEdit + { "set_filename", "set_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places { "set_focus_neighbour", "set_focus_neighbor" }, // Control { "set_frame_color", "set_color" }, // ColorRect { "set_global_rate_scale", "set_playback_speed_scale" }, // AudioServer @@ -975,6 +979,7 @@ static const char *gdscript_properties_renames[][2] = { // { "wrap_enabled", "wrap_mode" }, // TextEdit // { "zfar", "far" }, // Camera3D // { "znear", "near" }, // Camera3D + // { "filename", "scene_file_path" }, // Node { "as_normalmap", "as_normal_map" }, // NoiseTexture { "bbcode_text", "text" }, // RichTextLabel { "caret_moving_by_right_click", "caret_move_on_right_click" }, // TextEdit @@ -1595,12 +1600,33 @@ static const char *colors_renames[][2] = { { nullptr, nullptr }, }; +class ProjectConverter3To4::RegExContainer { +public: + RegEx reg_is_empty = RegEx("\\bempty\\("); + RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); + RegEx reg_json_to = RegEx("\\bto_json\\b"); + RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)"); + RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); + RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)"); + RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); + RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)"); + RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$"); + RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); + RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); + RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)"); + RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); + RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); + RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); +}; + // Function responsible for converting project int ProjectConverter3To4::convert() { print_line("Starting conversion."); + RegExContainer reg_container = RegExContainer(); + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); - ERR_FAIL_COND_V_MSG(!test_conversion(), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); // Checking if folder contains valid Godot 3 project. // Project cannot be converted 2 times @@ -1640,7 +1666,7 @@ int ProjectConverter3To4::convert() { uint64_t start_time = Time::get_singleton()->get_ticks_msec(); if (file_name.ends_with(".shader")) { - DirAccess::remove_file_or_error(file_name); + DirAccess::remove_file_or_error(file_name.trim_prefix("res://")); file_name = file_name.replace(".shader", ".gdshader"); } @@ -1653,7 +1679,7 @@ int ProjectConverter3To4::convert() { rename_enums(file_content); // Require to additional rename rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content); // Require to additional rename + rename_gdscript_functions(file_content, reg_container, false); // Require to additional rename rename_common(project_settings_renames, file_content); rename_gdscript_keywords(file_content); @@ -1671,7 +1697,7 @@ int ProjectConverter3To4::convert() { rename_enums(file_content); // Require to additional rename rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content); // Require to additional rename + rename_gdscript_functions(file_content, reg_container, true); // Require to additional rename rename_common(project_settings_renames, file_content); rename_gdscript_keywords(file_content); @@ -1688,6 +1714,7 @@ int ProjectConverter3To4::convert() { rename_common(csharp_properties_renames, file_content); rename_common(csharp_signals_renames, file_content); rename_csharp_functions(file_content); + rename_csharp_attributes(file_content); custom_rename(file_content, "public class ", "public partial class "); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { rename_common(shaders_renames, file_content); @@ -1708,7 +1735,7 @@ int ProjectConverter3To4::convert() { continue; } } else { - reason.append(" ERROR: File has exceeded the maximum size allowed - 500 KB"); + reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); is_ignored = true; } @@ -1718,7 +1745,7 @@ int ProjectConverter3To4::convert() { uint64_t hash_after = file_content.hash64(); // Don't need to save file without any changes // Save if this is a shader, because it was renamed - if (hash_before != hash_after || file_name.find(".gdshader") != -1) { + if (hash_before != hash_after || file_name.ends_with(".gdshader")) { converted_files++; Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE); @@ -1742,8 +1769,10 @@ int ProjectConverter3To4::convert() { int ProjectConverter3To4::validate_conversion() { print_line("Starting checking if project conversion can be done."); + RegExContainer reg_container = RegExContainer(); + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); - ERR_FAIL_COND_V_MSG(!test_conversion(), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); // Checking if folder contains valid Godot 3 project. // Project cannot be converted 2 times @@ -1784,7 +1813,7 @@ int ProjectConverter3To4::validate_conversion() { bool is_ignored = false; uint64_t start_time = Time::get_singleton()->get_ticks_msec(); - if (file_name.ends_with(".sader")) { + if (file_name.ends_with(".shader")) { reason.append("\tFile extension will be renamed from `shader` to `gdshader`."); } @@ -1796,7 +1825,7 @@ int ProjectConverter3To4::validate_conversion() { changed_elements.append_array(check_for_rename_enums(file_content)); changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content)); + changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, false)); changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); @@ -1814,7 +1843,7 @@ int ProjectConverter3To4::validate_conversion() { changed_elements.append_array(check_for_rename_enums(file_content)); changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content)); + changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, true)); changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); @@ -1831,6 +1860,7 @@ int ProjectConverter3To4::validate_conversion() { changed_elements.append_array(check_for_rename_common(csharp_properties_renames, file_content)); changed_elements.append_array(check_for_rename_common(csharp_signals_renames, file_content)); changed_elements.append_array(check_for_rename_csharp_functions(file_content)); + changed_elements.append_array(check_for_rename_csharp_attributes(file_content)); changed_elements.append_array(check_for_custom_rename(file_content, "public class ", "public partial class ")); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); @@ -1851,7 +1881,7 @@ int ProjectConverter3To4::validate_conversion() { continue; } } else { - reason.append("\tERROR: File has exceeded the maximum size allowed - 500 KB"); + reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); is_ignored = true; } @@ -1928,6 +1958,17 @@ bool ProjectConverter3To4::test_conversion_single_additional(String name, String return true; } +bool ProjectConverter3To4::test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { + String got = name; + (this->*func)(got, reg_container, builtin_script); + if (expected != got) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); + return false; + } + + return true; +} + bool ProjectConverter3To4::test_conversion_single_normal(String name, String expected, const char *array[][2], String what) { String got = name; rename_common(array, got); @@ -1939,7 +1980,7 @@ bool ProjectConverter3To4::test_conversion_single_normal(String name, String exp } // Validate if conversions are proper -bool ProjectConverter3To4::test_conversion() { +bool ProjectConverter3To4::test_conversion(const RegExContainer ®_container) { bool valid = true; valid = valid & test_conversion_single_normal("Spatial", "Node3D", class_renames, "class"); @@ -1970,26 +2011,37 @@ bool ProjectConverter3To4::test_conversion() { valid = valid & test_conversion_single_additional("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp"); valid = valid & test_conversion_single_additional("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename"); - valid = valid & test_conversion_single_additional("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); + valid = valid & test_conversion_single_additional("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + valid = valid & test_conversion_single_additional_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); valid = valid & test_conversion_single_additional("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); @@ -2002,82 +2054,88 @@ bool ProjectConverter3To4::test_conversion() { valid = valid & test_conversion_single_additional("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); valid = valid & test_conversion_single_additional("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); valid = valid & test_conversion_single_additional("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\n@rpc(any) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc(auth) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(auth,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - - valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); // TODO, this is only a workaround - valid = valid & test_conversion_single_additional("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("(start(A,B,C,D,E,F,G) != OK):", "(start(A,Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("(connect(A,B,C,D,E,F,G) != OK):", "(connect(A,Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); - valid = valid & test_conversion_single_additional("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); + valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); + + valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.\"timeout\"", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + + valid = valid & test_conversion_single_additional_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround + valid = valid & test_conversion_single_additional_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_single_additional_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_single_additional_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); valid = valid & test_conversion_single_additional("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_enums, "custom rename"); @@ -2535,7 +2593,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file void ProjectConverter3To4::rename_classes(String &file_content) { int current_index = 0; - // TODO Maybe it is better way to not rename gd, tscn and other files which are named are classes + // TODO Maybe it is better way to not rename gd, tscn and other files which are named as classes while (class_renames[current_index][0]) { // Begin renaming workaround `Resource.gd` -> `RefCounter.gd` RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"); @@ -2625,432 +2683,11 @@ Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &fi return found_things; } -void ProjectConverter3To4::rename_gdscript_functions(String &file_content) { - // Custom renaming, each rule needs to be set manually - // Don't forget to put validate each rule in validate_conversion function +void ProjectConverter3To4::rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin) { Vector<String> lines = file_content.split("\n"); - RegEx reg_is_empty = RegEx("\\bempty\\("); - RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); - RegEx reg_json_to = RegEx("\\bto_json\\b"); - RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)"); - RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); - RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)"); - RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); - RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)"); - RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$"); - RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); - RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); - RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)"); - RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); - RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); - RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); - - CRASH_COND(!reg_is_empty.is_valid()); - CRASH_COND(!reg_super.is_valid()); - CRASH_COND(!reg_json_to.is_valid()); - CRASH_COND(!reg_json_parse.is_valid()); - CRASH_COND(!reg_json_non_new.is_valid()); - CRASH_COND(!reg_export.is_valid()); - CRASH_COND(!reg_export_advanced.is_valid()); - CRASH_COND(!reg_setget_setget.is_valid()); - CRASH_COND(!reg_setget_set.is_valid()); - CRASH_COND(!reg_setget_get.is_valid()); - CRASH_COND(!reg_join.is_valid()); - CRASH_COND(!reg_mixed_tab_space.is_valid()); - CRASH_COND(!reg_image_lock.is_valid()); - CRASH_COND(!reg_image_unlock.is_valid()); - CRASH_COND(!reg_os_fullscreen.is_valid()); - for (String &line : lines) { - if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) { - line = reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); - line = reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); - } - - // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure - line = reg_mixed_tab_space.sub(line, "$1", true); - - // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray - line = reg_join.sub(line, "$2.join($1)", true); - - // -- empty() -> is_empty() Pool*Array - line = reg_is_empty.sub(line, "is_empty(", true); - - // -- \t.func() -> \tsuper.func() Object - line = reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" - - // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON - line = reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); - - // -- to_json(a) -> JSON.new().stringify(a) Object - line = reg_json_to.sub(line, "JSON.new().stringify", true); - - // -- parse_json(a) -> JSON.get_data() etc. Object - line = reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); - - // -- get_node(@ -> get_node( Node - line = line.replace("get_node(@", "get_node("); - - // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript - line = reg_export.sub(line, "export var $2: $1"); - - // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript - line = reg_export_advanced.sub(line, "export var $2$3 # ($1)"); - - // Setget Setget - line = reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); - - // Setget set - line = reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); - - // Setget get - line = reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); - - // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true) - line = reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); - - // -- r.move_and_slide( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide(") != -1) { - int start = line.find("move_and_slide("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - String base_obj = get_object_of_execution(line.substr(0, start)); - String starting_space = get_starting_space(line); - - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 1) { - String line_new; - - // motion_velocity - line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; - - // up_direction - if (parts.size() >= 2) { - line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n"; - } - - // stop_on_slope - if (parts.size() >= 3) { - line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n"; - } - - // max_slides - if (parts.size() >= 4) { - line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n"; - } - - // floor_max_angle - if (parts.size() >= 5) { - line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n"; - } - - // infiinite_interia - if (parts.size() >= 6) { - line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n"; - } - - line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); - } - } - } - - // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide_with_snap(") != -1) { - int start = line.find("move_and_slide_with_snap("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - String base_obj = get_object_of_execution(line.substr(0, start)); - String starting_space = get_starting_space(line); - - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 1) { - String line_new; - - // motion_velocity - line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; - - // snap - if (parts.size() >= 2) { - line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n"; - } - - // up_direction - if (parts.size() >= 3) { - line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n"; - } - - // stop_on_slope - if (parts.size() >= 4) { - line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n"; - } - - // max_slides - if (parts.size() >= 5) { - line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n"; - } - - // floor_max_angle - if (parts.size() >= 6) { - line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n"; - } - - // infiinite_interia - if (parts.size() >= 7) { - line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n"; - } - - line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); - } - } - } - - // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object - if (line.find("sort_custom(") != -1) { - int start = line.find("sort_custom("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start); - } - } - } - - // -- list_dir_begin( ) -> list_dir_begin() Object - if (line.find("list_dir_begin(") != -1) { - int start = line.find("list_dir_begin("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547"; - } - } - - // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem - if (line.find("draw_line(") != -1) { - int start = line.find("draw_line("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 5) { - line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start); - } - } - } - - // -- func c(var a, var b) -> func c(a, b) - if (line.find("func ") != -1 && line.find("var ") != -1) { - int start = line.find("func "); - start = line.substr(start).find("(") + start; - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - - String start_string = line.substr(0, start) + "("; - for (int i = 0; i < parts.size(); i++) { - start_string += parts[i].strip_edges().trim_prefix("var "); - if (i != parts.size() - 1) { - start_string += ", "; - } - } - line = start_string + ")" + line.substr(end + start); - } - } - - // -- yield(this, \"timeout\") -> await this.timeout GDScript - if (line.find("yield(") != -1) { - int start = line.find("yield("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\"", "").replace("\'", "").replace(" ", "") + line.substr(end + start); - } - } - } - - // -- parse_json( AA ) -> TODO Object - if (line.find("parse_json(") != -1) { - int start = line.find("parse_json("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start); - } - } - - // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform(") != -1) { - int start = line.find(".xform("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 1) { - line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start); - } - } - } - - // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform_inv(") != -1) { - int start = line.find(".xform_inv("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - String object_exec = get_object_of_execution(line.substr(0, start)); - if (line.find(object_exec + ".xform") != -1) { - int start2 = line.find(object_exec + ".xform"); - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 1) { - line = line.substr(0, start2) + parts[0] + " * " + object_exec + line.substr(end + start); - } - } - } - } - - // -- connect(,,,things) -> connect(,Callable(,),things) Object - if (line.find("connect(") != -1) { - int start = line.find("connect("); - // Protection from disconnect - if (start == 0 || line.get(start - 1) != 's') { - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - } - // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object - if (line.find("disconnect(") != -1) { - int start = line.find("disconnect("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object - if (line.find("is_connected(") != -1) { - int start = line.find("is_connected("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - // -- start(a,b,c) -> start(a,Callable(b,c)) Thread - if (line.find("start(") != -1) { - int start = line.find("start("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "start(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589 - if (line.find(" _init(") != -1) { - int start = line.find(" _init("); - int end = line.rfind(":") + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); - } - } - // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message - if (line.find("assert(") != -1) { - int start = line.find("assert("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")"; - } - } - } - // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture - if (line.find("create_from_image(") != -1) { - int start = line.find("create_from_image("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start); - } - } - } - // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e) - if (line.find("set_cell_item(") != -1) { - int start = line.find("set_cell_item("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() > 2) { - line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c)) - if (line.find("get_cell_item(") != -1) { - int start = line.find("get_cell_item("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c)) - if (line.find("get_cell_item_orientation(") != -1) { - int start = line.find("get_cell_item_orientation("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - // apply_impulse(A, B) -> apply_impulse(B, A) - if (line.find("apply_impulse(") != -1) { - int start = line.find("apply_impulse("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); - } - } - } - // apply_force(A, B) -> apply_force(B, A) - if (line.find("apply_force(") != -1) { - int start = line.find("apply_force("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); - } - } - } - // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c)) - if (line.find("map_to_world(") != -1) { - int start = line.find("map_to_world("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } + process_gdscript_line(line, reg_container, builtin); } // Collect vector to string @@ -3064,478 +2701,484 @@ void ProjectConverter3To4::rename_gdscript_functions(String &file_content) { } }; -// This is almost 1:1 copy of function which rename gdscript functions -Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content) { +Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin) { int current_line = 1; Vector<String> found_things; - RegEx reg_is_empty = RegEx("\\bempty\\("); - RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); - RegEx reg_json_to = RegEx("\\bto_json\\b"); - RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)"); - RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)"); - RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)"); - RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)"); - RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)"); - RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$"); - RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); - RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); - RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)"); - RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); - RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); - RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); - - CRASH_COND(!reg_is_empty.is_valid()); - CRASH_COND(!reg_super.is_valid()); - CRASH_COND(!reg_json_to.is_valid()); - CRASH_COND(!reg_json_parse.is_valid()); - CRASH_COND(!reg_json_non_new.is_valid()); - CRASH_COND(!reg_export.is_valid()); - CRASH_COND(!reg_export_advanced.is_valid()); - CRASH_COND(!reg_setget_setget.is_valid()); - CRASH_COND(!reg_setget_set.is_valid()); - CRASH_COND(!reg_setget_get.is_valid()); - CRASH_COND(!reg_join.is_valid()); - CRASH_COND(!reg_mixed_tab_space.is_valid()); - CRASH_COND(!reg_image_lock.is_valid()); - CRASH_COND(!reg_image_unlock.is_valid()); - CRASH_COND(!reg_os_fullscreen.is_valid()); - for (String &line : file_content) { String old_line = line; - - if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) { - line = reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); - line = reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); + process_gdscript_line(line, reg_container, builtin); + if (old_line != line) { + found_things.append(simple_line_formatter(current_line, old_line, line)); } + } - // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure - line = reg_mixed_tab_space.sub(line, "$1", true); + return found_things; +} +void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin) { + if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) { + line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); + line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); + } - // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray - line = reg_join.sub(line, "$2.join($1)", true); + // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure + line = reg_container.reg_mixed_tab_space.sub(line, "$1", true); - // -- empty() -> is_empty() Pool*Array - line = reg_is_empty.sub(line, "is_empty(", true); + // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray + line = reg_container.reg_join.sub(line, "$2.join($1)", true); - // -- \t.func() -> \tsuper.func() Object - line = reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" + // -- empty() -> is_empty() Pool*Array + line = reg_container.reg_is_empty.sub(line, "is_empty(", true); - // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON - line = reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + // -- \t.func() -> \tsuper.func() Object + line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" - // -- to_json(a) -> JSON.new().stringify(a) Object - line = reg_json_to.sub(line, "JSON.new().stringify", true); + // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON + line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); - // -- parse_json(a) -> JSON.get_data() etc. Object - line = reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + // -- to_json(a) -> JSON.new().stringify(a) Object + line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true); - // -- get_node(@ -> get_node( Node - line = line.replace("get_node(@", "get_node("); + // -- parse_json(a) -> JSON.get_data() etc. Object + line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); - // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript - line = reg_export.sub(line, "export var $2: $1"); + // -- get_node(@ -> get_node( Node + line = line.replace("get_node(@", "get_node("); - // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript - line = reg_export_advanced.sub(line, "export var $2$3 # ($1)"); + // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript + line = reg_container.reg_export.sub(line, "export var $2: $1"); - // Setget Setget - line = reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript + line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)"); - // Setget set - line = reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + // Setget Setget + line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); - // Setget get - line = reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + // Setget set + line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); - // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true) - line = reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + // Setget get + line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); - // -- r.move_and_slide( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide(") != -1) { - int start = line.find("move_and_slide("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - String base_obj = get_object_of_execution(line.substr(0, start)); - String starting_space = get_starting_space(line); + // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true) + if (builtin) { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true); + } else { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + } - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 1) { - String line_new; + // -- r.move_and_slide( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody + if (line.find("move_and_slide(") != -1) { + int start = line.find("move_and_slide("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + String base_obj = get_object_of_execution(line.substr(0, start)); + String starting_space = get_starting_space(line); - // motion_velocity - line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() >= 1) { + String line_new; - // up_direction - if (parts.size() >= 2) { - line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n"; - } + // motion_velocity + line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; - // stop_on_slope - if (parts.size() >= 3) { - line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n"; - } + // up_direction + if (parts.size() >= 2) { + line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n"; + } - // max_slides - if (parts.size() >= 4) { - line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n"; - } + // stop_on_slope + if (parts.size() >= 3) { + line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n"; + } - // floor_max_angle - if (parts.size() >= 5) { - line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n"; - } + // max_slides + if (parts.size() >= 4) { + line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n"; + } - // infiinite_interia - if (parts.size() >= 6) { - line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n"; - } + // floor_max_angle + if (parts.size() >= 5) { + line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n"; + } - line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); + // infiinite_interia + if (parts.size() >= 6) { + line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n"; } + + line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); } } + } - // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide_with_snap(") != -1) { - int start = line.find("move_and_slide_with_snap("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - String base_obj = get_object_of_execution(line.substr(0, start)); - String starting_space = get_starting_space(line); - - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 1) { - String line_new; + // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody + if (line.find("move_and_slide_with_snap(") != -1) { + int start = line.find("move_and_slide_with_snap("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + String base_obj = get_object_of_execution(line.substr(0, start)); + String starting_space = get_starting_space(line); - // motion_velocity - line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() >= 1) { + String line_new; - // snap - if (parts.size() >= 2) { - line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n"; - } + // motion_velocity + line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n"; - // up_direction - if (parts.size() >= 3) { - line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n"; - } + // snap + if (parts.size() >= 2) { + line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n"; + } - // stop_on_slope - if (parts.size() >= 4) { - line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n"; - } + // up_direction + if (parts.size() >= 3) { + line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n"; + } - // max_slides - if (parts.size() >= 5) { - line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n"; - } + // stop_on_slope + if (parts.size() >= 4) { + line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n"; + } - // floor_max_angle - if (parts.size() >= 6) { - line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n"; - } + // max_slides + if (parts.size() >= 5) { + line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n"; + } - // infiinite_interia - if (parts.size() >= 7) { - line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n"; - } + // floor_max_angle + if (parts.size() >= 6) { + line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n"; + } - line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); + // infiinite_interia + if (parts.size() >= 7) { + line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n"; } + + line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start); } } + } - // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object - if (line.find("sort_custom(") != -1) { - int start = line.find("sort_custom("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start); - } + // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object + if (line.find("sort_custom(") != -1) { + int start = line.find("sort_custom("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start); } } + } - // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem - if (line.find("draw_line(") != -1) { - int start = line.find("draw_line("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 5) { - line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start); - } - } + // -- list_dir_begin( ) -> list_dir_begin() Object + if (line.find("list_dir_begin(") != -1) { + int start = line.find("list_dir_begin("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547"; } + } - // -- func c(var a, var b) -> func c(a, b) - if (line.find("func ") != -1 && line.find("var ") != -1) { - int start = line.find("func "); - start = line.substr(start).find("(") + start; - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); + // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem + if (line.find("draw_line(") != -1) { + int start = line.find("draw_line("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 5) { + line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start); + } + } + } - String start_string = line.substr(0, start) + "("; - for (int i = 0; i < parts.size(); i++) { - start_string += parts[i].strip_edges().trim_prefix("var "); - if (i != parts.size() - 1) { - start_string += ", "; - } + // -- func c(var a, var b) -> func c(a, b) + if (line.find("func ") != -1 && line.find("var ") != -1) { + int start = line.find("func "); + start = line.substr(start).find("(") + start; + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + + String start_string = line.substr(0, start) + "("; + for (int i = 0; i < parts.size(); i++) { + start_string += parts[i].strip_edges().trim_prefix("var "); + if (i != parts.size() - 1) { + start_string += ", "; } - line = start_string + ")" + line.substr(end + start); } + line = start_string + ")" + line.substr(end + start); } + } - // -- yield(this, \"timeout\") -> await this.timeout GDScript - if (line.find("yield(") != -1) { - int start = line.find("yield("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { + // -- yield(this, \"timeout\") -> await this.timeout GDScript + if (line.find("yield(") != -1) { + int start = line.find("yield("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + if (builtin) { + line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace(" ", "") + line.substr(end + start); + } else { line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\"", "").replace("\'", "").replace(" ", "") + line.substr(end + start); } } } + } - // -- parse_json( AA ) -> TODO Object - if (line.find("parse_json(") != -1) { - int start = line.find("parse_json("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start); - } + // -- parse_json( AA ) -> TODO Object + if (line.find("parse_json(") != -1) { + int start = line.find("parse_json("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start); } + } - // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform(") != -1) { - int start = line.find(".xform("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 1) { - line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start); - } + // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform + if (line.find(".xform(") != -1) { + int start = line.find(".xform("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 1) { + line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start); } } + } - // -- .xform_inv(Vector3(a,b,c)) -> / Vector3(a,b,c) Transform - if (line.find(".xform_inv(") != -1) { - int start = line.find(".xform_inv("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { + // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform + if (line.find(".xform_inv(") != -1) { + int start = line.find(".xform_inv("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + String object_exec = get_object_of_execution(line.substr(0, start)); + if (line.find(object_exec + ".xform") != -1) { + int start2 = line.find(object_exec + ".xform"); Vector<String> parts = parse_arguments(line.substr(start, end)); if (parts.size() == 1) { - line = line.substr(0, start) + " / " + parts[0] + line.substr(end + start); + line = line.substr(0, start2) + parts[0] + " * " + object_exec + line.substr(end + start); } } } + } - // -- connect(,,,things) -> connect(,Callable(,),things) Object - if (line.find("connect(") != -1) { - int start = line.find("connect("); - // Protection from disconnect - if (start == 0 || line.get(start - 1) != 's') { - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - } - // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object - if (line.find("disconnect(") != -1) { - int start = line.find("disconnect("); + // -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object + if (line.find("connect(") != -1) { + int start = line.find("connect("); + // Protection from disconnect + if (start == 0 || line.get(start - 1) != 's') { int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { Vector<String> parts = parse_arguments(line.substr(start, end)); if (parts.size() == 3) { - line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); + line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); + } else if (parts.size() >= 4) { + line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ").bind(" + parts[3].lstrip("[").rstrip("]") + ")" + connect_arguments(parts, 4) + ")" + line.substr(end + start); } } } - // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object - if (line.find("is_connected(") != -1) { - int start = line.find("is_connected("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } + } + // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object + if (line.find("disconnect(") != -1) { + int start = line.find("disconnect("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } - // -- start(a,b,c) -> start(a,Callable(b,c)) Thread - if (line.find("start(") != -1) { - int start = line.find("start("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "start(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } + } + // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object + if (line.find("is_connected(") != -1) { + int start = line.find("is_connected("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } - // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589 - if (line.find(" _init(") != -1) { - int start = line.find(" _init("); - int end = line.rfind(":") + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + } + // -- start(a,b) -> start(Callable(a,b)) Thread + // -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread + if (line.find("start(") != -1) { + int start = line.find("start("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start); + } else if (parts.size() >= 3) { + line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); } } - // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message - if (line.find("assert(") != -1) { - int start = line.find("assert("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")"; - } + } + // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589 + if (line.find(" _init(") != -1) { + int start = line.find(" _init("); + int end = line.rfind(":") + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + } + } + // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message + if (line.find("assert(") != -1) { + int start = line.find("assert("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")"; } } - // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture - if (line.find("create_from_image(") != -1) { - int start = line.find("create_from_image("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start); - } + } + // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture + if (line.find("create_from_image(") != -1) { + int start = line.find("create_from_image("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start); } } - // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e) - if (line.find("set_cell_item(") != -1) { - int start = line.find("set_cell_item("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() > 2) { - line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } + } + // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e) + if (line.find("set_cell_item(") != -1) { + int start = line.find("set_cell_item("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() > 2) { + line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start); } } - // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c)) - if (line.find("get_cell_item(") != -1) { - int start = line.find("get_cell_item("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } + } + // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c)) + if (line.find("get_cell_item(") != -1) { + int start = line.find("get_cell_item("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } - // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c)) - if (line.find("get_cell_item_orientation(") != -1) { - int start = line.find("get_cell_item_orientation("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } + } + // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c)) + if (line.find("get_cell_item_orientation(") != -1) { + int start = line.find("get_cell_item_orientation("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } - - // apply_impulse(A, B) -> apply_impulse(B, A) - if (line.find("apply_impulse(") != -1) { - int start = line.find("apply_impulse("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); - } + } + // apply_impulse(A, B) -> apply_impulse(B, A) + if (line.find("apply_impulse(") != -1) { + int start = line.find("apply_impulse("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); } } - // apply_force(A, B) -> apply_force(B, A) - if (line.find("apply_force(") != -1) { - int start = line.find("apply_force("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 2) { - line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); - } + } + // apply_force(A, B) -> apply_force(B, A) + if (line.find("apply_force(") != -1) { + int start = line.find("apply_force("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 2) { + line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start); } } - // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c)) - if (line.find("map_to_world(") != -1) { - int start = line.find("get_cell_item_orientation("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } + } + // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c)) + if (line.find("map_to_world(") != -1) { + int start = line.find("map_to_world("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } - - if (old_line != line) { - found_things.append(simple_line_formatter(current_line, old_line, line)); + } + // OS.get_window_safe_area() -> DisplayServer.get_display_safe_area() + if (line.find("OS.get_window_safe_area(") != -1) { + int start = line.find("OS.get_window_safe_area("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 0) { + line = line.substr(0, start) + "DisplayServer.get_display_safe_area()" + line.substr(end + start); + } } } - - return found_things; } -void ProjectConverter3To4::rename_csharp_functions(String &file_content) { - // Custom renaming, each rule needs to be set manually - // Don't forget to put validate each rule in validate_conversion function - Vector<String> lines = file_content.split("\n"); +void ProjectConverter3To4::process_csharp_line(String &line) { + // TODO maybe this can be changed to normal rule + line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); - for (String &line : lines) { - // TODO maybe this can be changed to normal rule - line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); - - // -- Connect(,,,things) -> Connect(,Callable(,),things) Object - if (line.find("Connect(") != -1) { - int start = line.find("Connect("); - // Protection from disconnect - if (start == 0 || line.get(start - 1) != 's') { - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - } - // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object - if (line.find("Disconnect(") != -1) { - int start = line.find("Disconnect("); + // -- Connect(,,,things) -> Connect(,Callable(,),things) Object + if (line.find("Connect(") != -1) { + int start = line.find("Connect("); + // Protection from disconnect + if (start == 0 || line.get(start - 1) != 's') { int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "Disconnect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); + if (parts.size() >= 3) { + line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); } } } - // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object - if (line.find("IsConnected(") != -1) { - int start = line.find("IsConnected("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "IsConnected(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } + } + // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object + if (line.find("Disconnect(") != -1) { + int start = line.find("Disconnect("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "Disconnect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); } } } + // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object + if (line.find("IsConnected(") != -1) { + int start = line.find("IsConnected("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 3) { + line = line.substr(0, start) + "IsConnected(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); + } + } + } +} + +void ProjectConverter3To4::rename_csharp_functions(String &file_content) { + Vector<String> lines = file_content.split("\n"); + + for (String &line : lines) { + process_csharp_line(line); + } // Collect vector to string file_content = ""; @@ -3556,47 +3199,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<St for (String &line : file_content) { String old_line = line; - - // TODO maybe this can be changed to normal rule - line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); - - // -- Connect(,,,things) -> connect(,Callable(,),things) Object - if (line.find("Connect(") != -1) { - int start = line.find("Connect("); - // Protection from disconnect - if (start == 0 || line.get(start - 1) != 's') { - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() >= 3) { - line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start); - } - } - } - } - // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object - if (line.find("Disconnect(") != -1) { - int start = line.find("Disconnect("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "Disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object - if (line.find("IsConnected(") != -1) { - int start = line.find("IsConnected("); - int end = get_end_parenthess(line.substr(start)) + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - if (parts.size() == 3) { - line = line.substr(0, start) + "IsConnected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start); - } - } - } - + process_csharp_line(line); if (old_line != line) { found_things.append(simple_line_formatter(current_line, old_line, line)); } @@ -3605,88 +3208,205 @@ Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<St return found_things; } -void ProjectConverter3To4::rename_gdscript_keywords(String &file_content){ - { RegEx reg_tool = RegEx("([\n]+)tool"); -CRASH_COND(!reg_tool.is_valid()); -file_content = reg_tool.sub(file_content, "$1@tool", true); -RegEx reg_tool2 = RegEx("^tool"); -CRASH_COND(!reg_tool2.is_valid()); -file_content = reg_tool2.sub(file_content, "@tool", true); -} -{ - RegEx reg_export = RegEx("([\n\t]+)export\\b"); - CRASH_COND(!reg_export.is_valid()); - file_content = reg_export.sub(file_content, "$1@export", true); - RegEx reg_export2 = RegEx("^export"); - CRASH_COND(!reg_export2.is_valid()); - file_content = reg_export2.sub(file_content, "@export", true); -} -{ - RegEx reg_onready = RegEx("([\n]+)onready"); - CRASH_COND(!reg_onready.is_valid()); - file_content = reg_onready.sub(file_content, "$1@onready", true); - RegEx reg_onready2 = RegEx("^onready"); - CRASH_COND(!reg_onready2.is_valid()); - file_content = reg_onready2.sub(file_content, "@onready", true); -} -{ - RegEx reg_master = RegEx("([\n]+)master func"); - CRASH_COND(!reg_master.is_valid()); - file_content = reg_master.sub(file_content, "$1@rpc(any) func", true); - RegEx reg_master2 = RegEx("^master func"); - CRASH_COND(!reg_master2.is_valid()); - file_content = reg_master2.sub(file_content, "@rpc(any) func", true); -} -{ - RegEx reg_puppet = RegEx("([\n]+)puppet func"); - CRASH_COND(!reg_puppet.is_valid()); - file_content = reg_puppet.sub(file_content, "$1@rpc(auth) func", true); - RegEx reg_puppet2 = RegEx("^puppet func"); - CRASH_COND(!reg_puppet2.is_valid()); - file_content = reg_puppet2.sub(file_content, "@rpc(auth) func", true); -} -{ - RegEx reg_remote = RegEx("([\n]+)remote func"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, "$1@rpc(any) func", true); - RegEx reg_remote2 = RegEx("^remote func"); - CRASH_COND(!reg_remote2.is_valid()); - file_content = reg_remote2.sub(file_content, "@rpc(any) func", true); -} -{ - RegEx reg_remotesync = RegEx("([\n]+)remotesync func"); - CRASH_COND(!reg_remotesync.is_valid()); - file_content = reg_remotesync.sub(file_content, "$1@rpc(any,sync) func", true); - RegEx reg_remotesync2 = RegEx("^remotesync func"); - CRASH_COND(!reg_remotesync2.is_valid()); - file_content = reg_remotesync2.sub(file_content, "@rpc(any,sync) func", true); -} -{ - RegEx reg_sync = RegEx("([\n]+)sync func"); - CRASH_COND(!reg_sync.is_valid()); - file_content = reg_sync.sub(file_content, "$1@rpc(any,sync) func", true); - RegEx reg_sync2 = RegEx("^sync func"); - CRASH_COND(!reg_sync2.is_valid()); - file_content = reg_sync2.sub(file_content, "@rpc(any,sync) func", true); -} -{ - RegEx reg_puppetsync = RegEx("([\n]+)puppetsync func"); - CRASH_COND(!reg_puppetsync.is_valid()); - file_content = reg_puppetsync.sub(file_content, "$1@rpc(auth,sync) func", true); - RegEx reg_puppetsync2 = RegEx("^puppetsync func"); - CRASH_COND(!reg_puppetsync2.is_valid()); - file_content = reg_puppetsync2.sub(file_content, "@rpc(auth,sync) func", true); +void ProjectConverter3To4::rename_csharp_attributes(String &file_content) { + // -- [Remote] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer)] + { + RegEx reg_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_remote.is_valid()); + file_content = reg_remote.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + } + // -- [RemoteSync] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)] + { + RegEx reg_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_remotesync.is_valid()); + file_content = reg_remotesync.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + } + // -- [Puppet] -> [RPC] + { + RegEx reg_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_puppet.is_valid()); + file_content = reg_puppet.sub(file_content, "[RPC]", true); + } + // -- [PuppetSync] -> [RPC(CallLocal = true)] + { + RegEx reg_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_puppetsync.is_valid()); + file_content = reg_puppetsync.sub(file_content, "[RPC(CallLocal = true)]", true); + } + String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n"; + // -- [Master] -> [RPC] + { + RegEx reg_remote = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_remote.is_valid()); + file_content = reg_remote.sub(file_content, error_message + "[RPC]", true); + } + // -- [MasterSync] -> [RPC(CallLocal = true)] + { + RegEx reg_remote = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!reg_remote.is_valid()); + file_content = reg_remote.sub(file_content, error_message + "[RPC(CallLocal = true)]", true); + } } -{ - RegEx reg_mastersync = RegEx("([\n]+)mastersync func"); - CRASH_COND(!reg_mastersync.is_valid()); - file_content = reg_mastersync.sub(file_content, "$1@rpc(any,sync) func", true); - RegEx reg_mastersync2 = RegEx("^mastersync func"); - CRASH_COND(!reg_mastersync2.is_valid()); - file_content = reg_mastersync2.sub(file_content, "@rpc(any,sync) func", true); + +Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &file_content) { + int current_line = 1; + + Vector<String> found_things; + + for (String &line : file_content) { + String old; + old = line; + { + RegEx regex = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line)); + } + old = line; + { + RegEx regex = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line)); + } + old = line; + { + RegEx regex = RegEx("\\[Puppet(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[Puppet]", "[RPC]", line)); + } + old = line; + { + RegEx regex = RegEx("\\[(Puppet|Slave)Sync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC(CallLocal = true)]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line)); + } + old = line; + { + RegEx regex = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[Master]", "[RPC]", line)); + } + old = line; + { + RegEx regex = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "[RPC(CallLocal = true)]", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line)); + } + + current_line++; + } + + return found_things; } + +void ProjectConverter3To4::rename_gdscript_keywords(String &file_content) { + { + RegEx reg_first = RegEx("([\n]+)tool"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@tool", true); + RegEx reg_second = RegEx("^tool"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@tool", true); + } + { + RegEx reg_first = RegEx("([\n\t]+)export\\b"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@export", true); + RegEx reg_second = RegEx("^export"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@export", true); + } + { + RegEx reg_first = RegEx("([\n]+)onready"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@onready", true); + RegEx reg_second = RegEx("^onready"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@onready", true); + } + { + RegEx reg_first = RegEx("([\n]+)remote func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc(any_peer) func", true); + RegEx reg_second = RegEx("^remote func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc(any_peer) func", true); + } + { + RegEx reg_first = RegEx("([\n]+)remotesync func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); + RegEx reg_second = RegEx("^remotesync func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); + } + { + RegEx reg_first = RegEx("([\n]+)sync func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); + RegEx reg_second = RegEx("^sync func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); + } + { + RegEx reg_first = RegEx("([\n]+)slave func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc func", true); + RegEx reg_second = RegEx("^slave func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc func", true); + } + { + RegEx reg_first = RegEx("([\n]+)puppet func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc func", true); + RegEx reg_second = RegEx("^puppet func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc func", true); + } + { + RegEx reg_first = RegEx("([\n]+)puppetsync func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1@rpc(call_local) func", true); + RegEx reg_second = RegEx("^puppetsync func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, "@rpc(call_local) func", true); + } + String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n"; + { + RegEx reg_first = RegEx("([\n]+)master func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc func", true); + RegEx reg_second = RegEx("^master func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, error_message + "@rpc func", true); + } + { + RegEx reg_first = RegEx("([\n]+)mastersync func"); + CRASH_COND(!reg_first.is_valid()); + file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc(call_local) func", true); + RegEx reg_second = RegEx("^mastersync func"); + CRASH_COND(!reg_second.is_valid()); + file_content = reg_second.sub(file_content, error_message + "@rpc(call_local) func", true); + } } -; Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) { Vector<String> found_things; @@ -3697,96 +3417,105 @@ Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<S String old; old = line; { - RegEx reg_tool2 = RegEx("^tool"); - CRASH_COND(!reg_tool2.is_valid()); - line = reg_tool2.sub(line, "@tool", true); + RegEx reg_first = RegEx("^tool"); + CRASH_COND(!reg_first.is_valid()); + line = reg_first.sub(line, "@tool", true); } if (old != line) { found_things.append(line_formatter(current_line, "tool", "@tool", line)); } old = line; { - RegEx reg_export = RegEx("([\t]+)export\\b"); - CRASH_COND(!reg_export.is_valid()); - line = reg_export.sub(line, "$1@export", true); - RegEx reg_export2 = RegEx("^export"); - CRASH_COND(!reg_export2.is_valid()); - line = reg_export2.sub(line, "@export", true); + RegEx reg_first = RegEx("([\t]+)export\\b"); + CRASH_COND(!reg_first.is_valid()); + line = reg_first.sub(line, "$1@export", true); + RegEx reg_second = RegEx("^export"); + CRASH_COND(!reg_second.is_valid()); + line = reg_second.sub(line, "@export", true); } if (old != line) { found_things.append(line_formatter(current_line, "export", "@export", line)); } old = line; { - RegEx reg_onready2 = RegEx("^onready"); - CRASH_COND(!reg_onready2.is_valid()); - line = reg_onready2.sub(line, "@onready", true); + RegEx reg_first = RegEx("^onready"); + CRASH_COND(!reg_first.is_valid()); + line = reg_first.sub(line, "@onready", true); } if (old != line) { found_things.append(line_formatter(current_line, "onready", "@onready", line)); } old = line; { - RegEx reg_master2 = RegEx("^master func"); - CRASH_COND(!reg_master2.is_valid()); - line = reg_master2.sub(line, "@rpc(any) func", true); + RegEx regex = RegEx("^remote func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc(any_peer) func", true); + } + if (old != line) { + found_things.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); + } + old = line; + { + RegEx regex = RegEx("^remotesync func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "master func", "@rpc(any) func", line)); + found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); } old = line; { - RegEx reg_puppet2 = RegEx("^puppet func"); - CRASH_COND(!reg_puppet2.is_valid()); - line = reg_puppet2.sub(line, "@rpc(auth) func", true); + RegEx regex = RegEx("^sync func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "puppet func", "@rpc(auth) func", line)); + found_things.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); } old = line; { - RegEx reg_remote2 = RegEx("^remote func"); - CRASH_COND(!reg_remote2.is_valid()); - line = reg_remote2.sub(line, "@rpc(any) func", true); + RegEx regex = RegEx("^slave func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "remote func", "@rpc(any) func", line)); + found_things.append(line_formatter(current_line, "slave func", "@rpc func", line)); } old = line; { - RegEx reg_remotesync2 = RegEx("^remotesync func"); - CRASH_COND(!reg_remotesync2.is_valid()); - line = reg_remotesync2.sub(line, "@rpc(any,sync) func", true); + RegEx regex = RegEx("^puppet func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any,sync) func", line)); + found_things.append(line_formatter(current_line, "puppet func", "@rpc func", line)); } old = line; { - RegEx reg_sync2 = RegEx("^sync func"); - CRASH_COND(!reg_sync2.is_valid()); - line = reg_sync2.sub(line, "@rpc(any,sync) func", true); + RegEx regex = RegEx("^puppetsync func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc(call_local) func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "sync func", "@rpc(any,sync) func", line)); + found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); } old = line; { - RegEx reg_puppetsync2 = RegEx("^puppetsync func"); - CRASH_COND(!reg_puppetsync2.is_valid()); - line = reg_puppetsync2.sub(line, "@rpc(auth,sync) func", true); + RegEx regex = RegEx("^master func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(any,sync) func", line)); + found_things.append(line_formatter(current_line, "master func", "@rpc func", line)); } old = line; { - RegEx reg_mastersync2 = RegEx("^mastersync func"); - CRASH_COND(!reg_mastersync2.is_valid()); - line = reg_mastersync2.sub(line, "@rpc(any,sync) func", true); + RegEx regex = RegEx("^mastersync func"); + CRASH_COND(!regex.is_valid()); + line = regex.sub(line, "@rpc(call_local) func", true); } if (old != line) { - found_things.append(line_formatter(current_line, "mastersync", "@rpc(any,sync) func", line)); + found_things.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); } old = line; diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index 95239666e0..8526e2ceb9 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -37,17 +37,26 @@ #include "core/string/ustring.h" class ProjectConverter3To4 { +public: + class RegExContainer; + +private: void rename_enums(String &file_content); Vector<String> check_for_rename_enums(Vector<String> &file_content); void rename_classes(String &file_content); Vector<String> check_for_rename_classes(Vector<String> &file_content); - void rename_gdscript_functions(String &file_content); - Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content); + void rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin); + Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin); + void process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin); void rename_csharp_functions(String &file_content); Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content); + void process_csharp_line(String &line); + + void rename_csharp_attributes(String &file_content); + Vector<String> check_for_rename_csharp_attributes(Vector<String> &file_content); void rename_gdscript_keywords(String &file_content); Vector<String> check_for_rename_gdscript_keywords(Vector<String> &file_content); @@ -71,9 +80,10 @@ class ProjectConverter3To4 { bool test_single_array(const char *array[][2], bool ignore_second_check = false); bool test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what); + bool test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); bool test_conversion_single_normal(String name, String expected, const char *array[][2], String what); bool test_array_names(); - bool test_conversion(); + bool test_conversion(const RegExContainer ®_container); public: int validate_conversion(); diff --git a/modules/bmp/SCsub b/modules/bmp/SCsub index 4f3405ff28..9d317887c3 100644 --- a/modules/bmp/SCsub +++ b/modules/bmp/SCsub @@ -5,5 +5,5 @@ Import("env_modules") env_bmp = env_modules.Clone() -# Godot's own source files +# Godot source files env_bmp.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/csg/SCsub b/modules/csg/SCsub index c7307ddefd..55f859db11 100644 --- a/modules/csg/SCsub +++ b/modules/csg/SCsub @@ -3,10 +3,9 @@ Import("env") Import("env_modules") -# Godot's own source files env_csg = env_modules.Clone() -# Godot's own source files +# Godot source files env_csg.add_source_files(env.modules_sources, "*.cpp") if env["tools"]: env_csg.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index 4b2ea6faa5..8efcd72fb6 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -58,22 +58,23 @@ if env["builtin_freetype"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - thirdparty_brotli_dir = "#thirdparty/brotli/" - thirdparty_brotli_sources = [ - "common/constants.c", - "common/context.c", - "common/dictionary.c", - "common/platform.c", - "common/shared_dictionary.c", - "common/transform.c", - "dec/bit_reader.c", - "dec/decode.c", - "dec/huffman.c", - "dec/state.c", - ] - thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] - env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) - env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) + if env["brotli"]: + thirdparty_brotli_dir = "#thirdparty/brotli/" + thirdparty_brotli_sources = [ + "common/constants.c", + "common/context.c", + "common/dictionary.c", + "common/platform.c", + "common/shared_dictionary.c", + "common/transform.c", + "dec/bit_reader.c", + "dec/decode.c", + "dec/huffman.c", + "dec/state.c", + ] + thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources] + env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) + env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"]) if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"): env_freetype.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"]) diff --git a/modules/freetype/config.py b/modules/freetype/config.py index d22f9454ed..c0586d5536 100644 --- a/modules/freetype/config.py +++ b/modules/freetype/config.py @@ -2,5 +2,13 @@ def can_build(env, platform): return True +def get_opts(platform): + from SCons.Variables import BoolVariable + + return [ + BoolVariable("brotli", "Enable Brotli decompressor for WOFF2 fonts support", True), + ] + + def configure(env): pass diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index d752bef14f..dc6bfbb034 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -325,16 +325,23 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl for (int i = 0; i < msort.size(); i++) { props.push_front(sptr->member_info[msort[i].name]); } + +#ifdef TOOLS_ENABLED + r_list->push_back(sptr->get_class_category()); +#endif // TOOLS_ENABLED + + for (const PropertyInfo &E : props) { + r_list->push_back(E); + } + + props.clear(); + if (!p_include_base) { break; } sptr = sptr->_base; } - - for (const PropertyInfo &E : props) { - r_list->push_back(E); - } } void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const { @@ -434,10 +441,6 @@ void GDScript::set_source_code(const String &p_code) { #ifdef TOOLS_ENABLED void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) { - if (base_cache.is_valid()) { - base_cache->_update_exports_values(values, propnames); - } - for (const KeyValue<StringName, Variant> &E : member_default_values_cache) { values[E.key] = E.value; } @@ -445,6 +448,10 @@ void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List for (const PropertyInfo &E : members_cache) { propnames.push_back(E); } + + if (base_cache.is_valid()) { + base_cache->_update_exports_values(values, propnames); + } } void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) { @@ -703,6 +710,8 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc member_default_values_cache.clear(); _signals.clear(); + members_cache.push_back(get_class_category()); + for (int i = 0; i < c->members.size(); i++) { const GDScriptParser::ClassNode::Member &member = c->members[i]; @@ -728,6 +737,9 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc } _signals[member.signal->identifier->name] = parameters_names; } break; + case GDScriptParser::ClassNode::Member::GROUP: { + members_cache.push_back(member.annotation->export_info); + } break; default: break; // Nothing. } @@ -1510,11 +1522,17 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const props.push_front(sptr->member_info[msort[i].name]); } - sptr = sptr->_base; - } +#ifdef TOOLS_ENABLED + p_properties->push_back(sptr->get_class_category()); +#endif // TOOLS_ENABLED + + for (const PropertyInfo &prop : props) { + p_properties->push_back(prop); + } + + props.clear(); - for (const PropertyInfo &E : props) { - p_properties->push_back(E); + sptr = sptr->_base; } } diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub index 6634d5df7b..71f3ba58d9 100644 --- a/modules/gltf/SCsub +++ b/modules/gltf/SCsub @@ -5,7 +5,7 @@ Import("env_modules") env_gltf = env_modules.Clone() -# Godot's own source files +# Godot source files env_gltf.add_source_files(env.modules_sources, "*.cpp") env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp") env_gltf.add_source_files(env.modules_sources, "structures/*.cpp") diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub index 52777235b8..da3f7d4dd9 100644 --- a/modules/gridmap/SCsub +++ b/modules/gridmap/SCsub @@ -5,7 +5,7 @@ Import("env_modules") env_gridmap = env_modules.Clone() -# Godot's own source files +# Godot source files env_gridmap.add_source_files(env.modules_sources, "*.cpp") if env["tools"]: env_gridmap.add_source_files(env.modules_sources, "editor/*.cpp") diff --git a/modules/hdr/SCsub b/modules/hdr/SCsub index a709397c9a..10629bda3c 100644 --- a/modules/hdr/SCsub +++ b/modules/hdr/SCsub @@ -5,5 +5,5 @@ Import("env_modules") env_hdr = env_modules.Clone() -# Godot's own source files +# Godot source files env_hdr.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub index f4d1605d55..20e3165f38 100644 --- a/modules/minimp3/SCsub +++ b/modules/minimp3/SCsub @@ -13,5 +13,5 @@ if not env.msvc: else: env_minimp3.Prepend(CPPPATH=[thirdparty_dir]) -# Godot's own source files +# Godot source files env_minimp3.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/mono/config.py b/modules/mono/config.py index 3e6584590c..d895d2d92d 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -5,52 +5,44 @@ def can_build(env, platform): return not env["arch"].startswith("rv") -def configure(env): - platform = env["platform"] - - if platform not in supported_platforms: - raise RuntimeError("This module does not currently support building for this platform") - - env.add_module_version_string("mono") - - from SCons.Script import BoolVariable, PathVariable, Variables, Help +def get_opts(platform): + from SCons.Variables import BoolVariable, PathVariable default_mono_static = platform in ["ios", "javascript"] default_mono_bundles_zlib = platform in ["javascript"] - envvars = Variables() - envvars.Add( + return [ PathVariable( "mono_prefix", "Path to the Mono installation directory for the target platform and architecture", "", PathVariable.PathAccept, - ) - ) - envvars.Add( + ), PathVariable( "mono_bcl", "Path to a custom Mono BCL (Base Class Library) directory for the target platform", "", PathVariable.PathAccept, - ) - ) - envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static)) - envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True)) - envvars.Add(BoolVariable("build_cil", "Build C# solutions", True)) - envvars.Add( - BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True) - ) - - # TODO: It would be great if this could be detected automatically instead - envvars.Add( + ), + BoolVariable("mono_static", "Statically link Mono", default_mono_static), + BoolVariable("mono_glue", "Build with the Mono glue sources", True), + BoolVariable("build_cil", "Build C# solutions", True), + BoolVariable( + "copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True + ), BoolVariable( "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib - ) - ) + ), + ] + + +def configure(env): + platform = env["platform"] - envvars.Update(env) - Help(envvars.GenerateHelpText(env)) + if platform not in supported_platforms: + raise RuntimeError("This module does not currently support building for this platform") + + env.add_module_version_string("mono") if env["mono_bundles_zlib"]: # Mono may come with zlib bundled for WASM or on newer version when built with MinGW. diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index c7279be97f..475b483d6c 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1801,9 +1801,7 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { List<PropertyInfo> props; - for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) { - props.push_front(E.value); - } + script->get_script_property_list(&props); // Call _get_property_list @@ -2335,10 +2333,6 @@ void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) #ifdef TOOLS_ENABLED void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) { - if (base_cache.is_valid()) { - base_cache->_update_exports_values(values, propnames); - } - for (const KeyValue<StringName, Variant> &E : exported_members_defval_cache) { values[E.key] = E.value; } @@ -2346,6 +2340,10 @@ void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, for (const PropertyInfo &prop_info : exported_members_cache) { propnames.push_back(prop_info); } + + if (base_cache.is_valid()) { + base_cache->_update_exports_values(values, propnames); + } } void CSharpScript::_update_member_info_no_exports() { @@ -2357,6 +2355,7 @@ void CSharpScript::_update_member_info_no_exports() { member_info.clear(); GDMonoClass *top = script_class; + List<PropertyInfo> props; while (top && top != native) { PropertyInfo prop_info; @@ -2371,7 +2370,7 @@ void CSharpScript::_update_member_info_no_exports() { StringName member_name = field->get_name(); member_info[member_name] = prop_info; - exported_members_cache.push_front(prop_info); + props.push_front(prop_info); exported_members_defval_cache[member_name] = Variant(); } } @@ -2385,11 +2384,18 @@ void CSharpScript::_update_member_info_no_exports() { StringName member_name = property->get_name(); member_info[member_name] = prop_info; - exported_members_cache.push_front(prop_info); + props.push_front(prop_info); exported_members_defval_cache[member_name] = Variant(); } } + exported_members_cache.push_back(PropertyInfo(Variant::NIL, top->get_name(), PROPERTY_HINT_NONE, get_path(), PROPERTY_USAGE_CATEGORY)); + for (const PropertyInfo &E : props) { + exported_members_cache.push_back(E); + } + + props.clear(); + top = top->get_parent_class(); } } @@ -2464,6 +2470,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda #endif GDMonoClass *top = script_class; + List<PropertyInfo> props; while (top && top != native) { PropertyInfo prop_info; @@ -2482,7 +2489,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda if (exported) { #ifdef TOOLS_ENABLED if (is_editor) { - exported_members_cache.push_front(prop_info); + props.push_front(prop_info); if (tmp_object) { exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object)); @@ -2510,7 +2517,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda if (exported) { #ifdef TOOLS_ENABLED if (is_editor) { - exported_members_cache.push_front(prop_info); + props.push_front(prop_info); if (tmp_object) { MonoException *exc = nullptr; MonoObject *ret = property->get_value(tmp_object, &exc); @@ -2531,6 +2538,16 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda } } +#ifdef TOOLS_ENABLED + exported_members_cache.push_back(PropertyInfo(Variant::NIL, top->get_name(), PROPERTY_HINT_NONE, get_path(), PROPERTY_USAGE_CATEGORY)); + + for (const PropertyInfo &E : props) { + exported_members_cache.push_back(E); + } + + props.clear(); +#endif // TOOLS_ENABLED + top = top->get_parent_class(); } @@ -3491,9 +3508,15 @@ Ref<Script> CSharpScript::get_base_script() const { void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const { List<PropertyInfo> props; +#ifdef TOOLS_ENABLED + for (const PropertyInfo &E : exported_members_cache) { + props.push_back(E); + } +#else for (const KeyValue<StringName, PropertyInfo> &E : member_info) { props.push_front(E.value); } +#endif // TOOLS_ENABLED for (const PropertyInfo &prop : props) { r_list->push_back(prop); diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 73e5c2bf74..81b8e1ea5d 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -113,8 +113,11 @@ if env["builtin_harfbuzz"]: if freetype_enabled: thirdparty_sources += [ "src/hb-ft.cc", - "src/hb-graphite2.cc", ] + if env["graphite"]: + thirdparty_sources += [ + "src/hb-graphite2.cc", + ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] env_harfbuzz.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"]) @@ -133,7 +136,7 @@ if env["builtin_harfbuzz"]: ) if env["builtin_freetype"]: env_harfbuzz.Prepend(CPPPATH=["#thirdparty/freetype/include"]) - if env["builtin_graphite"]: + if env["builtin_graphite"] and env["graphite"]: env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"]) env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"]) @@ -165,7 +168,7 @@ if env["builtin_harfbuzz"]: env.Append(LIBS=[lib]) -if env["builtin_graphite"] and freetype_enabled: +if env["builtin_graphite"] and freetype_enabled and env["graphite"]: env_graphite = env_modules.Clone() env_graphite.disable_warnings() @@ -512,9 +515,10 @@ if env["builtin_msdfgen"] and msdfgen_enabled: env_text_server_adv.Prepend(CPPPATH=["#thirdparty/msdfgen"]) if env["builtin_freetype"] and freetype_enabled: + env_text_server_adv.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/freetype/include"]) -if env["builtin_graphite"] and freetype_enabled: +if env["builtin_graphite"] and freetype_enabled and env["graphite"]: env_text_server_adv.Prepend(CPPPATH=["#thirdparty/graphite/include"]) env_text_server_adv.add_source_files(module_obj, "*.cpp") diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py index 8c8df9b05e..179a2ff378 100644 --- a/modules/text_server_adv/config.py +++ b/modules/text_server_adv/config.py @@ -2,6 +2,14 @@ def can_build(env, platform): return True +def get_opts(platform): + from SCons.Variables import BoolVariable + + return [ + BoolVariable("graphite", "Enable SIL Graphite smart fonts support", True), + ] + + def configure(env): pass diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 21e1bfaa5c..73dbf2f443 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -4706,7 +4706,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; - if (c == 0x0640) { + if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) { sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION; } if (sd->jstops.has(sd_glyphs[i].start)) { diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index b337abea7a..7ae329d616 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -113,7 +113,10 @@ using namespace godot; #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_BBOX_H - +#include FT_CONFIG_OPTIONS_H +#if !defined(FT_CONFIG_OPTION_USE_BROTLI) && !defined(_MSC_VER) +#warning FreeType is configured without Brotli support, built-in fonts will not be available. +#endif #include <hb-ft.h> #include <hb-ot.h> #endif diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub index ca9322e450..8f626f02b8 100644 --- a/modules/text_server_fb/SCsub +++ b/modules/text_server_fb/SCsub @@ -12,6 +12,7 @@ if env["builtin_msdfgen"] and msdfgen_enabled: env_text_server_fb.Prepend(CPPPATH=["#thirdparty/msdfgen"]) if env["builtin_freetype"] and freetype_enabled: + env_text_server_fb.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"]) env_text_server_fb.Prepend(CPPPATH=["#thirdparty/freetype/include"]) env_text_server_fb.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index adb5cbb817..fef19d442b 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -98,6 +98,10 @@ using namespace godot; #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_BBOX_H +#include FT_CONFIG_OPTIONS_H +#if !defined(FT_CONFIG_OPTION_USE_BROTLI) && !defined(_MSC_VER) +#warning FreeType is configured without Brotli support, built-in fonts will not be available. +#endif #endif /*************************************************************************/ diff --git a/modules/tga/SCsub b/modules/tga/SCsub index 067caa6ea0..ccd7d2ee37 100644 --- a/modules/tga/SCsub +++ b/modules/tga/SCsub @@ -5,5 +5,5 @@ Import("env_modules") env_tga = env_modules.Clone() -# Godot's own source files +# Godot source files env_tga.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 4215a979e0..73249371cd 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1206,6 +1206,10 @@ bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { +#ifdef TOOLS_ENABLED + p_properties->push_back(script->get_class_category()); +#endif // TOOLS_ENABLED + for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) { if (!E.value._export) { continue; diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 65f9a3d4b8..54c479fc81 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -303,6 +303,7 @@ public: virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual void screen_set_keep_on(bool p_enable) override; + virtual bool screen_is_kept_on() const override; virtual Vector<int> get_window_list() const override; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 2f5efae69e..e228007246 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -1892,6 +1892,10 @@ float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const { return SCREEN_REFRESH_RATE_FALLBACK; } +bool DisplayServerMacOS::screen_is_kept_on() const { + return (screen_keep_on_assertion); +} + void DisplayServerMacOS::screen_set_keep_on(bool p_enable) { if (screen_keep_on_assertion) { IOPMAssertionRelease(screen_keep_on_assertion); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index f6baab1644..a975d09a9d 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -531,10 +531,43 @@ DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(in } void DisplayServerWindows::screen_set_keep_on(bool p_enable) { + if (keep_screen_on == p_enable) { + return; + } + + if (p_enable) { + const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true"; + Char16String reason_utf16 = reason.utf16(); + + REASON_CONTEXT context; + context.Version = POWER_REQUEST_CONTEXT_VERSION; + context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING; + context.Reason.SimpleReasonString = (LPWSTR)(reason_utf16.ptrw()); + power_request = PowerCreateRequest(&context); + if (power_request == INVALID_HANDLE_VALUE) { + print_error("Failed to enable screen_keep_on."); + return; + } + if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired) == 0) { + print_error("Failed to request system sleep override."); + return; + } + if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired) == 0) { + print_error("Failed to request display timeout override."); + return; + } + } else { + PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired); + PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired); + CloseHandle(power_request); + power_request = nullptr; + } + + keep_screen_on = p_enable; } bool DisplayServerWindows::screen_is_kept_on() const { - return false; + return keep_screen_on; } Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const { @@ -3619,6 +3652,9 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win // Init TTS tts = memnew(TTS_Windows); + // Enforce default keep screen on value. + screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); if (wintab_lib) { @@ -3822,6 +3858,9 @@ DisplayServerWindows::~DisplayServerWindows() { SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc); } + // Close power request handle. + screen_set_keep_on(false); + #ifdef GLES3_ENABLED // destroy windows .. NYI? // FIXME wglDeleteContext is never called diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index ddbf674c64..db9b589304 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -331,6 +331,8 @@ class DisplayServerWindows : public DisplayServer { HINSTANCE hInstance; // Holds The Instance Of The Application String rendering_driver; bool app_focused = false; + bool keep_screen_on = false; + HANDLE power_request; TTS_Windows *tts = nullptr; diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 7589af0924..316988d298 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -217,7 +217,7 @@ void ShapeCast2D::_notification(int p_what) { if (shape.is_null()) { break; } - Color draw_col = get_tree()->get_debug_collisions_color(); + Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color(); if (!enabled) { float g = draw_col.get_v(); draw_col.r = g; @@ -235,18 +235,25 @@ void ShapeCast2D::_notification(int p_what) { // Draw an arrow indicating where the ShapeCast is pointing to. if (target_position != Vector2()) { - Transform2D xf; - xf.rotate(target_position.angle()); - xf.translate_local(Vector2(target_position.length(), 0)); + const real_t max_arrow_size = 6; + const real_t line_width = 1.4; + bool no_line = target_position.length() < line_width; + real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); - draw_line(Vector2(), target_position, draw_col, 2); + if (no_line) { + arrow_size = target_position.length(); + } else { + draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width); + } - float tsize = 8; + Transform2D xf; + xf.rotate(target_position.angle()); + xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); Vector<Vector2> pts = { - xf.xform(Vector2(tsize, 0)), - xf.xform(Vector2(0, Math_SQRT12 * tsize)), - xf.xform(Vector2(0, -Math_SQRT12 * tsize)) + xf.xform(Vector2(arrow_size, 0)), + xf.xform(Vector2(0, 0.5 * arrow_size)), + xf.xform(Vector2(0, -0.5 * arrow_size)) }; Vector<Color> cols = { draw_col, draw_col, draw_col }; @@ -291,6 +298,8 @@ void ShapeCast2D::_update_shapecast_state() { collision_safe_fraction = 0.0; collision_unsafe_fraction = 0.0; + bool prev_collision_state = collided; + if (target_position != Vector2()) { dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction); if (collision_unsafe_fraction < 1.0) { @@ -314,6 +323,10 @@ void ShapeCast2D::_update_shapecast_state() { } } collided = !result.is_empty(); + + if (prev_collision_state != collided) { + update(); + } } void ShapeCast2D::force_shapecast_update() { diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp index af78d67e5a..ebd86e0937 100644 --- a/scene/gui/color_mode.cpp +++ b/scene/gui/color_mode.cpp @@ -159,7 +159,7 @@ void ColorModeHSV::slider_draw(int p_which) { } else if (p_which == 0) { Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false); return; } else { Color s_col; @@ -306,7 +306,7 @@ void ColorModeOKHSL::slider_draw(int p_which) { } else if (p_which == 0) { Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker")); slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); - slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true); + slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false); return; } else { Color s_col; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index c5054525a7..112b8c74af 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -450,7 +450,7 @@ void GraphNode::_validate_property(PropertyInfo &property) const { Control::_validate_property(property); GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent()); if (graph) { - if (property.name == "rect_position") { + if (property.name == "position") { property.usage |= PROPERTY_USAGE_READ_ONLY; } } diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h index 57a2cae37f..9ebd0f34b4 100644 --- a/tests/servers/test_text_server.h +++ b/tests/servers/test_text_server.h @@ -44,7 +44,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Loading fonts") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC)) { continue; @@ -52,7 +52,7 @@ TEST_SUITE("[TextServer]") { RID font = ts->create_font(); ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size); - TEST_FAIL_COND(font == RID(), "Loading font failed."); + CHECK_FALSE_MESSAGE(font == RID(), "Loading font failed."); ts->free_rid(font); } } @@ -60,7 +60,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Text layout: Font fallback") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { continue; @@ -79,26 +79,26 @@ TEST_SUITE("[TextServer]") { // 6^ 17^ RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size == 0, "Shaping failed"); + CHECK_FALSE_MESSAGE(gl_size == 0, "Shaping failed"); for (int j = 0; j < gl_size; j++) { if (glyphs[j].start < 6) { - TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected."); + CHECK_FALSE_MESSAGE(glyphs[j].font_rid != font[1], "Incorrect font selected."); } if ((glyphs[j].start > 6) && (glyphs[j].start < 16)) { - TEST_FAIL_COND(glyphs[j].font_rid != font[0], "Incorrect font selected."); + CHECK_FALSE_MESSAGE(glyphs[j].font_rid != font[0], "Incorrect font selected."); } if (glyphs[j].start > 16) { - TEST_FAIL_COND(glyphs[j].font_rid != RID(), "Incorrect font selected."); - TEST_FAIL_COND(glyphs[j].index != test[glyphs[j].start], "Incorrect glyph index."); + CHECK_FALSE_MESSAGE(glyphs[j].font_rid != RID(), "Incorrect font selected."); + CHECK_FALSE_MESSAGE(glyphs[j].index != test[glyphs[j].start], "Incorrect glyph index."); } - TEST_FAIL_COND((glyphs[j].start < 0 || glyphs[j].end > test.length()), "Incorrect glyph range."); - TEST_FAIL_COND(glyphs[j].font_size != 16, "Incorrect glyph font size."); + CHECK_FALSE_MESSAGE((glyphs[j].start < 0 || glyphs[j].end > test.length()), "Incorrect glyph range."); + CHECK_FALSE_MESSAGE(glyphs[j].font_size != 16, "Incorrect glyph font size."); } ts->free_rid(ctx); @@ -113,7 +113,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Text layout: BiDi") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) { continue; @@ -132,23 +132,23 @@ TEST_SUITE("[TextServer]") { // 7^ 26^ RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size == 0, "Shaping failed"); + CHECK_FALSE_MESSAGE(gl_size == 0, "Shaping failed"); for (int j = 0; j < gl_size; j++) { if (glyphs[j].count > 0) { if (glyphs[j].start < 7) { - TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); } if ((glyphs[j].start > 8) && (glyphs[j].start < 23)) { - TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) != TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) != TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); } if (glyphs[j].start > 26) { - TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); + CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction."); } } } @@ -165,7 +165,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Text layout: Line break and align points") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { continue; @@ -186,16 +186,16 @@ TEST_SUITE("[TextServer]") { { String test = U"Test test long text long text\n"; RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); ts->shaped_text_update_breaks(ctx); ts->shaped_text_update_justification_ops(ctx); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 30, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 30, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -203,11 +203,11 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 4 || j == 9 || j == 14 || j == 19 || j == 24) { - TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags."); } else if (j == 29) { - TEST_FAIL_COND((soft || !space || !hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || !space || !hard || virt || elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } ts->free_rid(ctx); @@ -216,21 +216,63 @@ TEST_SUITE("[TextServer]") { { String test = U"الحمـد"; RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); ts->shaped_text_update_breaks(ctx); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 6, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE; bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); + } + if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) { + ts->shaped_text_update_justification_ops(ctx); + + glyphs = ts->shaped_text_get_glyphs(ctx); + gl_size = ts->shaped_text_get_glyph_count(ctx); + + CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count."); + for (int j = 0; j < gl_size; j++) { + bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; + bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; + bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE; + bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; + bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; + if (j == 1) { + CHECK_FALSE_MESSAGE((soft || space || hard || virt || !elo), "Invalid glyph flags."); + } else { + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); + } + } + } + ts->free_rid(ctx); + } + + { + String test = U"الحمد"; + RID ctx = ts->create_shaped_text(); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); + bool ok = ts->shaped_text_add_string(ctx, test, font, 16); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); + ts->shaped_text_update_breaks(ctx); + + const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); + int gl_size = ts->shaped_text_get_glyph_count(ctx); + CHECK_FALSE_MESSAGE(gl_size != 5, "Invalid glyph count."); + for (int j = 0; j < gl_size; j++) { + bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; + bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; + bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE; + bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; + bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) { @@ -239,7 +281,7 @@ TEST_SUITE("[TextServer]") { glyphs = ts->shaped_text_get_glyphs(ctx); gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 6, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -247,9 +289,9 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 1) { - TEST_FAIL_COND((soft || space || hard || virt || !elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || !virt || !elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } } @@ -259,15 +301,15 @@ TEST_SUITE("[TextServer]") { { String test = U"الحمـد الرياضي العربي"; RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); ts->shaped_text_update_breaks(ctx); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 21, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 21, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -275,9 +317,9 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 6 || j == 14) { - TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } @@ -287,7 +329,7 @@ TEST_SUITE("[TextServer]") { glyphs = ts->shaped_text_get_glyphs(ctx); gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 23, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 23, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -295,13 +337,13 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 7 || j == 16) { - TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags."); } else if (j == 3 || j == 9) { - TEST_FAIL_COND((soft || space || hard || !virt || !elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || !virt || !elo), "Invalid glyph flags."); } else if (j == 18) { - TEST_FAIL_COND((soft || space || hard || virt || !elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || !elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } } @@ -312,16 +354,16 @@ TEST_SUITE("[TextServer]") { { String test = U"เป็น ภาษา ราชการ และ ภาษา"; RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); ts->shaped_text_update_breaks(ctx); ts->shaped_text_update_justification_ops(ctx); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 25, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 25, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -329,9 +371,9 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 4 || j == 9 || j == 16 || j == 20) { - TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } ts->free_rid(ctx); @@ -340,16 +382,16 @@ TEST_SUITE("[TextServer]") { if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) { String test = U"เป็นภาษาราชการและภาษา"; RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); ts->shaped_text_update_breaks(ctx); ts->shaped_text_update_justification_ops(ctx); const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx); int gl_size = ts->shaped_text_get_glyph_count(ctx); - TEST_FAIL_COND(gl_size != 25, "Invalid glyph count."); + CHECK_FALSE_MESSAGE(gl_size != 25, "Invalid glyph count."); for (int j = 0; j < gl_size; j++) { bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD; bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT; @@ -357,9 +399,9 @@ TEST_SUITE("[TextServer]") { bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL; bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION; if (j == 4 || j == 9 || j == 16 || j == 20) { - TEST_FAIL_COND((!soft || !space || hard || !virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((!soft || !space || hard || !virt || elo), "Invalid glyph flags."); } else { - TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags."); + CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags."); } } ts->free_rid(ctx); @@ -375,7 +417,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Text layout: Line breaking") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { continue; @@ -394,21 +436,21 @@ TEST_SUITE("[TextServer]") { font.push_back(font2); RID ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); PackedInt32Array brks = ts->shaped_text_get_line_breaks(ctx, 1); - TEST_FAIL_COND(brks.size() != 6, "Invalid line breaks number."); + CHECK_FALSE_MESSAGE(brks.size() != 6, "Invalid line breaks number."); if (brks.size() == 6) { - TEST_FAIL_COND(brks[0] != 0, "Invalid line break position."); - TEST_FAIL_COND(brks[1] != 5, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[0] != 0, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[1] != 5, "Invalid line break position."); - TEST_FAIL_COND(brks[2] != 5, "Invalid line break position."); - TEST_FAIL_COND(brks[3] != 10, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[2] != 5, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[3] != 10, "Invalid line break position."); - TEST_FAIL_COND(brks[4] != 10, "Invalid line break position."); - TEST_FAIL_COND(brks[5] != 14, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[4] != 10, "Invalid line break position."); + CHECK_FALSE_MESSAGE(brks[5] != 14, "Invalid line break position."); } ts->free_rid(ctx); @@ -423,7 +465,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Text layout: Justification") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { continue; @@ -448,40 +490,40 @@ TEST_SUITE("[TextServer]") { float width_old, width; if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) { ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); ok = ts->shaped_text_add_string(ctx, test_1, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); width_old = ts->shaped_text_get_width(ctx); width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); - TEST_FAIL_COND((width != width_old), "Invalid fill width."); + CHECK_FALSE_MESSAGE((width != width_old), "Invalid fill width."); width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); - TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width."); ts->free_rid(ctx); ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); ok = ts->shaped_text_add_string(ctx, test_2, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); width_old = ts->shaped_text_get_width(ctx); width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); - TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width."); width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA); - TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width."); ts->free_rid(ctx); } ctx = ts->create_shaped_text(); - TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed."); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); ok = ts->shaped_text_add_string(ctx, test_3, font, 16); - TEST_FAIL_COND(!ok, "Adding text to the buffer failed."); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); width_old = ts->shaped_text_get_width(ctx); width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND); - TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width."); + CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width."); ts->free_rid(ctx); @@ -495,7 +537,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Unicode identifiers") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); static const char32_t *data[19] = { U"-30", U"100", U"10.1", U"10,1", U"1e2", U"1e-2", U"1e2e3", U"0xAB", U"AB", U"Test1", U"1Test", U"Test*1", U"test_testeT", U"test_tes teT", U"عَلَيْكُمْ", U"عَلَيْكُمْTest", U"ӒӖӚӜ", U"_test", U"ÂÃÄÅĀĂĄÇĆĈĊ" }; static bool isid[19] = { false, false, false, false, false, false, false, false, true, true, false, false, true, false, true, true, true, true, true }; @@ -516,7 +558,7 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Strip Diacritics") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i); - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (ts->has_feature(TextServer::FEATURE_SHAPING)) { CHECK(ts->strip_diacritics(U"ٱلسَّلَامُ عَلَيْكُمْ") == U"ٱلسلام عليكم"); @@ -544,7 +586,7 @@ TEST_SUITE("[TextServer]") { continue; } - TEST_FAIL_COND(ts.is_null(), "Invalid TS interface."); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); { String text1 = U"linguistically similar and effectively form"; // 14^ 22^ 26^ 38^ diff --git a/thirdparty/README.md b/thirdparty/README.md index 009e56be00..664401fca6 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -599,7 +599,7 @@ Godot. See the patch in the `patches` folder for details. ## spirv-reflect - Upstream: https://github.com/KhronosGroup/SPIRV-Reflect -- Version: git (1aceb6af56e74b92a00378842dda5c5a73f49a4b, 2022) +- Version: git (1ef99b09fa7ce5aee2c5cf70c61a4f7458d27e09, 2022) - License: Apache 2.0 Does not track Vulkan SDK releases closely, but try to package a commit newer diff --git a/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h index c15736e255..ae81f141c4 100644 --- a/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h +++ b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h @@ -70,6 +70,7 @@ typedef enum SpvSourceLanguage_ { SpvSourceLanguageOpenCL_CPP = 4, SpvSourceLanguageHLSL = 5, SpvSourceLanguageCPP_for_OpenCL = 6, + SpvSourceLanguageSYCL = 7, SpvSourceLanguageMax = 0x7fffffff, } SpvSourceLanguage; @@ -184,6 +185,7 @@ typedef enum SpvExecutionMode_ { SpvExecutionModeNoGlobalOffsetINTEL = 5895, SpvExecutionModeNumSIMDWorkitemsINTEL = 5896, SpvExecutionModeSchedulerTargetFmaxMhzINTEL = 5903, + SpvExecutionModeNamedBarrierCountINTEL = 6417, SpvExecutionModeMax = 0x7fffffff, } SpvExecutionMode; @@ -546,6 +548,8 @@ typedef enum SpvDecoration_ { SpvDecorationPrefetchINTEL = 5902, SpvDecorationStallEnableINTEL = 5905, SpvDecorationFuseLoopsInFunctionINTEL = 5907, + SpvDecorationAliasScopeINTEL = 5914, + SpvDecorationNoAliasINTEL = 5915, SpvDecorationBufferLocationINTEL = 5921, SpvDecorationIOPipeStorageINTEL = 5944, SpvDecorationFunctionFloatingPointModeINTEL = 6080, @@ -677,6 +681,7 @@ typedef enum SpvBuiltIn_ { SpvBuiltInSMCountNV = 5375, SpvBuiltInWarpIDNV = 5376, SpvBuiltInSMIDNV = 5377, + SpvBuiltInCullMaskKHR = 6021, SpvBuiltInMax = 0x7fffffff, } SpvBuiltIn; @@ -804,6 +809,8 @@ typedef enum SpvMemoryAccessShift_ { SpvMemoryAccessMakePointerVisibleKHRShift = 4, SpvMemoryAccessNonPrivatePointerShift = 5, SpvMemoryAccessNonPrivatePointerKHRShift = 5, + SpvMemoryAccessAliasScopeINTELMaskShift = 16, + SpvMemoryAccessNoAliasINTELMaskShift = 17, SpvMemoryAccessMax = 0x7fffffff, } SpvMemoryAccessShift; @@ -818,6 +825,8 @@ typedef enum SpvMemoryAccessMask_ { SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, SpvMemoryAccessNonPrivatePointerMask = 0x00000020, SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, + SpvMemoryAccessAliasScopeINTELMaskMask = 0x00010000, + SpvMemoryAccessNoAliasINTELMaskMask = 0x00020000, } SpvMemoryAccessMask; typedef enum SpvScope_ { @@ -1059,6 +1068,7 @@ typedef enum SpvCapability_ { SpvCapabilityFPGAMemoryAccessesINTEL = 5898, SpvCapabilityFPGAClusterAttributesINTEL = 5904, SpvCapabilityLoopFuseINTEL = 5906, + SpvCapabilityMemoryAccessAliasingINTEL = 5910, SpvCapabilityFPGABufferLocationINTEL = 5920, SpvCapabilityArbitraryPrecisionFixedPointINTEL = 5922, SpvCapabilityUSMStorageClassesINTEL = 5935, @@ -1073,13 +1083,17 @@ typedef enum SpvCapability_ { SpvCapabilityDotProductInput4x8BitPackedKHR = 6018, SpvCapabilityDotProduct = 6019, SpvCapabilityDotProductKHR = 6019, + SpvCapabilityRayCullMaskKHR = 6020, SpvCapabilityBitInstructions = 6025, + SpvCapabilityGroupNonUniformRotateKHR = 6026, SpvCapabilityAtomicFloat32AddEXT = 6033, SpvCapabilityAtomicFloat64AddEXT = 6034, SpvCapabilityLongConstantCompositeINTEL = 6089, SpvCapabilityOptNoneINTEL = 6094, SpvCapabilityAtomicFloat16AddEXT = 6095, SpvCapabilityDebugInfoModuleINTEL = 6114, + SpvCapabilitySplitBarrierINTEL = 6141, + SpvCapabilityGroupUniformArithmeticKHR = 6400, SpvCapabilityMax = 0x7fffffff, } SpvCapability; @@ -1535,6 +1549,7 @@ typedef enum SpvOp_ { SpvOpSubgroupAllKHR = 4428, SpvOpSubgroupAnyKHR = 4429, SpvOpSubgroupAllEqualKHR = 4430, + SpvOpGroupNonUniformRotateKHR = 4431, SpvOpSubgroupReadInvocationKHR = 4432, SpvOpTraceRayKHR = 4445, SpvOpExecuteCallableKHR = 4446, @@ -1801,6 +1816,9 @@ typedef enum SpvOp_ { SpvOpArbitraryFloatPowRINTEL = 5881, SpvOpArbitraryFloatPowNINTEL = 5882, SpvOpLoopControlINTEL = 5887, + SpvOpAliasDomainDeclINTEL = 5911, + SpvOpAliasScopeDeclINTEL = 5912, + SpvOpAliasScopeListDeclINTEL = 5913, SpvOpFixedSqrtINTEL = 5923, SpvOpFixedRecipINTEL = 5924, SpvOpFixedRsqrtINTEL = 5925, @@ -1839,10 +1857,23 @@ typedef enum SpvOp_ { SpvOpTypeStructContinuedINTEL = 6090, SpvOpConstantCompositeContinuedINTEL = 6091, SpvOpSpecConstantCompositeContinuedINTEL = 6092, + SpvOpControlBarrierArriveINTEL = 6142, + SpvOpControlBarrierWaitINTEL = 6143, + SpvOpGroupIMulKHR = 6401, + SpvOpGroupFMulKHR = 6402, + SpvOpGroupBitwiseAndKHR = 6403, + SpvOpGroupBitwiseOrKHR = 6404, + SpvOpGroupBitwiseXorKHR = 6405, + SpvOpGroupLogicalAndKHR = 6406, + SpvOpGroupLogicalOrKHR = 6407, + SpvOpGroupLogicalXorKHR = 6408, SpvOpMax = 0x7fffffff, } SpvOp; #ifdef SPV_ENABLE_UTILITY_CODE +#ifndef __cplusplus +#include <stdbool.h> +#endif inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultType) { *hasResult = *hasResultType = false; switch (opcode) { @@ -2197,6 +2228,7 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformRotateKHR: *hasResult = true; *hasResultType = true; break; case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; case SpvOpTraceRayKHR: *hasResult = false; *hasResultType = false; break; case SpvOpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; @@ -2452,6 +2484,9 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpArbitraryFloatPowRINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpArbitraryFloatPowNINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpAliasDomainDeclINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpAliasScopeDeclINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpAliasScopeListDeclINTEL: *hasResult = true; *hasResultType = false; break; case SpvOpFixedSqrtINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpFixedRecipINTEL: *hasResult = true; *hasResultType = true; break; case SpvOpFixedRsqrtINTEL: *hasResult = true; *hasResultType = true; break; @@ -2490,9 +2525,18 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break; case SpvOpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; case SpvOpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpControlBarrierArriveINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpControlBarrierWaitINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupIMulKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMulKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupBitwiseAndKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupBitwiseOrKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupBitwiseXorKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupLogicalAndKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupLogicalOrKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupLogicalXorKHR: *hasResult = true; *hasResultType = true; break; } } #endif /* SPV_ENABLE_UTILITY_CODE */ #endif - diff --git a/thirdparty/spirv-reflect/patches/specialization-constants.patch b/thirdparty/spirv-reflect/patches/specialization-constants.patch index 9bb5f97cd3..99815c9162 100644 --- a/thirdparty/spirv-reflect/patches/specialization-constants.patch +++ b/thirdparty/spirv-reflect/patches/specialization-constants.patch @@ -1,8 +1,8 @@ diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c -index e9b11bf495..f181df5fa2 100644 +index cdcf3ca663..c174ae1900 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.c +++ b/thirdparty/spirv-reflect/spirv_reflect.c -@@ -125,6 +125,9 @@ typedef struct SpvReflectPrvDecorations { +@@ -126,6 +126,9 @@ typedef struct SpvReflectPrvDecorations { SpvReflectPrvNumberDecoration location; SpvReflectPrvNumberDecoration offset; SpvReflectPrvNumberDecoration uav_counter_buffer; @@ -12,7 +12,7 @@ index e9b11bf495..f181df5fa2 100644 SpvReflectPrvStringDecoration semantic; uint32_t array_stride; uint32_t matrix_stride; -@@ -631,6 +634,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) +@@ -639,6 +642,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; @@ -22,7 +22,7 @@ index e9b11bf495..f181df5fa2 100644 } // Mark source file id node p_parser->source_file_id = (uint32_t)INVALID_VALUE; -@@ -821,10 +827,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) +@@ -829,10 +835,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); } break; @@ -41,7 +41,7 @@ index e9b11bf495..f181df5fa2 100644 case SpvOpSpecConstantComposite: case SpvOpSpecConstantOp: { CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); -@@ -856,7 +868,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) +@@ -864,7 +876,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id); // // SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index: @@ -50,7 +50,7 @@ index e9b11bf495..f181df5fa2 100644 // p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET); if (p_access_chain->index_count > 0) { -@@ -1338,6 +1350,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) +@@ -1346,6 +1358,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) skip = true; } break; @@ -60,7 +60,7 @@ index e9b11bf495..f181df5fa2 100644 case SpvDecorationRelaxedPrecision: case SpvDecorationBlock: case SpvDecorationBufferBlock: -@@ -1481,7 +1496,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) +@@ -1495,7 +1510,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) p_target_decorations->input_attachment_index.word_offset = word_offset; } break; @@ -76,7 +76,7 @@ index e9b11bf495..f181df5fa2 100644 case SpvReflectDecorationHlslCounterBufferGOOGLE: { uint32_t word_offset = p_node->word_offset + member_offset+ 3; CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); -@@ -1789,6 +1811,13 @@ static SpvReflectResult ParseType( +@@ -1803,6 +1825,13 @@ static SpvReflectResult ParseType( p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; } break; @@ -90,7 +90,7 @@ index e9b11bf495..f181df5fa2 100644 } if (result == SPV_REFLECT_RESULT_SUCCESS) { -@@ -3269,6 +3298,69 @@ static SpvReflectResult ParseExecutionModes( +@@ -3332,6 +3361,69 @@ static SpvReflectResult ParseExecutionModes( return SPV_REFLECT_RESULT_SUCCESS; } @@ -160,7 +160,7 @@ index e9b11bf495..f181df5fa2 100644 static SpvReflectResult ParsePushConstantBlocks( SpvReflectPrvParser* p_parser, SpvReflectShaderModule* p_module) -@@ -3650,6 +3742,12 @@ static SpvReflectResult CreateShaderModule( +@@ -3717,6 +3809,12 @@ static SpvReflectResult CreateShaderModule( result = ParsePushConstantBlocks(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } @@ -173,8 +173,8 @@ index e9b11bf495..f181df5fa2 100644 if (result == SPV_REFLECT_RESULT_SUCCESS) { result = ParseEntryPoints(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); -@@ -3807,6 +3905,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) - SafeFree(p_entry->used_push_constants); +@@ -3875,6 +3973,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) + SafeFree(p_entry->execution_modes); } SafeFree(p_module->entry_points); +// -- GODOT begin -- @@ -183,7 +183,7 @@ index e9b11bf495..f181df5fa2 100644 // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { -@@ -4077,6 +4178,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( +@@ -4145,6 +4246,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( return SPV_REFLECT_RESULT_SUCCESS; } @@ -223,10 +223,10 @@ index e9b11bf495..f181df5fa2 100644 const SpvReflectShaderModule* p_module, uint32_t* p_count, diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h -index e9e4c40755..948533d3c0 100644 +index 02b81613a1..02850f8811 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.h +++ b/thirdparty/spirv-reflect/spirv_reflect.h -@@ -323,6 +323,28 @@ typedef struct SpvReflectTypeDescription { +@@ -329,6 +329,28 @@ typedef struct SpvReflectTypeDescription { struct SpvReflectTypeDescription* members; } SpvReflectTypeDescription; @@ -255,7 +255,7 @@ index e9e4c40755..948533d3c0 100644 /*! @struct SpvReflectInterfaceVariable -@@ -472,6 +494,10 @@ typedef struct SpvReflectShaderModule { +@@ -483,6 +505,10 @@ typedef struct SpvReflectShaderModule { SpvReflectInterfaceVariable* interface_variables; // Uses value(s) from first entry point uint32_t push_constant_block_count; // Uses value(s) from first entry point SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point @@ -266,7 +266,7 @@ index e9e4c40755..948533d3c0 100644 struct Internal { SpvReflectModuleFlags module_flags; -@@ -744,6 +770,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( +@@ -755,6 +781,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( SpvReflectInterfaceVariable** pp_variables ); diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c index f181df5fa2..c174ae1900 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.c +++ b/thirdparty/spirv-reflect/spirv_reflect.c @@ -119,6 +119,7 @@ typedef struct SpvReflectPrvDecorations { bool is_noperspective; bool is_flat; bool is_non_writable; + bool is_non_readable; SpvReflectPrvNumberDecoration set; SpvReflectPrvNumberDecoration binding; SpvReflectPrvNumberDecoration input_attachment_index; @@ -306,7 +307,12 @@ static SpvReflectResult IntersectSortedUint32( size_t* res_size ) { + *pp_res = NULL; *res_size = 0; + if (IsNull(p_arr0) || IsNull(p_arr1)) { + return SPV_REFLECT_RESULT_SUCCESS; + } + const uint32_t* arr0_end = p_arr0 + arr0_size; const uint32_t* arr1_end = p_arr1 + arr1_size; @@ -324,7 +330,6 @@ static SpvReflectResult IntersectSortedUint32( } } - *pp_res = NULL; if (*res_size > 0) { *pp_res = (uint32_t*)calloc(*res_size, sizeof(**pp_res)); if (IsNull(*pp_res)) { @@ -488,6 +493,9 @@ static SpvReflectDecorationFlags ApplyDecorations(const SpvReflectPrvDecorations if (p_decoration_fields->is_non_writable) { decorations |= SPV_REFLECT_DECORATION_NON_WRITABLE; } + if (p_decoration_fields->is_non_readable) { + decorations |= SPV_REFLECT_DECORATION_NON_READABLE; + } return decorations; } @@ -1364,6 +1372,7 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) case SpvDecorationNoPerspective: case SpvDecorationFlat: case SpvDecorationNonWritable: + case SpvDecorationNonReadable: case SpvDecorationLocation: case SpvDecorationBinding: case SpvDecorationDescriptorSet: @@ -1462,6 +1471,11 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser) } break; + case SpvDecorationNonReadable: { + p_target_decorations->is_non_readable = true; + } + break; + case SpvDecorationLocation: { uint32_t word_offset = p_node->word_offset + member_offset + 3; CHECKED_READU32(p_parser, word_offset, p_target_decorations->location.value); @@ -1970,6 +1984,7 @@ static SpvReflectResult ParseDescriptorBindings( p_descriptor->count = 1; p_descriptor->uav_counter_id = p_node->decorations.uav_counter_buffer.value; p_descriptor->type_description = p_type; + p_descriptor->decoration_flags = ApplyDecorations(&p_node->decorations); // If this is in the StorageBuffer storage class, it's for sure a storage // buffer descriptor. We need to handle this case earlier because in SPIR-V @@ -3208,8 +3223,8 @@ static SpvReflectResult ParseExecutionModes( // Read entry point id uint32_t entry_point_id = 0; CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id); - - // Find entry point + + // Find entry point SpvReflectEntryPoint* p_entry_point = NULL; for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { if (p_module->entry_points[entry_point_idx].id == entry_point_id) { @@ -3221,7 +3236,7 @@ static SpvReflectResult ParseExecutionModes( if (IsNull(p_entry_point)) { return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT; } - + // Read execution mode uint32_t execution_mode = (uint32_t)INVALID_VALUE; CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode); @@ -3288,12 +3303,60 @@ static SpvReflectResult ParseExecutionModes( case SpvExecutionModeLocalSizeId: case SpvExecutionModeLocalSizeHintId: case SpvExecutionModePostDepthCoverage: + case SpvExecutionModeDenormPreserve: + case SpvExecutionModeDenormFlushToZero: + case SpvExecutionModeSignedZeroInfNanPreserve: + case SpvExecutionModeRoundingModeRTE: + case SpvExecutionModeRoundingModeRTZ: case SpvExecutionModeStencilRefReplacingEXT: + case SpvExecutionModeOutputLinesNV: case SpvExecutionModeOutputPrimitivesNV: case SpvExecutionModeOutputTrianglesNV: break; } + p_entry_point->execution_mode_count++; + } + uint32_t* indices = (uint32_t*)calloc(p_module->entry_point_count, sizeof(indices)); + if (IsNull(indices)) { + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; } + for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { + SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx]; + p_entry_point->execution_modes = + (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes)); + if (IsNull(p_entry_point->execution_modes)) { + SafeFree(indices); + return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED; + } + } + + for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) { + SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]); + if (p_node->op != SpvOpExecutionMode) { + continue; + } + + // Read entry point id + uint32_t entry_point_id = 0; + CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id); + + // Find entry point + SpvReflectEntryPoint* p_entry_point = NULL; + uint32_t* idx = NULL; + for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) { + if (p_module->entry_points[entry_point_idx].id == entry_point_id) { + p_entry_point = &p_module->entry_points[entry_point_idx]; + idx = &indices[entry_point_idx]; + break; + } + } + + // Read execution mode + uint32_t execution_mode = (uint32_t)INVALID_VALUE; + CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode); + p_entry_point->execution_modes[(*idx)++] = (SpvExecutionMode)execution_mode; + } + SafeFree(indices); } return SPV_REFLECT_RESULT_SUCCESS; } @@ -3649,7 +3712,11 @@ static SpvReflectResult CreateShaderModule( if (flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) { // Set internal size and pointer to args passed in p_module->_internal->spirv_size = size; +#if defined(__cplusplus) + p_module->_internal->spirv_code = const_cast<uint32_t*>(static_cast<const uint32_t*>(p_code)); // cast that const away +#else p_module->_internal->spirv_code = (void*)p_code; // cast that const away +#endif p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE); } else { @@ -3903,6 +3970,7 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_entry->interface_variables); SafeFree(p_entry->used_uniforms); SafeFree(p_entry->used_push_constants); + SafeFree(p_entry->execution_modes); } SafeFree(p_module->entry_points); // -- GODOT begin -- @@ -5093,6 +5161,7 @@ const char* spvReflectSourceLanguage(SpvSourceLanguage source_lang) case SpvSourceLanguageOpenCL_CPP : return "OpenCL_CPP"; case SpvSourceLanguageHLSL : return "HLSL"; case SpvSourceLanguageCPP_for_OpenCL : return "CPP_for_OpenCL"; + case SpvSourceLanguageSYCL : return "SYCL"; case SpvSourceLanguageMax: break; } diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h index 948533d3c0..02850f8811 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.h +++ b/thirdparty/spirv-reflect/spirv_reflect.h @@ -30,7 +30,12 @@ VERSION HISTORY #ifndef SPIRV_REFLECT_H #define SPIRV_REFLECT_H +#if defined(SPIRV_REFLECT_USE_SYSTEM_SPIRV_H) +#include <spirv/unified1/spirv.h> +#else #include "./include/spirv/unified1/spirv.h" +#endif + #include <stdint.h> #include <string.h> @@ -139,6 +144,7 @@ typedef enum SpvReflectDecorationFlagBits { SPV_REFLECT_DECORATION_FLAT = 0x00000040, SPV_REFLECT_DECORATION_NON_WRITABLE = 0x00000080, SPV_REFLECT_DECORATION_RELAXED_PRECISION = 0x00000100, + SPV_REFLECT_DECORATION_NON_READABLE = 0x00000200, } SpvReflectDecorationFlagBits; typedef uint32_t SpvReflectDecorationFlags; @@ -422,6 +428,8 @@ typedef struct SpvReflectDescriptorBinding { uint32_t binding; uint32_t set; } word_offset; + + SpvReflectDecorationFlags decoration_flags; } SpvReflectDescriptorBinding; /*! @struct SpvReflectDescriptorSet @@ -458,6 +466,9 @@ typedef struct SpvReflectEntryPoint { uint32_t used_push_constant_count; uint32_t* used_push_constants; + uint32_t execution_mode_count; + SpvExecutionMode* execution_modes; + struct LocalSize { uint32_t x; uint32_t y; |