Merge pull request #61093 from akien-mga/3.x-cherrypicks

Cherry-picks for the 3.x branch (future 3.5) - 21st batch
This commit is contained in:
Rémi Verschelde 2022-05-16 22:15:07 +02:00 committed by GitHub
commit b62ed1f005
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 549 additions and 153 deletions

View File

@ -5,7 +5,7 @@ on: [push, pull_request]
env:
GODOT_BASE_BRANCH: 3.x
SCONSFLAGS: verbose=yes warnings=all werror=yes debug_symbols=no
EM_VERSION: 2.0.25
EM_VERSION: 3.1.10
EM_CACHE_FOLDER: "emsdk-cache"
concurrency:

View File

@ -370,7 +370,7 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
const uint8_t *rofs = &p_src[((y * p_width) + x) * (read_bytes + (read_alpha ? 1 : 0))];
uint8_t *wofs = &p_dst[((y * p_width) + x) * (write_bytes + (write_alpha ? 1 : 0))];
uint8_t rgba[4];
uint8_t rgba[4] = { 0, 0, 0, 255 };
if (read_gray) {
rgba[0] = rofs[0];
@ -388,7 +388,7 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
if (write_gray) {
//TODO: not correct grayscale, should use fixed point version of actual weights
wofs[0] = uint8_t((uint16_t(rofs[0]) + uint16_t(rofs[1]) + uint16_t(rofs[2])) / 3);
wofs[0] = uint8_t((uint16_t(rgba[0]) + uint16_t(rgba[1]) + uint16_t(rgba[2])) / 3);
} else {
for (uint32_t i = 0; i < write_bytes; i++) {
wofs[i] = rgba[i];
@ -1733,12 +1733,14 @@ PoolVector<uint8_t> Image::get_data() const {
}
void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
"The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + "pixels.");
ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT,
"The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + "pixels.");
ERR_FAIL_COND_MSG(write_lock.ptr(), "Cannot create image when it is locked.");
ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum.");
ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum.");
int mm = 0;
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
@ -1755,16 +1757,32 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
}
void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const PoolVector<uint8_t> &p_data) {
ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0.");
ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + ".");
ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + ".");
ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum.");
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
"The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + " pixels.");
ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT,
"The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + " pixels.");
ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum.");
int mm;
int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0);
ERR_FAIL_COND_MSG(p_data.size() != size, "Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes.");
if (unlikely(p_data.size() != size)) {
String description_mipmaps;
if (p_use_mipmaps) {
const int num_mipmaps = get_image_required_mipmaps(p_width, p_height, p_format);
if (num_mipmaps != 1) {
description_mipmaps = vformat("with %d mipmaps", num_mipmaps);
} else {
description_mipmaps = "with 1 mipmap";
}
} else {
description_mipmaps = "without mipmaps";
}
const String description = vformat("%dx%dx%d (%s)", p_width, p_height, get_format_pixel_size(p_format), description_mipmaps);
ERR_FAIL_MSG(vformat("Expected Image data size of %s = %d bytes, got %d bytes instead.", description, size, p_data.size()));
}
height = p_height;
width = p_width;

View File

