浏览代码

Merge pull request #70185 from timothyqiu/3.x-cherrypicks

Cherry-picks for the 3.x branch (future 3.6) - 11th batch
Rémi Verschelde 2 年之前
父节点
当前提交
edbfaa1d80
共有 39 个文件被更改,包括 411 次插入150 次删除
  1. 1 0
      core/global_constants.cpp
  2. 1 0
      core/object.h
  3. 0 4
      core/os/os.cpp
  4. 1 1
      core/os/os.h
  5. 38 35
      doc/classes/@GlobalScope.xml
  6. 7 7
      doc/classes/Input.xml
  7. 10 1
      doc/classes/LinkButton.xml
  8. 3 3
      doc/classes/Navigation2DServer.xml
  9. 3 3
      doc/classes/NavigationServer.xml
  10. 157 26
      editor/editor_properties.cpp
  11. 14 2
      editor/editor_properties.h
  12. 1 0
      editor/editor_property_name_processor.cpp
  13. 1 0
      editor/icons/icon_unlinked.svg
  14. 29 0
      editor/inspector_dock.cpp
  15. 4 0
      editor/inspector_dock.h
  16. 34 10
      editor/plugins/material_editor_plugin.cpp
  17. 5 0
      editor/plugins/material_editor_plugin.h
  18. 28 13
      editor/scene_tree_dock.cpp
  19. 3 3
      modules/navigation/godot_navigation_server.cpp
  20. 1 1
      modules/navigation/godot_navigation_server.h
  21. 1 1
      scene/2d/camera_2d.cpp
  22. 3 3
      scene/2d/navigation_agent_2d.cpp
  23. 1 1
      scene/2d/node_2d.cpp
  24. 1 1
      scene/2d/parallax_background.cpp
  25. 1 1
      scene/2d/parallax_layer.cpp
  26. 4 1
      scene/2d/polygon_2d.cpp
  27. 3 3
      scene/3d/navigation_agent.cpp
  28. 1 1
      scene/3d/spatial.cpp
  29. 4 0
      scene/gui/control.cpp
  30. 20 1
      scene/gui/link_button.cpp
  31. 4 0
      scene/gui/link_button.h
  32. 1 1
      scene/main/canvas_layer.cpp
  33. 6 0
      scene/main/scene_tree.cpp
  34. 2 2
      scene/resources/material.cpp
  35. 9 16
      scene/resources/texture.cpp
  36. 6 6
      servers/navigation_2d_server.cpp
  37. 1 1
      servers/navigation_2d_server.h
  38. 1 1
      servers/navigation_server.cpp
  39. 1 1
      servers/navigation_server.h

+ 1 - 0
core/global_constants.cpp

@@ -587,6 +587,7 @@ void register_global_constants() {
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_ENUM_SUGGESTION);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LENGTH);
+	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_LINK);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_KEY_ACCEL);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
 	BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_HINT_FLAGS);
 
 

+ 1 - 0
core/object.h

@@ -62,6 +62,7 @@ enum PropertyHint {
 	PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
 	PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
 	PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
 	PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
 	PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
 	PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
+	PROPERTY_HINT_LINK,
 	PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat.
 	PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat.
 	PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
 	PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
 	PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
 	PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)

+ 0 - 4
core/os/os.cpp

@@ -186,10 +186,6 @@ int OS::get_process_id() const {
 	return -1;
 	return -1;
 };
 };
 
 
-void OS::vibrate_handheld(int p_duration_ms) {
-	WARN_PRINT("vibrate_handheld() only works with Android, iOS and HTML5");
-}
-
 bool OS::is_stdout_verbose() const {
 bool OS::is_stdout_verbose() const {
 	return _verbose_stdout;
 	return _verbose_stdout;
 }
 }

+ 1 - 1
core/os/os.h

@@ -365,7 +365,7 @@ public:
 	virtual Error kill(const ProcessID &p_pid) = 0;
 	virtual Error kill(const ProcessID &p_pid) = 0;
 	virtual int get_process_id() const;
 	virtual int get_process_id() const;
 	virtual bool is_process_running(const ProcessID &p_pid) const = 0;
 	virtual bool is_process_running(const ProcessID &p_pid) const = 0;
-	virtual void vibrate_handheld(int p_duration_ms = 500);
+	virtual void vibrate_handheld(int p_duration_ms = 500) {}
 
 
 	virtual Error shell_open(String p_uri);
 	virtual Error shell_open(String p_uri);
 	virtual Error set_cwd(const String &p_cwd);
 	virtual Error set_cwd(const String &p_cwd);

+ 38 - 35
doc/classes/@GlobalScope.xml

@@ -1421,7 +1421,7 @@
 			Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
 			Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
 			The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. Whitespaces are [b]not[/b] removed from either end of a name. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code].
 			The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. Whitespaces are [b]not[/b] removed from either end of a name. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code].
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="39" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="40" enum="PropertyHint">
 			Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
 			Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
 			Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
 			Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
 		</constant>
 		</constant>
@@ -1431,63 +1431,66 @@
 		<constant name="PROPERTY_HINT_LENGTH" value="5" enum="PropertyHint">
 		<constant name="PROPERTY_HINT_LENGTH" value="5" enum="PropertyHint">
 			Deprecated hint, unused.
 			Deprecated hint, unused.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_KEY_ACCEL" value="7" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LINK" value="6" enum="PropertyHint">
+			Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together).
+		</constant>
+		<constant name="PROPERTY_HINT_KEY_ACCEL" value="8" enum="PropertyHint">
 			Deprecated hint, unused.
 			Deprecated hint, unused.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_FLAGS" value="8" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_FLAGS" value="9" enum="PropertyHint">
 			Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
 			Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="9" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="10" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 2D render layers.
 			Hints that an integer property is a bitmask using the optionally named 2D render layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="10" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="11" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 2D physics layers.
 			Hints that an integer property is a bitmask using the optionally named 2D physics layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="11" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="12" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
 			Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="12" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="13" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 3D render layers.
 			Hints that an integer property is a bitmask using the optionally named 3D render layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="13" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="14" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 3D physics layers.
 			Hints that an integer property is a bitmask using the optionally named 3D physics layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="14" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="15" enum="PropertyHint">
 			Hints that an integer property is a bitmask using the optionally named 3D navigation layers.
 			Hints that an integer property is a bitmask using the optionally named 3D navigation layers.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_FILE" value="15" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_FILE" value="16" enum="PropertyHint">
 			Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
 			Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_DIR" value="16" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_DIR" value="17" enum="PropertyHint">
 			Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
 			Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_GLOBAL_FILE" value="17" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_GLOBAL_FILE" value="18" enum="PropertyHint">
 			Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
 			Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_GLOBAL_DIR" value="18" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_GLOBAL_DIR" value="19" enum="PropertyHint">
 			Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
 			Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_RESOURCE_TYPE" value="19" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_RESOURCE_TYPE" value="20" enum="PropertyHint">
 			Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
 			Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="20" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="21" enum="PropertyHint">
 			Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
 			Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="21" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="22" enum="PropertyHint">
 			Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
 			Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="22" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="23" enum="PropertyHint">
 			Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
 			Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="23" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="24" enum="PropertyHint">
 			Hints that an image is compressed using lossy compression.
 			Hints that an image is compressed using lossy compression.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="24" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="25" enum="PropertyHint">
 			Hints that an image is compressed using lossless compression.
 			Hints that an image is compressed using lossless compression.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_OBJECT_ID" value="25" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_OBJECT_ID" value="26" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_TYPE_STRING" value="26" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_TYPE_STRING" value="27" enum="PropertyHint">
 			Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
 			Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
 			[codeblock]
 			[codeblock]
 			hint_string = "%s:" % [TYPE_INT] # Array of inteters.
 			hint_string = "%s:" % [TYPE_INT] # Array of inteters.
