summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/static_checks.yml2
-rw-r--r--core/core_bind.cpp21
-rw-r--r--core/core_bind.h1
-rw-r--r--core/io/file_access.cpp7
-rw-r--r--core/io/file_access.h1
-rw-r--r--core/os/os.h1
-rw-r--r--doc/classes/DisplayServer.xml16
-rw-r--r--doc/classes/OS.xml25
-rw-r--r--doc/classes/PhysicsServer3D.xml31
-rw-r--r--doc/classes/TileData.xml11
-rw-r--r--drivers/unix/file_access_unix_pipe.cpp185
-rw-r--r--drivers/unix/file_access_unix_pipe.h96
-rw-r--r--drivers/unix/os_unix.cpp102
-rw-r--r--drivers/unix/os_unix.h1
-rw-r--r--drivers/windows/file_access_windows_pipe.cpp159
-rw-r--r--drivers/windows/file_access_windows_pipe.h95
-rw-r--r--editor/dependency_editor.cpp2
-rw-r--r--editor/scene_tree_dock.cpp1
-rw-r--r--platform/android/display_server_android.cpp2
-rw-r--r--platform/ios/display_server_ios.mm2
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp4
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp6
-rw-r--r--platform/macos/display_server_macos.mm2
-rw-r--r--platform/web/display_server_web.cpp2
-rw-r--r--platform/web/os_web.cpp4
-rw-r--r--platform/web/os_web.h1
-rw-r--r--platform/windows/display_server_windows.cpp2
-rw-r--r--platform/windows/os_windows.cpp101
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--scene/gui/file_dialog.cpp4
-rw-r--r--scene/resources/2d/tile_set.cpp1
-rw-r--r--servers/display_server.cpp2
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/physics_server_3d.cpp10
34 files changed, 874 insertions, 29 deletions
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 0d5c1906b5..74935bb618 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -32,7 +32,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if [ "${{ github.event_name }}" == "pull_request" ]; then
- files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only)
+ files=$(git diff-tree --no-commit-id --name-only -r HEAD~${{ github.event.pull_request.commits }}..HEAD 2> /dev/null || true)
elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then
files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true)
fi
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 6927db002b..8c85030783 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -283,8 +283,8 @@ String OS::read_string_from_stdin() {
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
String pipe;
int exitcode = 0;
@@ -296,10 +296,18 @@ int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r
return exitcode;
}
+Dictionary OS::execute_with_pipe(const String &p_path, const Vector<String> &p_arguments) {
+ List<String> args;
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
+ }
+ return ::OS::get_singleton()->execute_with_pipe(p_path, args);
+}
+
int OS::create_instance(const Vector<String> &p_arguments) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
::OS::ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_instance(args, &pid);
@@ -311,8 +319,8 @@ int OS::create_instance(const Vector<String> &p_arguments) {
int OS::create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console) {
List<String> args;
- for (int i = 0; i < p_arguments.size(); i++) {
- args.push_back(p_arguments[i]);
+ for (const String &arg : p_arguments) {
+ args.push_back(arg);
}
::OS::ProcessID pid = 0;
Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console);
@@ -587,6 +595,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::execute_with_pipe);
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill);
diff --git a/core/core_bind.h b/core/core_bind.h
index 305f616cef..d46321cf5c 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -156,6 +156,7 @@ public:
String get_executable_path() const;
String read_string_from_stdin();
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
+ Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
int create_instance(const Vector<String> &p_arguments);
Error kill(int p_pid);
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 55286277fa..d2a5103953 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -47,6 +47,7 @@ thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
+ ERR_FAIL_NULL_V(create_func[p_access], nullptr);
Ref<FileAccess> ret = create_func[p_access]();
ret->_set_access_type(p_access);
@@ -75,7 +76,8 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
ret = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
ret = create(ACCESS_USERDATA);
-
+ } else if (p_path.begins_with("pipe://")) {
+ ret = create(ACCESS_PIPE);
} else {
ret = create(ACCESS_FILESYSTEM);
}
@@ -209,6 +211,9 @@ String FileAccess::fix_path(const String &p_path) const {
}
} break;
+ case ACCESS_PIPE: {
+ return r_path;
+ } break;
case ACCESS_FILESYSTEM: {
return r_path;
} break;
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 122ae3b190..0b631f68b1 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -50,6 +50,7 @@ public:
ACCESS_RESOURCES,
ACCESS_USERDATA,
ACCESS_FILESYSTEM,
+ ACCESS_PIPE,
ACCESS_MAX
};
diff --git a/core/os/os.h b/core/os/os.h
index 4f0df1543f..370e724c53 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -170,6 +170,7 @@ public:
virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return Vector<String>(); };
virtual String get_executable_path() const;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0;
+ virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) { return Dictionary(); }
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0;
virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); };
virtual Error kill(const ProcessID &p_pid) = 0;
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index ae0dc53f5d..9eb5f9e334 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -103,7 +103,7 @@
<param index="3" name="callback" type="Callable" />
<description>
Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [String] parameter which contains the text field's contents.
- [b]Note:[/b] This method is implemented only on macOS and Windows.
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_INPUT] feature. Supported platforms include macOS and Windows.
</description>
</method>
<method name="dialog_show">
@@ -114,7 +114,7 @@
<param index="3" name="callback" type="Callable" />
<description>
Shows a text dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [int] parameter which corresponds to the index of the pressed button.
- [b]Note:[/b] This method is implemented only on macOS and Windows.
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include macOS and Windows.
</description>
</method>
<method name="enable_for_stealing_focus">
@@ -138,7 +138,7 @@
Displays OS native dialog for selecting files or directories in the file system.
Each filter string in the [param filters] array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted. See also [member FileDialog.filters].
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code].
- [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
[b]Note:[/b] [param current_directory] might be ignored.
[b]Note:[/b] On Linux, [param show_hidden] is ignored.
[b]Note:[/b] On macOS, native file dialogs have no title.
@@ -164,7 +164,7 @@
- [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used.
- [code]"default"[/code] - default selected option index ([int]) or default boolean value ([bool]).
Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code].
- [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
+ [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS.
[b]Note:[/b] [param current_directory] might be ignored.
[b]Note:[/b] On Linux (X11), [param show_hidden] is ignored.
[b]Note:[/b] On macOS, native file dialogs have no title.
@@ -1784,7 +1784,7 @@
Display server supports setting the mouse cursor shape to a custom image. [b]Windows, macOS, Linux (X11/Wayland), Web[/b]
</constant>
<constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature">
- Display server supports spawning dialogs using the operating system's native look-and-feel. [b]Windows, macOS, Linux (X11/Wayland)[/b]
+ Display server supports spawning text dialogs using the operating system's native look-and-feel. See [method dialog_show]. [b]Windows, macOS[/b]
</constant>
<constant name="FEATURE_IME" value="10" enum="Feature">
Display server supports [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url], which is commonly used for inputting Chinese/Japanese/Korean text. This is handled by the operating system, rather than by Godot. [b]Windows, macOS, Linux (X11)[/b]
@@ -1825,6 +1825,12 @@
<constant name="FEATURE_NATIVE_HELP" value="23" enum="Feature">
Display server supports native help system search callbacks. See [method help_set_search_callbacks].
</constant>
+ <constant name="FEATURE_NATIVE_DIALOG_INPUT" value="24" enum="Feature">
+ Display server supports spawning text input dialogs using the operating system's native look-and-feel. See [method dialog_input_text]. [b]Windows, macOS[/b]
+ </constant>
+ <constant name="FEATURE_NATIVE_DIALOG_FILE" value="25" enum="Feature">
+ Display server supports spawning dialogs for selecting files or directories using the operating system's native look-and-feel. See [method file_dialog_show] and [method file_dialog_with_options_show]. [b]Windows, macOS, Linux (X11/Wayland)[/b]
+ </constant>
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
Makes the mouse cursor visible if it is hidden.
</constant>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index be7394a30b..bd1bd9afa7 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -50,9 +50,9 @@
<param index="1" name="arguments" type="PackedStringArray" />
<param index="2" name="open_console" type="bool" default="false" />
<description>
- Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space.
+ Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be an executable file or macOS [code].app[/code] bundle. The path is resolved based on the current platform. The [param arguments] are used in the given order and separated by a space.
On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened.
- If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise this method returns [code]-1[/code].
+ If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise, this method returns [code]-1[/code].
For example, running another instance of the project:
[codeblocks]
[gdscript]
@@ -63,7 +63,7 @@
[/csharp]
[/codeblocks]
See [method execute] if you wish to run an external command and retrieve the results.
- [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows.
[b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export or system .app bundle, system .app bundles will ignore arguments.
</description>
</method>
@@ -120,7 +120,7 @@
OS.Execute("CMD.exe", new string[] {"/C", "cd %TEMP% &amp;&amp; dir"}, output);
[/csharp]
[/codeblocks]
- [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows.
[b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [param path], [code]/c[/code] as the first argument, and the desired command as the second argument.
[b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [param path], [code]-Command[/code] as the first argument, and the desired command as the second argument.
[b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [param path], [code]-c[/code] as the first argument, and the desired command as the second argument.
@@ -128,6 +128,23 @@
[b]Note:[/b] On Android, system commands such as [code]dumpsys[/code] can only be run on a rooted device.
</description>
</method>
+ <method name="execute_with_pipe">
+ <return type="Dictionary" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="arguments" type="PackedStringArray" />
+ <description>
+ Creates a new process that runs independently of Godot with redirected IO. It will not terminate when Godot terminates. The path specified in [param path] must exist and be an executable file or macOS [code].app[/code] bundle. The path is resolved based on the current platform. The [param arguments] are used in the given order and separated by a space.
+ If the process cannot be created, this method returns an empty [Dictionary]. Otherwise, this method returns a [Dictionary] with the following keys:
+ - [code]"stdio"[/code] - [FileAccess] to access the process stdin and stdout pipes (read/write).
+ - [code]"stderr"[/code] - [FileAccess] to access the process stderr pipe (read only).
+ - [code]"pid"[/code] - Process ID as an [int], which you can use to monitor the process (and potentially terminate it with [method kill]).
+ [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows.
+ [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [param path], [code]/c[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [param path], [code]-Command[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [param path], [code]-c[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export or system .app bundle, system .app bundles will ignore arguments.
+ </description>
+ </method>
<method name="find_keycode_from_string" qualifiers="const">
<return type="int" enum="Key" />
<param index="0" name="string" type="String" />
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 4735091f20..e40d73862b 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -740,7 +740,7 @@
<param index="1" name="axis" type="int" enum="Vector3.Axis" />
<param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
<description>
- Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
+ Returns the value of a generic 6DOF joint flag. See [enum G6DOFJointAxisFlag] for the list of available flags.
</description>
</method>
<method name="generic_6dof_joint_get_param" qualifiers="const">
@@ -749,7 +749,7 @@
<param index="1" name="axis" type="int" enum="Vector3.Axis" />
<param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
<description>
- Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
+ Returns the value of a generic 6DOF joint parameter. See [enum G6DOFJointAxisParam] for the list of available parameters.
</description>
</method>
<method name="generic_6dof_joint_set_flag">
@@ -759,7 +759,7 @@
<param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
<param index="3" name="enable" type="bool" />
<description>
- Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
+ Sets the value of a given generic 6DOF joint flag. See [enum G6DOFJointAxisFlag] for the list of available flags.
</description>
</method>
<method name="generic_6dof_joint_set_param">
@@ -769,7 +769,7 @@
<param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
<param index="3" name="value" type="float" />
<description>
- Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
+ Sets the value of a given generic 6DOF joint parameter. See [enum G6DOFJointAxisParam] for the list of available parameters.
</description>
</method>
<method name="get_process_info">
@@ -876,6 +876,7 @@
<param index="3" name="body_B" type="RID" />
<param index="4" name="local_ref_B" type="Transform3D" />
<description>
+ Make the joint a generic six degrees of freedom (6DOF) joint. Use [method generic_6dof_joint_set_flag] and [method generic_6dof_joint_set_param] to set the joint's flags and parameters respectively.
</description>
</method>
<method name="joint_make_hinge">
@@ -1497,6 +1498,12 @@
<constant name="G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="G6DOFJointAxisParam">
The maximum force that the linear motor can apply while trying to reach the target velocity.
</constant>
+ <constant name="G6DOF_JOINT_LINEAR_SPRING_STIFFNESS" value="7" enum="G6DOFJointAxisParam">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_SPRING_DAMPING" value="8" enum="G6DOFJointAxisParam">
+ </constant>
+ <constant name="G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT" value="9" enum="G6DOFJointAxisParam">
+ </constant>
<constant name="G6DOF_JOINT_ANGULAR_LOWER_LIMIT" value="10" enum="G6DOFJointAxisParam">
The minimum rotation in negative direction to break loose and rotate around the axes.
</constant>
@@ -1524,18 +1531,34 @@
<constant name="G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="G6DOFJointAxisParam">
Maximum acceleration for the motor at the axes.
</constant>
+ <constant name="G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS" value="19" enum="G6DOFJointAxisParam">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_SPRING_DAMPING" value="20" enum="G6DOFJointAxisParam">
+ </constant>
+ <constant name="G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT" value="21" enum="G6DOFJointAxisParam">
+ </constant>
+ <constant name="G6DOF_JOINT_MAX" value="22" enum="G6DOFJointAxisParam">
+ Represents the size of the [enum G6DOFJointAxisParam] enum.
+ </constant>
<constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="G6DOFJointAxisFlag">
If set, linear motion is possible within the given limits.
</constant>
<constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="G6DOFJointAxisFlag">
If set, rotational motion is possible.
</constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING" value="2" enum="G6DOFJointAxisFlag">
+ </constant>
+ <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING" value="3" enum="G6DOFJointAxisFlag">
+ </constant>
<constant name="G6DOF_JOINT_FLAG_ENABLE_MOTOR" value="4" enum="G6DOFJointAxisFlag">
If set, there is a rotational motor across these axes.
</constant>
<constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="G6DOFJointAxisFlag">
If set, there is a linear motor on this axis that targets a specific velocity.
</constant>
+ <constant name="G6DOF_JOINT_FLAG_MAX" value="6" enum="G6DOFJointAxisFlag">
+ Represents the size of the [enum G6DOFJointAxisFlag] enum.
+ </constant>
<constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType">
The [Shape3D] is a [WorldBoundaryShape3D].
</constant>
diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml
index c5b86f079e..91df90580c 100644
--- a/doc/classes/TileData.xml
+++ b/doc/classes/TileData.xml
@@ -93,7 +93,7 @@
<return type="int" />
<param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
<description>
- Returns the tile's terrain bit for the given [param peering_bit] direction.
+ Returns the tile's terrain bit for the given [param peering_bit] direction. To check that a direction is valid, use [method is_valid_terrain_peering_bit].
</description>
</method>
<method name="is_collision_polygon_one_way" qualifiers="const">
@@ -104,6 +104,13 @@
Returns whether one-way collisions are enabled for the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
+ <method name="is_valid_terrain_peering_bit" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
+ <description>
+ Returns whether the given [param peering_bit] direction is valid for this tile.
+ </description>
+ </method>
<method name="remove_collision_polygon">
<return type="void" />
<param index="0" name="layer_id" type="int" />
@@ -200,7 +207,7 @@
<param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
<param index="1" name="terrain" type="int" />
<description>
- Sets the tile's terrain bit for the given [param peering_bit] direction.
+ Sets the tile's terrain bit for the given [param peering_bit] direction. To check that a direction is valid, use [method is_valid_terrain_peering_bit].
</description>
</method>
</methods>
diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp
new file mode 100644
index 0000000000..5d9a27ad05
--- /dev/null
+++ b/drivers/unix/file_access_unix_pipe.cpp
@@ -0,0 +1,185 @@
+/**************************************************************************/
+/* file_access_unix_pipe.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "file_access_unix_pipe.h"
+
+#if defined(UNIX_ENABLED)
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd) {
+ // Open pipe using handles created by pipe(fd) call in the OS.execute_with_pipe.
+ _close();
+
+ path_src = String();
+ unlink_on_close = false;
+ ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
+ fd[0] = p_rfd;
+ fd[1] = p_wfd;
+
+ last_error = OK;
+ return OK;
+}
+
+Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags) {
+ _close();
+
+ path_src = p_path;
+ ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
+
+ path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_");
+ struct stat st = {};
+ int err = stat(path.utf8().get_data(), &st);
+ if (err) {
+ if (mkfifo(path.utf8().get_data(), 0666) != 0) {
+ last_error = ERR_FILE_CANT_OPEN;
+ return last_error;
+ }
+ unlink_on_close = true;
+ } else {
+ ERR_FAIL_COND_V_MSG(!S_ISFIFO(st.st_mode), ERR_ALREADY_IN_USE, "Pipe name is already used by file.");
+ }
+
+ int f = ::open(path.utf8().get_data(), O_RDWR | O_CLOEXEC);
+ if (f < 0) {
+ switch (errno) {
+ case ENOENT: {
+ last_error = ERR_FILE_NOT_FOUND;
+ } break;
+ default: {
+ last_error = ERR_FILE_CANT_OPEN;
+ } break;
+ }
+ return last_error;
+ }
+
+ // Set close on exec to avoid leaking it to subprocesses.
+ fd[0] = f;
+ fd[1] = f;
+
+ last_error = OK;
+ return OK;
+}
+
+void FileAccessUnixPipe::_close() {
+ if (fd[0] < 0) {
+ return;
+ }
+
+ if (fd[1] != fd[0]) {
+ ::close(fd[1]);
+ }
+ ::close(fd[0]);
+ fd[0] = -1;
+ fd[1] = -1;
+
+ if (unlink_on_close) {
+ ::unlink(path.utf8().ptr());
+ }
+ unlink_on_close = false;
+}
+
+bool FileAccessUnixPipe::is_open() const {
+ return (fd[0] >= 0 || fd[1] >= 0);
+}
+
+String FileAccessUnixPipe::get_path() const {
+ return path_src;
+}
+
+String FileAccessUnixPipe::get_path_absolute() const {
+ return path_src;
+}
+
+uint8_t FileAccessUnixPipe::get_8() const {
+ ERR_FAIL_COND_V_MSG(fd[0] < 0, 0, "Pipe must be opened before use.");
+
+ uint8_t b;
+ if (::read(fd[0], &b, 1) == 0) {
+ last_error = ERR_FILE_CANT_READ;
+ b = '\0';
+ } else {
+ last_error = OK;
+ }
+ return b;
+}
+
+uint64_t FileAccessUnixPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V_MSG(fd[0] < 0, -1, "Pipe must be opened before use.");
+
+ uint64_t read = ::read(fd[0], p_dst, p_length);
+ if (read == p_length) {
+ last_error = ERR_FILE_CANT_READ;
+ } else {
+ last_error = OK;
+ }
+ return read;
+}
+
+Error FileAccessUnixPipe::get_error() const {
+ return last_error;
+}
+
+void FileAccessUnixPipe::store_8(uint8_t p_src) {
+ ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use.");
+ if (::write(fd[1], &p_src, 1) != 1) {
+ last_error = ERR_FILE_CANT_WRITE;
+ } else {
+ last_error = OK;
+ }
+}
+
+void FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) {
+ ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use.");
+ ERR_FAIL_COND(!p_src && p_length > 0);
+ if (::write(fd[1], p_src, p_length) != (ssize_t)p_length) {
+ last_error = ERR_FILE_CANT_WRITE;
+ } else {
+ last_error = OK;
+ }
+}
+
+void FileAccessUnixPipe::close() {
+ _close();
+}
+
+FileAccessUnixPipe::~FileAccessUnixPipe() {
+ _close();
+}
+
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/file_access_unix_pipe.h b/drivers/unix/file_access_unix_pipe.h
new file mode 100644
index 0000000000..d14f897d8f
--- /dev/null
+++ b/drivers/unix/file_access_unix_pipe.h
@@ -0,0 +1,96 @@
+/**************************************************************************/
+/* file_access_unix_pipe.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef FILE_ACCESS_UNIX_PIPE_H
+#define FILE_ACCESS_UNIX_PIPE_H
+
+#include "core/io/file_access.h"
+#include "core/os/memory.h"
+
+#include <stdio.h>
+
+#if defined(UNIX_ENABLED)
+
+class FileAccessUnixPipe : public FileAccess {
+ bool unlink_on_close = false;
+
+ int fd[2] = { -1, -1 };
+
+ mutable Error last_error = OK;
+ String path;
+ String path_src;
+
+ void _close();
+
+public:
+ Error open_existing(int p_rfd, int p_wfd);
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
+
+ virtual bool is_open() const override; ///< true when file is open
+
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
+
+ virtual void seek(uint64_t p_position) override {}
+ virtual void seek_end(int64_t p_position = 0) override {}
+ virtual uint64_t get_position() const override { return 0; }
+ virtual uint64_t get_length() const override { return 0; }
+
+ virtual bool eof_reached() const override { return false; }
+
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
+
+ virtual Error get_error() const override; ///< get last error
+
+ virtual void flush() override {}
+ virtual void store_8(uint8_t p_src) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
+
+ virtual bool file_exists(const String &p_path) override { return false; }
+
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return ERR_UNAVAILABLE; }
+
+ virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
+ virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
+
+ virtual void close() override;
+
+ FileAccessUnixPipe() {}
+ virtual ~FileAccessUnixPipe();
+};
+
+#endif // UNIX_ENABLED
+
+#endif // FILE_ACCESS_UNIX_PIPE_H
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 74b703b09e..597e41fd22 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -37,6 +37,7 @@
#include "core/debugger/script_debugger.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
+#include "drivers/unix/file_access_unix_pipe.h"
#include "drivers/unix/net_socket_posix.h"
#include "drivers/unix/thread_posix.h"
#include "servers/rendering_server.h"
@@ -160,6 +161,7 @@ void OS_Unix::initialize_core() {
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
+ FileAccess::make_default<FileAccessUnixPipe>(FileAccess::ACCESS_PIPE);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
@@ -489,6 +491,106 @@ Dictionary OS_Unix::get_memory_info() const {
return meminfo;
}
+Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &p_arguments) {
+#define CLEAN_PIPES \
+ if (pipe_in[0] >= 0) { \
+ ::close(pipe_in[0]); \
+ } \
+ if (pipe_in[1] >= 0) { \
+ ::close(pipe_in[1]); \
+ } \
+ if (pipe_out[0] >= 0) { \
+ ::close(pipe_out[0]); \
+ } \
+ if (pipe_out[1] >= 0) { \
+ ::close(pipe_out[1]); \
+ } \
+ if (pipe_err[0] >= 0) { \
+ ::close(pipe_err[0]); \
+ } \
+ if (pipe_err[1] >= 0) { \
+ ::close(pipe_err[1]); \
+ }
+
+ Dictionary ret;
+#ifdef __EMSCRIPTEN__
+ // Don't compile this code at all to avoid undefined references.
+ // Actual virtual call goes to OS_Web.
+ ERR_FAIL_V(ret);
+#else
+ // Create pipes.
+ int pipe_in[2] = { -1, -1 };
+ int pipe_out[2] = { -1, -1 };
+ int pipe_err[2] = { -1, -1 };
+
+ ERR_FAIL_COND_V(pipe(pipe_in) != 0, ret);
+ if (pipe(pipe_out) != 0) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ if (pipe(pipe_err) != 0) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+
+ // Create process.
+ pid_t pid = fork();
+ if (pid < 0) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+
+ if (pid == 0) {
+ // The child process.
+ Vector<CharString> cs;
+ cs.push_back(p_path.utf8());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ cs.push_back(p_arguments[i].utf8());
+ }
+
+ Vector<char *> args;
+ for (int i = 0; i < cs.size(); i++) {
+ args.push_back((char *)cs[i].get_data());
+ }
+ args.push_back(0);
+
+ ::close(STDIN_FILENO);
+ ::dup2(pipe_in[0], STDIN_FILENO);
+
+ ::close(STDOUT_FILENO);
+ ::dup2(pipe_out[1], STDOUT_FILENO);
+
+ ::close(STDERR_FILENO);
+ ::dup2(pipe_err[1], STDERR_FILENO);
+
+ CLEAN_PIPES
+
+ execvp(p_path.utf8().get_data(), &args[0]);
+ // The execvp() function only returns if an error occurs.
+ ERR_PRINT("Could not create child process: " + p_path);
+ raise(SIGKILL);
+ }
+ ::close(pipe_in[0]);
+ ::close(pipe_out[1]);
+ ::close(pipe_err[1]);
+
+ Ref<FileAccessUnixPipe> main_pipe;
+ main_pipe.instantiate();
+ main_pipe->open_existing(pipe_out[0], pipe_in[1]);
+
+ Ref<FileAccessUnixPipe> err_pipe;
+ err_pipe.instantiate();
+ err_pipe->open_existing(pipe_err[0], 0);
+
+ ret["stdio"] = main_pipe;
+ ret["stderr"] = err_pipe;
+ ret["pid"] = pid;
+
+#undef CLEAN_PIPES
+ return ret;
+#endif
+}
+
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index d3393c98ec..abbaf9b8cd 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -76,6 +76,7 @@ public:
virtual Dictionary get_memory_info() const override;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
+ virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
diff --git a/drivers/windows/file_access_windows_pipe.cpp b/drivers/windows/file_access_windows_pipe.cpp
new file mode 100644
index 0000000000..7902c8e1d8
--- /dev/null
+++ b/drivers/windows/file_access_windows_pipe.cpp
@@ -0,0 +1,159 @@
+/**************************************************************************/
+/* file_access_windows_pipe.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifdef WINDOWS_ENABLED
+
+#include "file_access_windows_pipe.h"
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+Error FileAccessWindowsPipe::open_existing(HANDLE p_rfd, HANDLE p_wfd) {
+ // Open pipe using handles created by CreatePipe(rfd, wfd, NULL, 4096) call in the OS.execute_with_pipe.
+ _close();
+
+ path_src = String();
+ ERR_FAIL_COND_V_MSG(fd[0] != 0 || fd[1] != 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
+ fd[0] = p_rfd;
+ fd[1] = p_wfd;
+
+ last_error = OK;
+ return OK;
+}
+
+Error FileAccessWindowsPipe::open_internal(const String &p_path, int p_mode_flags) {
+ _close();
+
+ path_src = p_path;
+ ERR_FAIL_COND_V_MSG(fd[0] != 0 || fd[1] != 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
+
+ path = String("\\\\.\\pipe\\LOCAL\\") + p_path.replace("pipe://", "").replace("/", "_");
+
+ HANDLE h = CreateFileW((LPCWSTR)path.utf16().get_data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ h = CreateNamedPipeW((LPCWSTR)path.utf16().get_data(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, nullptr);
+ if (h == INVALID_HANDLE_VALUE) {
+ last_error = ERR_FILE_CANT_OPEN;
+ return last_error;
+ }
+ ConnectNamedPipe(h, NULL);
+ }
+ fd[0] = h;
+ fd[1] = h;
+
+ last_error = OK;
+ return OK;
+}
+
+void FileAccessWindowsPipe::_close() {
+ if (fd[0] == 0) {
+ return;
+ }
+ if (fd[1] != fd[0]) {
+ CloseHandle(fd[1]);
+ }
+ CloseHandle(fd[0]);
+ fd[0] = 0;
+ fd[1] = 0;
+}
+
+bool FileAccessWindowsPipe::is_open() const {
+ return (fd[0] != 0 || fd[1] != 0);
+}
+
+String FileAccessWindowsPipe::get_path() const {
+ return path_src;
+}
+
+String FileAccessWindowsPipe::get_path_absolute() const {
+ return path_src;
+}
+
+uint8_t FileAccessWindowsPipe::get_8() const {
+ ERR_FAIL_COND_V_MSG(fd[0] == 0, 0, "Pipe must be opened before use.");
+
+ uint8_t b;
+ if (!ReadFile(fd[0], &b, 1, nullptr, nullptr)) {
+ last_error = ERR_FILE_CANT_READ;
+ b = '\0';
+ } else {
+ last_error = OK;
+ }
+ return b;
+}
+
+uint64_t FileAccessWindowsPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
+ ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
+ ERR_FAIL_COND_V_MSG(fd[0] == 0, -1, "Pipe must be opened before use.");
+
+ DWORD read = -1;
+ if (!ReadFile(fd[0], p_dst, p_length, &read, nullptr) || read != p_length) {
+ last_error = ERR_FILE_CANT_READ;
+ } else {
+ last_error = OK;
+ }
+ return read;
+}
+
+Error FileAccessWindowsPipe::get_error() const {
+ return last_error;
+}
+
+void FileAccessWindowsPipe::store_8(uint8_t p_src) {
+ ERR_FAIL_COND_MSG(fd[1] == 0, "Pipe must be opened before use.");
+ if (!WriteFile(fd[1], &p_src, 1, nullptr, nullptr)) {
+ last_error = ERR_FILE_CANT_WRITE;
+ } else {
+ last_error = OK;
+ }
+}
+
+void FileAccessWindowsPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) {
+ ERR_FAIL_COND_MSG(fd[1] == 0, "Pipe must be opened before use.");
+ ERR_FAIL_COND(!p_src && p_length > 0);
+
+ DWORD read = -1;
+ bool ok = WriteFile(fd[1], p_src, p_length, &read, nullptr);
+ if (!ok || read != p_length) {
+ last_error = ERR_FILE_CANT_WRITE;
+ } else {
+ last_error = OK;
+ }
+}
+
+void FileAccessWindowsPipe::close() {
+ _close();
+}
+
+FileAccessWindowsPipe::~FileAccessWindowsPipe() {
+ _close();
+}
+
+#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/file_access_windows_pipe.h b/drivers/windows/file_access_windows_pipe.h
new file mode 100644
index 0000000000..e6abe61fa3
--- /dev/null
+++ b/drivers/windows/file_access_windows_pipe.h
@@ -0,0 +1,95 @@
+/**************************************************************************/
+/* file_access_windows_pipe.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef FILE_ACCESS_WINDOWS_PIPE_H
+#define FILE_ACCESS_WINDOWS_PIPE_H
+
+#ifdef WINDOWS_ENABLED
+
+#include "core/io/file_access.h"
+#include "core/os/memory.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+class FileAccessWindowsPipe : public FileAccess {
+ HANDLE fd[2] = { 0, 0 };
+
+ mutable Error last_error = OK;
+
+ String path;
+ String path_src;
+
+ void _close();
+
+public:
+ Error open_existing(HANDLE p_rfd, HANDLE p_wfd);
+
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
+
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
+
+ virtual void seek(uint64_t p_position) override {}
+ virtual void seek_end(int64_t p_position = 0) override {}
+ virtual uint64_t get_position() const override { return 0; }
+ virtual uint64_t get_length() const override { return 0; }
+
+ virtual bool eof_reached() const override { return false; }
+
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
+
+ virtual Error get_error() const override; ///< get last error
+
+ virtual void flush() override {}
+ virtual void store_8(uint8_t p_src) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
+
+ virtual bool file_exists(const String &p_name) override { return false; }
+
+ uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return ERR_UNAVAILABLE; }
+
+ virtual bool _get_hidden_attribute(const String &p_file) override { return false; }
+ virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; }
+ virtual bool _get_read_only_attribute(const String &p_file) override { return false; }
+ virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; }
+
+ virtual void close() override;
+
+ FileAccessWindowsPipe() {}
+ virtual ~FileAccessWindowsPipe();
+};
+
+#endif // WINDOWS_ENABLED
+
+#endif // FILE_ACCESS_WINDOWS_PIPE_H
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index a178f8e3ec..8c3cad3e89 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -66,7 +66,7 @@ void DependencyEditor::_load_pressed(Object *p_item, int p_cell, int p_button, M
List<String> ext;
ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0), &ext);
for (const String &E : ext) {
- search->add_filter("*" + E);
+ search->add_filter("*." + E);
}
search->popup_file_dialog();
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index c6e122dde8..ded6fc2a35 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -3511,6 +3511,7 @@ void SceneTreeDock::_update_tree_menu() {
tree_menu->set_item_tooltip(tree_menu->get_item_index(TOOL_CENTER_PARENT), TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible."));
PopupMenu *resource_list = memnew(PopupMenu);
+ resource_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list));
resource_list->connect("index_pressed", callable_mp(this, &SceneTreeDock::_edit_subresource).bind(resource_list));
tree_menu->add_submenu_node_item(TTR("All Scene Sub-Resources"), resource_list);
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 90759810b1..c6f2f82117 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -71,6 +71,8 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const {
case FEATURE_MOUSE:
//case FEATURE_MOUSE_WARP:
//case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
+ //case FEATURE_NATIVE_DIALOG_FILE:
//case FEATURE_NATIVE_ICON:
//case FEATURE_WINDOW_TRANSPARENCY:
case FEATURE_CLIPBOARD:
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index e1c3dcd372..f84fb01ad0 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -328,6 +328,8 @@ bool DisplayServerIOS::has_feature(Feature p_feature) const {
// case FEATURE_MOUSE:
// case FEATURE_MOUSE_WARP:
// case FEATURE_NATIVE_DIALOG:
+ // case FEATURE_NATIVE_DIALOG_INPUT:
+ // case FEATURE_NATIVE_DIALOG_FILE:
// case FEATURE_NATIVE_ICON:
// case FEATURE_WINDOW_TRANSPARENCY:
case FEATURE_CLIPBOARD:
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index 80b6029c9d..d00d5deb2c 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -210,8 +210,10 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
return true;
} break;
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
#ifdef DBUS_ENABLED
- case FEATURE_NATIVE_DIALOG: {
+ case FEATURE_NATIVE_DIALOG_FILE: {
return true;
} break;
#endif
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 226e123648..9069dd423f 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -128,8 +128,10 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
//case FEATURE_HIDPI:
case FEATURE_ICON:
#ifdef DBUS_ENABLED
- case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_FILE:
#endif
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
//case FEATURE_NATIVE_ICON:
case FEATURE_SWAP_BUFFERS:
#ifdef DBUS_ENABLED
@@ -5210,7 +5212,7 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
if (g_set_icon_error) {
g_set_icon_error = false;
- WARN_PRINT("Icon too large, attempting to resize icon.");
+ WARN_PRINT(vformat("Icon too large (%dx%d), attempting to downscale icon.", w, h));
int new_width, new_height;
if (w > h) {
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 99e9d20f2b..3d26054219 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -755,6 +755,8 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const {
case FEATURE_CURSOR_SHAPE:
case FEATURE_CUSTOM_CURSOR_SHAPE:
case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_INPUT:
+ case FEATURE_NATIVE_DIALOG_FILE:
case FEATURE_IME:
case FEATURE_WINDOW_TRANSPARENCY:
case FEATURE_HIDPI:
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 281f312000..06f5eb82f7 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -1128,6 +1128,8 @@ bool DisplayServerWeb::has_feature(Feature p_feature) const {
return true;
//case FEATURE_MOUSE_WARP:
//case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
+ //case FEATURE_NATIVE_DIALOG_FILE:
//case FEATURE_NATIVE_ICON:
//case FEATURE_WINDOW_TRANSPARENCY:
//case FEATURE_KEEP_SCREEN_ON:
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index 45671ca491..4b93ce9e75 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -105,6 +105,10 @@ Error OS_Web::execute(const String &p_path, const List<String> &p_arguments, Str
return create_process(p_path, p_arguments);
}
+Dictionary OS_Web::execute_with_pipe(const String &p_path, const List<String> &p_arguments) {
+ ERR_FAIL_V_MSG(Dictionary(), "OS::execute_with_pipe is not available on the Web platform.");
+}
+
Error OS_Web::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
Array args;
for (const String &E : p_arguments) {
diff --git a/platform/web/os_web.h b/platform/web/os_web.h
index e578c93925..16f8ea8550 100644
--- a/platform/web/os_web.h
+++ b/platform/web/os_web.h
@@ -80,6 +80,7 @@ public:
bool main_loop_iterate();
Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
+ Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override;
Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
Error kill(const ProcessID &p_pid) override;
int get_process_id() const override;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 79078456a5..e540b7617f 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -114,6 +114,8 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
case FEATURE_ICON:
case FEATURE_NATIVE_ICON:
case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_INPUT:
+ case FEATURE_NATIVE_DIALOG_FILE:
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_TEXT_TO_SPEECH:
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 152b9ac10f..c39b327953 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -42,6 +42,7 @@
#include "drivers/unix/net_socket_posix.h"
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
+#include "drivers/windows/file_access_windows_pipe.h"
#include "main/main.h"
#include "servers/audio_server.h"
#include "servers/rendering/rendering_server_default.h"
@@ -178,6 +179,7 @@ void OS_Windows::initialize() {
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
+ FileAccess::make_default<FileAccessWindowsPipe>(FileAccess::ACCESS_PIPE);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
@@ -727,6 +729,105 @@ Dictionary OS_Windows::get_memory_info() const {
return meminfo;
}
+Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String> &p_arguments) {
+#define CLEAN_PIPES \
+ if (pipe_in[0] != 0) { \
+ CloseHandle(pipe_in[0]); \
+ } \
+ if (pipe_in[1] != 0) { \
+ CloseHandle(pipe_in[1]); \
+ } \
+ if (pipe_out[0] != 0) { \
+ CloseHandle(pipe_out[0]); \
+ } \
+ if (pipe_out[1] != 0) { \
+ CloseHandle(pipe_out[1]); \
+ } \
+ if (pipe_err[0] != 0) { \
+ CloseHandle(pipe_err[0]); \
+ } \
+ if (pipe_err[1] != 0) { \
+ CloseHandle(pipe_err[1]); \
+ }
+
+ Dictionary ret;
+
+ String path = p_path.replace("/", "\\");
+ String command = _quote_command_line_argument(path);
+ for (const String &E : p_arguments) {
+ command += " " + _quote_command_line_argument(E);
+ }
+
+ // Create pipes.
+ HANDLE pipe_in[2] = { 0, 0 };
+ HANDLE pipe_out[2] = { 0, 0 };
+ HANDLE pipe_err[2] = { 0, 0 };
+
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = true;
+ sa.lpSecurityDescriptor = nullptr;
+
+ ERR_FAIL_COND_V(!CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0), ret);
+ if (!SetHandleInformation(pipe_in[1], HANDLE_FLAG_INHERIT, 0)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ if (!CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ if (!SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ if (!CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ ERR_FAIL_COND_V(!SetHandleInformation(pipe_err[0], HANDLE_FLAG_INHERIT, 0), ret);
+
+ // Create process.
+ ProcessInfo pi;
+ ZeroMemory(&pi.si, sizeof(pi.si));
+ pi.si.cb = sizeof(pi.si);
+ ZeroMemory(&pi.pi, sizeof(pi.pi));
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+
+ pi.si.dwFlags |= STARTF_USESTDHANDLES;
+ pi.si.hStdInput = pipe_in[0];
+ pi.si.hStdOutput = pipe_out[1];
+ pi.si.hStdError = pipe_err[1];
+
+ DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW;
+
+ if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, nullptr, si_w, &pi.pi)) {
+ CLEAN_PIPES
+ ERR_FAIL_V_MSG(ret, "Could not create child process: " + command);
+ }
+ CloseHandle(pipe_in[0]);
+ CloseHandle(pipe_out[1]);
+ CloseHandle(pipe_err[1]);
+
+ ProcessID pid = pi.pi.dwProcessId;
+ process_map->insert(pid, pi);
+
+ Ref<FileAccessWindowsPipe> main_pipe;
+ main_pipe.instantiate();
+ main_pipe->open_existing(pipe_out[0], pipe_in[1]);
+
+ Ref<FileAccessWindowsPipe> err_pipe;
+ err_pipe.instantiate();
+ err_pipe->open_existing(pipe_err[0], 0);
+
+ ret["stdio"] = main_pipe;
+ ret["stderr"] = err_pipe;
+ ret["pid"] = pid;
+
+#undef CLEAN_PIPES
+ return ret;
+}
+
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
String path = p_path.replace("/", "\\");
String command = _quote_command_line_argument(path);
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 351cb32c9b..c703a3ddca 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -181,6 +181,7 @@ public:
virtual Dictionary get_memory_info() const override;
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override;
+ virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override;
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override;
virtual Error kill(const ProcessID &p_pid) override;
virtual int get_process_id() const override;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index c344272f38..1163c0e390 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -68,7 +68,7 @@ void FileDialog::popup(const Rect2i &p_rect) {
}
#endif
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
String root;
if (access == ACCESS_RESOURCES) {
root = ProjectSettings::get_singleton()->get_resource_path();
@@ -91,7 +91,7 @@ void FileDialog::set_visible(bool p_visible) {
}
#endif
- if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
if (p_visible) {
String root;
if (access == ACCESS_RESOURCES) {
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index 66d97398b9..6ae97944e0 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -6918,6 +6918,7 @@ void TileData::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
+ ClassDB::bind_method(D_METHOD("is_valid_terrain_peering_bit", "peering_bit"), &TileData::is_valid_terrain_peering_bit);
// Navigation
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 8e6c659565..9ceb6909fe 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -1014,6 +1014,8 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_SCREEN_CAPTURE);
BIND_ENUM_CONSTANT(FEATURE_STATUS_INDICATOR);
BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
diff --git a/servers/display_server.h b/servers/display_server.h
index 39a80ae7c1..f1a98c2c17 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -140,6 +140,8 @@ public:
FEATURE_SCREEN_CAPTURE,
FEATURE_STATUS_INDICATOR,
FEATURE_NATIVE_HELP,
+ FEATURE_NATIVE_DIALOG_INPUT,
+ FEATURE_NATIVE_DIALOG_FILE,
};
virtual bool has_feature(Feature p_feature) const = 0;
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 15d43ff5dd..f56ef11c14 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -985,6 +985,9 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING);
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY);
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_STIFFNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS);
@@ -994,11 +997,18 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_MAX);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_MAX);
ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer3D::joint_get_type);