@ -271,7 +271,7 @@ static int _bsp_find_best_half_plane(const Face3 *p_faces, const Vector<int> &p_
const Face3 &f = p_faces[indices[i]];
Plane p = f.get_plane();
int num_over = 0, num_under = 0, num_spanning = 0;
int num_over = 0, num_under = 0; //num_spanning = 0;
for (int j = 0; j < ic; j++) {
if (i == j) {
@ -294,7 +294,7 @@ static int _bsp_find_best_half_plane(const Face3 *p_faces, const Vector<int> &p_
}
if (over && under) {
num_spanning++;
//num_spanning++;
} else if (over) {
num_over++;
} else {

View File

@ -394,7 +394,6 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
if (O->get().plane.is_equal_approx(f.plane)) {
//merge and delete edge and contiguous face, while repointing edges (uuugh!)
int ois = O->get().indices.size();
int merged = 0;
for (int j = 0; j < ois; j++) {
//search a
@ -409,7 +408,6 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
if (idx != a) {
f.indices.insert(i + 1, idx);
i++;
merged++;
}
Edge e2(idx, idxn);

View File

@ -261,7 +261,7 @@ String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const {
return vformat("%02d:%02d:%02d", hour, minute, second);
}
Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const {
Dictionary Time::get_datetime_dict_from_datetime_string(String p_datetime, bool p_weekday) const {
PARSE_ISO8601_STRING(Dictionary())
Dictionary dict;
dict[YEAR_KEY] = year;
@ -279,7 +279,7 @@ Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday
return dict;
}
String Time::get_datetime_string_from_dict(const Dictionary p_datetime, bool p_use_space) const {
String Time::get_datetime_string_from_datetime_dict(const Dictionary p_datetime, bool p_use_space) const {
ERR_FAIL_COND_V_MSG(p_datetime.empty(), "", "Invalid datetime Dictionary: Dictionary is empty.");
EXTRACT_FROM_DICTIONARY
VALIDATE_YMDHMS("")
@ -410,8 +410,8 @@ void Time::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time);
ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time);
ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string);
ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict);
ClassDB::bind_method(D_METHOD("get_datetime_dict_from_datetime_string", "datetime", "weekday"), &Time::get_datetime_dict_from_datetime_string);
ClassDB::bind_method(D_METHOD("get_datetime_string_from_datetime_dict", "datetime", "use_space"), &Time::get_datetime_string_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string);
ClassDB::bind_method(D_METHOD("get_offset_string_from_offset_minutes", "offset_minutes"), &Time::get_offset_string_from_offset_minutes);

View File

@ -85,8 +85,8 @@ public:
String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const;
String get_date_string_from_unix_time(int64_t p_unix_time_val) const;
String get_time_string_from_unix_time(int64_t p_unix_time_val) const;
Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const;
String get_datetime_string_from_dict(const Dictionary p_datetime, bool p_use_space = false) const;
Dictionary get_datetime_dict_from_datetime_string(String p_datetime, bool p_weekday = true) const;
String get_datetime_string_from_datetime_dict(const Dictionary p_datetime, bool p_use_space = false) const;
int64_t get_unix_time_from_datetime_dict(const Dictionary p_datetime) const;
int64_t get_unix_time_from_datetime_string(String p_datetime) const;
String get_offset_string_from_offset_minutes(int64_t p_offset_minutes) const;

View File

@ -1069,6 +1069,20 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
GLOBAL_DEF("display/window/size/width", 1024);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width", PropertyInfo(Variant::INT, "display/window/size/width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/height", 600);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/height", PropertyInfo(Variant::INT, "display/window/size/height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/resizable", true);
GLOBAL_DEF("display/window/size/borderless", false);
GLOBAL_DEF("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
GLOBAL_DEF("display/window/size/test_width", 0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_width", PropertyInfo(Variant::INT, "display/window/size/test_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/test_height", 0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_height", PropertyInfo(Variant::INT, "display/window/size/test_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater")); // 8K resolution
GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");

View File

@ -157,6 +157,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
return OK;
}
if (ch == '\n') {
line++;
break;
}
}
@ -1457,6 +1458,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
return ERR_FILE_EOF;
}
if (ch == '\n') {
line++;
break;
}
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimatedSprite" inherits="Node2D" version="3.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Sprite node that can use multiple textures for animation.
Sprite node that contains multiple textures as frames to play for animation.
</brief_description>
<description>
Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
[b]Note:[/b] You can associate a set of normal maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] suffix. For example, having 2 [SpriteFrames] resources [code]run[/code] and [code]run_normal[/code] will make it so the [code]run[/code] animation uses the normal map.
[AnimatedSprite] is similar to the [Sprite] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
[b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
<link title="2D Sprite animation">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
@ -29,7 +29,7 @@
</methods>
<members>
<member name="animation" type="String" setter="set_animation" getter="get_animation" default="&quot;default&quot;">
The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset.
The current animation from the [member frames] resource. If this value changes, the [code]frame[/code] counter is reset.
</member>
<member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
If [code]true[/code], texture will be centered.
@ -44,7 +44,7 @@
The displayed animation frame's index.
</member>
<member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames">
The [SpriteFrames] resource containing the animation(s).
The [SpriteFrames] resource containing the animation(s). Allows you the option to load, edit, clear, make unique and save the states of the [SpriteFrames] resource.
</member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )">
The texture's drawing offset.

View File

@ -159,6 +159,7 @@
<argument index="1" name="update" type="bool" default="false" />
<description>
Seeks the animation to the [code]seconds[/code] point in time (in seconds). If [code]update[/code] is [code]true[/code], the animation updates too, otherwise it updates at process time. Events between the current frame and [code]seconds[/code] are skipped.
[b]Note:[/b] Seeking to the end of the animation doesn't emit [signal animation_finished]. If you want to skip animation and emit the signal, use [method advance].
</description>
</method>
<method name="set_blend_time">

View File

@ -75,14 +75,14 @@
<return type="Vector3" />
<argument index="0" name="screen_point" type="Vector2" />
<description>
Returns a normal vector in world space, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
Returns a normal vector in world space, that is the result of projecting a point on the [Viewport] rectangle by the inverse camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
</description>
</method>
<method name="project_ray_origin" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="screen_point" type="Vector2" />
<description>
Returns a 3D position in world space, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
Returns a 3D position in world space, that is the result of projecting a point on the [Viewport] rectangle by the inverse camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
</description>
</method>
<method name="set_cull_mask_bit">

View File

@ -19,6 +19,7 @@
</member>
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
If [code]true[/code], only edges that face up, relative to [CollisionPolygon2D]'s rotation, will collide with other objects.
[b]Note:[/b] This property has no effect if this [CollisionPolygon2D] is a child of an [Area2D] node.
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the polygon at a high velocity.

View File

@ -20,6 +20,7 @@
</member>
<member name="one_way_collision" type="bool" setter="set_one_way_collision" getter="is_one_way_collision_enabled" default="false">
Sets whether this collision shape should only detect collision on one side (top or bottom).
[b]Note:[/b] This property has no effect if this [CollisionShape2D] is a child of an [Area2D] node.
</member>
<member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0">
The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the shape at a high velocity.

View File

@ -14,6 +14,9 @@
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" />
<member name="hide_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false">
If [code]true[/code], the slider is hidden.
</member>
<member name="label" type="String" setter="set_label" getter="get_label" default="&quot;&quot;">
</member>
<member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false">

View File

@ -20,6 +20,13 @@
Creates the agent.
</description>
</method>
<method name="agent_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="agent" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]agent[/code] is currently assigned to.
</description>
</method>
<method name="agent_is_map_changed" qualifiers="const">
<return type="bool" />
<argument index="0" name="agent" type="RID" />
@ -122,6 +129,13 @@
Create a new map.
</description>
</method>
<method name="map_get_agents" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
<description>
Returns all navigation agents [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_get_cell_size" qualifiers="const">
<return type="float" />
<argument index="0" name="map" type="RID" />
@ -162,6 +176,13 @@
Returns the navigation path to reach the destination from the origin.
</description>
</method>
<method name="map_get_regions" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
<description>
Returns all navigation regions [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_is_active" qualifiers="const">
<return type="bool" />
<argument index="0" name="nap" type="RID" />
@ -199,6 +220,13 @@
Creates a new region.
</description>
</method>
<method name="region_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="region" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
</description>
</method>
<method name="region_set_map" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />

View File

@ -1,10 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationMeshGenerator" inherits="Object" version="3.5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
This class is responsible for creating and clearing navigation meshes.
Helper class for creating and clearing navigation meshes.
</brief_description>
<description>
This class is responsible for creating and clearing navigation meshes.
This class is responsible for creating and clearing 3D navigation meshes used as [NavigationMesh] resources inside [NavigationMeshInstance]. The [NavigationMeshGenerator] has very limited to no use for 2D as the navigation mesh baking process expects 3D node types and 3D source geometry to parse.
The entire navigation mesh baking is best done in a separate thread as the voxelization, collision tests and mesh optimization steps involved are very performance and time hungry operations.
Navigation mesh baking happens in multiple steps and the result depends on 3D source geometry and properties of the [NavigationMesh] resource. In the first step, starting from a root node and depending on [NavigationMesh] properties all valid 3D source geometry nodes are collected from the [SceneTree]. Second, all collected nodes are parsed for their relevant 3D geometry data and a combined 3D mesh is build. Due to the many different types of parsable objects, from normal [MeshInstance]s to [CSGShape]s or various [CollisionObject]s, some operations to collect geometry data can trigger [VisualServer] and [PhysicsServer] synchronizations. Server synchronization can have a negative effect on baking time or framerate as it often involves [Mutex] locking for thread security. Many parsable objects and the continuous synchronization with other threaded Servers can increase the baking time significantly. On the other hand only a few but very large and complex objects will take some time to prepare for the Servers which can noticeably stall the next frame render. As a general rule the total amount of parsable objects and their individual size and complexity should be balanced to avoid framerate issues or very long baking times. The combined mesh is then passed to the Recast Navigation Object to test the source geometry for walkable terrain suitable to [NavigationMesh] agent properties by creating a voxel world around the meshes bounding area.
The finalized navigation mesh is then returned and stored inside the [NavigationMesh] for use as a resource inside [NavigationMeshInstance] nodes.
</description>
<tutorials>
</tutorials>
@ -14,14 +17,14 @@
<argument index="0" name="nav_mesh" type="NavigationMesh" />
<argument index="1" name="root_node" type="Node" />
<description>
Bakes the navigation mesh. This will allow you to use pathfinding with the navigation system.
Bakes navigation data to the provided [code]nav_mesh[/code] by parsing child nodes under the provided [code]root_node[/code] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry/parsed_geometry_type] and [member NavigationMesh.geometry/source_geometry_mode] properties on the [NavigationMesh] resource.
</description>
</method>
<method name="clear">
<return type="void" />
<argument index="0" name="nav_mesh" type="NavigationMesh" />
<description>
Clears the navigation mesh.
Removes all polygons and vertices from the provided [code]nav_mesh[/code] resource.
</description>
</method>
</methods>

View File

@ -13,7 +13,7 @@
<return type="void" />
<argument index="0" name="on_thread" type="bool" default="true" />
<description>
Bakes the [NavigationMesh]. If [code]on_thread[/code] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization.
Bakes the [NavigationMesh]. If [code]on_thread[/code] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization. Also, please note that baking on a separate thread is automatically disabled on operating systems that cannot use threads (such as HTML5 with threads disabled).
</description>
</method>
<method name="get_region_rid" qualifiers="const">

View File

@ -15,6 +15,12 @@
Returns the [Navigation] node that the obstacle is using for its navigation system.
</description>
</method>
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of this obstacle on the [NavigationServer].
</description>
</method>
<method name="set_navigation">
<return type="void" />
<argument index="0" name="navigation" type="Node" />

View File

@ -15,6 +15,12 @@
Returns the [Navigation2D] node that the obstacle is using for its navigation system.
</description>
</method>
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of this obstacle on the [Navigation2DServer].
</description>
</method>
<method name="set_navigation">
<return type="void" />
<argument index="0" name="navigation" type="Node" />

View File

@ -20,6 +20,13 @@
Creates the agent.
</description>
</method>
<method name="agent_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="agent" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]agent[/code] is currently assigned to.
</description>
</method>
<method name="agent_is_map_changed" qualifiers="const">
<return type="bool" />
<argument index="0" name="agent" type="RID" />
@ -122,6 +129,13 @@
Create a new map.
</description>
</method>
<method name="map_get_agents" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
<description>
Returns all navigation agents [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_get_cell_height" qualifiers="const">
<return type="float" />
<argument index="0" name="map" type="RID" />
@ -187,6 +201,13 @@
Returns the navigation path to reach the destination from the origin.
</description>
</method>
<method name="map_get_regions" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
<description>
Returns all navigation regions [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_get_up" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="map" type="RID" />
@ -264,6 +285,13 @@
Creates a new region.
</description>
</method>
<method name="region_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="region" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
</description>
</method>
<method name="region_set_map" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />

View File

@ -26,7 +26,9 @@
<argument index="1" name="with_shape" type="Shape2D" />
<argument index="2" name="shape_xform" type="Transform2D" />
<description>
Returns a list of the points where this shape touches another. If there are no collisions the list is empty.
Returns a list of contact point pairs where this shape touches another.
If there are no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
</description>
</method>
@ -50,7 +52,9 @@
<argument index="3" name="shape_xform" type="Transform2D" />
<argument index="4" name="shape_motion" type="Vector2" />
<description>
Returns a list of the points where this shape would touch another, if a given movement was applied. If there are no collisions the list is empty.
Returns a list of contact point pairs where this shape would touch another, if a given movement was applied.
If there would be no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test onto the other object ([code]shape_motion[/code]).
</description>
</method>

View File

@ -43,7 +43,7 @@
Converts the given Unix timestamp to an ISO 8601 date string (YYYY-MM-DD).
</description>
</method>
<method name="get_datetime_dict_from_string" qualifiers="const">
<method name="get_datetime_dict_from_datetime_string" qualifiers="const">
<return type="Dictionary" />
<argument index="0" name="datetime" type="String" />
<argument index="1" name="weekday" type="bool" />
@ -68,7 +68,7 @@
The returned Dictionary's values will be the same as the [method get_datetime_dict_from_system] if the Unix timestamp is the current time, with the exception of Daylight Savings Time as it cannot be determined from the epoch.
</description>
</method>
<method name="get_datetime_string_from_dict" qualifiers="const">
<method name="get_datetime_string_from_datetime_dict" qualifiers="const">
<return type="String" />
<argument index="0" name="datetime" type="Dictionary" />
<argument index="1" name="use_space" type="bool" />

View File

@ -592,7 +592,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for value in e.values.values():
f.write("- **{}** = **{}**".format(value.name, value.value))
if value.text is not None and value.text.strip() != "":
f.write(" --- " + rstize_text(value.text.strip(), state))
# If value.text contains a bullet point list, each entry needs additional indentation
f.write(" --- " + indent_bullets(rstize_text(value.text.strip(), state)))
f.write("\n\n")
@ -738,7 +739,7 @@ def rstize_text(text, state): # type: (str, State) -> str
pre_text = text[:pos]
indent_level = 0
while text[pos + 1] == "\t":
while pos + 1 < len(text) and text[pos + 1] == "\t":
pos += 1
indent_level += 1
post_text = text[pos + 1 :]
@ -1190,5 +1191,24 @@ def make_link(url, title): # type: (str, str) -> str
return "`" + url + " <" + url + ">`__"
def indent_bullets(text): # type: (str) -> str
# Take the text and check each line for a bullet point represented by "-".
# Where found, indent the given line by a further "\t".
# Used to properly indent bullet points contained in the description for enum values.
# Ignore the first line - text will be prepended to it so bullet points wouldn't work anyway.
bullet_points = "-"
lines = text.splitlines(keepends=True)
for line_index, line in enumerate(lines[1:], start=1):
pos = 0
while pos < len(line) and line[pos] == "\t":
pos += 1
if pos < len(line) and line[pos] in bullet_points:
lines[line_index] = line[:pos] + "\t" + line[pos:]
return "".join(lines)
if __name__ == "__main__":
main()

View File

@ -3228,7 +3228,7 @@ Ref<Animation> AnimationTrackEditor::get_current_animation() const {
return animation;
}
void AnimationTrackEditor::_root_removed(Node *p_root) {
void AnimationTrackEditor::_root_removed() {
root = nullptr;
}

View File

@ -376,7 +376,7 @@ class AnimationTrackEditor : public VBoxContainer {
TrackIndices _confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, Ref<Animation> p_reset_anim, bool p_create_beziers);
void _insert_delay(bool p_create_reset, bool p_create_beziers);
void _root_removed(Node *p_root);
void _root_removed();
PropertyInfo _find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val = nullptr);

View File

@ -562,6 +562,9 @@ void EditorSpinSlider::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flat", "flat"), &EditorSpinSlider::set_flat);
ClassDB::bind_method(D_METHOD("is_flat"), &EditorSpinSlider::is_flat);
ClassDB::bind_method(D_METHOD("set_hide_slider", "hide_slider"), &EditorSpinSlider::set_hide_slider);
ClassDB::bind_method(D_METHOD("is_hiding_slider"), &EditorSpinSlider::is_hiding_slider);
ClassDB::bind_method(D_METHOD("_gui_input"), &EditorSpinSlider::_gui_input);
ClassDB::bind_method(D_METHOD("_value_input_gui_input", "event"), &EditorSpinSlider::_value_input_gui_input);
ClassDB::bind_method(D_METHOD("_grabber_mouse_entered"), &EditorSpinSlider::_grabber_mouse_entered);
@ -574,6 +577,7 @@ void EditorSpinSlider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_slider"), "set_hide_slider", "is_hiding_slider");
}
EditorSpinSlider::EditorSpinSlider() {

View File

@ -2852,11 +2852,13 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
edited_theme->get_stylebox_list(edited_type, &names);
List<Ref<StyleBox>> styleboxes;
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (E->get() == leading_stylebox.item_name) {
Ref<StyleBox> sb = edited_theme->get_stylebox(E->get(), edited_type);
// Avoid itself, stylebox can be shared between items.
if (sb == leading_stylebox.stylebox) {
continue;
}
Ref<StyleBox> sb = edited_theme->get_stylebox(E->get(), edited_type);
if (sb->get_class() == leading_stylebox.stylebox->get_class()) {
styleboxes.push_back(sb);
}

View File

@ -1082,19 +1082,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Assigning here, to be sure that it appears in docs
GLOBAL_DEF("rendering/2d/options/use_nvidia_rect_flicker_workaround", false);
GLOBAL_DEF("display/window/size/width", 1024);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/width", PropertyInfo(Variant::INT, "display/window/size/width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/height", 600);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/height", PropertyInfo(Variant::INT, "display/window/size/height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/resizable", true);
GLOBAL_DEF("display/window/size/borderless", false);
GLOBAL_DEF("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
GLOBAL_DEF("display/window/size/test_width", 0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_width", PropertyInfo(Variant::INT, "display/window/size/test_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater")); // 8K resolution
GLOBAL_DEF("display/window/size/test_height", 0);
ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/test_height", PropertyInfo(Variant::INT, "display/window/size/test_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater")); // 8K resolution
if (use_custom_res) {
if (!force_res) {
video_mode.width = GLOBAL_GET("display/window/size/width");

View File

@ -68,6 +68,11 @@
height: 100%;
overflow: auto;
background-color: hsla(0, 0%, 0%, 0.5);
text-align: left;
}
.welcome-modal-title {
text-align: center;
}
.welcome-modal-content {
@ -238,7 +243,7 @@
onclick="if (event.target === this) closeWelcomeModal(false)"
>
<div class="welcome-modal-content">
<h2 id="welcome-modal-title">Important - Please read before continuing</h2>
<h2 id="welcome-modal-title" class="welcome-modal-title">Important - Please read before continuing</h2>
<div id="welcome-modal-description">
<p>
The Godot Web Editor has some limitations compared to the native version.
@ -254,9 +259,38 @@
>Web editor documentation</a> for usage instructions and limitations.
</p>
</div>
<button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
OK, don't show again
</button>
<div id="welcome-modal-description-no-cross-origin-isolation" style="display: none">
<p>
The web server does not support cross-origin isolation,
which is required for the Godot Web Editor to function.
</p>
<p>
<strong>Reasons for cross-origin isolation being disabled:</strong>
<ul>
<li id="welcome-modal-reason-not-secure">
This page is not served from a secure context (HTTPS <i>or</i> localhost).
</li>
<li>
This page may not be served with cross-origin isolation headers
(check with the developer tools' Network tab).
</li>
</ul>
</p>
<p>
If you are self-hosting the web editor,
refer to
<a
href="https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html#threads"
target="_blank"
rel="noopener"
>Exporting for the Web - Threads</a> for more information.
</p>
</div>
<div style="text-align: center">
<button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
OK, don't show again
</button>
</div>
</div>
</div>
<div id="tabs-buttons">
@ -361,7 +395,16 @@
});
}
if (localStorage.getItem("welcomeModalDismissed") !== 'true') {
if (!crossOriginIsolated) {
// Display error dialog as threading support is required for the editor.
setButtonEnabled('startButton', false);
document.getElementById("welcome-modal-description").style.display = "none";
document.getElementById("welcome-modal-description-no-cross-origin-isolation").style.display = "block";
document.getElementById("welcome-modal-dismiss").style.display = "none";
document.getElementById("welcome-modal-reason-not-secure").style.display = window.isSecureContext ? "none" : "list-item";
}
if (!crossOriginIsolated || localStorage.getItem("welcomeModalDismissed") !== 'true') {
document.getElementById("welcome-modal").style.display = "block";
document.getElementById("welcome-modal-dismiss").focus();
}

View File

@ -1,8 +1,12 @@
[Desktop Entry]
Name=Godot Engine
GenericName=Libre game engine
GenericName[el]=Ελεύθερη μηχανή παιχνιδιού
GenericName[fr]=Moteur de jeu libre
GenericName[zh_CN]=
Comment=Multi-platform 2D and 3D game engine with a feature-rich editor
Comment[el]=2D και 3D μηχανή παιχνιδιού πολλαπλών πλατφορμών με επεξεργαστή πλούσιο σε χαρακτηριστικά
Comment[fr]=Moteur de jeu 2D et 3D multiplateforme avec un éditeur riche en fonctionnalités
Comment[zh_CN]= 2D 3D
Exec=godot %f
Icon=godot

View File

@ -1387,13 +1387,13 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure B has points either side of or in the plane of A.
int in_plane_count = 0, over_count = 0, under_count = 0;
int over_count = 0, under_count = 0;
Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]);
ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face.");
for (int i = 0; i < 3; i++) {
if (plane_a.has_point(vertices_b[i])) {
in_plane_count++;
// In plane.
} else if (plane_a.is_point_over(vertices_b[i])) {
over_count++;
} else {
@ -1406,7 +1406,6 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure A has points either side of or in the plane of B.
in_plane_count = 0;
over_count = 0;
under_count = 0;
Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]);
@ -1414,7 +1413,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
for (int i = 0; i < 3; i++) {
if (plane_b.has_point(vertices_a[i])) {
in_plane_count++;
// In plane.
} else if (plane_b.is_point_over(vertices_a[i])) {
over_count++;
} else {

View File

@ -852,26 +852,24 @@
<method name="range" qualifiers="vararg">
<return type="Array" />
<description>
Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run.
Returns an array with the given range. [method range] can be called in three ways:
[code]range(n: int)[/code]: Starts from 0, increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The argument [code]n[/code] is [b]exclusive[/b].
[code]range(b: int, n: int)[/code]: Starts from [code]b[/code], increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively.
[code]range(b: int, n: int, s: int)[/code]: Starts from [code]b[/code], increases/decreases by steps of [code]s[/code], and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. The argument [code]s[/code] [b]can[/b] be negative, but not [code]0[/code]. If [code]s[/code] is [code]0[/code], an error message is printed.
[method range] converts all arguments to [int] before processing.
[b]Note:[/b] Returns an empty array if no value meets the value constraint (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
Examples:
[codeblock]
print(range(4))
print(range(2, 5))
print(range(0, 6, 2))
[/codeblock]
Output:
[codeblock]
[0, 1, 2, 3]
[2, 3, 4]
[0, 2, 4]
print(range(4)) # Prints [0, 1, 2, 3]
print(range(2, 5)) # Prints [2, 3, 4]
print(range(0, 6, 2)) # Prints [0, 2, 4]
print(range(4, 1, -1)) # Prints [4, 3, 2]
[/codeblock]
To iterate over an [Array] backwards, use:
[codeblock]
var array = [3, 6, 9]
var i := array.size() - 1
while i &gt;= 0:
print(array[i])
i -= 1
for i in range(array.size(), 0, -1):
print(array[i - 1])
[/codeblock]
Output:
[codeblock]

View File

@ -1316,7 +1316,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level, int p_break_addr, int p_continue_addr) {
codegen.push_stack_identifiers();
int new_identifiers = 0;
codegen.current_line = p_block->line;
for (int i = 0; i < p_block->statements.size(); i++) {
@ -1347,7 +1346,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
// copied because there is no _parse_statement :(
codegen.add_stack_identifier(id->name, p_stack_level++);
codegen.alloc_stack(p_stack_level);
new_identifiers++;
GDScriptParser::OperatorNode *op = memnew(GDScriptParser::OperatorNode);
op->op = GDScriptParser::OperatorNode::OP_ASSIGN;
@ -1605,8 +1603,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
codegen.add_stack_identifier(lv->name, p_stack_level++);
codegen.alloc_stack(p_stack_level);
new_identifiers++;
} break;
default: {
//expression

View File

@ -938,6 +938,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
}
update_palette();
_update_cursor_instance();
set_process(true);

View File

@ -63,6 +63,7 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
if (UsingMonoMsBuildOnWindows)
{

View File

@ -174,7 +174,8 @@ namespace GodotTools.Utils
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
UseShellExecute = false,
CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))

View File

@ -250,6 +250,38 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3
return map->get_closest_point_owner(p_point);
}
Array GodotNavigationServer::map_get_regions(RID p_map) const {
Array regions_rids;
const NavMap *map = map_owner.getornull(p_map);
ERR_FAIL_COND_V(map == nullptr, regions_rids);
for (NavRegion *region : map->get_regions()) {
regions_rids.push_back(region->get_self());
}
return regions_rids;
}
Array GodotNavigationServer::map_get_agents(RID p_map) const {
Array agents_rids;
const NavMap *map = map_owner.getornull(p_map);
ERR_FAIL_COND_V(map == nullptr, agents_rids);
for (RvoAgent *agent : map->get_agents()) {
agents_rids.push_back(agent->get_self());
}
return agents_rids;
}
RID GodotNavigationServer::region_get_map(RID p_region) const {
NavRegion *region = region_owner.getornull(p_region);
ERR_FAIL_COND_V(region == nullptr, RID());
return region->get_map()->get_self();
}
RID GodotNavigationServer::agent_get_map(RID p_agent) const {
RvoAgent *agent = agent_owner.getornull(p_agent);
ERR_FAIL_COND_V(agent == nullptr, RID());
return agent->get_map()->get_self();
}
RID GodotNavigationServer::region_create() const {
auto mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);

View File

@ -108,14 +108,19 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const;
virtual Array map_get_regions(RID p_map) const;
virtual Array map_get_agents(RID p_map) const;
virtual RID region_create() const;
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
virtual RID region_get_map(RID p_region) const;
COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
virtual RID agent_create() const;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
virtual RID agent_get_map(RID p_agent) const;
COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist);
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count);
COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time);

View File

@ -447,7 +447,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size());
cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size());
cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly();
cfg.detailSampleDist = p_nav_mesh->get_detail_sample_distance() < 0.9f ? 0 : p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance();
cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
cfg.bmin[0] = bmin[0];
@ -463,6 +463,14 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
#endif
rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
// ~30000000 seems to be around sweetspot where Editor baking breaks
if ((cfg.width * cfg.height) > 30000000) {
WARN_PRINT("NavigationMesh baking process will likely fail."
"\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings."
"\nIf baking does not fail, the resulting NavigationMesh will create serious pathfinding performance issues."
"\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry.");
}
#ifdef TOOLS_ENABLED
if (ep)
ep->step(TTR("Creating heightfield..."), 3);

View File

@ -193,8 +193,11 @@ def configure(env):
if env["target"].startswith("release"):
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(LINKFLAGS=["-O2"])
env.Append(CCFLAGS=["-O2", "-fomit-frame-pointer"])
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
env.Append(LINKFLAGS=[opt])
env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])

View File

@ -51,8 +51,11 @@ def configure(env):
if env["target"].startswith("release"):
env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)])
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["-O2", "-ftree-vectorize", "-fomit-frame-pointer"])
env.Append(LINKFLAGS=["-O2"])
# `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
# when using `target=release_debug`.
opt = "-O3" if env["target"] == "release" else "-O2"
env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"])
env.Append(LINKFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(LINKFLAGS=["-Os"])

View File

@ -2312,6 +2312,10 @@ void OS_Windows::_update_window_style(bool p_repaint, bool p_maximized) {
}
}
if (icon.is_valid()) {
set_icon(icon);
}
SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
if (p_repaint) {
@ -2799,6 +2803,31 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const {
return p_text;
}
static void _append_to_pipe(char *p_bytes, int p_size, String *r_pipe, Mutex *p_pipe_mutex) {
// Try to convert from default ANSI code page to Unicode.
LocalVector<wchar_t> wchars;
int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0);
if (total_wchars > 0) {
wchars.resize(total_wchars);
if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) {
wchars.clear();
}
}
if (p_pipe_mutex) {
p_pipe_mutex->lock();
}
if (wchars.empty()) {
// Let's hope it's compatible with UTF-8.
(*r_pipe) += String::utf8(p_bytes, p_size);
} else {
(*r_pipe) += String(wchars.ptr(), total_wchars);
}
if (p_pipe_mutex) {
p_pipe_mutex->unlock();
}
}
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
String path = p_path.replace("/", "\\");
@ -2857,21 +2886,44 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
if (p_blocking) {
if (r_pipe) {
CloseHandle(pipe[1]); // Close pipe write handle (only child process is writing).
char buf[4096];
LocalVector<char> bytes;
int bytes_in_buffer = 0;
const int CHUNK_SIZE = 4096;
DWORD read = 0;
for (;;) { // Read StdOut and StdErr from pipe.
bool success = ReadFile(pipe[0], buf, 4096, &read, NULL);
bytes.resize(bytes_in_buffer + CHUNK_SIZE);
const bool success = ReadFile(pipe[0], bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL);
if (!success || read == 0) {
break;
}
if (p_pipe_mutex) {
p_pipe_mutex->lock();
// Assume that all possible encodings are ASCII-compatible.
// Break at newline to allow receiving long output in portions.
int newline_index = -1;
for (int i = read - 1; i >= 0; i--) {
if (bytes[bytes_in_buffer + i] == '\n') {
newline_index = i;
break;
}
}
(*r_pipe) += String::utf8(buf, read);
if (p_pipe_mutex) {
p_pipe_mutex->unlock();
if (newline_index == -1) {
bytes_in_buffer += read;
continue;
}
};
const int bytes_to_convert = bytes_in_buffer + (newline_index + 1);
_append_to_pipe(bytes.ptr(), bytes_to_convert, r_pipe, p_pipe_mutex);
bytes_in_buffer = read - (newline_index + 1);
memmove(bytes.ptr(), bytes.ptr() + bytes_to_convert, bytes_in_buffer);
}
if (bytes_in_buffer > 0) {
_append_to_pipe(bytes.ptr(), bytes_in_buffer, r_pipe, p_pipe_mutex);
}
CloseHandle(pipe[0]); // Close pipe read handle.
} else {
WaitForSingleObject(pi.pi.hProcess, INFINITE);
@ -2893,7 +2945,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
process_map->insert(pid, pi);
}
return OK;
};
}
Error OS_Windows::kill(const ProcessID &p_pid) {
ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED);
@ -3040,9 +3092,12 @@ void OS_Windows::set_native_icon(const String &p_filename) {
void OS_Windows::set_icon(const Ref<Image> &p_icon) {
ERR_FAIL_COND(!p_icon.is_valid());
Ref<Image> icon = p_icon->duplicate();
if (icon->get_format() != Image::FORMAT_RGBA8)
icon->convert(Image::FORMAT_RGBA8);
if (icon != p_icon) {
icon = p_icon->duplicate();
if (icon->get_format() != Image::FORMAT_RGBA8) {
icon->convert(Image::FORMAT_RGBA8);
}
}
int w = icon->get_width();
int h = icon->get_height();

View File

@ -318,6 +318,8 @@ class OS_Windows : public OS {
uint32_t move_timer_id;
Ref<Image> icon;
HCURSOR hCursor;
Size2 min_size;

View File

@ -599,6 +599,7 @@ void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards)
}
}
is_over = false;
set_playing(true);
}