@@ -1497,34 +1500,34 @@
 			[/codeblock]
 			[/codeblock]
 			[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
 			[b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="27" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="28" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="28" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_METHOD_OF_VARIANT_TYPE" value="29" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="29" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_METHOD_OF_BASE_TYPE" value="30" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="30" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_METHOD_OF_INSTANCE" value="31" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="31" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_METHOD_OF_SCRIPT" value="32" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="32" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE" value="33" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="33" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_PROPERTY_OF_BASE_TYPE" value="34" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="34" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_PROPERTY_OF_INSTANCE" value="35" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="35" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="36" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="36" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="37" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="37" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="38" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_SAVE_FILE" value="38" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_SAVE_FILE" value="39" enum="PropertyHint">
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_LOCALE_ID" value="40" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_LOCALE_ID" value="41" enum="PropertyHint">
 			Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
 			Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
 		</constant>
 		</constant>
-		<constant name="PROPERTY_HINT_MAX" value="41" enum="PropertyHint">
+		<constant name="PROPERTY_HINT_MAX" value="42" enum="PropertyHint">
 		</constant>
 		</constant>
 		<constant name="PROPERTY_USAGE_STORAGE" value="1" enum="PropertyUsageFlags">
 		<constant name="PROPERTY_USAGE_STORAGE" value="1" enum="PropertyUsageFlags">
 			The property is serialized and saved in the scene file (default).
 			The property is serialized and saved in the scene file (default).

+ 7 - 7
doc/classes/Input.xml

@@ -364,7 +364,7 @@
 			<argument index="2" name="strong_magnitude" type="float" />
 			<argument index="2" name="strong_magnitude" type="float" />
 			<argument index="3" name="duration" type="float" default="0" />
 			<argument index="3" name="duration" type="float" default="0" />
 			<description>
 			<description>
-				Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [code]weak_magnitude[/code] is the strength of the weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the strength of the strong motor (between 0 and 1). [code]duration[/code] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
+				Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [code]weak_magnitude[/code] is the strength of the weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the strength of the strong motor (between 0 and 1). [code]duration[/code] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely). The vibration can be stopped early by calling [method stop_joy_vibration].
 				[b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
 				[b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
 			</description>
 			</description>
 		</method>
 		</method>
@@ -372,18 +372,18 @@
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="device" type="int" />
 			<argument index="0" name="device" type="int" />
 			<description>
 			<description>
-				Stops the vibration of the joypad.
+				Stops the vibration of the joypad started with [method start_joy_vibration].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="vibrate_handheld">
 		<method name="vibrate_handheld">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="duration_ms" type="int" default="500" />
 			<argument index="0" name="duration_ms" type="int" default="500" />
 			<description>
 			<description>
-				Vibrate handheld devices.
-				[b]Note:[/b] This method is implemented on Android, iOS, and HTML5.
-				[b]Note:[/b] For Android, it requires enabling the [code]VIBRATE[/code] permission in the export preset.
-				[b]Note:[/b] For iOS, specifying the duration is supported in iOS 13 and later.
-				[b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support this method.
+				Vibrate the handheld device for the specified duration in milliseconds.
+				[b]Note:[/b] This method is implemented on Android, iOS, and HTML5. It has no effect on other platforms.
+				[b]Note:[/b] For Android, [method vibrate_handheld] requires enabling the [code]VIBRATE[/code] permission in the export preset. Otherwise, [method vibrate_handheld] will have no effect.
+				[b]Note:[/b] For iOS, specifying the duration is only supported in iOS 13 and later.
+				[b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support [method vibrate_handheld].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="warp_mouse_position">
 		<method name="warp_mouse_position">

+ 10 - 1
doc/classes/LinkButton.xml

@@ -18,7 +18,16 @@
 			The button's text that will be displayed inside the button's area.
 			The button's text that will be displayed inside the button's area.
 		</member>
 		</member>
 		<member name="underline" type="int" setter="set_underline_mode" getter="get_underline_mode" enum="LinkButton.UnderlineMode" default="0">
 		<member name="underline" type="int" setter="set_underline_mode" getter="get_underline_mode" enum="LinkButton.UnderlineMode" default="0">
-			Determines when to show the underline. See [enum UnderlineMode] for options.
+			The underline mode to use for the text. See [enum LinkButton.UnderlineMode] for the available modes.
+		</member>
+		<member name="uri" type="String" setter="set_uri" getter="get_uri" default="&quot;&quot;">
+			The [url=https://en.wikipedia.org/wiki/Uniform_Resource_Identifier]URI[/url] for this [LinkButton]. If set to a valid URI, pressing the button opens the URI using the operating system's default program for the protocol (via [method OS.shell_open]). HTTP and HTTPS URLs open the default web browser.
+			[b]Examples:[/b]
+			[codeblock]
+			uri = "https://godotengine.org"  # Opens the URL in the default web browser.
+			uri = "C:\SomeFolder"  # Opens the file explorer at the given path.
+			uri = "C:\SomeImage.png"  # Opens the given image in the default viewing app.
+			[/codeblock]
 		</member>
 		</member>
 	</members>
 	</members>
 	<constants>
 	<constants>

+ 3 - 3
doc/classes/Navigation2DServer.xml

@@ -40,12 +40,12 @@
 		<method name="agent_set_callback" qualifiers="const">
 		<method name="agent_set_callback" qualifiers="const">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="agent" type="RID" />
 			<argument index="0" name="agent" type="RID" />
-			<argument index="1" name="receiver" type="Object" />
+			<argument index="1" name="object_id" type="int" />
 			<argument index="2" name="method" type="String" />
 			<argument index="2" name="method" type="String" />
 			<argument index="3" name="userdata" type="Variant" default="null" />
 			<argument index="3" name="userdata" type="Variant" default="null" />
 			<description>
 			<description>
-				Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [code]receiver[/code] object with a signal to the chosen [code]method[/code] name.
-				[b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [code]receiver[/code].
+				Sets the callback [code]object_id[/code] and [code]method[/code] that gets called after each avoidance processing step for the [code]agent[/code]. The calculated [code]safe_velocity[/code] will be dispatched with a signal to the object just before the physics calculations.
+				[b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]0[/code] ObjectID as the [code]object_id[/code].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="agent_set_map" qualifiers="const">
 		<method name="agent_set_map" qualifiers="const">

+ 3 - 3
doc/classes/NavigationServer.xml

@@ -40,12 +40,12 @@
 		<method name="agent_set_callback" qualifiers="const">
 		<method name="agent_set_callback" qualifiers="const">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="agent" type="RID" />
 			<argument index="0" name="agent" type="RID" />
-			<argument index="1" name="receiver" type="Object" />
+			<argument index="1" name="object_id" type="int" />
 			<argument index="2" name="method" type="String" />
 			<argument index="2" name="method" type="String" />
 			<argument index="3" name="userdata" type="Variant" default="null" />
 			<argument index="3" name="userdata" type="Variant" default="null" />
 			<description>
 			<description>
-				Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [code]receiver[/code] object with a signal to the chosen [code]method[/code] name.
-				[b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [code]receiver[/code].
+				Sets the callback [code]object_id[/code] and [code]method[/code] that gets called after each avoidance processing step for the [code]agent[/code]. The calculated [code]safe_velocity[/code] will be dispatched with a signal to the object just before the physics calculations.
+				[b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]0[/code] ObjectID as the [code]object_id[/code].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="agent_set_map" qualifiers="const">
 		<method name="agent_set_map" qualifiers="const">

+ 157 - 26
editor/editor_properties.cpp

@@ -1509,10 +1509,22 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
 		return;
 		return;
 	}
 	}
 
 
+	if (linked->is_pressed()) {
+		setting = true;
+		if (p_name == "x") {
+			spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+		}
+
+		if (p_name == "y") {
+			spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+		}
+		setting = false;
+	}
+
 	Vector2 v2;
 	Vector2 v2;
 	v2.x = spin[0]->get_value();
 	v2.x = spin[0]->get_value();
 	v2.y = spin[1]->get_value();
 	v2.y = spin[1]->get_value();
-	emit_changed(get_edited_property(), v2, p_name);
+	emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
 }
 }
 
 
 void EditorPropertyVector2::update_property() {
 void EditorPropertyVector2::update_property() {
@@ -1521,24 +1533,46 @@ void EditorPropertyVector2::update_property() {
 	spin[0]->set_value(val.x);
 	spin[0]->set_value(val.x);
 	spin[1]->set_value(val.y);
 	spin[1]->set_value(val.y);
 	setting = false;
 	setting = false;
+	_update_ratio();
+}
+
+void EditorPropertyVector2::_update_ratio() {
+	linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+	if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+		ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+		ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+	} else {
+		ratio_xy = 1.0;
+		ratio_yx = 1.0;
+	}
 }
 }
 
 
 void EditorPropertyVector2::_notification(int p_what) {
 void EditorPropertyVector2::_notification(int p_what) {
-	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
-		Color base = get_color("accent_color", "Editor");
-		for (int i = 0; i < 2; i++) {
-			Color c = base;
-			c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v());
-			spin[i]->set_custom_label_color(true, c);
-		}
+	switch (p_what) {
+		case NOTIFICATION_ENTER_TREE:
+		case NOTIFICATION_THEME_CHANGED: {
+			Ref<Texture> normal_icon = get_icon("Unlinked", "EditorIcons");
+			linked->set_custom_minimum_size(Vector2(normal_icon->get_width(), 0));
+			linked->set_normal_texture(normal_icon);
+			linked->set_pressed_texture(get_icon("Instance", "EditorIcons"));
+
+			Color base = get_color("accent_color", "Editor");
+			for (int i = 0; i < 2; i++) {
+				Color c = base;
+				c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v());
+				spin[i]->set_custom_label_color(true, c);
+			}
+		} break;
 	}
 	}
 }
 }
 
 
 void EditorPropertyVector2::_bind_methods() {
 void EditorPropertyVector2::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_update_ratio"), &EditorPropertyVector2::_update_ratio);
 	ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector2::_value_changed);
 	ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector2::_value_changed);
 }
 }
 
 
