summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/project_settings.cpp2
-rw-r--r--doc/classes/Environment.xml6
-rw-r--r--doc/classes/Popup.xml2
-rw-r--r--doc/classes/ViewportContainer.xml3
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp9
-rw-r--r--editor/editor_help_search.cpp6
-rw-r--r--editor/editor_help_search.h1
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/editor_profiler.cpp3
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp3
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp18
-rw-r--r--editor/plugins/script_editor_plugin.cpp37
-rw-r--r--main/main.cpp3
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml3
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp81
-rw-r--r--modules/enet/networked_multiplayer_enet.h3
-rw-r--r--modules/gdnative/videodecoder/video_stream_gdnative.cpp10
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml20
-rw-r--r--modules/gridmap/grid_map.cpp25
-rw-r--r--modules/gridmap/grid_map.h5
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp4
-rw-r--r--scene/gui/item_list.cpp6
-rw-r--r--scene/gui/range.cpp2
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/text_edit.cpp2
-rwxr-xr-xscene/main/timer.cpp2
-rw-r--r--scene/resources/environment.cpp4
-rw-r--r--scene/resources/material.h2
-rw-r--r--servers/visual/visual_server_canvas.cpp20
30 files changed, 176 insertions, 114 deletions
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index ba5cdd782f..067578e354 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -107,7 +107,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
if (plocal == "") {
return "";
};
- return plocal + path.substr((sep + 1), path.size() - (sep + 1));
+ return plocal + path.substr(sep, path.size() - sep);
};
}
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 2b44eb81b1..0d64f0ff64 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -96,13 +96,13 @@
[Sky] resource's custom field of view.
</member>
<member name="background_sky_orientation" type="Basis" setter="set_sky_orientation" getter="get_sky_orientation" default="Basis( 1, 0, 0, 0, 1, 0, 0, 0, 1 )">
- [Sky] resource's rotation expressed as a [Basis]
+ [Sky] resource's rotation expressed as a [Basis].
</member>
<member name="background_sky_rotation" type="Vector3" setter="set_sky_rotation" getter="get_sky_rotation" default="Vector3( 0, 0, 0 )">
- [Sky] resource's rotation expressed as euler angles in radians
+ [Sky] resource's rotation expressed as Euler angles in radians.
</member>
<member name="background_sky_rotation_degrees" type="Vector3" setter="set_sky_rotation_degrees" getter="get_sky_rotation_degrees" default="Vector3( 0, 0, 0 )">
- [Sky] resource's rotation expressed as euler angles in degrees
+ [Sky] resource's rotation expressed as Euler angles in degrees.
</member>
<member name="dof_blur_far_amount" type="float" setter="set_dof_blur_far_amount" getter="get_dof_blur_far_amount" default="0.1">
Amount of far blur.
diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml
index 2357ee2469..6b15b5a1ea 100644
--- a/doc/classes/Popup.xml
+++ b/doc/classes/Popup.xml
@@ -4,7 +4,7 @@
Base container control for popups and dialogs.
</brief_description>
<description>
- Popup is a base [Control] used to show dialogs and popups. It's a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior.
+ Popup is a base [Control] used to show dialogs and popups. It's a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior. All popup methods ensure correct placement within the viewport.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ViewportContainer.xml b/doc/classes/ViewportContainer.xml
index e4c6091909..2f1bc5d799 100644
--- a/doc/classes/ViewportContainer.xml
+++ b/doc/classes/ViewportContainer.xml
@@ -15,6 +15,9 @@
If [code]true[/code], the viewport will be scaled to the control's size.
</member>
<member name="stretch_shrink" type="int" setter="set_stretch_shrink" getter="get_stretch_shrink" default="1">
+ Divides the viewport's effective resolution by this value while preserving its scale. This can be used to speed up rendering.
+ For example, a 1280×720 viewport with [member stretch_shrink] set to [code]2[/code] will be rendered at 640×360 while occupying the same size in the container.
+ [b]Note:[/b] [member stretch] must be [code]true[/code] for this property to work.
</member>
</members>
<constants>
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index 15b2193cbe..40e7f0c441 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -85,7 +85,9 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
#define glClearDepth glClearDepthf
// enable extensions manually for android and ios
+#ifndef UWP_ENABLED
#include <dlfcn.h> // needed to load extensions
+#endif
#ifdef IPHONE_ENABLED
@@ -93,13 +95,18 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
//void *glRenderbufferStorageMultisampleAPPLE;
//void *glResolveMultisampleFramebufferAPPLE;
#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
-#elif ANDROID_ENABLED
+#elif defined(ANDROID_ENABLED)
#include <GLES2/gl2ext.h>
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT;
#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT
#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT
+
+#elif defined(UWP_ENABLED)
+#include <GLES2/gl2ext.h>
+#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleANGLE
+#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleANGLE
#endif
#define GL_MAX_SAMPLES 0x8D57
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 27e61362ed..517a1c34d1 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -170,7 +170,11 @@ void EditorHelpSearch::popup_dialog(const String &p_term) {
if (p_term == "") {
search_box->clear();
} else {
- old_search = true;
+ if (old_term == p_term)
+ old_search = true;
+ else
+ old_term = p_term;
+
search_box->set_text(p_term);
search_box->select_all();
}
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 12ffd024a7..0be2f3419b 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -59,6 +59,7 @@ class EditorHelpSearch : public ConfirmationDialog {
OptionButton *filter_combo;
Tree *results_tree;
bool old_search;
+ String old_term;
class Runner;
Ref<Runner> search;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ef382c0a19..ab41019ac3 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -6121,7 +6121,7 @@ EditorNode::EditorNode() {
p = debug_menu->get_popup();
p->set_hide_on_window_lose_focus(true);
- p->set_hide_on_item_selection(false);
+ p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged."));
p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network FS")), RUN_FILE_SERVER);
diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp
index 471742948f..020cb3bada 100644
--- a/editor/editor_profiler.cpp
+++ b/editor/editor_profiler.cpp
@@ -88,14 +88,13 @@ void EditorProfiler::clear() {
frame_metrics.resize(metric_size);
last_metric = -1;
variables->clear();
- //activate->set_pressed(false);
plot_sigs.clear();
plot_sigs.insert("physics_frame_time");
plot_sigs.insert("category_frame_time");
updating_frame = true;
cursor_metric_edit->set_min(0);
- cursor_metric_edit->set_max(0);
+ cursor_metric_edit->set_max(100); // Doesn't make much sense, but we can't have min == max. Doesn't hurt.
cursor_metric_edit->set_value(0);
updating_frame = false;
hover_metric = -1;
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index a10d27f7cd..be066e15a5 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -2143,7 +2143,6 @@ Error EditorSceneImporterGLTF::_create_skeletons(GLTFState &state) {
skeleton->add_bone(node->name);
skeleton->set_bone_rest(bone_index, node->xform);
- skeleton->set_bone_pose(bone_index, node->xform);
if (node->parent >= 0 && state.nodes[node->parent]->skeleton == skel_i) {
const int bone_parent = skeleton->find_bone(state.nodes[node->parent]->name);
@@ -2324,7 +2323,7 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) {
Array samplers = d["samplers"];
if (d.has("name")) {
- animation.name = d["name"];
+ animation.name = _sanitize_scene_name(d["name"]);
}
for (int j = 0; j < channels.size(); j++) {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index e07f041eb1..475e4c8d67 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -702,13 +702,13 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL);
min_value = memnew(SpinBox);
- min_value->set_max(0);
min_value->set_min(-10000);
+ min_value->set_max(0);
min_value->set_step(0.01);
max_value = memnew(SpinBox);
- max_value->set_max(10000);
max_value->set_min(0.01);
+ max_value->set_max(10000);
max_value->set_step(0.01);
label_value = memnew(LineEdit);
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 007ce58bd7..204562ac38 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -827,19 +827,23 @@ void EditorFontPreviewPlugin::_bind_methods() {
bool EditorFontPreviewPlugin::handles(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "DynamicFontData");
+ return ClassDB::is_parent_class(p_type, "DynamicFontData") || ClassDB::is_parent_class(p_type, "DynamicFont");
}
Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
- Ref<DynamicFontData> SampledFont;
- SampledFont.instance();
- SampledFont->set_font_path(p_path);
-
+ RES res = ResourceLoader::load(p_path);
Ref<DynamicFont> sampled_font;
- sampled_font.instance();
+ if (res->is_class("DynamicFont")) {
+ sampled_font = res->duplicate();
+ if (sampled_font->get_outline_color() == Color(1, 1, 1, 1)) {
+ sampled_font->set_outline_color(Color(0, 0, 0, 1));
+ }
+ } else if (res->is_class("DynamicFontData")) {
+ sampled_font.instance();
+ sampled_font->set_font_data(res);
+ }
sampled_font->set_size(50);
- sampled_font->set_font_data(SampledFont);
String sampled_text = "Abg";
Vector2 size = sampled_font->get_string_size(sampled_text);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index f7e997a269..54bf8ce5a2 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2497,7 +2497,10 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
EditorHelp *eh = Object::cast_to<EditorHelp>(node);
if (se || eh) {
- int new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ int new_index = 0;
+ if (script_list->get_item_count() > 0) {
+ new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ }
tab_container->move_child(node, new_index);
tab_container->set_current_tab(new_index);
_update_script_names();
@@ -2514,7 +2517,10 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
EditorHelp *eh = Object::cast_to<EditorHelp>(node);
if (se || eh) {
- int new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ int new_index = 0;
+ if (script_list->get_item_count() > 0) {
+ new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ }
tab_container->move_child(node, new_index);
tab_container->set_current_tab(new_index);
_update_script_names();
@@ -2525,7 +2531,10 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
Vector<String> files = d["files"];
- int new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ int new_index = 0;
+ if (script_list->get_item_count() > 0) {
+ new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
+ }
int num_tabs_before = tab_container->get_child_count();
for (int i = 0; i < files.size(); i++) {
String file = files[i];
@@ -2551,16 +2560,20 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo())
return;
if (ED_IS_SHORTCUT("script_editor/next_script", p_event)) {
- int next_tab = script_list->get_current() + 1;
- next_tab %= script_list->get_item_count();
- _go_to_tab(script_list->get_item_metadata(next_tab));
- _update_script_names();
+ if (script_list->get_item_count() > 1) {
+ int next_tab = script_list->get_current() + 1;
+ next_tab %= script_list->get_item_count();
+ _go_to_tab(script_list->get_item_metadata(next_tab));
+ _update_script_names();
+ }
}
if (ED_IS_SHORTCUT("script_editor/prev_script", p_event)) {
- int next_tab = script_list->get_current() - 1;
- next_tab = next_tab >= 0 ? next_tab : script_list->get_item_count() - 1;
- _go_to_tab(script_list->get_item_metadata(next_tab));
- _update_script_names();
+ if (script_list->get_item_count() > 1) {
+ int next_tab = script_list->get_current() - 1;
+ next_tab = next_tab >= 0 ? next_tab : script_list->get_item_count() - 1;
+ _go_to_tab(script_list->get_item_metadata(next_tab));
+ _update_script_names();
+ }
}
if (ED_IS_SHORTCUT("script_editor/window_move_up", p_event)) {
_menu_option(WINDOW_MOVE_UP);
@@ -3238,7 +3251,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP);
ED_SHORTCUT("script_editor/window_move_down", TTR("Move Down"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_DOWN);
ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_PERIOD); // these should be KEY_GREATER and KEY_LESS but those don't work
- ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_COLON);
+ ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_COMMA);
set_process_unhandled_input(true);
file_menu = memnew(MenuButton);
diff --git a/main/main.cpp b/main/main.cpp
index c34d3da618..22a31d597e 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1517,6 +1517,9 @@ bool Main::start() {
ERR_FAIL_COND_V_MSG(script_res.is_null(), false, "Can't load script: " + script);
if (check_only) {
+ if (!script_res->is_valid()) {
+ OS::get_singleton()->set_exit_code(1);
+ }
return false;
}
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index 4c10588aa6..78a8e94012 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -116,6 +116,9 @@
The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all.
</member>
<member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" />
+ <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true">
+ Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server.
+ </member>
<member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1">
Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels, one for reliable and one for unreliable packets. Channel [code]0[/code] is reserved, and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data.
</member>
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index a787cd3b80..2f5307d041 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -255,6 +255,10 @@ void NetworkedMultiplayerENet::poll() {
emit_signal("peer_connected", *new_id);
if (server) {
+ // Do not notify other peers when server_relay is disabled.
+ if (!server_relay)
+ break;
+
// Someone connected, notify all the peers available
for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
@@ -287,31 +291,34 @@ void NetworkedMultiplayerENet::poll() {
if (!server) {
emit_signal("connection_failed");
}
- } else {
+ // Never fully connected.
+ break;
+ }
- if (server) {
- // Someone disconnected, notify everyone else
- for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
+ if (!server) {
- if (E->key() == *id)
- continue;
+ // Client just disconnected from server.
+ emit_signal("server_disconnected");
+ close_connection();
+ return;
+ } else if (server_relay) {
- ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
- encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
- encode_uint32(*id, &packet->data[4]);
- enet_peer_send(E->get(), SYSCH_CONFIG, packet);
- }
- } else {
- emit_signal("server_disconnected");
- close_connection();
- return;
- }
+ // Server just received a client disconnect and is in relay mode, notify everyone else.
+ for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
+
+ if (E->key() == *id)
+ continue;
- emit_signal("peer_disconnected", *id);
- peer_map.erase(*id);
- memdelete(id);
+ ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
+ encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
+ encode_uint32(*id, &packet->data[4]);
+ enet_peer_send(E->get(), SYSCH_CONFIG, packet);
+ }
}
+ emit_signal("peer_disconnected", *id);
+ peer_map.erase(*id);
+ memdelete(id);
} break;
case ENET_EVENT_TYPE_RECEIVE: {
@@ -361,7 +368,13 @@ void NetworkedMultiplayerENet::poll() {
packet.from = *id;
- if (target == 0) {
+ if (target == 1) {
+ // To myself and only myself
+ incoming_packets.push_back(packet);
+ } else if (!server_relay) {
+ // No other destination is allowed when server is not relaying
+ continue;
+ } else if (target == 0) {
// Re-send to everyone but sender :|
incoming_packets.push_back(packet);
@@ -398,9 +411,6 @@ void NetworkedMultiplayerENet::poll() {
enet_packet_destroy(packet.packet);
}
- } else if (target == 1) {
- // To myself and only myself
- incoming_packets.push_back(packet);
} else {
// To someone else, specifically
ERR_CONTINUE(!peer_map.has(target));
@@ -440,6 +450,8 @@ void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) {
for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
if (E->get()) {
enet_peer_disconnect_now(E->get(), unique_id);
+ int *id = (int *)(E->get()->data);
+ memdelete(id);
peers_disconnected = true;
}
}
@@ -455,6 +467,7 @@ void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) {
enet_host_destroy(host);
active = false;
incoming_packets.clear();
+ peer_map.clear();
unique_id = 1; // Server is 1
connection_status = CONNECTION_DISCONNECTED;
}
@@ -471,10 +484,13 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) {
// enet_peer_disconnect_now doesn't generate ENET_EVENT_TYPE_DISCONNECT,
// notify everyone else, send disconnect signal & remove from peer_map like in poll()
+ int *id = NULL;
for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
- if (E->key() == p_peer)
+ if (E->key() == p_peer) {
+ id = (int *)(E->get()->data);
continue;
+ }
ENetPacket *packet = enet_packet_create(NULL, 8, ENET_PACKET_FLAG_RELIABLE);
encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
@@ -482,6 +498,9 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) {
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
}
+ if (id)
+ memdelete(id);
+
emit_signal("peer_disconnected", p_peer);
peer_map.erase(p_peer);
} else {
@@ -818,6 +837,16 @@ bool NetworkedMultiplayerENet::is_always_ordered() const {
return always_ordered;
}
+void NetworkedMultiplayerENet::set_server_relay_enabled(bool p_enabled) {
+ ERR_FAIL_COND(active);
+
+ server_relay = p_enabled;
+}
+
+bool NetworkedMultiplayerENet::is_server_relay_enabled() const {
+ return server_relay;
+}
+
void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
@@ -838,11 +867,14 @@ void NetworkedMultiplayerENet::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_channel_count"), &NetworkedMultiplayerENet::get_channel_count);
ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &NetworkedMultiplayerENet::set_always_ordered);
ClassDB::bind_method(D_METHOD("is_always_ordered"), &NetworkedMultiplayerENet::is_always_ordered);
+ ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &NetworkedMultiplayerENet::set_server_relay_enabled);
+ ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &NetworkedMultiplayerENet::is_server_relay_enabled);
ADD_PROPERTY(PropertyInfo(Variant::INT, "compression_mode", PROPERTY_HINT_ENUM, "None,Range Coder,FastLZ,ZLib,ZStd"), "set_compression_mode", "get_compression_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel"), "set_transfer_channel", "get_transfer_channel");
ADD_PROPERTY(PropertyInfo(Variant::INT, "channel_count"), "set_channel_count", "get_channel_count");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "always_ordered"), "set_always_ordered", "is_always_ordered");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled");
BIND_ENUM_CONSTANT(COMPRESS_NONE);
BIND_ENUM_CONSTANT(COMPRESS_RANGE_CODER);
@@ -856,6 +888,7 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
active = false;
server = false;
refuse_connections = false;
+ server_relay = true;
unique_id = 0;
target_peer = 0;
current_packet.packet = NULL;
diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h
index 8dcb202314..1c4c15ae7b 100644
--- a/modules/enet/networked_multiplayer_enet.h
+++ b/modules/enet/networked_multiplayer_enet.h
@@ -78,6 +78,7 @@ private:
ENetHost *host;
bool refuse_connections;
+ bool server_relay;
ConnectionStatus connection_status;
@@ -158,6 +159,8 @@ public:
int get_channel_count() const;
void set_always_ordered(bool p_ordered);
bool is_always_ordered() const;
+ void set_server_relay_enabled(bool p_enabled);
+ bool is_server_relay_enabled() const;
NetworkedMultiplayerENet();
~NetworkedMultiplayerENet();
diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
index 14b7f9a2ef..ab14f01858 100644
--- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp
+++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp
@@ -123,9 +123,12 @@ bool VideoStreamPlaybackGDNative::open_file(const String &p_file) {
godot_vector2 vec = interface->get_texture_size(data_struct);
texture_size = *(Vector2 *)&vec;
+ // Only do memset if num_channels > 0 otherwise it will crash.
+ if (num_channels > 0) {
+ pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float));
+ memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float));
+ }
- pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float));
- memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float));
pcm_write_idx = -1;
samples_decoded = 0;
@@ -146,7 +149,8 @@ void VideoStreamPlaybackGDNative::update(float p_delta) {
ERR_FAIL_COND(interface == NULL);
interface->update(data_struct, p_delta);
- if (mix_callback) {
+ // Don't mix if there's no audio (num_channels == 0).
+ if (mix_callback && num_channels > 0) {
if (pcm_write_idx >= 0) {
// Previous remains
int mixed = mix_callback(mix_udata, pcm + pcm_write_idx * num_channels, samples_decoded);
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 840971dcf8..a22d18b970 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -1363,6 +1363,26 @@
Stops the function execution and returns the current suspended state to the calling function.
From the caller, call [method GDScriptFunctionState.resume] on the state to resume execution. This invalidates the state. Within the resumed function, [code]yield()[/code] returns whatever was passed to the [code]resume()[/code] function call.
If passed an object and a signal, the execution is resumed when the object emits the given signal. In this case, [code]yield()[/code] returns the argument passed to [code]emit_signal()[/code] if the signal takes only one argument, or an array containing all the arguments passed to [code]emit_signal()[/code] if the signal takes multiple arguments.
+ You can also use [code]yield[/code] to wait for a function to finish:
+ [codeblock]
+ func _ready():
+ yield(do_something(), "completed")
+ yield(do_something_else(), "completed")
+ print("All functions are done!")
+
+ func do_something():
+ print("Something is done!")
+
+ func do_something_else():
+ print("Something else is done!")
+
+ # prints:
+ # Something is done!
+ # Something else is done!
+ # All functions are done!
+ [/codeblock]
+ When yielding on a function, the [code]completed[/code] signal will be emitted automatically when the function returns. It can, therefore, be used as the [code]signal[/code] parameter of the [code]yield[/code] method to resume.
+ If you are planning on calling the same function within a loop, you should consider using [code]yield(get_tree(), "idle_frame")[/code] also.
</description>
</method>
</methods>
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 47ac0de7f9..d69e60ced3 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -193,22 +193,6 @@ bool GridMap::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
-#ifndef DISABLE_DEPRECATED
-void GridMap::set_theme(const Ref<MeshLibrary> &p_theme) {
-
- WARN_DEPRECATED_MSG("GridMap.theme/set_theme() is deprecated and will be removed in a future version. Use GridMap.mesh_library/set_mesh_library() instead.");
-
- set_mesh_library(p_theme);
-}
-
-Ref<MeshLibrary> GridMap::get_theme() const {
-
- WARN_DEPRECATED_MSG("GridMap.theme/get_theme() is deprecated and will be removed in a future version. Use GridMap.mesh_library/get_mesh_library() instead.");
-
- return get_mesh_library();
-}
-#endif // DISABLE_DEPRECATED
-
void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
if (!mesh_library.is_null())
@@ -838,11 +822,6 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &GridMap::set_collision_layer_bit);
ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &GridMap::get_collision_layer_bit);
-#ifndef DISABLE_DEPRECATED
- ClassDB::bind_method(D_METHOD("set_theme", "theme"), &GridMap::set_theme);
- ClassDB::bind_method(D_METHOD("get_theme"), &GridMap::get_theme);
-#endif // DISABLE_DEPRECATED
-
ClassDB::bind_method(D_METHOD("set_mesh_library", "mesh_library"), &GridMap::set_mesh_library);
ClassDB::bind_method(D_METHOD("get_mesh_library"), &GridMap::get_mesh_library);
@@ -885,10 +864,6 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_baked_meshes"), &GridMap::clear_baked_meshes);
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
-#ifndef DISABLE_DEPRECATED
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary", 0), "set_theme", "get_theme");
-#endif // DISABLE_DEPRECATED
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
ADD_GROUP("Cell", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size");
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index f4407099f5..10c96956b7 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -227,11 +227,6 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
-#ifndef DISABLE_DEPRECATED
- void set_theme(const Ref<MeshLibrary> &p_theme);
- Ref<MeshLibrary> get_theme() const;
-#endif // DISABLE_DEPRECATED
-
void set_mesh_library(const Ref<MeshLibrary> &p_mesh_library);
Ref<MeshLibrary> get_mesh_library() const;
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index e1d42d3217..894f223597 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -262,10 +262,6 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
header.channels = channel_infos;
header.pixel_types = pixel_types;
header.requested_pixel_types = requested_pixel_types;
- // TODO DEBUG REMOVE
- for (int i = 0; i < 4; ++i) {
- print_line(String("requested_pixel_types{0}: {1}").format(varray(i, requested_pixel_types[i])));
- }
CharString utf8_filename = p_path.utf8();
const char *err;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 1406586361..3884622942 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -969,16 +969,16 @@ void ItemList::_notification(int p_what) {
}
if (all_fit) {
- float page = size.height - bg->get_minimum_size().height;
+ float page = MAX(0, size.height - bg->get_minimum_size().height);
float max = MAX(page, ofs.y + max_h);
if (auto_height)
auto_height_value = ofs.y + max_h + bg->get_minimum_size().height;
- scroll_bar->set_max(max);
- scroll_bar->set_page(page);
if (max <= page) {
scroll_bar->set_value(0);
scroll_bar->hide();
} else {
+ scroll_bar->set_max(max);
+ scroll_bar->set_page(page);
scroll_bar->show();
if (do_autoscroll_to_bottom)
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index 362697b4ad..5682232bc4 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -100,7 +100,6 @@ void Range::set_value(double p_val) {
shared->emit_value_changed();
}
void Range::set_min(double p_min) {
-
shared->min = p_min;
set_value(shared->val);
@@ -109,7 +108,6 @@ void Range::set_min(double p_min) {
update_configuration_warning();
}
void Range::set_max(double p_max) {
-
shared->max = p_max;
set_value(shared->val);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index a840e3fec1..fa23bf91dd 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -388,7 +388,6 @@ void ScrollContainer::update_scrollbars() {
if (hide_scroll_v) {
v_scroll->hide();
- v_scroll->set_max(0);
scroll.y = 0;
} else {
@@ -406,7 +405,6 @@ void ScrollContainer::update_scrollbars() {
if (hide_scroll_h) {
h_scroll->hide();
- h_scroll->set_max(0);
scroll.x = 0;
} else {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index b997d7a064..2558a930b6 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -417,7 +417,6 @@ void TextEdit::_update_scrollbars() {
cursor.line_ofs = 0;
cursor.wrap_ofs = 0;
v_scroll->set_value(0);
- v_scroll->set_max(0);
v_scroll->hide();
}
@@ -436,7 +435,6 @@ void TextEdit::_update_scrollbars() {
cursor.x_ofs = 0;
h_scroll->set_value(0);
- h_scroll->set_max(0);
h_scroll->hide();
}
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 14cc705edb..da96c6e89c 100755
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -108,7 +108,7 @@ bool Timer::has_autostart() const {
void Timer::start(float p_time) {
- ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree!");
+ ERR_FAIL_COND_MSG(!is_inside_tree(), "Timer was not added to the SceneTree. Either add it or set autostart to true.");
if (p_time > 0) {
set_wait_time(p_time);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index bc96b5e9f3..ddf97f48d1 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -978,7 +978,9 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "background_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "background_sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_sky_custom_fov", "get_sky_custom_fov");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "background_sky_orientation"), "set_sky_orientation", "get_sky_orientation");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "background_sky_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_sky_rotation", "get_sky_rotation");
+ // Only display rotation in degrees in the inspector (like in Spatial).
+ // This avoids displaying the same information twice.
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "background_sky_rotation", PROPERTY_HINT_NONE, "", 0), "set_sky_rotation", "get_sky_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "background_sky_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_sky_rotation_degrees", "get_sky_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy");
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 1c69a754b6..11f8f20cf3 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -252,7 +252,7 @@ private:
uint64_t flags : 18;
uint64_t detail_blend_mode : 2;
uint64_t diffuse_mode : 3;
- uint64_t specular_mode : 2;
+ uint64_t specular_mode : 3;
uint64_t invalid_key : 1;
uint64_t deep_parallax : 1;
uint64_t billboard_mode : 2;
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index ed06a67e4c..7bb97e0577 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -75,10 +75,10 @@ void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2
}
void _mark_ysort_dirty(VisualServerCanvas::Item *ysort_owner, RID_Owner<VisualServerCanvas::Item> &canvas_item_owner) {
- while (ysort_owner && ysort_owner->sort_y) {
+ do {
ysort_owner->ysort_children_count = -1;
ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : NULL;
- }
+ } while (ysort_owner && ysort_owner->sort_y);
}
void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) {
@@ -362,7 +362,9 @@ void VisualServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) {
Item *item_owner = canvas_item_owner.get(canvas_item->parent);
item_owner->child_items.erase(canvas_item);
- _mark_ysort_dirty(item_owner, canvas_item_owner);
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
}
canvas_item->parent = RID();
@@ -382,7 +384,9 @@ void VisualServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) {
item_owner->child_items.push_back(canvas_item);
item_owner->children_order_dirty = true;
- _mark_ysort_dirty(item_owner, canvas_item_owner);
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
} else {
@@ -399,9 +403,7 @@ void VisualServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) {
canvas_item->visible = p_visible;
- if (canvas_item->parent.is_valid() && canvas_item_owner.owns(canvas_item->parent)) {
- _mark_ysort_dirty(canvas_item_owner.get(canvas_item->parent), canvas_item_owner);
- }
+ _mark_ysort_dirty(canvas_item, canvas_item_owner);
}
void VisualServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) {
@@ -1382,7 +1384,9 @@ bool VisualServerCanvas::free(RID p_rid) {
Item *item_owner = canvas_item_owner.get(canvas_item->parent);
item_owner->child_items.erase(canvas_item);
- _mark_ysort_dirty(item_owner, canvas_item_owner);
+ if (item_owner->sort_y) {
+ _mark_ysort_dirty(item_owner, canvas_item_owner);
+ }
}
}