View File

@ -32,6 +32,7 @@
#include "collision_object_2d.h"
#include "core/engine.h"
#include "scene/2d/area_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
@ -273,6 +274,9 @@ String CollisionPolygon2D::get_configuration_warning() const {
warning += TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode.");
}
}
if (one_way_collision && Object::cast_to<Area2D>(get_parent())) {
warning += TTR("The One Way Collision property will be ignored when the parent is an Area2D.");
}
return warning;
}
@ -295,6 +299,7 @@ void CollisionPolygon2D::set_one_way_collision(bool p_enable) {
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
update_configuration_warning();
}
bool CollisionPolygon2D::is_one_way_collision_enabled() const {

View File

@ -32,6 +32,7 @@
#include "collision_object_2d.h"
#include "core/engine.h"
#include "scene/2d/area_2d.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
@ -204,6 +205,9 @@ String CollisionShape2D::get_configuration_warning() const {
warning += TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.");
}
}
if (one_way_collision && Object::cast_to<Area2D>(get_parent())) {
warning += TTR("The One Way Collision property will be ignored when the parent is an Area2D.");
}
return warning;
}
@ -226,6 +230,7 @@ void CollisionShape2D::set_one_way_collision(bool p_enable) {
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
update_configuration_warning();
}
bool CollisionShape2D::is_one_way_collision_enabled() const {

View File

@ -36,8 +36,11 @@
#include "servers/navigation_2d_server.h"
void NavigationObstacle2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid);
ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle2D::set_navigation_node);
ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle2D::get_navigation_node);
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius);
@ -92,7 +95,7 @@ void NavigationObstacle2D::_notification(int p_what) {
parent_node2d = nullptr;
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (parent_node2d) {
if (parent_node2d && parent_node2d->is_inside_tree()) {
Navigation2DServer::get_singleton()->agent_set_position(agent, parent_node2d->get_global_transform().get_origin());
}
@ -136,6 +139,11 @@ String NavigationObstacle2D::get_configuration_warning() const {
return TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
}
if (Object::cast_to<StaticBody2D>(get_parent())) {
return TTR("The NavigationObstacle2D is intended for constantly moving bodies like KinematicBody2D or RigidBody2D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
"\nNot constantly moving or complete static objects should be captured with a refreshed NavigationPolygon so agents can not only avoid them but also move along those objects outline at high detail");
}
return String();
}
@ -155,13 +163,13 @@ void NavigationObstacle2D::reevaluate_agent_radius() {
}
real_t NavigationObstacle2D::estimate_agent_radius() const {
if (parent_node2d) {
if (parent_node2d && parent_node2d->is_inside_tree()) {
// Estimate the radius of this physics body
real_t radius = 0.0;
for (int i(0); i < parent_node2d->get_child_count(); i++) {
// For each collision shape
CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(parent_node2d->get_child(i));
if (cs) {
if (cs && cs->is_inside_tree()) {
// Take the distance between the Body center to the shape center
real_t r = cs->get_transform().get_origin().length();
if (cs->get_shape().is_valid()) {
@ -172,6 +180,9 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
r *= MAX(s.x, s.y);
// Takes the biggest radius
radius = MAX(radius, r);
} else if (cs && !cs->is_inside_tree()) {
WARN_PRINT("A CollisionShape2D of the NavigationObstacle2D parent node was not inside the SceneTree when estimating the obstacle radius."
"\nMove the NavigationObstacle2D to a child position below any CollisionShape2D node of the parent node so the CollisionShape2D is already inside the SceneTree.");
}
}
Vector2 s = parent_node2d->get_global_transform().get_scale();

View File

@ -30,6 +30,7 @@
#include "navigation_mesh_instance.h"
#include "core/os/os.h"
#include "core/os/thread.h"
#include "mesh_instance.h"
#include "navigation.h"
@ -178,7 +179,12 @@ void NavigationMeshInstance::bake_navigation_mesh(bool p_on_thread) {
BakeThreadsArgs *args = memnew(BakeThreadsArgs);
args->nav_region = this;
if (p_on_thread) {
if (p_on_thread && !OS::get_singleton()->can_use_threads()) {
WARN_PRINT("NavigationMesh bake 'on_thread' will be disabled as the current OS does not support multiple threads."
"\nAs a fallback the navigation mesh will bake on the main thread which can cause framerate issues.");
}
if (p_on_thread && OS::get_singleton()->can_use_threads()) {
bake_thread.start(_bake_navigation_mesh, args);
} else {
_bake_navigation_mesh(args);

View File

@ -36,6 +36,8 @@
#include "servers/navigation_server.h"
void NavigationObstacle::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle::get_rid);
ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle::set_navigation_node);
ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle::get_navigation_node);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle::is_radius_estimated);
@ -92,7 +94,7 @@ void NavigationObstacle::_notification(int p_what) {
parent_spatial = nullptr;
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (parent_spatial) {
if (parent_spatial && parent_spatial->is_inside_tree()) {
NavigationServer::get_singleton()->agent_set_position(agent, parent_spatial->get_global_transform().origin);
}
@ -140,7 +142,12 @@ Node *NavigationObstacle::get_navigation_node() const {
String NavigationObstacle::get_configuration_warning() const {
if (!Object::cast_to<Spatial>(get_parent())) {
return TTR("The NavigationObstacle only serves to provide collision avoidance to a spatial object.");
return TTR("The NavigationObstacle only serves to provide collision avoidance to a Spatial inheriting parent object.");
}
if (Object::cast_to<StaticBody>(get_parent())) {
return TTR("The NavigationObstacle is intended for constantly moving bodies like KinematicBody3D or RigidBody3D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
"\nNot constantly moving or complete static objects should be (re)baked to a NavigationMesh so agents can not only avoid them but also move along those objects outline at high detail");
}
return String();
@ -162,13 +169,13 @@ void NavigationObstacle::reevaluate_agent_radius() {
}
real_t NavigationObstacle::estimate_agent_radius() const {
if (parent_spatial) {
if (parent_spatial && parent_spatial->is_inside_tree()) {
// Estimate the radius of this physics body
real_t radius = 0.0;
for (int i(0); i < parent_spatial->get_child_count(); i++) {
// For each collision shape
CollisionShape *cs = Object::cast_to<CollisionShape>(parent_spatial->get_child(i));
if (cs) {
if (cs && cs->is_inside_tree()) {
// Take the distance between the Body center to the shape center
real_t r = cs->get_transform().origin.length();
if (cs->get_shape().is_valid()) {
@ -179,6 +186,9 @@ real_t NavigationObstacle::estimate_agent_radius() const {
r *= MAX(s.x, MAX(s.y, s.z));
// Takes the biggest radius
radius = MAX(radius, r);
} else if (cs && !cs->is_inside_tree()) {
WARN_PRINT("A CollisionShape of the NavigationObstacle parent node was not inside the SceneTree when estimating the obstacle radius."
"\nMove the NavigationObstacle to a child position below any CollisionShape node of the parent node so the CollisionShape is already inside the SceneTree.");
}
}
Vector3 s = parent_spatial->get_global_transform().basis.get_scale();

View File

@ -854,8 +854,6 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
float distance_adv = _get_normal_advance(light_axis);
int success_count = 0;
Vector3 light_energy = Vector3(p_color.r, p_color.g, p_color.b) * p_energy * p_indirect_energy;
int idx = first_leaf;
@ -916,7 +914,6 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
light->direct_accum[i][2] += light_energy.z * s;
}
}
success_count++;
}
idx = light_data[idx].next_leaf;

View File

@ -332,7 +332,7 @@ bool SceneTreeTween::can_process(bool p_tree_paused) const {
if (is_bound && pause_mode == TWEEN_PAUSE_BOUND) {
Node *bound_node = get_bound_node();
if (bound_node) {
return bound_node->can_process();
return bound_node->is_inside_tree() && bound_node->can_process();
}
}

View File

@ -199,7 +199,8 @@ void Button::_notification(int p_what) {
if (expand_icon) {
Size2 _size = get_size() - style->get_offset() * 2;
_size.width -= get_constant("hseparation") + icon_ofs_region;
int icon_text_separation = text.empty() ? 0 : get_constant("h_separation");
_size.width -= icon_text_separation + icon_ofs_region;
if (!clip_text && icon_align != ALIGN_CENTER) {
_size.width -= get_font("font")->get_string_size(xl_text).width;
}

View File

@ -142,12 +142,45 @@ void GridContainer::_notification(int p_what) {
}
// Finally, fit the nodes.
int col_expand = col_expanded.size() > 0 ? remaining_space.width / col_expanded.size() : 0;
int row_expand = row_expanded.size() > 0 ? remaining_space.height / row_expanded.size() : 0;
int col_remaining_pixel = 0;
int col_expand = 0;
if (col_expanded.size() > 0) {
col_expand = remaining_space.width / col_expanded.size();
col_remaining_pixel = remaining_space.width - col_expanded.size() * col_expand;
}
int row_remaining_pixel = 0;
int row_expand = 0;
if (row_expanded.size() > 0) {
row_expand = remaining_space.height / row_expanded.size();
row_remaining_pixel = remaining_space.height - row_expanded.size() * row_expand;
}
int col_ofs = 0;
int row_ofs = 0;
// Calculate the index of rows and columns that receive the remaining pixel.
int col_remaining_pixel_index = 0;
for (int i = 0; i < max_col; i++) {
if (col_remaining_pixel == 0) {
break;
}
if (col_expanded.has(i)) {
col_remaining_pixel_index = i + 1;
col_remaining_pixel--;
}
}
int row_remaining_pixel_index = 0;
for (int i = 0; i < max_row; i++) {
if (row_remaining_pixel == 0) {
break;
}
if (row_expanded.has(i)) {
row_remaining_pixel_index = i + 1;
row_remaining_pixel--;
}
}
valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@ -162,14 +195,26 @@ void GridContainer::_notification(int p_what) {
col_ofs = 0;
if (row > 0) {
row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep;
if (row_expanded.has(row - 1) && row - 1 < row_remaining_pixel_index) {
// Apply the remaining pixel of the previous row.
row_ofs++;
}
}
}
Point2 p(col_ofs, row_ofs);
Size2 s(col_expanded.has(col) ? col_expand : col_minw[col], row_expanded.has(row) ? row_expand : row_minh[row]);
fit_child_in_rect(c, Rect2(p, s));
// Add the remaining pixel to the expanding columns and rows, starting from left and top.
if (col_expanded.has(col) && col < col_remaining_pixel_index) {
s.x++;
}
if (row_expanded.has(row) && row < row_remaining_pixel_index) {
s.y++;
}
Point2 p(col_ofs, row_ofs);
fit_child_in_rect(c, Rect2(p, s));
col_ofs += s.width + hsep;
}

View File

@ -223,7 +223,7 @@ float NavigationMesh::get_verts_per_poly() const {
}
void NavigationMesh::set_detail_sample_distance(float p_value) {
ERR_FAIL_COND(p_value < 0);
ERR_FAIL_COND(p_value < 0.1);
detail_sample_distance = p_value;
}
@ -494,7 +494,7 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles");

View File

@ -114,6 +114,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
const NodeData &n = nd[i];
Node *parent = nullptr;
String old_parent_path;
if (i > 0) {
ERR_FAIL_COND_V_MSG(n.parent == -1, nullptr, vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]));
@ -121,6 +122,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
#ifdef DEBUG_ENABLED
if (!nparent && (n.parent & FLAG_ID_IS_PATH)) {
WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instancing: '" + get_path() + "'.").ascii().get_data());
old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace("/", "@");
nparent = ret_nodes[0];
}
#endif
parent = nparent;
@ -305,6 +308,10 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
}
if (!old_parent_path.empty()) {
node->_set_name_nocheck(old_parent_path + "@" + node->get_name());
}
if (n.owner >= 0) {
NODE_FROM_ID(owner, n.owner);
if (owner) {

View File

@ -137,7 +137,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
Edge ignore_to_edge(-1, -1);
if (!_is_point_inside(from)) {
float closest_dist = 1e20;
float closest_dist = 1e20f;
Vector2 closest_point;
for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
@ -161,7 +161,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
};
if (!_is_point_inside(to)) {
float closest_dist = 1e20;
float closest_dist = 1e20f;
Vector2 closest_point;
for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
@ -489,7 +489,7 @@ bool PolygonPathFinder::is_point_inside(const Vector2 &p_point) const {
}
Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
float closest_dist = 1e20;
float closest_dist = 1e20f;
Vector2 closest_point;
for (Set<Edge>::Element *E = edges.front(); E; E = E->next()) {
@ -508,7 +508,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
}
}
ERR_FAIL_COND_V(closest_dist == 1e20, Vector2());
ERR_FAIL_COND_V(Math::is_equal_approx(closest_dist, 1e20f), Vector2());
return closest_point;
}

View File

@ -179,7 +179,15 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
list.sort();
String prev_type;
for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
// Add groups for types so that their names are left unchanged in the inspector.
String current_type = E->get().name.get_slice("/", 0);
if (prev_type != current_type) {
p_list->push_back(PropertyInfo(Variant::NIL, current_type, PROPERTY_HINT_NONE, current_type + "/", PROPERTY_USAGE_GROUP));
prev_type = current_type;
}
p_list->push_back(E->get());
}
}

View File

@ -142,13 +142,18 @@ void Navigation2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &Navigation2DServer::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &Navigation2DServer::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &Navigation2DServer::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &Navigation2DServer::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &Navigation2DServer::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &Navigation2DServer::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &Navigation2DServer::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &Navigation2DServer::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navpoly", "region", "nav_poly"), &Navigation2DServer::region_set_navpoly);
ClassDB::bind_method(D_METHOD("agent_create"), &Navigation2DServer::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &Navigation2DServer::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &Navigation2DServer::agent_get_map);
ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &Navigation2DServer::agent_set_neighbor_dist);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &Navigation2DServer::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &Navigation2DServer::agent_set_time_horizon);
@ -171,6 +176,14 @@ Navigation2DServer::~Navigation2DServer() {
singleton = nullptr;
}
Array FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
Array FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
RID FORWARD_1_C(region_get_map, RID, p_region, rid_to_rid);
RID FORWARD_1_C(agent_get_map, RID, p_agent, rid_to_rid);
RID FORWARD_0_C(map_create);
void FORWARD_2_C(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to_bool);

View File

@ -82,11 +82,15 @@ public:
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
virtual Array map_get_regions(RID p_map) const;
virtual Array map_get_agents(RID p_map) const;
/// Creates a new region.
virtual RID region_create() const;
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
virtual RID region_get_map(RID p_region) const;
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform2D p_transform) const;
@ -99,6 +103,7 @@ public:
/// Put the agent in the map.
virtual void agent_set_map(RID p_agent, RID p_map) const;
virtual RID agent_get_map(RID p_agent) const;
/// The maximum distance (center point to
/// center point) to other agents this agent

View File

@ -54,14 +54,19 @@ void NavigationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer::map_get_closest_point_normal);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer::region_create);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer::region_set_transform);
ClassDB::bind_method(D_METHOD("region_set_navmesh", "region", "nav_mesh"), &NavigationServer::region_set_navmesh);
ClassDB::bind_method(D_METHOD("region_bake_navmesh", "mesh", "node"), &NavigationServer::region_bake_navmesh);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer::agent_get_map);
ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer::agent_set_neighbor_dist);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer::agent_set_time_horizon);

View File

@ -101,11 +101,15 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0;
virtual Array map_get_regions(RID p_map) const = 0;
virtual Array map_get_agents(RID p_map) const = 0;
/// Creates a new region.
virtual RID region_create() const = 0;
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
virtual RID region_get_map(RID p_region) const = 0;
/// Set the global transformation of this region.
virtual void region_set_transform(RID p_region, Transform p_transform) const = 0;
@ -121,6 +125,7 @@ public:
/// Put the agent in the map.
virtual void agent_set_map(RID p_agent, RID p_map) const = 0;
virtual RID agent_get_map(RID p_agent) const = 0;
/// The maximum distance (center point to
/// center point) to other agents this agent

View File

@ -526,7 +526,6 @@ int PortalRoomsBSP::evaluate_room_split_plane(int p_room_a_id, int p_room_b_id,
int PortalRoomsBSP::evaluate_plane(const VSPortal *p_portal, const Plane &p_plane, const LocalVector<int32_t, int32_t> &p_room_ids, LocalVector<int32_t, int32_t> *r_room_ids_back, LocalVector<int32_t, int32_t> *r_room_ids_front) {
int rooms_front = 0;
int rooms_back = 0;
int rooms_split = 0;
if (r_room_ids_back) {
DEV_ASSERT(!r_room_ids_back->size());
@ -622,8 +621,6 @@ int PortalRoomsBSP::evaluate_plane(const VSPortal *p_portal, const Plane &p_plan
if (r_room_ids_back) {
r_room_ids_back->push_back(rid);
}
rooms_split++;
}
#undef GODOT_BSP_PUSH_BACK

View File

@ -3750,10 +3750,6 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
float distance_adv = _get_normal_advance(light_axis);
int success_count = 0;
// uint64_t us = OS::get_singleton()->get_ticks_usec();
for (int i = 0; i < p_leaf_count; i++) {
uint32_t idx = leaves[i];
@ -3802,18 +3798,11 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
light->energy[0] += int32_t(light_r * att * ((cell->albedo >> 16) & 0xFF) / 255.0);
light->energy[1] += int32_t(light_g * att * ((cell->albedo >> 8) & 0xFF) / 255.0);
light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
success_count++;
}
}
// print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
// print_line("valid cells: " + itos(success_count));
} break;
case VS::LIGHT_OMNI:
case VS::LIGHT_SPOT: {
// uint64_t us = OS::get_singleton()->get_ticks_usec();
Vector3 light_pos = light_cache.transform.origin;
Vector3 spot_axis = -light_cache.transform.basis.get_axis(2).normalized();
@ -3911,7 +3900,6 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0);
}
}
//print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0));
} break;
}
}