-void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
+void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link) {
 	for (int i = 0; i < 2; i++) {
 	for (int i = 0; i < 2; i++) {
 		spin[i]->set_min(p_min);
 		spin[i]->set_min(p_min);
 		spin[i]->set_max(p_max);
 		spin[i]->set_max(p_max);
@@ -1547,21 +1581,31 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo
 		spin[i]->set_allow_greater(true);
 		spin[i]->set_allow_greater(true);
 		spin[i]->set_allow_lesser(true);
 		spin[i]->set_allow_lesser(true);
 	}
 	}
+
+	if (!p_link) {
+		linked->hide();
+	} else {
+		linked->set_pressed(true);
+	}
 }
 }
 
 
 EditorPropertyVector2::EditorPropertyVector2() {
 EditorPropertyVector2::EditorPropertyVector2() {
 	bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing");
 	bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing");
 
 
+	HBoxContainer *hb = memnew(HBoxContainer);
+	hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
 	BoxContainer *bc;
 	BoxContainer *bc;
 
 
 	if (horizontal) {
 	if (horizontal) {
 		bc = memnew(HBoxContainer);
 		bc = memnew(HBoxContainer);
-		add_child(bc);
-		set_bottom_editor(bc);
+		hb->add_child(bc);
+		set_bottom_editor(hb);
 	} else {
 	} else {
 		bc = memnew(VBoxContainer);
 		bc = memnew(VBoxContainer);
-		add_child(bc);
+		hb->add_child(bc);
 	}
 	}
+	bc->set_h_size_flags(SIZE_EXPAND_FILL);
 
 
 	static const char *desc[2] = { "x", "y" };
 	static const char *desc[2] = { "x", "y" };
 	for (int i = 0; i < 2; i++) {
 	for (int i = 0; i < 2; i++) {
@@ -1576,6 +1620,14 @@ EditorPropertyVector2::EditorPropertyVector2() {
 		}
 		}
 	}
 	}
 
 
+	linked = memnew(TextureButton);
+	linked->set_toggle_mode(true);
+	linked->set_expand(true);
+	linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+	linked->connect("pressed", this, "_update_ratio");
+	hb->add_child(linked);
+
+	add_child(hb);
 	if (!horizontal) {
 	if (!horizontal) {
 		set_label_reference(spin[0]); //show text and buttons around this
 		set_label_reference(spin[0]); //show text and buttons around this
 	}
 	}
@@ -1671,11 +1723,30 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
 		return;
 		return;
 	}
 	}
 
 
+	if (linked->is_pressed()) {
+		setting = true;
+		if (p_name == "x") {
+			spin[1]->set_value(spin[0]->get_value() * ratio_yx);
+			spin[2]->set_value(spin[0]->get_value() * ratio_zx);
+		}
+
+		if (p_name == "y") {
+			spin[0]->set_value(spin[1]->get_value() * ratio_xy);
+			spin[2]->set_value(spin[1]->get_value() * ratio_zy);
+		}
+
+		if (p_name == "z") {
+			spin[0]->set_value(spin[2]->get_value() * ratio_xz);
+			spin[1]->set_value(spin[2]->get_value() * ratio_yz);
+		}
+		setting = false;
+	}
+
 	Vector3 v3;
 	Vector3 v3;
 	v3.x = spin[0]->get_value();
 	v3.x = spin[0]->get_value();
 	v3.y = spin[1]->get_value();
 	v3.y = spin[1]->get_value();
 	v3.z = spin[2]->get_value();
 	v3.z = spin[2]->get_value();
-	emit_changed(get_edited_property(), v3, p_name);
+	emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
 }
 }
 
 
 void EditorPropertyVector3::update_property() {
 void EditorPropertyVector3::update_property() {
@@ -1685,22 +1756,54 @@ void EditorPropertyVector3::update_property() {
 	spin[1]->set_value(val.y);
 	spin[1]->set_value(val.y);
 	spin[2]->set_value(val.z);
 	spin[2]->set_value(val.z);
 	setting = false;
 	setting = false;
+
+	_update_ratio();
 }
 }
+
+void EditorPropertyVector3::_update_ratio() {
+	linked->set_modulate(Color(1, 1, 1, linked->is_pressed() ? 1.0 : 0.5));
+
+	if (spin[0]->get_value() != 0 && spin[1]->get_value() != 0) {
+		ratio_yx = spin[1]->get_value() / spin[0]->get_value();
+		ratio_zx = spin[2]->get_value() / spin[0]->get_value();
+		ratio_xy = spin[0]->get_value() / spin[1]->get_value();
+		ratio_zy = spin[2]->get_value() / spin[1]->get_value();
+		ratio_xz = spin[0]->get_value() / spin[2]->get_value();
+		ratio_yz = spin[1]->get_value() / spin[2]->get_value();
+	} else {
+		ratio_yx = 1.0;
+		ratio_zx = 1.0;
+		ratio_xy = 1.0;
+		ratio_zy = 1.0;
+		ratio_xz = 1.0;
+		ratio_yz = 1.0;
+	}
+}
+
 void EditorPropertyVector3::_notification(int p_what) {
 void EditorPropertyVector3::_notification(int p_what) {
-	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
-		Color base = get_color("accent_color", "Editor");
-		for (int i = 0; i < 3; i++) {
-			Color c = base;
-			c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v());
-			spin[i]->set_custom_label_color(true, c);
-		}
+	switch (p_what) {
+		case NOTIFICATION_ENTER_TREE:
+		case NOTIFICATION_THEME_CHANGED: {
+			Ref<Texture> normal_icon = get_icon("Unlinked", "EditorIcons");
+			linked->set_custom_minimum_size(Vector2(normal_icon->get_width(), 0));
+			linked->set_normal_texture(normal_icon);
+			linked->set_pressed_texture(get_icon("Instance", "EditorIcons"));
+
+			Color base = get_color("accent_color", "Editor");
+			for (int i = 0; i < 3; i++) {
+				Color c = base;
+				c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v());
+				spin[i]->set_custom_label_color(true, c);
+			}
+		} break;
 	}
 	}
 }
 }
 void EditorPropertyVector3::_bind_methods() {
 void EditorPropertyVector3::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_update_ratio"), &EditorPropertyVector3::_update_ratio);
 	ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector3::_value_changed);
 	ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector3::_value_changed);
 }
 }
 
 
