summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/rigid_body_bullet.cpp3
-rw-r--r--modules/bullet/space_bullet.cpp1
-rw-r--r--modules/csg/csg_shape.cpp11
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp6
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml27
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp82
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/register_types.cpp12
-rw-r--r--modules/regex/doc_classes/RegEx.xml13
12 files changed, 133 insertions, 33 deletions
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 5c1144b875..32c3240a35 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -897,8 +897,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) {
}
void RigidBodyBullet::reload_space_override_modificator() {
- // Make sure that kinematic bodies have their total gravity calculated
- if (!is_active() && PhysicsServer3D::BODY_MODE_KINEMATIC != mode) {
+ if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
return;
}
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 2b60f8df36..d0515e7c97 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -177,6 +177,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
bt_xform_to.getOrigin() += bt_motion;
if ((bt_xform_to.getOrigin() - bt_xform_from.getOrigin()).fuzzyZero()) {
+ shape->destroy_bt_shape(btShape);
return false;
}
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 6653849384..a10e03b3b2 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -132,18 +132,13 @@ void CSGShape3D::_make_dirty() {
return;
}
- if (dirty) {
- return;
- }
-
- dirty = true;
-
if (parent) {
parent->_make_dirty();
- } else {
- //only parent will do
+ } else if (!dirty) {
call_deferred("_update_shape");
}
+
+ dirty = true;
}
CSGBrush *CSGShape3D::_get_brush() {
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index ed3924f2d2..64977ad237 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -104,6 +104,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int
if (dtls_enabled) {
enet_host_dtls_server_setup(host, dtls_key.ptr(), dtls_cert.ptr());
}
+ enet_host_refuse_new_connections(host, refuse_connections);
#endif
_setup_compressor();
@@ -160,6 +161,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por
if (dtls_enabled) {
enet_host_dtls_client_setup(host, dtls_cert.ptr(), dtls_verify, p_address.utf8().get_data());
}
+ enet_host_refuse_new_connections(host, refuse_connections);
#endif
_setup_compressor();
@@ -641,7 +643,9 @@ int NetworkedMultiplayerENet::get_unique_id() const {
void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) {
refuse_connections = p_enable;
#ifdef GODOT_ENET
- enet_host_refuse_new_connections(host, p_enable);
+ if (active) {
+ enet_host_refuse_new_connections(host, p_enable);
+ }
#endif
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index c86b974f47..9e40a69712 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -112,7 +112,7 @@
</argument>
<description>
Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code].
- The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[code] and [code]x[/code].
+ The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code].
[codeblock]
a = atan(0.5) # a is 0.463648
[/codeblock]
@@ -735,16 +735,17 @@
<argument index="0" name="json" type="String">
</argument>
<description>
- Parse JSON text to a Variant (use [method typeof] to check if it is what you expect).
- Be aware that the JSON specification does not define integer or float types, but only a number type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
- Note that JSON objects do not preserve key order like Godot dictionaries, thus you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
+ Parse JSON text to a Variant. (Use [method typeof] to check if the Variant's type is what you expect.)
+ [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types.
+ [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements:
[codeblock]
- p = parse_json('["a", "b", "c"]')
- if typeof(p) == TYPE_ARRAY:
- print(p[0]) # Prints a
+ var p = JSON.parse('["hello", "world", "!"]')
+ if typeof(p.result) == TYPE_ARRAY:
+ print(p.result[0]) # Prints "hello"
else:
- print("unexpected results")
+ push_error("Unexpected results.")
[/codeblock]
+ See also [JSON] for an alternative way to parse JSON text.
</description>
</method>
<method name="polar2cartesian">
@@ -1220,12 +1221,16 @@
<argument index="0" name="var" type="Variant">
</argument>
<description>
- Converts a Variant [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network.
+ Converts a [Variant] [code]var[/code] to JSON text and return the result. Useful for serializing data to store or send over the network.
[codeblock]
+ # Both numbers below are integers.
a = { "a": 1, "b": 2 }
b = to_json(a)
print(b) # {"a":1, "b":2}
+ # Both numbers above are floats, even if they display without any decimal places.
[/codeblock]
+ [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a [Variant] to JSON text will convert all numerical values to [float] types.
+ See also [JSON] for an alternative way to convert a [Variant] to JSON text.
</description>
</method>
<method name="type_exists">
@@ -1268,9 +1273,9 @@
j = to_json([1, 2, 3])
v = validate_json(j)
if not v:
- print("valid")
+ print("Valid JSON.")
else:
- prints("invalid", v)
+ push_error("Invalid JSON: " + v)
[/codeblock]
</description>
</method>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index aba3e07134..ae1f2893f1 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -82,6 +82,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
const String &str = text_edit->get_line(p_line);
const int line_length = str.length();
Color prev_color;
+
+ if (in_region != -1 && str.length() == 0) {
+ color_region_cache[p_line] = in_region;
+ }
for (int j = 0; j < str.length(); j++) {
Dictionary highlighter_info;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 4098425518..1e72216ad2 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -71,6 +71,10 @@ static StringName get_real_class_name(const StringName &p_source) {
return p_source;
}
+void GDScriptAnalyzer::cleanup() {
+ underscore_map.clear();
+}
+
static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) {
GDScriptParser::DataType type;
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -494,7 +498,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
if (member.variable->initializer != nullptr) {
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) {
- push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
+ push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer);
} else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
#ifdef DEBUG_ENABLED
parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
@@ -989,7 +993,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
if (p_variable->initializer != nullptr) {
if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) {
- push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer);
+ push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer);
#ifdef DEBUG_ENABLED
} else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) {
parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION);
@@ -1369,11 +1373,61 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!is_type_compatible(p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), true)) {
- if (p_assignment->assignee->get_datatype().is_hard_type()) {
- push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value);
+ Variant::Operator vop = Variant::Operator::OP_EQUAL;
+ switch (p_assignment->operation) {
+ case GDScriptParser::AssignmentNode::OP_NONE:
+ vop = Variant::Operator::OP_EQUAL;
+ break;
+ case GDScriptParser::AssignmentNode::OP_ADDITION:
+ vop = Variant::Operator::OP_ADD;
+ break;
+ case GDScriptParser::AssignmentNode::OP_SUBTRACTION:
+ vop = Variant::Operator::OP_SUBTRACT;
+ break;
+ case GDScriptParser::AssignmentNode::OP_MULTIPLICATION:
+ vop = Variant::Operator::OP_MULTIPLY;
+ break;
+ case GDScriptParser::AssignmentNode::OP_DIVISION:
+ vop = Variant::Operator::OP_DIVIDE;
+ break;
+ case GDScriptParser::AssignmentNode::OP_MODULO:
+ vop = Variant::Operator::OP_MODULE;
+ break;
+ case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_LEFT:
+ vop = Variant::Operator::OP_SHIFT_LEFT;
+ break;
+ case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_RIGHT:
+ vop = Variant::Operator::OP_SHIFT_RIGHT;
+ break;
+ case GDScriptParser::AssignmentNode::OP_BIT_AND:
+ vop = Variant::Operator::OP_BIT_AND;
+ break;
+ case GDScriptParser::AssignmentNode::OP_BIT_OR:
+ vop = Variant::Operator::OP_BIT_OR;
+ break;
+ case GDScriptParser::AssignmentNode::OP_BIT_XOR:
+ vop = Variant::Operator::OP_BIT_XOR;
+ break;
+ }
+
+ if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) {
+ bool compatible = true;
+ GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype();
+ if (vop != Variant::OP_EQUAL) {
+ op_type = get_operation_type(vop, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible);
+ }
+
+ if (compatible) {
+ compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true);
+ if (!compatible) {
+ if (p_assignment->assignee->get_datatype().is_hard_type()) {
+ push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value);
+ } else {
+ // TODO: Warning in this case.
+ }
+ }
} else {
- // TODO: Warning in this case.
+ push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment);
}
}
@@ -1488,7 +1542,19 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) {
p_binary_op->is_constant = true;
if (p_binary_op->variant_op < Variant::OP_MAX) {
- p_binary_op->reduced_value = Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value);
+ bool valid = false;
+ Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value, p_binary_op->reduced_value, valid);
+ if (!valid) {
+ if (p_binary_op->reduced_value.get_type() == Variant::STRING) {
+ push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op);
+ } else {
+ push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)",
+ Variant::get_operator_name(p_binary_op->variant_op),
+ Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()),
+ Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())),
+ p_binary_op);
+ }
+ }
} else {
if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) {
GDScriptParser::DataType test_type = right_type;
@@ -2019,7 +2085,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
GDScriptParser::ClassNode *outer = base_class->outer;
while (outer != nullptr) {
if (outer->has_member(name)) {
- const GDScriptParser::ClassNode::Member &member = base_class->get_member(name);
+ const GDScriptParser::ClassNode::Member &member = outer->get_member(name);
if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) {
// TODO: Make sure loops won't cause problem. And make special error message for those.
// For out-of-order resolution:
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 85183d3272..06d3530cb6 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -113,6 +113,8 @@ public:
Error analyze();
GDScriptAnalyzer(GDScriptParser *p_parser);
+
+ static void cleanup();
};
#endif // GDSCRIPT_ANALYZER_H
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index af07457750..1f3e1c1e40 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -94,6 +94,10 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX;
}
+void GDScriptParser::cleanup() {
+ builtin_types.clear();
+}
+
GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) {
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index a741ae0cc7..c9ab3d4e12 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1335,6 +1335,7 @@ public:
void print_tree(const GDScriptParser &p_parser);
};
#endif // DEBUG_ENABLED
+ static void cleanup();
};
#endif // GDSCRIPT_PARSER_H
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 5c1d2f6f1b..c554cbac05 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -35,6 +35,7 @@
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "gdscript.h"
+#include "gdscript_analyzer.h"
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
@@ -57,6 +58,8 @@ GDScriptCache *gdscript_cache = nullptr;
#include "language_server/gdscript_language_server.h"
#endif // !GDSCRIPT_NO_LSP
+Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin;
+
class EditorExportGDScript : public EditorExportPlugin {
GDCLASS(EditorExportGDScript, EditorExportPlugin);
@@ -120,7 +123,6 @@ void register_gdscript_types() {
#ifdef TOOLS_ENABLED
EditorNode::add_init_callback(_editor_init);
- Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin;
gdscript_translation_parser_plugin.instance();
EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
#endif // TOOLS_ENABLED
@@ -142,4 +144,12 @@ void unregister_gdscript_types() {
ResourceSaver::remove_resource_format_saver(resource_saver_gd);
resource_saver_gd.unref();
+
+#ifdef TOOLS_ENABLED
+ EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ gdscript_translation_parser_plugin.unref();
+#endif // TOOLS_ENABLED
+
+ GDScriptParser::cleanup();
+ GDScriptAnalyzer::cleanup();
}
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index c00fa96b2e..312275842a 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -11,7 +11,7 @@
regex.compile("\\w-(\\d+)")
[/codeblock]
The search pattern must be escaped first for GDScript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code].
- Using [method search] you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using functions such as [method RegExMatch.get_string] and [method RegExMatch.get_start].
+ Using [method search], you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using methods such as [method RegExMatch.get_string] and [method RegExMatch.get_start].
[codeblock]
var regex = RegEx.new()
regex.compile("\\w-(\\d+)")
@@ -19,7 +19,7 @@
if result:
print(result.get_string()) # Would print n-0123
[/codeblock]
- The results of capturing groups [code]()[/code] can be retrieved by passing the group number to the various functions in [RegExMatch]. Group 0 is the default and will always refer to the entire pattern. In the above example, calling [code]result.get_string(1)[/code] would give you [code]0123[/code].
+ The results of capturing groups [code]()[/code] can be retrieved by passing the group number to the various methods in [RegExMatch]. Group 0 is the default and will always refer to the entire pattern. In the above example, calling [code]result.get_string(1)[/code] would give you [code]0123[/code].
This version of RegEx also supports named capturing groups, and the names can be used to retrieve the results. If two or more groups have the same name, the name would only refer to the first one with a match.
[codeblock]
var regex = RegEx.new()
@@ -34,6 +34,15 @@
print(result.get_string("digit"))
# Would print 01 03 0 3f 42
[/codeblock]
+ [b]Example of splitting a string using a RegEx:[/b]
+ [codeblock]
+ var regex = RegEx.new()
+ regex.compile("\\S+") # Negated whitespace character class.
+ var results = []
+ for match in regex.search_all("One Two \n\tThree"):
+ results.push_back(match.get_string())
+ # The `results` array now contains "One", "Two", "Three".
+ [/codeblock]
[b]Note:[/b] Godot's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].
[b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test regular expressions online.
</description>