summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig3
-rw-r--r--doc/classes/Button.xml1
-rw-r--r--doc/classes/TouchScreenButton.xml2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp10
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp12
-rw-r--r--scene/2d/line_2d.cpp1
-rw-r--r--scene/main/node.cpp17
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/resources/packed_scene.cpp6
-rw-r--r--servers/rendering/shader_language.cpp12
10 files changed, 45 insertions, 20 deletions
diff --git a/.editorconfig b/.editorconfig
index 49517a5104..7743622e78 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,7 +17,8 @@ indent_size = 4
indent_style = space
indent_size = 4
-[.travis.yml]
+# YAML requires indentation with spaces instead of tabs.
+[*.{yml,yaml}]
indent_style = space
indent_size = 2
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index 96ff5e0293..51c35b15ce 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -34,6 +34,7 @@
[/codeblocks]
Buttons (like all Control nodes) can also be created in the editor, but some situations may require creating them from code.
See also [BaseButton] which contains common properties and methods associated with this node.
+ [b]Note:[/b] Buttons do not interpret touch input and therefore don't support multitouch, since mouse emulation can only press one button at a given time. Use [TouchScreenButton] for buttons that trigger gameplay movement or actions, as [TouchScreenButton] supports multitouch.
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml
index 768971aecf..bb4c17c531 100644
--- a/doc/classes/TouchScreenButton.xml
+++ b/doc/classes/TouchScreenButton.xml
@@ -4,7 +4,7 @@
Button for touch screen devices for gameplay use.
</brief_description>
<description>
- TouchScreenButton allows you to create on-screen buttons for touch devices. It's intended for gameplay use, such as a unit you have to touch to move.
+ TouchScreenButton allows you to create on-screen buttons for touch devices. It's intended for gameplay use, such as a unit you have to touch to move. Unlike [Button], TouchScreenButton supports multitouch out of the box. Several TouchScreenButtons can be pressed at the same time with touch input.
This node inherits from [Node2D]. Unlike with [Control] nodes, you cannot set anchors on it. If you want to create menus or user interfaces, you may want to use [Button] nodes instead. To make button nodes react to touch events, you can enable the Emulate Mouse option in the Project Settings.
You can configure TouchScreenButton to be visible only on touch devices, helping you develop your game both for desktop and mobile devices.
</description>
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index d92837b68d..6fa3c923eb 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -629,9 +629,9 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
Node *node = r_items[i].item;
// Make sure the selected node is in the current scene, or editable
- while (node && node != get_tree()->get_edited_scene_root() && node->get_owner() != scene && !scene->is_editable_instance(node->get_owner())) {
- node = node->get_parent();
- };
+ if (node && node != get_tree()->get_edited_scene_root()) {
+ node = scene->get_deepest_editable_node(node);
+ }
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
if (!p_allow_locked) {
@@ -762,7 +762,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
Node *scene = editor->get_edited_scene();
- bool editable = p_node == scene || p_node->get_owner() == scene || scene->is_editable_instance(p_node->get_owner());
+ bool editable = p_node == scene || p_node->get_owner() == scene || p_node == scene->get_deepest_editable_node(p_node);
bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_");
bool locked = _is_node_locked(p_node);
@@ -3867,7 +3867,7 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) {
CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
Node *scene = editor->get_edited_scene();
- if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner()))) {
+ if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && canvas_item != scene->get_deepest_editable_node(canvas_item))) {
return false;
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 610ef0c601..713837df44 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -534,10 +534,7 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, b
}
if (dist < closest_dist) {
- item = Object::cast_to<Node>(spat);
- while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
- item = item->get_owner();
- }
+ item = edited_scene->get_deepest_editable_node(Object::cast_to<Node>(spat));
closest = item->get_instance_id();
closest_dist = dist;
@@ -696,10 +693,7 @@ void Node3DEditorViewport::_select_region() {
continue;
}
- Node *item = Object::cast_to<Node>(sp);
- while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
- item = item->get_owner();
- }
+ Node *item = edited_scene->get_deepest_editable_node(Object::cast_to<Node>(sp));
// Replace the node by the group if grouped
if (item->is_class("Node3D")) {
@@ -1027,7 +1021,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
for (int i = 0; i < selection_results.size(); i++) {
Node3D *item = selection_results[i].item;
- if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
+ if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) {
//invalid result
selection_results.remove(i);
i--;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 2959ea1a36..37eb45c21d 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -116,6 +116,7 @@ Vector<Vector2> Line2D::get_points() const {
}
void Line2D::set_point_position(int i, Vector2 p_pos) {
+ ERR_FAIL_INDEX(i, _points.size());
_points.set(i, p_pos);
update();
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index f6a0f5a6c0..f0c562260f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1966,6 +1966,23 @@ bool Node::is_editable_instance(const Node *p_node) const {
return p_node->data.editable_instance;
}
+Node *Node::get_deepest_editable_node(Node *p_start_node) const {
+ ERR_FAIL_NULL_V(p_start_node, nullptr);
+ ERR_FAIL_COND_V(!is_a_parent_of(p_start_node), nullptr);
+
+ Node const *iterated_item = p_start_node;
+ Node *node = p_start_node;
+
+ while (iterated_item->get_owner() && iterated_item->get_owner() != this) {
+ if (!is_editable_instance(iterated_item->get_owner()))
+ node = iterated_item->get_owner();
+
+ iterated_item = iterated_item->get_owner();
+ }
+
+ return node;
+}
+
void Node::set_scene_instance_state(const Ref<SceneState> &p_state) {
data.instance_state = p_state;
}
diff --git a/scene/main/node.h b/scene/main/node.h
index b3979993e0..249a0ff86e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -330,6 +330,7 @@ public:
void set_editable_instance(Node *p_node, bool p_editable);
bool is_editable_instance(const Node *p_node) const;
+ Node *get_deepest_editable_node(Node *p_start_node) const;
/* NOTIFICATIONS */
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index beb365d44e..5d351f51f7 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -469,6 +469,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
p_node->get_property_list(&plist);
StringName type = p_node->get_class();
+ Ref<Script> script = p_node->get_script();
+ if (script.is_valid()) {
+ script->update_exports();
+ }
+
for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
continue;
@@ -484,7 +489,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
}
- Ref<Script> script = p_node->get_script();
if (!isdefault && script.is_valid() && script->get_property_default_value(name, default_value)) {
isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value));
}
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index e52d97e4d9..cb98a71e86 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5861,6 +5861,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_BUG;
}
+ String return_struct_name = String(b->parent_function->return_struct_name);
+
ControlFlowNode *flow = alloc_node<ControlFlowNode>();
flow->flow_op = FLOW_OP_RETURN;
@@ -5869,7 +5871,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (tk.type == TK_SEMICOLON) {
//all is good
if (b->parent_function->return_type != TYPE_VOID) {
- _set_error("Expected return with expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
} else {
@@ -5879,8 +5881,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- if (b->parent_function->return_type != expr->get_datatype()) {
- _set_error("Expected return expression of type '" + get_datatype_name(b->parent_function->return_type) + "'");
+ if (b->parent_function->return_type != expr->get_datatype() || return_struct_name != expr->get_datatype_name()) {
+ _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + "'");
return ERR_PARSE_ERROR;
}
@@ -6133,6 +6135,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
st.name = tk.text;
+ if (shader->structs.has(st.name)) {
+ _set_error("Redefinition of '" + String(st.name) + "'");
+ return ERR_PARSE_ERROR;
+ }
tk = _get_token();
if (tk.type != TK_CURLY_BRACKET_OPEN) {
_set_error("Expected '{'");