-void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider) {
+void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link) {
 	for (int i = 0; i < 3; i++) {
 	for (int i = 0; i < 3; i++) {
 		spin[i]->set_min(p_min);
 		spin[i]->set_min(p_min);
 		spin[i]->set_max(p_max);
 		spin[i]->set_max(p_max);
@@ -1709,21 +1812,31 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo
 		spin[i]->set_allow_greater(true);
 		spin[i]->set_allow_greater(true);
 		spin[i]->set_allow_lesser(true);
 		spin[i]->set_allow_lesser(true);
 	}
 	}
+
+	if (!p_link) {
+		linked->hide();
+	} else {
+		linked->set_pressed(true);
+	}
 }
 }
 
 
 EditorPropertyVector3::EditorPropertyVector3() {
 EditorPropertyVector3::EditorPropertyVector3() {
 	bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing");
 	bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing");
 
 
+	HBoxContainer *hb = memnew(HBoxContainer);
+	hb->set_h_size_flags(SIZE_EXPAND_FILL);
+
 	BoxContainer *bc;
 	BoxContainer *bc;
 
 
 	if (horizontal) {
 	if (horizontal) {
 		bc = memnew(HBoxContainer);
 		bc = memnew(HBoxContainer);
-		add_child(bc);
-		set_bottom_editor(bc);
+		hb->add_child(bc);
+		set_bottom_editor(hb);
 	} else {
 	} else {
 		bc = memnew(VBoxContainer);
 		bc = memnew(VBoxContainer);
-		add_child(bc);
+		hb->add_child(bc);
 	}
 	}
+	bc->set_h_size_flags(SIZE_EXPAND_FILL);
 
 
 	static const char *desc[3] = { "x", "y", "z" };
 	static const char *desc[3] = { "x", "y", "z" };
 	for (int i = 0; i < 3; i++) {
 	for (int i = 0; i < 3; i++) {
@@ -1738,11 +1851,21 @@ EditorPropertyVector3::EditorPropertyVector3() {
 		}
 		}
 	}
 	}
 
 
+	linked = memnew(TextureButton);
+	linked->set_toggle_mode(true);
+	linked->set_expand(true);
+	linked->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
+	linked->connect("pressed", this, "_update_ratio");
+	hb->add_child(linked);
+
+	add_child(hb);
 	if (!horizontal) {
 	if (!horizontal) {
 		set_label_reference(spin[0]); //show text and buttons around this
 		set_label_reference(spin[0]); //show text and buttons around this
 	}
 	}
 	setting = false;
 	setting = false;
+	_update_ratio();
 }
 }
+
 ///////////////////// PLANE /////////////////////////
 ///////////////////// PLANE /////////////////////////
 
 
 void EditorPropertyPlane::_value_changed(double val, const String &p_name) {
 void EditorPropertyPlane::_value_changed(double val, const String &p_name) {
@@ -2485,7 +2608,10 @@ void EditorPropertyResource::_resource_selected(const RES &p_resource, bool p_ed
 void EditorPropertyResource::_resource_changed(const RES &p_resource) {
 void EditorPropertyResource::_resource_changed(const RES &p_resource) {
 	// Make visual script the correct type.
 	// Make visual script the correct type.
 	Ref<Script> s = p_resource;
 	Ref<Script> s = p_resource;
+	bool is_script = false;
 	if (get_edited_object() && s.is_valid()) {
 	if (get_edited_object() && s.is_valid()) {
+		is_script = true;
+		EditorNode::get_singleton()->get_inspector_dock()->store_script_properties(get_edited_object());
 		s->call("set_instance_base_type", get_edited_object()->get_class());
 		s->call("set_instance_base_type", get_edited_object()->get_class());
 	}
 	}
 
 
@@ -2511,6 +2637,11 @@ void EditorPropertyResource::_resource_changed(const RES &p_resource) {
 	emit_changed(get_edited_property(), p_resource);
 	emit_changed(get_edited_property(), p_resource);
 	update_property();
 	update_property();
 
 
+	if (is_script) {
+		// Restore properties if script was changed.
+		EditorNode::get_singleton()->get_inspector_dock()->apply_script_properties(get_edited_object());
+	}
+
 	// Automatically suggest setting up the path for a ViewportTexture.
 	// Automatically suggest setting up the path for a ViewportTexture.
 	if (vpt.is_valid() && vpt->get_viewport_path_in_scene().is_empty()) {
 	if (vpt.is_valid() && vpt->get_viewport_path_in_scene().is_empty()) {
 		if (!scene_tree) {
 		if (!scene_tree) {
@@ -3035,7 +3166,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
 				hide_slider = false;
 				hide_slider = false;
 			}
 			}
 
 
-			editor->setup(min, max, step, hide_slider);
+			editor->setup(min, max, step, hide_slider, p_hint == PROPERTY_HINT_LINK);
 			add_property_editor(p_path, editor);
 			add_property_editor(p_path, editor);
 
 
 		} break; // 5
 		} break; // 5
@@ -3070,7 +3201,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
 				hide_slider = false;
 				hide_slider = false;
 			}
 			}
 
 
-			editor->setup(min, max, step, hide_slider);
+			editor->setup(min, max, step, hide_slider, p_hint == PROPERTY_HINT_LINK);
 			add_property_editor(p_path, editor);
 			add_property_editor(p_path, editor);
 
 
 		} break;
 		} break;

+ 14 - 2
editor/editor_properties.h

@@ -376,6 +376,10 @@ class EditorPropertyVector2 : public EditorProperty {
 	GDCLASS(EditorPropertyVector2, EditorProperty);
 	GDCLASS(EditorPropertyVector2, EditorProperty);
 	EditorSpinSlider *spin[2];
 	EditorSpinSlider *spin[2];
 	bool setting;
 	bool setting;
+	double ratio_xy = 1.0;
+	double ratio_yx = 1.0;
+	TextureButton *linked = nullptr;
+	void _update_ratio();
 	void _value_changed(double p_val, const String &p_name);
 	void _value_changed(double p_val, const String &p_name);
 
 
 protected:
 protected:
@@ -384,7 +388,7 @@ protected:
 
 
 public:
 public:
 	virtual void update_property();
 	virtual void update_property();
-	void setup(double p_min, double p_max, double p_step, bool p_no_slider);
+	void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false);
 	EditorPropertyVector2();
 	EditorPropertyVector2();
 };
 };
 
 
@@ -408,6 +412,14 @@ class EditorPropertyVector3 : public EditorProperty {
 	GDCLASS(EditorPropertyVector3, EditorProperty);
 	GDCLASS(EditorPropertyVector3, EditorProperty);
 	EditorSpinSlider *spin[3];
 	EditorSpinSlider *spin[3];
 	bool setting;
 	bool setting;
+	double ratio_yx = 1.0;
+	double ratio_zx = 1.0;
+	double ratio_xy = 1.0;
+	double ratio_zy = 1.0;
+	double ratio_xz = 1.0;
+	double ratio_yz = 1.0;
+	TextureButton *linked = nullptr;
+	void _update_ratio();
 	void _value_changed(double p_val, const String &p_name);
 	void _value_changed(double p_val, const String &p_name);
 
 
 protected:
 protected:
@@ -416,7 +428,7 @@ protected:
 
 
 public:
 public:
 	virtual void update_property();
 	virtual void update_property();
-	void setup(double p_min, double p_max, double p_step, bool p_no_slider);
+	void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false);
 	EditorPropertyVector3();
 	EditorPropertyVector3();
 };
 };
 
 

+ 1 - 0
editor/editor_property_name_processor.cpp

@@ -230,6 +230,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
 	capitalize_string_remaps["tcp"] = "TCP";
 	capitalize_string_remaps["tcp"] = "TCP";
 	capitalize_string_remaps["tls"] = "TLS";
 	capitalize_string_remaps["tls"] = "TLS";
 	capitalize_string_remaps["ui"] = "UI";
 	capitalize_string_remaps["ui"] = "UI";
+	capitalize_string_remaps["uri"] = "URI";
 	capitalize_string_remaps["url"] = "URL";
 	capitalize_string_remaps["url"] = "URL";
 	capitalize_string_remaps["urls"] = "URLs";
 	capitalize_string_remaps["urls"] = "URLs";
 	capitalize_string_remaps["us"] = String::utf8("(µs)"); // Unit.
 	capitalize_string_remaps["us"] = String::utf8("(µs)"); // Unit.

