summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp2
-rw-r--r--modules/gdscript/gdscript_editor.cpp9
-rw-r--r--modules/gdscript/gdscript_parser.cpp46
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.gd12
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.out2
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp50
-rw-r--r--modules/text_server_adv/text_server_adv.h3
15 files changed, 119 insertions, 34 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 026b603683..e05b17168d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -576,10 +576,10 @@
@rpc
func fn(): pass
- @rpc(any_peer, unreliable_ordered)
+ @rpc("any_peer", "unreliable_ordered")
func fn_update_pos(): pass
- @rpc(authority, call_remote, unreliable, 0) # Equivalent to @rpc
+ @rpc("authority", "call_remote", "unreliable", 0) # Equivalent to @rpc
func fn_default(): pass
[/codeblock]
</description>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index e84c79d681..cafc7328e0 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -4113,7 +4113,6 @@ void GDScriptAnalyzer::reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternar
if (!is_type_compatible(true_type, false_type)) {
result = false_type;
if (!is_type_compatible(false_type, true_type)) {
- result.type_source = GDScriptParser::DataType::UNDETECTED;
result.kind = GDScriptParser::DataType::VARIANT;
#ifdef DEBUG_ENABLED
parser->push_warning(p_ternary_op, GDScriptWarning::INCOMPATIBLE_TERNARY);
@@ -4121,6 +4120,7 @@ void GDScriptAnalyzer::reduce_ternary_op(GDScriptParser::TernaryOpNode *p_ternar
}
}
}
+ result.type_source = true_type.is_hard_type() && false_type.is_hard_type() ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;
p_ternary_op->set_datatype(result);
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 12c10642ec..4e7d278aab 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -800,6 +800,15 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
warning.insert_text = warning.display.quote(p_quote_style);
r_result.insert(warning.display, warning);
}
+ } else if (p_annotation->name == SNAME("@rpc")) {
+ if (p_argument == 0 || p_argument == 1 || p_argument == 2) {
+ static const char *options[7] = { "call_local", "call_remote", "any_peer", "authority", "reliable", "unreliable", "unreliable_ordered" };
+ for (int i = 0; i < 7; i++) {
+ ScriptLanguage::CodeCompletionOption option(options[i], ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ option.insert_text = option.display.quote(p_quote_style);
+ r_result.insert(option.display, option);
+ }
+ }
}
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d99a2b86a2..acc3c5d079 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3611,6 +3611,10 @@ bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p
bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node *p_node) {
ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, R"("@onready" annotation can only be applied to class variables.)");
+ if (head && !ClassDB::is_parent_class(head->get_datatype().native_type, SNAME("Node"))) {
+ push_error(R"("@onready" can only be used in classes that inherit "Node".)", p_annotation);
+ }
+
VariableNode *variable = static_cast<VariableNode *>(p_node);
if (variable->onready) {
push_error(R"("@onready" annotation can only be used once per variable.)");
@@ -3902,26 +3906,46 @@ bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_
push_error(R"(Invalid RPC arguments. At most 4 arguments are allowed, where only the last argument can be an integer to specify the channel.')", p_annotation);
return false;
}
+
+ unsigned char locality_args = 0;
+ unsigned char permission_args = 0;
+ unsigned char transfer_mode_args = 0;
+
for (int i = last; i >= 0; i--) {
- String mode = p_annotation->resolved_arguments[i].operator String();
- if (mode == "any_peer") {
- rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER;
- } else if (mode == "authority") {
- rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY;
- } else if (mode == "call_local") {
+ String arg = p_annotation->resolved_arguments[i].operator String();
+ if (arg == "call_local") {
+ locality_args++;
rpc_config["call_local"] = true;
- } else if (mode == "call_remote") {
+ } else if (arg == "call_remote") {
+ locality_args++;
rpc_config["call_local"] = false;
- } else if (mode == "reliable") {
+ } else if (arg == "any_peer") {
+ permission_args++;
+ rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_ANY_PEER;
+ } else if (arg == "authority") {
+ permission_args++;
+ rpc_config["rpc_mode"] = MultiplayerAPI::RPC_MODE_AUTHORITY;
+ } else if (arg == "reliable") {
+ transfer_mode_args++;
rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE;
- } else if (mode == "unreliable") {
+ } else if (arg == "unreliable") {
+ transfer_mode_args++;
rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE;
- } else if (mode == "unreliable_ordered") {
+ } else if (arg == "unreliable_ordered") {
+ transfer_mode_args++;
rpc_config["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED;
} else {
- push_error(R"(Invalid RPC argument. Must be one of: 'call_local'/'call_remote' (local calls), 'any_peer'/'authority' (permission), 'reliable'/'unreliable'/'unreliable_ordered' (transfer mode).)", p_annotation);
+ push_error(R"(Invalid RPC argument. Must be one of: "call_local"/"call_remote" (local calls), "any_peer"/"authority" (permission), "reliable"/"unreliable"/"unreliable_ordered" (transfer mode).)", p_annotation);
}
}
+
+ if (locality_args > 1) {
+ push_error(R"(Invalid RPC config. The locality ("call_local"/"call_remote") must be specified no more than once.)", p_annotation);
+ } else if (permission_args > 1) {
+ push_error(R"(Invalid RPC config. The permission ("any_peer"/"authority") must be specified no more than once.)", p_annotation);
+ } else if (transfer_mode_args > 1) {
+ push_error(R"(Invalid RPC config. The transfer mode ("reliable"/"unreliable"/"unreliable_ordered") must be specified no more than once.)", p_annotation);
+ }
}
function->rpc_config = rpc_config;
return true;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.gd b/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.gd
new file mode 100644
index 0000000000..91f5071fa9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.gd
@@ -0,0 +1,5 @@
+extends RefCounted
+
+func test():
+ var nope := $Node
+ print("Cannot use $ without a Node base")
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.out b/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.out
new file mode 100644
index 0000000000..33365908bf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/get_node_shorthand_within_non_node.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.gd b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.gd
new file mode 100644
index 0000000000..e781315266
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.gd
@@ -0,0 +1,6 @@
+extends RefCounted
+
+@onready var nope := 0
+
+func test():
+ print("Cannot use @onready without a Node base")
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.out b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.out
new file mode 100644
index 0000000000..8088d28329
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/onready_within_non_node.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+"@onready" can only be used in classes that inherit "Node".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.gd b/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.gd
new file mode 100644
index 0000000000..fac0e8756c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.gd
@@ -0,0 +1,6 @@
+func test():
+ var left_hard_int := 1
+ var right_weak_int = 2
+ var result_hm_int := left_hard_int if true else right_weak_int
+
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.out b/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.out
new file mode 100644
index 0000000000..71d1e2f8ae
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/ternary_weak_infer.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot infer the type of "result_hm_int" variable because the value doesn't have a set type.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.gd b/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.gd
new file mode 100644
index 0000000000..fbb7530615
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.gd
@@ -0,0 +1,12 @@
+func test():
+ var left_hard_int := 1
+ var right_hard_int := 2
+ var result_hard_int := left_hard_int if true else right_hard_int
+ assert(result_hard_int == 1)
+
+ var left_hard_variant := 1 as Variant
+ var right_hard_variant := 2.0 as Variant
+ var result_hard_variant := left_hard_variant if true else right_hard_variant
+ assert(result_hard_variant == 1)
+
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.out b/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.out
new file mode 100644
index 0000000000..1b47ed10dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/ternary_hard_infer.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+ok
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
index 02d0226e90..93baf4e51c 100644
--- a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
@@ -30,7 +30,7 @@ namespace GodotPlugins
if (baseDirectory != null)
{
if (!Path.EndsInDirectorySeparator(baseDirectory))
- baseDirectory += Path.PathSeparator;
+ baseDirectory += Path.DirectorySeparatorChar;
// This SetData call effectively sets AppContext.BaseDirectory
// See https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/AppContext.cs#L21-L25
AppDomain.CurrentDomain.SetData("APP_CONTEXT_BASE_DIRECTORY", baseDirectory);
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 9b474bf2ce..b55188ce0c 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -6118,20 +6118,22 @@ int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedS
Vector<UChar *> skeletons;
skeletons.resize(p_dict.size());
- USpoofChecker *sc = uspoof_open(&status);
- uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ if (sc_conf == nullptr) {
+ sc_conf = uspoof_open(&status);
+ uspoof_setChecks(sc_conf, USPOOF_CONFUSABLE, &status);
+ }
for (int i = 0; i < p_dict.size(); i++) {
Char16String word = p_dict[i].utf16();
- int32_t len = uspoof_getSkeleton(sc, 0, word.get_data(), -1, NULL, 0, &status);
+ int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, NULL, 0, &status);
skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));
status = U_ZERO_ERROR;
- uspoof_getSkeleton(sc, 0, word.get_data(), -1, skeletons.write[i], len, &status);
+ uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);
}
- int32_t len = uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, NULL, 0, &status);
+ int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, NULL, 0, &status);
UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));
status = U_ZERO_ERROR;
- uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, skel, len, &status);
+ uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);
for (int i = 0; i < skeletons.size(); i++) {
if (u_strcmp(skel, skeletons[i]) == 0) {
match_index = i;
@@ -6143,7 +6145,6 @@ int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedS
for (int i = 0; i < skeletons.size(); i++) {
memfree(skeletons.write[i]);
}
- uspoof_close(sc);
ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));
@@ -6159,19 +6160,18 @@ bool TextServerAdvanced::_spoof_check(const String &p_string) const {
UErrorCode status = U_ZERO_ERROR;
Char16String utf16 = p_string.utf16();
- USet *allowed = uset_openEmpty();
- uset_addAll(allowed, uspoof_getRecommendedSet(&status));
- uset_addAll(allowed, uspoof_getInclusionSet(&status));
-
- USpoofChecker *sc = uspoof_open(&status);
- uspoof_setAllowedChars(sc, allowed, &status);
- uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
-
- int32_t bitmask = uspoof_check(sc, utf16.get_data(), -1, NULL, &status);
-
- uspoof_close(sc);
- uset_close(allowed);
+ if (allowed == nullptr) {
+ allowed = uset_openEmpty();
+ uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ uset_addAll(allowed, uspoof_getInclusionSet(&status));
+ }
+ if (sc_spoof == nullptr) {
+ sc_spoof = uspoof_open(&status);
+ uspoof_setAllowedChars(sc_spoof, allowed, &status);
+ uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);
+ }
+ int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, NULL, &status);
ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));
return (bitmask != 0);
@@ -6587,5 +6587,17 @@ TextServerAdvanced::~TextServerAdvanced() {
FT_Done_FreeType(ft_library);
}
#endif
+ if (sc_spoof != nullptr) {
+ uspoof_close(sc_spoof);
+ sc_spoof = nullptr;
+ }
+ if (sc_conf != nullptr) {
+ uspoof_close(sc_conf);
+ sc_conf = nullptr;
+ }
+ if (allowed != nullptr) {
+ uset_close(allowed);
+ allowed = nullptr;
+ }
u_cleanup();
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index c7fe46d554..1acf5b21f0 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -159,6 +159,9 @@ class TextServerAdvanced : public TextServerExtension {
// ICU support data.
bool icu_data_loaded = false;
+ mutable USet *allowed = nullptr;
+ mutable USpoofChecker *sc_spoof = nullptr;
+ mutable USpoofChecker *sc_conf = nullptr;
// Font cache data.