View File

@ -107,8 +107,6 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
if (!p_viewport->hide_canvas) {
int i = 0;
Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map;
Rect2 clip_rect(0, 0, p_viewport->size.x, p_viewport->size.y);
@ -117,8 +115,6 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
RasterizerCanvas::Light *lights_with_mask = nullptr;
Rect2 shadow_rect;
int light_count = 0;
for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get().canvas);
@ -164,8 +160,6 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
cl->mask_next_ptr = lights_with_mask;
lights_with_mask = cl;
}
light_count++;
}
VSG::canvas_render->light_internal_update(cl->light_internal, cl);
@ -235,7 +229,6 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect, canvas_layer_id);
i++;
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
if (!can_draw_3d) {

View File

@ -233,9 +233,9 @@ struct btSparseSdf
//int sz = sizeof(Cell);
if (ncells > m_clampCells)
{
static int numResets = 0;
numResets++;
// printf("numResets=%d\n",numResets);
//static int numResets = 0;
//numResets++;
//printf("numResets=%d\n",numResets);
Reset();
}

View File

@ -0,0 +1,17 @@
diff --git a/thirdparty/bullet/BulletSoftBody/btSparseSDF.h b/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
index ae1288d9e6..243b80f8ae 100644
--- a/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
+++ b/thirdparty/bullet/BulletSoftBody/btSparseSDF.h
@@ -233,9 +233,9 @@ struct btSparseSdf
//int sz = sizeof(Cell);
if (ncells > m_clampCells)
{
- static int numResets = 0;
- numResets++;
- // printf("numResets=%d\n",numResets);
+ //static int numResets = 0;
+ //numResets++;
+ //printf("numResets=%d\n",numResets);
Reset();
}