+ 1 - 0
editor/icons/icon_unlinked.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><defs><clipPath id="a"><path d="M0 0h16v16H0z"/></clipPath></defs><g clip-path="url(#a)" fill="#e0e0e0"><path d="M1.136 12.036a3.994 3.994 0 0 1-.137-1.047 4.007 4.007 0 0 1 2.965-3.853 1 1 0 0 1 1.225.707 1 1 0 0 1 .034.25 1 1 0 0 1-.741.975 2 2 0 0 0-1.483 1.926 1.994 1.994 0 0 0 .068.523 2 2 0 0 0 2.45 1.415 2 2 0 0 0 1.484-1.931 2 2 0 0 0-.068-.523 1 1 0 0 1-.034-.25 1 1 0 0 1 .742-.975 1 1 0 0 1 1.225.707 3.991 3.991 0 0 1 .137 1.046 4.007 4.007 0 0 1-2.965 3.852 3.993 3.993 0 0 1-1.035.137 4.006 4.006 0 0 1-3.867-2.959zM9.965 8.863a1 1 0 0 1-.742-.975 1 1 0 0 1 .034-.25 1 1 0 0 1 1.225-.706 2 2 0 0 0 2.449-1.415A1.994 1.994 0 0 0 13 4.994a2 2 0 0 0-1.483-1.926 2 2 0 0 0-2.45 1.414 1 1 0 0 1-1.224.707 1 1 0 0 1-.742-.975 1 1 0 0 1 .034-.25 4 4 0 0 1 4.9-2.829A4.008 4.008 0 0 1 15 4.988a3.993 3.993 0 0 1-.137 1.047 4.006 4.006 0 0 1-3.862 2.966 3.989 3.989 0 0 1-1.036-.138zM5.5 4a.5.5 0 0 1-.5-.5v-2a.5.5 0 0 1 .5-.5.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5zM4.5 5a.5.5 0 0 1-.354-.146l-2-2a.5.5 0 0 1 0-.707.5.5 0 0 1 .707 0l2 2A.5.5 0 0 1 4.5 5zM3.5 6h-2a.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5z"/></g></svg>

+ 29 - 0
editor/inspector_dock.cpp

@@ -400,6 +400,9 @@ void InspectorDock::_bind_methods() {
 	ClassDB::bind_method("_edit_forward", &InspectorDock::_edit_forward);
 	ClassDB::bind_method("_edit_forward", &InspectorDock::_edit_forward);
 	ClassDB::bind_method("_edit_back", &InspectorDock::_edit_back);
 	ClassDB::bind_method("_edit_back", &InspectorDock::_edit_back);
 
 
+	ClassDB::bind_method("store_script_properties", &InspectorDock::store_script_properties);
+	ClassDB::bind_method("apply_script_properties", &InspectorDock::apply_script_properties);
+
 	ADD_SIGNAL(MethodInfo("request_help"));
 	ADD_SIGNAL(MethodInfo("request_help"));
 }
 }
 
 
@@ -527,6 +530,32 @@ EditorPropertyNameProcessor::Style InspectorDock::get_property_name_style() cons
 	return property_name_style;
 	return property_name_style;
 }
 }
 
 
+void InspectorDock::store_script_properties(Object *p_object) {
+	ERR_FAIL_NULL(p_object);
+	ScriptInstance *si = p_object->get_script_instance();
+	if (!si) {
+		return;
+	}
+	si->get_property_state(stored_properties);
+}
+
+void InspectorDock::apply_script_properties(Object *p_object) {
+	ERR_FAIL_NULL(p_object);
+	ScriptInstance *si = p_object->get_script_instance();
+	if (!si) {
+		return;
+	}
+
+	for (List<Pair<StringName, Variant>>::Element *E = stored_properties.front(); E; E = E->next()) {
+		const Pair<StringName, Variant> &p = E->get();
+		Variant current;
+		if (si->get(p.first, current) && current.get_type() == p.second.get_type()) {
+			si->set(p.first, p.second);
+		}
+	}
+	stored_properties.clear();
+}
+
 InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
 InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
 	set_name("Inspector");
 	set_name("Inspector");
 	set_theme(p_editor->get_gui_base()->get_theme());
 	set_theme(p_editor->get_gui_base()->get_theme());

+ 4 - 0
editor/inspector_dock.h

@@ -100,6 +100,7 @@ class InspectorDock : public VBoxContainer {
 	AcceptDialog *warning_dialog;
 	AcceptDialog *warning_dialog;
 
 
 	EditorPropertyNameProcessor::Style property_name_style;
 	EditorPropertyNameProcessor::Style property_name_style;
+	List<Pair<StringName, Variant>> stored_properties;
 
 
 	void _prepare_menu();
 	void _prepare_menu();
 	void _menu_option(int p_option);
 	void _menu_option(int p_option);
@@ -144,6 +145,9 @@ public:
 
 
 	EditorPropertyNameProcessor::Style get_property_name_style() const;
 	EditorPropertyNameProcessor::Style get_property_name_style() const;
 
 
+	void store_script_properties(Object *p_object);
+	void apply_script_properties(Object *p_object);
+
 	InspectorDock(EditorNode *p_editor, EditorData &p_editor_data);
 	InspectorDock(EditorNode *p_editor, EditorData &p_editor_data);
 	~InspectorDock();
 	~InspectorDock();
 };
 };

+ 34 - 10
editor/plugins/material_editor_plugin.cpp

@@ -34,6 +34,19 @@
 #include "scene/gui/viewport_container.h"
 #include "scene/gui/viewport_container.h"
 #include "scene/resources/particles_material.h"
 #include "scene/resources/particles_material.h"
 
 
+void MaterialEditor::_gui_input(const Ref<InputEvent> &p_event) {
+	ERR_FAIL_COND(p_event.is_null());
+
+	Ref<InputEventMouseMotion> mm = p_event;
+	if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+		rot.x -= mm->get_relative().y * 0.01;
+		rot.y -= mm->get_relative().x * 0.01;
+
+		rot.x = CLAMP(rot.x, -Math_PI / 2, Math_PI / 2);
+		_update_rotation();
+	}
+}
+
 void MaterialEditor::_notification(int p_what) {
 void MaterialEditor::_notification(int p_what) {
 	if (p_what == NOTIFICATION_READY) {
 	if (p_what == NOTIFICATION_READY) {
 		//get_scene()->connect("node_removed",this,"_node_removed");
 		//get_scene()->connect("node_removed",this,"_node_removed");
@@ -63,6 +76,13 @@ void MaterialEditor::_notification(int p_what) {
 	}
 	}
 }
 }
 
 
+void MaterialEditor::_update_rotation() {
+	Transform t;
+	t.basis.rotate(Vector3(0, 1, 0), -rot.y);
+	t.basis.rotate(Vector3(1, 0, 0), -rot.x);
+	rotation->set_transform(t);
+}
+
 void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
 void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) {
 	material = p_material;
 	material = p_material;
 	camera->set_environment(p_env);
 	camera->set_environment(p_env);
@@ -72,6 +92,10 @@ void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_en
 	} else {
 	} else {
 		hide();
 		hide();
 	}
 	}
+
+	rot.x = Math::deg2rad(-15.0);
+	rot.y = Math::deg2rad(30.0);
+	_update_rotation();
 }
 }
 
 
 void MaterialEditor::_button_pressed(Node *p_button) {
 void MaterialEditor::_button_pressed(Node *p_button) {
@@ -101,6 +125,7 @@ void MaterialEditor::_button_pressed(Node *p_button) {
 }
 }
 
 
 void MaterialEditor::_bind_methods() {
 void MaterialEditor::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("_gui_input"), &MaterialEditor::_gui_input);
 	ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed);
 	ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed);
 }
 }
 
 
@@ -119,7 +144,7 @@ MaterialEditor::MaterialEditor() {
 	viewport->set_msaa(Viewport::MSAA_4X);
 	viewport->set_msaa(Viewport::MSAA_4X);
 
 
 	camera = memnew(Camera);
 	camera = memnew(Camera);
-	camera->set_transform(Transform(Basis(), Vector3(0, 0, 3)));
+	camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1)));
 	camera->set_perspective(45, 0.1, 10);
 	camera->set_perspective(45, 0.1, 10);
 	camera->make_current();
 	camera->make_current();
 	viewport->add_child(camera);
 	viewport->add_child(camera);
@@ -133,18 +158,17 @@ MaterialEditor::MaterialEditor() {
 	light2->set_color(Color(0.7, 0.7, 0.7));
 	light2->set_color(Color(0.7, 0.7, 0.7));
 	viewport->add_child(light2);
 	viewport->add_child(light2);
 
 
+	rotation = memnew(Spatial);
+	viewport->add_child(rotation);
+
 	sphere_instance = memnew(MeshInstance);
 	sphere_instance = memnew(MeshInstance);
-	viewport->add_child(sphere_instance);
+	rotation->add_child(sphere_instance);
 
 
 	box_instance = memnew(MeshInstance);
 	box_instance = memnew(MeshInstance);
-	viewport->add_child(box_instance);
-
-	Transform box_xform;
-	box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
-	box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
-	box_xform.basis.scale(Vector3(0.8, 0.8, 0.8));
-	box_xform.origin.y = 0.2;
-	box_instance->set_transform(box_xform);
+	rotation->add_child(box_instance);
+
+	box_instance->set_transform(Transform(Basis() * 0.25, Vector3() * 0.25));
+	sphere_instance->set_transform(Transform(Basis() * 0.375, Vector3() * 0.375));
 
 
 	sphere_mesh.instance();
 	sphere_mesh.instance();
 	sphere_instance->set_mesh(sphere_mesh);
 	sphere_instance->set_mesh(sphere_mesh);

+ 5 - 0
editor/plugins/material_editor_plugin.h

@@ -46,8 +46,11 @@ class ViewportContainer;
 class MaterialEditor : public Control {
 class MaterialEditor : public Control {
 	GDCLASS(MaterialEditor, Control);
 	GDCLASS(MaterialEditor, Control);
 
 
+	Vector2 rot = Vector2();
+
 	ViewportContainer *vc;
 	ViewportContainer *vc;
 	Viewport *viewport;
 	Viewport *viewport;
+	Spatial *rotation;
 	MeshInstance *sphere_instance;
 	MeshInstance *sphere_instance;
 	MeshInstance *box_instance;
 	MeshInstance *box_instance;
 	DirectionalLight *light1;
 	DirectionalLight *light1;
@@ -70,6 +73,8 @@ class MaterialEditor : public Control {
 
 
 protected:
 protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
+	void _gui_input(const Ref<InputEvent> &p_event);
+	void _update_rotation();
 
 
 	static void _bind_methods();
 	static void _bind_methods();
 
 

+ 28 - 13
editor/scene_tree_dock.cpp

@@ -2050,16 +2050,24 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
 		return;
 		return;
 	}
 	}
 
 
-	editor_data->get_undo_redo().create_action(TTR("Attach Script"));
+	InspectorDock *inspector_dock = EditorNode::get_singleton()->get_inspector_dock();
+	UndoRedo &undo_redo = editor_data->get_undo_redo();
+
+	undo_redo.create_action(TTR("Attach Script"));
 	for (List<Node *>::Element *E = selected.front(); E; E = E->next()) {
 	for (List<Node *>::Element *E = selected.front(); E; E = E->next()) {
-		Ref<Script> existing = E->get()->get_script();
-		editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script.get_ref_ptr());
-		editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
-		editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
-		editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+		Node *node = E->get();
+		Ref<Script> existing = node->get_script();
+		undo_redo.add_do_method(inspector_dock, "store_script_properties", node);
+		undo_redo.add_undo_method(inspector_dock, "store_script_properties", node);
+		undo_redo.add_do_method(node, "set_script", p_script.get_ref_ptr());
+		undo_redo.add_undo_method(node, "set_script", existing);
+		undo_redo.add_do_method(inspector_dock, "apply_script_properties", node);
+		undo_redo.add_undo_method(inspector_dock, "apply_script_properties", node);
+		undo_redo.add_do_method(this, "_update_script_button");
+		undo_redo.add_undo_method(this, "_update_script_button");
 	}
 	}
 
 
-	editor_data->get_undo_redo().commit_action();
+	undo_redo.commit_action();
 
 
 	_push_item(p_script.operator->());
 	_push_item(p_script.operator->());
 	_update_script_button();
 	_update_script_button();
@@ -2706,12 +2714,19 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
 	ERR_FAIL_COND(!scr.is_valid());
 	ERR_FAIL_COND(!scr.is_valid());
 	Node *n = get_node(p_to);
 	Node *n = get_node(p_to);
 	if (n) {
 	if (n) {
-		editor_data->get_undo_redo().create_action(TTR("Attach Script"));
-		editor_data->get_undo_redo().add_do_method(n, "set_script", scr);
-		editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script());
-		editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
-		editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
-		editor_data->get_undo_redo().commit_action();
+		InspectorDock *inspector_dock = EditorNode::get_singleton()->get_inspector_dock();
+		UndoRedo &undo_redo = editor_data->get_undo_redo();
+
+		undo_redo.create_action(TTR("Attach Script"));
+		undo_redo.add_do_method(inspector_dock, "store_script_properties", n);
+		undo_redo.add_undo_method(inspector_dock, "store_script_properties", n);
+		undo_redo.add_do_method(n, "set_script", scr);
+		undo_redo.add_undo_method(n, "set_script", n->get_script());
+		undo_redo.add_do_method(inspector_dock, "apply_script_properties", n);
+		undo_redo.add_undo_method(inspector_dock, "apply_script_properties", n);
+		undo_redo.add_do_method(this, "_update_script_button");
+		undo_redo.add_undo_method(this, "_update_script_button");
+		undo_redo.commit_action();
 	}
 	}
 }
 }
 
 

+ 3 - 3
modules/navigation/godot_navigation_server.cpp

@@ -537,14 +537,14 @@ bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const {
 	return agent->is_map_changed();
 	return agent->is_map_changed();
 }
 }
 
 
-COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata) {
+COMMAND_4(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata) {
 	RvoAgent *agent = agent_owner.getornull(p_agent);
 	RvoAgent *agent = agent_owner.getornull(p_agent);
 	ERR_FAIL_COND(agent == nullptr);
 	ERR_FAIL_COND(agent == nullptr);
 
 
-	agent->set_callback(p_receiver == nullptr ? 0 : p_receiver->get_instance_id(), p_method, p_udata);
+	agent->set_callback(p_object_id, p_method, p_udata);
 
 
 	if (agent->get_map()) {
 	if (agent->get_map()) {
-		if (p_receiver == nullptr) {
+		if (p_object_id == ObjectID()) {
 			agent->get_map()->remove_agent_as_controlled(agent);
 			agent->get_map()->remove_agent_as_controlled(agent);
 		} else {
 		} else {
 			agent->get_map()->set_agent_as_controlled(agent);
 			agent->get_map()->set_agent_as_controlled(agent);

+ 1 - 1
modules/navigation/godot_navigation_server.h

@@ -147,7 +147,7 @@ public:
 	COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position);
 	COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position);
 	COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore);
 	COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore);
 	virtual bool agent_is_map_changed(RID p_agent) const;
 	virtual bool agent_is_map_changed(RID p_agent) const;
-	COMMAND_4_DEF(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, Variant());
+	COMMAND_4_DEF(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata, Variant());
 
 
 	COMMAND_1(free, RID, p_object);
 	COMMAND_1(free, RID, p_object);
 
 

+ 1 - 1
scene/2d/camera_2d.cpp

@@ -713,7 +713,7 @@ void Camera2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
 
 

+ 3 - 3
scene/2d/navigation_agent_2d.cpp

@@ -211,9 +211,9 @@ NavigationAgent2D::~NavigationAgent2D() {
 void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
 void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
 	avoidance_enabled = p_enabled;
 	avoidance_enabled = p_enabled;
 	if (avoidance_enabled) {
 	if (avoidance_enabled) {
-		Navigation2DServer::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+		Navigation2DServer::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done");
 	} else {
 	} else {
-		Navigation2DServer::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+		Navigation2DServer::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
 	}
 	}
 }
 }
 
 
@@ -223,7 +223,7 @@ bool NavigationAgent2D::get_avoidance_enabled() const {
 
 
 void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
 void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
 	// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
 	// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
-	Navigation2DServer::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+	Navigation2DServer::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
 	if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
 	if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
 		// place agent on navigation map first or else the RVO agent callback creation fails silently later
 		// place agent on navigation map first or else the RVO agent callback creation fails silently later
 		agent_parent = Object::cast_to<Node2D>(p_agent_parent);
 		agent_parent = Object::cast_to<Node2D>(p_agent_parent);

+ 1 - 1
scene/2d/node_2d.cpp

@@ -425,7 +425,7 @@ void Node2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");

+ 1 - 1
scene/2d/parallax_background.cpp

@@ -178,7 +178,7 @@ void ParallaxBackground::_bind_methods() {
 	ADD_GROUP("Scroll", "scroll_");
 	ADD_GROUP("Scroll", "scroll_");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_offset", "get_scroll_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_offset", "get_scroll_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_offset"), "set_scroll_base_offset", "get_scroll_base_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_offset"), "set_scroll_base_offset", "get_scroll_base_offset");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_scale"), "set_scroll_base_scale", "get_scroll_base_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_scale", PROPERTY_HINT_LINK), "set_scroll_base_scale", "get_scroll_base_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_begin"), "set_limit_begin", "get_limit_begin");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_begin"), "set_limit_begin", "get_limit_begin");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_end"), "set_limit_end", "get_limit_end");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_end"), "set_limit_end", "get_limit_end");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_ignore_camera_zoom"), "set_ignore_camera_zoom", "is_ignore_camera_zoom");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_ignore_camera_zoom"), "set_ignore_camera_zoom", "is_ignore_camera_zoom");

+ 1 - 1
scene/2d/parallax_layer.cpp

@@ -156,7 +156,7 @@ void ParallaxLayer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_mirroring"), &ParallaxLayer::get_mirroring);
 	ClassDB::bind_method(D_METHOD("get_mirroring"), &ParallaxLayer::get_mirroring);
 
 
 	ADD_GROUP("Motion", "motion_");
 	ADD_GROUP("Motion", "motion_");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_scale"), "set_motion_scale", "get_motion_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_scale", PROPERTY_HINT_LINK), "set_motion_scale", "get_motion_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_offset"), "set_motion_offset", "get_motion_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_offset"), "set_motion_offset", "get_motion_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_mirroring"), "set_mirroring", "get_mirroring");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_mirroring"), "set_mirroring", "get_mirroring");
 }
 }

+ 4 - 1
scene/2d/polygon_2d.cpp

@@ -617,13 +617,16 @@ void Polygon2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased");
+
 	ADD_GROUP("Texture", "");
 	ADD_GROUP("Texture", "");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+
 	ADD_GROUP("Texture", "texture_");
 	ADD_GROUP("Texture", "texture_");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale", PROPERTY_HINT_LINK), "set_texture_scale", "get_texture_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
+
 	ADD_GROUP("Skeleton", "");
 	ADD_GROUP("Skeleton", "");
 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
 
 

+ 3 - 3
scene/3d/navigation_agent.cpp

@@ -214,9 +214,9 @@ NavigationAgent::~NavigationAgent() {
 void NavigationAgent::set_avoidance_enabled(bool p_enabled) {
 void NavigationAgent::set_avoidance_enabled(bool p_enabled) {
 	avoidance_enabled = p_enabled;
 	avoidance_enabled = p_enabled;
 	if (avoidance_enabled) {
 	if (avoidance_enabled) {
-		NavigationServer::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+		NavigationServer::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done");
 	} else {
 	} else {
-		NavigationServer::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+		NavigationServer::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
 	}
 	}
 }
 }
 
 
@@ -245,7 +245,7 @@ Node *NavigationAgent::get_navigation_node() const {
 
 
 void NavigationAgent::set_agent_parent(Node *p_agent_parent) {
 void NavigationAgent::set_agent_parent(Node *p_agent_parent) {
 	// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
 	// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
-	NavigationServer::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+	NavigationServer::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
 	if (Object::cast_to<Spatial>(p_agent_parent) != nullptr) {
 	if (Object::cast_to<Spatial>(p_agent_parent) != nullptr) {
 		// place agent on navigation map first or else the RVO agent callback creation fails silently later
 		// place agent on navigation map first or else the RVO agent callback creation fails silently later
 		agent_parent = Object::cast_to<Spatial>(p_agent_parent);
 		agent_parent = Object::cast_to<Spatial>(p_agent_parent);

+ 1 - 1
scene/3d/spatial.cpp

@@ -938,7 +938,7 @@ void Spatial::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_translation", PROPERTY_HINT_NONE, "", 0), "set_global_translation", "get_global_translation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_translation", PROPERTY_HINT_NONE, "", 0), "set_global_translation", "get_global_translation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation");

+ 4 - 0
scene/gui/control.cpp

@@ -432,6 +432,10 @@ void Control::_validate_property(PropertyInfo &property) const {
 
 
 		property.hint_string = hint_string;
 		property.hint_string = hint_string;
 	}
 	}
+
+	if (property.name == "rect_scale") {
+		property.hint = PROPERTY_HINT_LINK;
+	}
 }
 }
 
 
 Control *Control::get_parent_control() const {
 Control *Control::get_parent_control() const {

+ 20 - 1
scene/gui/link_button.cpp

@@ -30,6 +30,7 @@
 
 
 #include "link_button.h"
 #include "link_button.h"
 
 
+#include "core/os/os.h"
 #include "core/translation.h"
 #include "core/translation.h"
 
 
 void LinkButton::set_text(const String &p_text) {
 void LinkButton::set_text(const String &p_text) {
@@ -47,6 +48,14 @@ String LinkButton::get_text() const {
 	return text;
 	return text;
 }
 }
 
 
+void LinkButton::set_uri(const String &p_uri) {
+	uri = p_uri;
+}
+
+String LinkButton::get_uri() const {
+	return uri;
+}
+
 void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) {
 void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) {
 	underline_mode = p_underline_mode;
 	underline_mode = p_underline_mode;
 	update();
 	update();
@@ -56,6 +65,14 @@ LinkButton::UnderlineMode LinkButton::get_underline_mode() const {
 	return underline_mode;
 	return underline_mode;
 }
 }
 
 
+void LinkButton::pressed() {
+	if (uri.empty()) {
+		return;
+	}
+
+	OS::get_singleton()->shell_open(uri);
+}
+
 Size2 LinkButton::get_minimum_size() const {
 Size2 LinkButton::get_minimum_size() const {
 	return get_font("font")->get_string_size(xl_text);
 	return get_font("font")->get_string_size(xl_text);
 }
 }
@@ -129,7 +146,8 @@ void LinkButton::_notification(int p_what) {
 void LinkButton::_bind_methods() {
 void LinkButton::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_text", "text"), &LinkButton::set_text);
 	ClassDB::bind_method(D_METHOD("set_text", "text"), &LinkButton::set_text);
 	ClassDB::bind_method(D_METHOD("get_text"), &LinkButton::get_text);
 	ClassDB::bind_method(D_METHOD("get_text"), &LinkButton::get_text);
-
+	ClassDB::bind_method(D_METHOD("set_uri", "uri"), &LinkButton::set_uri);
+	ClassDB::bind_method(D_METHOD("get_uri"), &LinkButton::get_uri);
 	ClassDB::bind_method(D_METHOD("set_underline_mode", "underline_mode"), &LinkButton::set_underline_mode);
 	ClassDB::bind_method(D_METHOD("set_underline_mode", "underline_mode"), &LinkButton::set_underline_mode);
 	ClassDB::bind_method(D_METHOD("get_underline_mode"), &LinkButton::get_underline_mode);
 	ClassDB::bind_method(D_METHOD("get_underline_mode"), &LinkButton::get_underline_mode);
 
 
@@ -139,6 +157,7 @@ void LinkButton::_bind_methods() {
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode");
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "uri"), "set_uri", "get_uri");
 }
 }
 
 
 LinkButton::LinkButton() {
 LinkButton::LinkButton() {

+ 4 - 0
scene/gui/link_button.h

@@ -48,8 +48,10 @@ private:
 	String text;
 	String text;
 	String xl_text;
 	String xl_text;
 	UnderlineMode underline_mode;
 	UnderlineMode underline_mode;
+	String uri;
 
 
 protected:
 protected:
+	virtual void pressed();
 	virtual Size2 get_minimum_size() const;
 	virtual Size2 get_minimum_size() const;
 	void _notification(int p_what);
 	void _notification(int p_what);
 	static void _bind_methods();
 	static void _bind_methods();
@@ -57,6 +59,8 @@ protected:
 public:
 public:
 	void set_text(const String &p_text);
 	void set_text(const String &p_text);
 	String get_text() const;
 	String get_text() const;
+	void set_uri(const String &p_uri);
+	String get_uri() const;
 
 
 	void set_underline_mode(UnderlineMode p_underline_mode);
 	void set_underline_mode(UnderlineMode p_underline_mode);
 	UnderlineMode get_underline_mode() const;
 	UnderlineMode get_underline_mode() const;

+ 1 - 1
scene/main/canvas_layer.cpp

@@ -332,7 +332,7 @@ void CanvasLayer::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
 	ADD_GROUP("", "");
 	ADD_GROUP("", "");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");

+ 6 - 0
scene/main/scene_tree.cpp

@@ -777,6 +777,12 @@ void SceneTree::finish() {
 		E->get()->release_connections();
 		E->get()->release_connections();
 	}
 	}
 	timers.clear();
 	timers.clear();
+
+	// Cleanup tweens.
+	for (List<Ref<SceneTreeTween>>::Element *E = tweens.front(); E; E = E->next()) {
+		E->get()->clear();
+	}
+	tweens.clear();
 }
 }
 
 
 void SceneTree::quit(int p_exit_code) {
 void SceneTree::quit(int p_exit_code) {

+ 2 - 2
scene/resources/material.cpp

@@ -2174,13 +2174,13 @@ void SpatialMaterial::_bind_methods() {
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
 	ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "detail_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_DETAIL_NORMAL);
 
 
 	ADD_GROUP("UV1", "uv1_");
 	ADD_GROUP("UV1", "uv1_");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale"), "set_uv1_scale", "get_uv1_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_scale", PROPERTY_HINT_LINK), "set_uv1_scale", "get_uv1_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_offset"), "set_uv1_offset", "get_uv1_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv1_offset"), "set_uv1_offset", "get_uv1_offset");
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_TRIPLANAR);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv1_triplanar"), "set_flag", "get_flag", FLAG_UV1_USE_TRIPLANAR);
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "uv1_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv1_triplanar_blend_sharpness", "get_uv1_triplanar_blend_sharpness");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "uv1_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv1_triplanar_blend_sharpness", "get_uv1_triplanar_blend_sharpness");
 
 
 	ADD_GROUP("UV2", "uv2_");
 	ADD_GROUP("UV2", "uv2_");
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale"), "set_uv2_scale", "get_uv2_scale");
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_scale", PROPERTY_HINT_LINK), "set_uv2_scale", "get_uv2_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_offset"), "set_uv2_offset", "get_uv2_offset");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "uv2_offset"), "set_uv2_offset", "get_uv2_offset");
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_TRIPLANAR);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_TRIPLANAR);
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "uv2_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv2_triplanar_blend_sharpness", "get_uv2_triplanar_blend_sharpness");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "uv2_triplanar_sharpness", PROPERTY_HINT_EXP_EASING), "set_uv2_triplanar_blend_sharpness", "get_uv2_triplanar_blend_sharpness");

+ 9 - 16
scene/resources/texture.cpp

@@ -1046,35 +1046,28 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
 		return false;
 		return false;
 	}
 	}
 
 
-	Rect2 rc = region;
-
 	Rect2 src = p_src_rect;
 	Rect2 src = p_src_rect;
 	if (src.size == Size2()) {
 	if (src.size == Size2()) {
-		src.size = rc.size;
+		src.size = region.size;
 	}
 	}
 	Vector2 scale = p_rect.size / src.size;
 	Vector2 scale = p_rect.size / src.size;
 
 
-	src.position += (rc.position - margin.position);
-	Rect2 src_c = rc.clip(src);
-	if (src_c.size == Size2()) {
+	src.position += (region.position - margin.position);
+	Rect2 src_clipped = region.clip(src);
+	if (src_clipped.size == Size2()) {
 		return false;
 		return false;
 	}
 	}
-	Vector2 ofs = (src_c.position - src.position);
 
 
+	Vector2 ofs = (src_clipped.position - src.position);
 	if (scale.x < 0) {
 	if (scale.x < 0) {
-		float mx = (margin.size.width - margin.position.x);
-		mx -= margin.position.x;
-		ofs.x = -(ofs.x + mx);
+		ofs.x += (src_clipped.size.x - src.size.x);
 	}
 	}
 	if (scale.y < 0) {
 	if (scale.y < 0) {
-		float my = margin.size.height - margin.position.y;
-		my -= margin.position.y;
-		ofs.y = -(ofs.y + my);
+		ofs.y += (src_clipped.size.y - src.size.y);
 	}
 	}
-	Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale);
 
 
-	r_rect = dr;
-	r_src_rect = src_c;
+	r_rect = Rect2(p_rect.position + ofs * scale, src_clipped.size * scale);
+	r_src_rect = src_clipped;
 	return true;
 	return true;
 }
 }
 
 

+ 6 - 6
servers/navigation_2d_server.cpp

@@ -146,10 +146,6 @@ Transform trf2_to_trf3(const Transform2D &d) {
 	return Transform(b, o);
 	return Transform(b, o);
 }
 }
 
 
-Object *obj_to_obj(Object *d) {
-	return d;
-}
-
 StringName sn_to_sn(StringName &d) {
 StringName sn_to_sn(StringName &d) {
 	return d;
 	return d;
 }
 }
@@ -158,6 +154,10 @@ Variant var_to_var(Variant &d) {
 	return d;
 	return d;
 }
 }
 
 
+ObjectID id_to_id(const ObjectID &id) {
+	return id;
+}
+
 Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
 Ref<NavigationMesh> poly_to_mesh(Ref<NavigationPolygon> d) {
 	if (d.is_valid()) {
 	if (d.is_valid()) {
 		return d->get_mesh();
 		return d->get_mesh();
@@ -218,7 +218,7 @@ void Navigation2DServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &Navigation2DServer::agent_set_target_velocity);
 	ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &Navigation2DServer::agent_set_target_velocity);
 	ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &Navigation2DServer::agent_set_position);
 	ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &Navigation2DServer::agent_set_position);
 	ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &Navigation2DServer::agent_is_map_changed);
 	ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &Navigation2DServer::agent_is_map_changed);
-	ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &Navigation2DServer::agent_set_callback, DEFVAL(Variant()));
+	ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "object_id", "method", "userdata"), &Navigation2DServer::agent_set_callback, DEFVAL(Variant()));
 
 
 	ClassDB::bind_method(D_METHOD("free_rid", "rid"), &Navigation2DServer::free);
 	ClassDB::bind_method(D_METHOD("free_rid", "rid"), &Navigation2DServer::free);
 
 
@@ -319,6 +319,6 @@ void FORWARD_2_C(agent_set_ignore_y, RID, p_agent, bool, p_ignore, rid_to_rid, b
 
 
 bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
 bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
 
 
-void FORWARD_4_C(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, rid_to_rid, obj_to_obj, sn_to_sn, var_to_var);
+void FORWARD_4_C(agent_set_callback, RID, p_agent, ObjectID, p_object_id, StringName, p_method, Variant, p_udata, rid_to_rid, id_to_id, sn_to_sn, var_to_var);
 
 
 void FORWARD_1_C(free, RID, p_object, rid_to_rid);
 void FORWARD_1_C(free, RID, p_object, rid_to_rid);

+ 1 - 1
servers/navigation_2d_server.h

@@ -181,7 +181,7 @@ public:
 	virtual bool agent_is_map_changed(RID p_agent) const;
 	virtual bool agent_is_map_changed(RID p_agent) const;
 
 
 	/// Callback called at the end of the RVO process
 	/// Callback called at the end of the RVO process
-	virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const;
+	virtual void agent_set_callback(RID p_agent, ObjectID p_object_id, StringName p_method, Variant p_udata = Variant()) const;
 
 
 	/// Destroy the `RID`
 	/// Destroy the `RID`
 	virtual void free(RID p_object) const;
 	virtual void free(RID p_object) const;

+ 1 - 1
servers/navigation_server.cpp

@@ -87,7 +87,7 @@ void NavigationServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer::agent_set_target_velocity);
 	ClassDB::bind_method(D_METHOD("agent_set_target_velocity", "agent", "target_velocity"), &NavigationServer::agent_set_target_velocity);
 	ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer::agent_set_position);
 	ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer::agent_set_position);
 	ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer::agent_is_map_changed);
 	ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer::agent_is_map_changed);
-	ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "receiver", "method", "userdata"), &NavigationServer::agent_set_callback, DEFVAL(Variant()));
+	ClassDB::bind_method(D_METHOD("agent_set_callback", "agent", "object_id", "method", "userdata"), &NavigationServer::agent_set_callback, DEFVAL(Variant()));
 
 
 	ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer::free);
 	ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer::free);
 
 

+ 1 - 1
servers/navigation_server.h

@@ -197,7 +197,7 @@ public:
 	virtual bool agent_is_map_changed(RID p_agent) const = 0;
 	virtual bool agent_is_map_changed(RID p_agent) const = 0;
 
 
 	/// Callback called at the end of the RVO process
 	/// Callback called at the end of the RVO process
-	virtual void agent_set_callback(RID p_agent, Object *p_receiver, StringName p_method, Variant p_udata = Variant()) const = 0;
+	virtual void agent_set_callback(RID p_agent, ObjectID p_object_id, StringName p_method, Variant p_udata = Variant()) const = 0;
 
 
 	/// Destroy the `RID`
 	/// Destroy the `RID`
 	virtual void free(RID p_object) const = 0;
 	virtual void free(RID p_object) const = 0;