summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/enet/enet_connection.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp3
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp16
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp77
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h9
-rw-r--r--modules/gdscript/gdscript_codegen.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp20
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp82
-rw-r--r--modules/gdscript/gdscript_editor.cpp4
-rw-r--r--modules/gdscript/gdscript_function.h42
-rw-r--r--modules/gdscript/gdscript_parser.cpp6
-rw-r--r--modules/gdscript/gdscript_vm.cpp472
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd6
-rw-r--r--modules/gltf/gltf_document.cpp2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp156
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h4
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl8
-rw-r--r--modules/lightmapper_rd/register_types.cpp2
-rw-r--r--modules/mono/config.py2
-rw-r--r--modules/mono/csharp_script.cpp5
-rw-r--r--modules/mono/csharp_script.h1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props14
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.props8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets58
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs44
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs78
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs290
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs1
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Compat.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs61
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs34
-rw-r--r--modules/mono/managed_callable.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp26
-rw-r--r--modules/mono/mono_gd/support/ios_support.h50
-rw-r--r--modules/mono/mono_gd/support/ios_support.mm150
-rw-r--r--modules/multiplayer/multiplayer_debugger.cpp4
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp4
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.h1
-rw-r--r--modules/multiplayer/scene_cache_interface.cpp52
-rw-r--r--modules/multiplayer/scene_cache_interface.h6
-rw-r--r--modules/multiplayer/scene_multiplayer.cpp8
-rw-r--r--modules/multiplayer/scene_multiplayer.h3
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp44
-rw-r--r--modules/multiplayer/scene_replication_interface.h6
-rw-r--r--modules/multiplayer/scene_rpc_interface.cpp48
-rw-r--r--modules/multiplayer/scene_rpc_interface.h11
-rw-r--r--modules/openxr/util.h4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp2
-rw-r--r--modules/webrtc/library_godot_webrtc.js20
-rw-r--r--modules/websocket/library_godot_websocket.js5
56 files changed, 1108 insertions, 885 deletions
diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp
index 94473c76c0..2ccfd5d326 100644
--- a/modules/enet/enet_connection.cpp
+++ b/modules/enet/enet_connection.cpp
@@ -252,7 +252,7 @@ int ENetConnection::get_max_channels() const {
int ENetConnection::get_local_port() const {
ERR_FAIL_NULL_V_MSG(host, 0, "The ENetConnection instance isn't currently active.");
- ERR_FAIL_COND_V_MSG(!(host->socket), 0, "The ENetConnection instance isn't currently bound");
+ ERR_FAIL_COND_V_MSG(!(host->socket), 0, "The ENetConnection instance isn't currently bound.");
ENetAddress address;
ERR_FAIL_COND_V_MSG(enet_socket_get_address(host->socket, &address), 0, "Unable to get socket address");
return address.port;
@@ -344,7 +344,7 @@ void ENetConnection::_broadcast(int p_channel, PackedByteArray p_packet, int p_f
void ENetConnection::socket_send(const String &p_address, int p_port, const PackedByteArray &p_packet) {
ERR_FAIL_NULL_MSG(host, "The ENetConnection instance isn't currently active.");
- ERR_FAIL_COND_MSG(!(host->socket), "The ENetConnection instance isn't currently bound");
+ ERR_FAIL_COND_MSG(!(host->socket), "The ENetConnection instance isn't currently bound.");
ERR_FAIL_COND_MSG(p_port < 1 || p_port > 65535, "The remote port number must be between 1 and 65535 (inclusive).");
IPAddress ip;
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index cffd661261..c3979dd290 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -304,7 +304,8 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
method_doc.qualifiers = m_func->is_static ? "static" : "";
if (m_func->return_type) {
- _doctype_from_gdtype(m_func->return_type->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
+ // `m_func->return_type->get_datatype()` is a metatype.
+ _doctype_from_gdtype(m_func->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
} else if (!m_func->body->has_return) {
// If no `return` statement, then return type is `void`, not `Variant`.
method_doc.return_type = "void";
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 45ac142eaa..144dd41f1a 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -149,7 +149,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
// Check if it's the whole line.
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
// Don't skip comments, for highlighting markers.
- if (color_regions[in_region].start_key == "#") {
+ if (color_regions[in_region].start_key.begins_with("#")) {
break;
}
if (from + end_key_length > line_length) {
@@ -171,7 +171,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
// Don't skip comments, for highlighting markers.
- if (j == line_length && color_regions[in_region].start_key != "#") {
+ if (j == line_length && !color_regions[in_region].start_key.begins_with("#")) {
continue;
}
}
@@ -193,7 +193,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
highlighter_info["color"] = region_color;
color_map[j] = highlighter_info;
- if (color_regions[in_region].start_key == "#") {
+ if (color_regions[in_region].start_key.begins_with("#")) {
int marker_start_pos = from;
int marker_len = 0;
while (from <= line_length) {
@@ -740,6 +740,16 @@ void GDScriptSyntaxHighlighter::_update_cache() {
add_color_region(beg, end, comment_color, end.is_empty());
}
+ /* Doc comments */
+ const Color doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color");
+ List<String> doc_comments;
+ gdscript->get_doc_comment_delimiters(&doc_comments);
+ for (const String &doc_comment : doc_comments) {
+ String beg = doc_comment.get_slice(" ", 0);
+ String end = doc_comment.get_slice_count(" ") > 1 ? doc_comment.get_slice(" ", 1) : String();
+ add_color_region(beg, end, doc_comment_color, end.is_empty());
+ }
+
/* Strings */
string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index eb8e95025a..7cde0fb978 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -501,6 +501,7 @@ public:
virtual void get_reserved_words(List<String> *p_words) const override;
virtual bool is_control_flow_keyword(String p_keywords) const override;
virtual void get_comment_delimiters(List<String> *p_delimiters) const override;
+ virtual void get_doc_comment_delimiters(List<String> *p_delimiters) const override;
virtual void get_string_delimiters(List<String> *p_delimiters) const override;
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 8394fce9b3..25e20c0e76 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -400,7 +400,6 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
}
function->_stack_size = RESERVED_STACK + max_locals + temporaries.size();
function->_instruction_args_size = instr_args_max;
- function->_ptrcall_args_size = ptrcall_max;
#ifdef DEBUG_ENABLED
function->operator_names = operator_names;
@@ -1225,75 +1224,35 @@ void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target,
ct.cleanup();
}
-void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
-#define CASE_TYPE(m_type) \
- case Variant::m_type: \
- append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_PTRCALL_##m_type, 2 + p_arguments.size()); \
- break
-
- bool is_ptrcall = true;
-
- if (p_method->has_return()) {
- MethodInfo info;
- ClassDB::get_method_info(p_method->get_instance_class(), p_method->get_name(), &info);
- switch (info.return_val.type) {
- CASE_TYPE(BOOL);
- CASE_TYPE(INT);
- CASE_TYPE(FLOAT);
- CASE_TYPE(STRING);
- CASE_TYPE(VECTOR2);
- CASE_TYPE(VECTOR2I);
- CASE_TYPE(RECT2);
- CASE_TYPE(RECT2I);
- CASE_TYPE(VECTOR3);
- CASE_TYPE(VECTOR3I);
- CASE_TYPE(TRANSFORM2D);
- CASE_TYPE(PLANE);
- CASE_TYPE(AABB);
- CASE_TYPE(BASIS);
- CASE_TYPE(TRANSFORM3D);
- CASE_TYPE(COLOR);
- CASE_TYPE(STRING_NAME);
- CASE_TYPE(NODE_PATH);
- CASE_TYPE(RID);
- CASE_TYPE(QUATERNION);
- CASE_TYPE(OBJECT);
- CASE_TYPE(CALLABLE);
- CASE_TYPE(SIGNAL);
- CASE_TYPE(DICTIONARY);
- CASE_TYPE(ARRAY);
- CASE_TYPE(PACKED_BYTE_ARRAY);
- CASE_TYPE(PACKED_INT32_ARRAY);
- CASE_TYPE(PACKED_INT64_ARRAY);
- CASE_TYPE(PACKED_FLOAT32_ARRAY);
- CASE_TYPE(PACKED_FLOAT64_ARRAY);
- CASE_TYPE(PACKED_STRING_ARRAY);
- CASE_TYPE(PACKED_VECTOR2_ARRAY);
- CASE_TYPE(PACKED_VECTOR3_ARRAY);
- CASE_TYPE(PACKED_COLOR_ARRAY);
- default:
- append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
- is_ptrcall = false;
- break;
+void GDScriptByteCodeGenerator::write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
+ Variant::Type return_type = Variant::NIL;
+ bool has_return = p_method->has_return();
+
+ if (has_return) {
+ PropertyInfo return_info = p_method->get_return_info();
+ return_type = return_info.type;
+ }
+
+ CallTarget ct = get_call_target(p_target, return_type);
+
+ if (has_return) {
+ Variant::Type temp_type = temporaries[ct.target.address].type;
+ if (temp_type != return_type) {
+ write_type_adjust(ct.target, return_type);
}
- } else {
- append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_PTRCALL_NO_RETURN, 2 + p_arguments.size());
}
+ GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN;
+ append_opcode_and_argcount(code, 2 + p_arguments.size());
+
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
append(p_base);
- CallTarget ct = get_call_target(p_target);
append(ct.target);
append(p_arguments.size());
append(p_method);
ct.cleanup();
- if (is_ptrcall) {
- alloc_ptrcall(p_arguments.size());
- }
-
-#undef CASE_TYPE
}
void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 671dea5d6d..9bface6136 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -97,7 +97,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
int max_locals = 0;
int current_line = 0;
int instr_args_max = 0;
- int ptrcall_max = 0;
#ifdef DEBUG_ENABLED
List<int> temp_stack;
@@ -346,12 +345,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
- void alloc_ptrcall(int p_params) {
- if (p_params >= ptrcall_max) {
- ptrcall_max = p_params;
- }
- }
-
CallTarget get_call_target(const Address &p_target, Variant::Type p_type = Variant::NIL);
int address_of(const Address &p_address) {
@@ -519,7 +512,7 @@ public:
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
- virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index cf17353dec..7ad8f841aa 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -129,7 +129,7 @@ public:
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
- virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index f417d323db..bf648abc9e 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -229,13 +229,13 @@ static bool _is_exact_type(const PropertyInfo &p_par_type, const GDScriptDataTyp
}
}
-static bool _can_use_ptrcall(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
+static bool _can_use_validate_call(const MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {
if (p_method->is_vararg()) {
- // ptrcall won't work with vararg methods.
+ // Validated call won't work with vararg methods.
return false;
}
if (p_method->get_argument_count() != p_arguments.size()) {
- // ptrcall won't work with default arguments.
+ // Validated call won't work with default arguments.
return false;
}
MethodInfo info;
@@ -636,9 +636,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
self.mode = GDScriptCodeGenerator::Address::SELF;
MethodBind *method = ClassDB::get_method(codegen.script->native->get_name(), call->function_name);
- if (_can_use_ptrcall(method, arguments)) {
- // Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, self, method, arguments);
+ if (_can_use_validate_call(method, arguments)) {
+ // Exact arguments, use validated call.
+ gen->write_call_method_bind_validated(result, self, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, self, method, arguments);
@@ -686,9 +686,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
if (ClassDB::class_exists(class_name) && ClassDB::has_method(class_name, call->function_name)) {
MethodBind *method = ClassDB::get_method(class_name, call->function_name);
- if (_can_use_ptrcall(method, arguments)) {
- // Exact arguments, use ptrcall.
- gen->write_call_ptrcall(result, base, method, arguments);
+ if (_can_use_validate_call(method, arguments)) {
+ // Exact arguments, use validated call.
+ gen->write_call_method_bind_validated(result, base, method, arguments);
} else {
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, base, method, arguments);
@@ -733,7 +733,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype(), codegen.script));
MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
- gen->write_call_ptrcall(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
+ gen->write_call_method_bind_validated(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
return result;
} break;
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 438ec02740..26f7cb7537 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -670,10 +670,29 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 4 + argc;
} break;
- case OPCODE_CALL_PTRCALL_NO_RETURN: {
+
+ case OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN: {
int instr_var_args = _code_ptr[++ip];
+ text += "call method-bind validated (return) ";
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+ text += DADDR(2 + argc) + " = ";
+ text += DADDR(1 + argc) + ".";
+ text += method->get_name();
+ text += "(";
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(1 + i);
+ }
+ text += ")";
+ incr = 5 + argc;
+ } break;
- text += "call-ptrcall (no return) ";
+ case OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN: {
+ int instr_var_args = _code_ptr[++ip];
+
+ text += "call method-bind validated (no return) ";
MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]];
@@ -694,65 +713,6 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 5 + argc;
} break;
-#define DISASSEMBLE_PTRCALL(m_type) \
- case OPCODE_CALL_PTRCALL_##m_type: { \
- int instr_var_args = _code_ptr[++ip]; \
- text += "call-ptrcall (return "; \
- text += #m_type; \
- text += ") "; \
- MethodBind *method = _methods_ptr[_code_ptr[ip + 2 + instr_var_args]]; \
- int argc = _code_ptr[ip + 1 + instr_var_args]; \
- text += DADDR(2 + argc) + " = "; \
- text += DADDR(1 + argc) + "."; \
- text += method->get_name(); \
- text += "("; \
- for (int i = 0; i < argc; i++) { \
- if (i > 0) \
- text += ", "; \
- text += DADDR(1 + i); \
- } \
- text += ")"; \
- incr = 5 + argc; \
- } break
-
- DISASSEMBLE_PTRCALL(BOOL);
- DISASSEMBLE_PTRCALL(INT);
- DISASSEMBLE_PTRCALL(FLOAT);
- DISASSEMBLE_PTRCALL(STRING);
- DISASSEMBLE_PTRCALL(VECTOR2);
- DISASSEMBLE_PTRCALL(VECTOR2I);
- DISASSEMBLE_PTRCALL(RECT2);
- DISASSEMBLE_PTRCALL(RECT2I);
- DISASSEMBLE_PTRCALL(VECTOR3);
- DISASSEMBLE_PTRCALL(VECTOR3I);
- DISASSEMBLE_PTRCALL(TRANSFORM2D);
- DISASSEMBLE_PTRCALL(VECTOR4);
- DISASSEMBLE_PTRCALL(VECTOR4I);
- DISASSEMBLE_PTRCALL(PLANE);
- DISASSEMBLE_PTRCALL(AABB);
- DISASSEMBLE_PTRCALL(BASIS);
- DISASSEMBLE_PTRCALL(TRANSFORM3D);
- DISASSEMBLE_PTRCALL(PROJECTION);
- DISASSEMBLE_PTRCALL(COLOR);
- DISASSEMBLE_PTRCALL(STRING_NAME);
- DISASSEMBLE_PTRCALL(NODE_PATH);
- DISASSEMBLE_PTRCALL(RID);
- DISASSEMBLE_PTRCALL(QUATERNION);
- DISASSEMBLE_PTRCALL(OBJECT);
- DISASSEMBLE_PTRCALL(CALLABLE);
- DISASSEMBLE_PTRCALL(SIGNAL);
- DISASSEMBLE_PTRCALL(DICTIONARY);
- DISASSEMBLE_PTRCALL(ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_BYTE_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_INT32_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_INT64_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_FLOAT32_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_FLOAT64_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_STRING_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_VECTOR2_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_VECTOR3_ARRAY);
- DISASSEMBLE_PTRCALL(PACKED_COLOR_ARRAY);
-
case OPCODE_CALL_BUILTIN_TYPE_VALIDATED: {
int instr_var_args = _code_ptr[++ip];
int argc = _code_ptr[ip + 1 + instr_var_args];
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 9cd3560063..e40f692889 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -54,6 +54,10 @@ void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const
p_delimiters->push_back("#");
}
+void GDScriptLanguage::get_doc_comment_delimiters(List<String> *p_delimiters) const {
+ p_delimiters->push_back("##");
+}
+
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("\" \"");
p_delimiters->push_back("' '");
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index e984d97149..c9b543fbb9 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -241,45 +241,8 @@ public:
OPCODE_CALL_METHOD_BIND_RET,
OPCODE_CALL_BUILTIN_STATIC,
OPCODE_CALL_NATIVE_STATIC,
- // ptrcall have one instruction per return type.
- OPCODE_CALL_PTRCALL_NO_RETURN,
- OPCODE_CALL_PTRCALL_BOOL,
- OPCODE_CALL_PTRCALL_INT,
- OPCODE_CALL_PTRCALL_FLOAT,
- OPCODE_CALL_PTRCALL_STRING,
- OPCODE_CALL_PTRCALL_VECTOR2,
- OPCODE_CALL_PTRCALL_VECTOR2I,
- OPCODE_CALL_PTRCALL_RECT2,
- OPCODE_CALL_PTRCALL_RECT2I,
- OPCODE_CALL_PTRCALL_VECTOR3,
- OPCODE_CALL_PTRCALL_VECTOR3I,
- OPCODE_CALL_PTRCALL_TRANSFORM2D,
- OPCODE_CALL_PTRCALL_VECTOR4,
- OPCODE_CALL_PTRCALL_VECTOR4I,
- OPCODE_CALL_PTRCALL_PLANE,
- OPCODE_CALL_PTRCALL_QUATERNION,
- OPCODE_CALL_PTRCALL_AABB,
- OPCODE_CALL_PTRCALL_BASIS,
- OPCODE_CALL_PTRCALL_TRANSFORM3D,
- OPCODE_CALL_PTRCALL_PROJECTION,
- OPCODE_CALL_PTRCALL_COLOR,
- OPCODE_CALL_PTRCALL_STRING_NAME,
- OPCODE_CALL_PTRCALL_NODE_PATH,
- OPCODE_CALL_PTRCALL_RID,
- OPCODE_CALL_PTRCALL_OBJECT,
- OPCODE_CALL_PTRCALL_CALLABLE,
- OPCODE_CALL_PTRCALL_SIGNAL,
- OPCODE_CALL_PTRCALL_DICTIONARY,
- OPCODE_CALL_PTRCALL_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY,
- OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY,
+ OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN,
+ OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
OPCODE_CREATE_LAMBDA,
@@ -425,7 +388,6 @@ private:
int _argument_count = 0;
int _stack_size = 0;
int _instruction_args_size = 0;
- int _ptrcall_args_size = 0;
SelfList<GDScriptFunction> function_list{ this };
mutable Variant nil;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 057c2b49ab..db7b3e7ace 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -32,10 +32,6 @@
#include "gdscript.h"
-#ifdef DEBUG_ENABLED
-#include "gdscript_warning.h"
-#endif
-
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
@@ -5410,7 +5406,7 @@ void GDScriptParser::TreePrinter::print_while(WhileNode *p_while) {
}
void GDScriptParser::TreePrinter::print_tree(const GDScriptParser &p_parser) {
- ERR_FAIL_COND_MSG(p_parser.get_tree() == nullptr, "Parse the code before printing the parse tree.");
+ ERR_FAIL_NULL_MSG(p_parser.get_tree(), "Parse the code before printing the parse tree.");
if (p_parser.is_tool()) {
push_line("@tool");
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 5ecae08f6c..75dc2e4f8b 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -187,191 +187,155 @@ void (*type_init_function_table[])(Variant *) = {
};
#if defined(__GNUC__)
-#define OPCODES_TABLE \
- static const void *switch_table_ops[] = { \
- &&OPCODE_OPERATOR, \
- &&OPCODE_OPERATOR_VALIDATED, \
- &&OPCODE_TYPE_TEST_BUILTIN, \
- &&OPCODE_TYPE_TEST_ARRAY, \
- &&OPCODE_TYPE_TEST_NATIVE, \
- &&OPCODE_TYPE_TEST_SCRIPT, \
- &&OPCODE_SET_KEYED, \
- &&OPCODE_SET_KEYED_VALIDATED, \
- &&OPCODE_SET_INDEXED_VALIDATED, \
- &&OPCODE_GET_KEYED, \
- &&OPCODE_GET_KEYED_VALIDATED, \
- &&OPCODE_GET_INDEXED_VALIDATED, \
- &&OPCODE_SET_NAMED, \
- &&OPCODE_SET_NAMED_VALIDATED, \
- &&OPCODE_GET_NAMED, \
- &&OPCODE_GET_NAMED_VALIDATED, \
- &&OPCODE_SET_MEMBER, \
- &&OPCODE_GET_MEMBER, \
- &&OPCODE_SET_STATIC_VARIABLE, \
- &&OPCODE_GET_STATIC_VARIABLE, \
- &&OPCODE_ASSIGN, \
- &&OPCODE_ASSIGN_TRUE, \
- &&OPCODE_ASSIGN_FALSE, \
- &&OPCODE_ASSIGN_TYPED_BUILTIN, \
- &&OPCODE_ASSIGN_TYPED_ARRAY, \
- &&OPCODE_ASSIGN_TYPED_NATIVE, \
- &&OPCODE_ASSIGN_TYPED_SCRIPT, \
- &&OPCODE_CAST_TO_BUILTIN, \
- &&OPCODE_CAST_TO_NATIVE, \
- &&OPCODE_CAST_TO_SCRIPT, \
- &&OPCODE_CONSTRUCT, \
- &&OPCODE_CONSTRUCT_VALIDATED, \
- &&OPCODE_CONSTRUCT_ARRAY, \
- &&OPCODE_CONSTRUCT_TYPED_ARRAY, \
- &&OPCODE_CONSTRUCT_DICTIONARY, \
- &&OPCODE_CALL, \
- &&OPCODE_CALL_RETURN, \
- &&OPCODE_CALL_ASYNC, \
- &&OPCODE_CALL_UTILITY, \
- &&OPCODE_CALL_UTILITY_VALIDATED, \
- &&OPCODE_CALL_GDSCRIPT_UTILITY, \
- &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
- &&OPCODE_CALL_SELF_BASE, \
- &&OPCODE_CALL_METHOD_BIND, \
- &&OPCODE_CALL_METHOD_BIND_RET, \
- &&OPCODE_CALL_BUILTIN_STATIC, \
- &&OPCODE_CALL_NATIVE_STATIC, \
- &&OPCODE_CALL_PTRCALL_NO_RETURN, \
- &&OPCODE_CALL_PTRCALL_BOOL, \
- &&OPCODE_CALL_PTRCALL_INT, \
- &&OPCODE_CALL_PTRCALL_FLOAT, \
- &&OPCODE_CALL_PTRCALL_STRING, \
- &&OPCODE_CALL_PTRCALL_VECTOR2, \
- &&OPCODE_CALL_PTRCALL_VECTOR2I, \
- &&OPCODE_CALL_PTRCALL_RECT2, \
- &&OPCODE_CALL_PTRCALL_RECT2I, \
- &&OPCODE_CALL_PTRCALL_VECTOR3, \
- &&OPCODE_CALL_PTRCALL_VECTOR3I, \
- &&OPCODE_CALL_PTRCALL_TRANSFORM2D, \
- &&OPCODE_CALL_PTRCALL_VECTOR4, \
- &&OPCODE_CALL_PTRCALL_VECTOR4I, \
- &&OPCODE_CALL_PTRCALL_PLANE, \
- &&OPCODE_CALL_PTRCALL_QUATERNION, \
- &&OPCODE_CALL_PTRCALL_AABB, \
- &&OPCODE_CALL_PTRCALL_BASIS, \
- &&OPCODE_CALL_PTRCALL_TRANSFORM3D, \
- &&OPCODE_CALL_PTRCALL_PROJECTION, \
- &&OPCODE_CALL_PTRCALL_COLOR, \
- &&OPCODE_CALL_PTRCALL_STRING_NAME, \
- &&OPCODE_CALL_PTRCALL_NODE_PATH, \
- &&OPCODE_CALL_PTRCALL_RID, \
- &&OPCODE_CALL_PTRCALL_OBJECT, \
- &&OPCODE_CALL_PTRCALL_CALLABLE, \
- &&OPCODE_CALL_PTRCALL_SIGNAL, \
- &&OPCODE_CALL_PTRCALL_DICTIONARY, \
- &&OPCODE_CALL_PTRCALL_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_BYTE_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_INT32_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_INT64_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_FLOAT32_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_FLOAT64_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_STRING_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_VECTOR2_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_VECTOR3_ARRAY, \
- &&OPCODE_CALL_PTRCALL_PACKED_COLOR_ARRAY, \
- &&OPCODE_AWAIT, \
- &&OPCODE_AWAIT_RESUME, \
- &&OPCODE_CREATE_LAMBDA, \
- &&OPCODE_CREATE_SELF_LAMBDA, \
- &&OPCODE_JUMP, \
- &&OPCODE_JUMP_IF, \
- &&OPCODE_JUMP_IF_NOT, \
- &&OPCODE_JUMP_TO_DEF_ARGUMENT, \
- &&OPCODE_JUMP_IF_SHARED, \
- &&OPCODE_RETURN, \
- &&OPCODE_RETURN_TYPED_BUILTIN, \
- &&OPCODE_RETURN_TYPED_ARRAY, \
- &&OPCODE_RETURN_TYPED_NATIVE, \
- &&OPCODE_RETURN_TYPED_SCRIPT, \
- &&OPCODE_ITERATE_BEGIN, \
- &&OPCODE_ITERATE_BEGIN_INT, \
- &&OPCODE_ITERATE_BEGIN_FLOAT, \
- &&OPCODE_ITERATE_BEGIN_VECTOR2, \
- &&OPCODE_ITERATE_BEGIN_VECTOR2I, \
- &&OPCODE_ITERATE_BEGIN_VECTOR3, \
- &&OPCODE_ITERATE_BEGIN_VECTOR3I, \
- &&OPCODE_ITERATE_BEGIN_STRING, \
- &&OPCODE_ITERATE_BEGIN_DICTIONARY, \
- &&OPCODE_ITERATE_BEGIN_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
- &&OPCODE_ITERATE_BEGIN_OBJECT, \
- &&OPCODE_ITERATE, \
- &&OPCODE_ITERATE_INT, \
- &&OPCODE_ITERATE_FLOAT, \
- &&OPCODE_ITERATE_VECTOR2, \
- &&OPCODE_ITERATE_VECTOR2I, \
- &&OPCODE_ITERATE_VECTOR3, \
- &&OPCODE_ITERATE_VECTOR3I, \
- &&OPCODE_ITERATE_STRING, \
- &&OPCODE_ITERATE_DICTIONARY, \
- &&OPCODE_ITERATE_ARRAY, \
- &&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
- &&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
- &&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
- &&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
- &&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
- &&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
- &&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
- &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
- &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
- &&OPCODE_ITERATE_OBJECT, \
- &&OPCODE_STORE_GLOBAL, \
- &&OPCODE_STORE_NAMED_GLOBAL, \
- &&OPCODE_TYPE_ADJUST_BOOL, \
- &&OPCODE_TYPE_ADJUST_INT, \
- &&OPCODE_TYPE_ADJUST_FLOAT, \
- &&OPCODE_TYPE_ADJUST_STRING, \
- &&OPCODE_TYPE_ADJUST_VECTOR2, \
- &&OPCODE_TYPE_ADJUST_VECTOR2I, \
- &&OPCODE_TYPE_ADJUST_RECT2, \
- &&OPCODE_TYPE_ADJUST_RECT2I, \
- &&OPCODE_TYPE_ADJUST_VECTOR3, \
- &&OPCODE_TYPE_ADJUST_VECTOR3I, \
- &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
- &&OPCODE_TYPE_ADJUST_VECTOR4, \
- &&OPCODE_TYPE_ADJUST_VECTOR4I, \
- &&OPCODE_TYPE_ADJUST_PLANE, \
- &&OPCODE_TYPE_ADJUST_QUATERNION, \
- &&OPCODE_TYPE_ADJUST_AABB, \
- &&OPCODE_TYPE_ADJUST_BASIS, \
- &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
- &&OPCODE_TYPE_ADJUST_PROJECTION, \
- &&OPCODE_TYPE_ADJUST_COLOR, \
- &&OPCODE_TYPE_ADJUST_STRING_NAME, \
- &&OPCODE_TYPE_ADJUST_NODE_PATH, \
- &&OPCODE_TYPE_ADJUST_RID, \
- &&OPCODE_TYPE_ADJUST_OBJECT, \
- &&OPCODE_TYPE_ADJUST_CALLABLE, \
- &&OPCODE_TYPE_ADJUST_SIGNAL, \
- &&OPCODE_TYPE_ADJUST_DICTIONARY, \
- &&OPCODE_TYPE_ADJUST_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
- &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
- &&OPCODE_ASSERT, \
- &&OPCODE_BREAKPOINT, \
- &&OPCODE_LINE, \
- &&OPCODE_END \
- }; \
+#define OPCODES_TABLE \
+ static const void *switch_table_ops[] = { \
+ &&OPCODE_OPERATOR, \
+ &&OPCODE_OPERATOR_VALIDATED, \
+ &&OPCODE_TYPE_TEST_BUILTIN, \
+ &&OPCODE_TYPE_TEST_ARRAY, \
+ &&OPCODE_TYPE_TEST_NATIVE, \
+ &&OPCODE_TYPE_TEST_SCRIPT, \
+ &&OPCODE_SET_KEYED, \
+ &&OPCODE_SET_KEYED_VALIDATED, \
+ &&OPCODE_SET_INDEXED_VALIDATED, \
+ &&OPCODE_GET_KEYED, \
+ &&OPCODE_GET_KEYED_VALIDATED, \
+ &&OPCODE_GET_INDEXED_VALIDATED, \
+ &&OPCODE_SET_NAMED, \
+ &&OPCODE_SET_NAMED_VALIDATED, \
+ &&OPCODE_GET_NAMED, \
+ &&OPCODE_GET_NAMED_VALIDATED, \
+ &&OPCODE_SET_MEMBER, \
+ &&OPCODE_GET_MEMBER, \
+ &&OPCODE_SET_STATIC_VARIABLE, \
+ &&OPCODE_GET_STATIC_VARIABLE, \
+ &&OPCODE_ASSIGN, \
+ &&OPCODE_ASSIGN_TRUE, \
+ &&OPCODE_ASSIGN_FALSE, \
+ &&OPCODE_ASSIGN_TYPED_BUILTIN, \
+ &&OPCODE_ASSIGN_TYPED_ARRAY, \
+ &&OPCODE_ASSIGN_TYPED_NATIVE, \
+ &&OPCODE_ASSIGN_TYPED_SCRIPT, \
+ &&OPCODE_CAST_TO_BUILTIN, \
+ &&OPCODE_CAST_TO_NATIVE, \
+ &&OPCODE_CAST_TO_SCRIPT, \
+ &&OPCODE_CONSTRUCT, \
+ &&OPCODE_CONSTRUCT_VALIDATED, \
+ &&OPCODE_CONSTRUCT_ARRAY, \
+ &&OPCODE_CONSTRUCT_TYPED_ARRAY, \
+ &&OPCODE_CONSTRUCT_DICTIONARY, \
+ &&OPCODE_CALL, \
+ &&OPCODE_CALL_RETURN, \
+ &&OPCODE_CALL_ASYNC, \
+ &&OPCODE_CALL_UTILITY, \
+ &&OPCODE_CALL_UTILITY_VALIDATED, \
+ &&OPCODE_CALL_GDSCRIPT_UTILITY, \
+ &&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
+ &&OPCODE_CALL_SELF_BASE, \
+ &&OPCODE_CALL_METHOD_BIND, \
+ &&OPCODE_CALL_METHOD_BIND_RET, \
+ &&OPCODE_CALL_BUILTIN_STATIC, \
+ &&OPCODE_CALL_NATIVE_STATIC, \
+ &&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
+ &&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
+ &&OPCODE_AWAIT, \
+ &&OPCODE_AWAIT_RESUME, \
+ &&OPCODE_CREATE_LAMBDA, \
+ &&OPCODE_CREATE_SELF_LAMBDA, \
+ &&OPCODE_JUMP, \
+ &&OPCODE_JUMP_IF, \
+ &&OPCODE_JUMP_IF_NOT, \
+ &&OPCODE_JUMP_TO_DEF_ARGUMENT, \
+ &&OPCODE_JUMP_IF_SHARED, \
+ &&OPCODE_RETURN, \
+ &&OPCODE_RETURN_TYPED_BUILTIN, \
+ &&OPCODE_RETURN_TYPED_ARRAY, \
+ &&OPCODE_RETURN_TYPED_NATIVE, \
+ &&OPCODE_RETURN_TYPED_SCRIPT, \
+ &&OPCODE_ITERATE_BEGIN, \
+ &&OPCODE_ITERATE_BEGIN_INT, \
+ &&OPCODE_ITERATE_BEGIN_FLOAT, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR2, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR2I, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR3, \
+ &&OPCODE_ITERATE_BEGIN_VECTOR3I, \
+ &&OPCODE_ITERATE_BEGIN_STRING, \
+ &&OPCODE_ITERATE_BEGIN_DICTIONARY, \
+ &&OPCODE_ITERATE_BEGIN_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
+ &&OPCODE_ITERATE_BEGIN_OBJECT, \
+ &&OPCODE_ITERATE, \
+ &&OPCODE_ITERATE_INT, \
+ &&OPCODE_ITERATE_FLOAT, \
+ &&OPCODE_ITERATE_VECTOR2, \
+ &&OPCODE_ITERATE_VECTOR2I, \
+ &&OPCODE_ITERATE_VECTOR3, \
+ &&OPCODE_ITERATE_VECTOR3I, \
+ &&OPCODE_ITERATE_STRING, \
+ &&OPCODE_ITERATE_DICTIONARY, \
+ &&OPCODE_ITERATE_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
+ &&OPCODE_ITERATE_OBJECT, \
+ &&OPCODE_STORE_GLOBAL, \
+ &&OPCODE_STORE_NAMED_GLOBAL, \
+ &&OPCODE_TYPE_ADJUST_BOOL, \
+ &&OPCODE_TYPE_ADJUST_INT, \
+ &&OPCODE_TYPE_ADJUST_FLOAT, \
+ &&OPCODE_TYPE_ADJUST_STRING, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2I, \
+ &&OPCODE_TYPE_ADJUST_RECT2, \
+ &&OPCODE_TYPE_ADJUST_RECT2I, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3I, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
+ &&OPCODE_TYPE_ADJUST_VECTOR4, \
+ &&OPCODE_TYPE_ADJUST_VECTOR4I, \
+ &&OPCODE_TYPE_ADJUST_PLANE, \
+ &&OPCODE_TYPE_ADJUST_QUATERNION, \
+ &&OPCODE_TYPE_ADJUST_AABB, \
+ &&OPCODE_TYPE_ADJUST_BASIS, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
+ &&OPCODE_TYPE_ADJUST_PROJECTION, \
+ &&OPCODE_TYPE_ADJUST_COLOR, \
+ &&OPCODE_TYPE_ADJUST_STRING_NAME, \
+ &&OPCODE_TYPE_ADJUST_NODE_PATH, \
+ &&OPCODE_TYPE_ADJUST_RID, \
+ &&OPCODE_TYPE_ADJUST_OBJECT, \
+ &&OPCODE_TYPE_ADJUST_CALLABLE, \
+ &&OPCODE_TYPE_ADJUST_SIGNAL, \
+ &&OPCODE_TYPE_ADJUST_DICTIONARY, \
+ &&OPCODE_TYPE_ADJUST_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
+ &&OPCODE_ASSERT, \
+ &&OPCODE_BREAKPOINT, \
+ &&OPCODE_LINE, \
+ &&OPCODE_END \
+ }; \
static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
#define OPCODE(m_op) \
@@ -489,7 +453,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Variant retvalue;
Variant *stack = nullptr;
Variant **instruction_args = nullptr;
- const void **call_args_ptr = nullptr;
int defarg = 0;
#ifdef DEBUG_ENABLED
@@ -578,12 +541,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
}
- if (_ptrcall_args_size) {
- call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
- } else {
- call_args_ptr = nullptr;
- }
-
if (p_instance) {
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr();
@@ -1954,106 +1911,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
-#ifdef DEBUG_ENABLED
-#define OPCODE_CALL_PTR(m_type) \
- OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
- LOAD_INSTRUCTION_ARGS \
- CHECK_SPACE(3 + instr_arg_count); \
- ip += instr_arg_count; \
- int argc = _code_ptr[ip + 1]; \
- GD_ERR_BREAK(argc < 0); \
- GET_INSTRUCTION_ARG(base, argc); \
- GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); \
- MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
- bool freed = false; \
- Object *base_obj = base->get_validated_object_with_check(freed); \
- if (freed) { \
- err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR(method); \
- OPCODE_BREAK; \
- } else if (!base_obj) { \
- err_text = METHOD_CALL_ON_NULL_VALUE_ERROR(method); \
- OPCODE_BREAK; \
- } \
- const void **argptrs = call_args_ptr; \
- for (int i = 0; i < argc; i++) { \
- GET_INSTRUCTION_ARG(v, i); \
- argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
- } \
- uint64_t call_time = 0; \
- if (GDScriptLanguage::get_singleton()->profiling) { \
- call_time = OS::get_singleton()->get_ticks_usec(); \
- } \
- GET_INSTRUCTION_ARG(ret, argc + 1); \
- VariantInternal::initialize(ret, Variant::m_type); \
- void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
- method->ptrcall(base_obj, argptrs, ret_opaque); \
- if (GDScriptLanguage::get_singleton()->profiling) { \
- function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; \
- } \
- ip += 3; \
- } \
- DISPATCH_OPCODE
-#else
-#define OPCODE_CALL_PTR(m_type) \
- OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
- LOAD_INSTRUCTION_ARGS \
- CHECK_SPACE(3 + instr_arg_count); \
- ip += instr_arg_count; \
- int argc = _code_ptr[ip + 1]; \
- GET_INSTRUCTION_ARG(base, argc); \
- MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
- Object *base_obj = *VariantInternal::get_object(base); \
- const void **argptrs = call_args_ptr; \
- for (int i = 0; i < argc; i++) { \
- GET_INSTRUCTION_ARG(v, i); \
- argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v); \
- } \
- GET_INSTRUCTION_ARG(ret, argc + 1); \
- VariantInternal::initialize(ret, Variant::m_type); \
- void *ret_opaque = VariantInternal::OP_GET_##m_type(ret); \
- method->ptrcall(base_obj, argptrs, ret_opaque); \
- ip += 3; \
- } \
- DISPATCH_OPCODE
-#endif
-
- OPCODE_CALL_PTR(BOOL);
- OPCODE_CALL_PTR(INT);
- OPCODE_CALL_PTR(FLOAT);
- OPCODE_CALL_PTR(STRING);
- OPCODE_CALL_PTR(VECTOR2);
- OPCODE_CALL_PTR(VECTOR2I);
- OPCODE_CALL_PTR(RECT2);
- OPCODE_CALL_PTR(RECT2I);
- OPCODE_CALL_PTR(VECTOR3);
- OPCODE_CALL_PTR(VECTOR3I);
- OPCODE_CALL_PTR(TRANSFORM2D);
- OPCODE_CALL_PTR(VECTOR4);
- OPCODE_CALL_PTR(VECTOR4I);
- OPCODE_CALL_PTR(PLANE);
- OPCODE_CALL_PTR(QUATERNION);
- OPCODE_CALL_PTR(AABB);
- OPCODE_CALL_PTR(BASIS);
- OPCODE_CALL_PTR(TRANSFORM3D);
- OPCODE_CALL_PTR(PROJECTION);
- OPCODE_CALL_PTR(COLOR);
- OPCODE_CALL_PTR(STRING_NAME);
- OPCODE_CALL_PTR(NODE_PATH);
- OPCODE_CALL_PTR(RID);
- OPCODE_CALL_PTR(CALLABLE);
- OPCODE_CALL_PTR(SIGNAL);
- OPCODE_CALL_PTR(DICTIONARY);
- OPCODE_CALL_PTR(ARRAY);
- OPCODE_CALL_PTR(PACKED_BYTE_ARRAY);
- OPCODE_CALL_PTR(PACKED_INT32_ARRAY);
- OPCODE_CALL_PTR(PACKED_INT64_ARRAY);
- OPCODE_CALL_PTR(PACKED_FLOAT32_ARRAY);
- OPCODE_CALL_PTR(PACKED_FLOAT64_ARRAY);
- OPCODE_CALL_PTR(PACKED_STRING_ARRAY);
- OPCODE_CALL_PTR(PACKED_VECTOR2_ARRAY);
- OPCODE_CALL_PTR(PACKED_VECTOR3_ARRAY);
- OPCODE_CALL_PTR(PACKED_COLOR_ARRAY);
- OPCODE(OPCODE_CALL_PTRCALL_OBJECT) {
+ OPCODE(OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN) {
LOAD_INSTRUCTION_ARGS
CHECK_SPACE(3 + instr_arg_count);
@@ -2066,6 +1924,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]];
GET_INSTRUCTION_ARG(base, argc);
+
#ifdef DEBUG_ENABLED
bool freed = false;
Object *base_obj = base->get_validated_object_with_check(freed);
@@ -2080,12 +1939,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Object *base_obj = *VariantInternal::get_object(base);
#endif
- const void **argptrs = call_args_ptr;
+ Variant **argptrs = instruction_args;
- for (int i = 0; i < argc; i++) {
- GET_INSTRUCTION_ARG(v, i);
- argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
- }
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
@@ -2095,16 +1950,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
GET_INSTRUCTION_ARG(ret, argc + 1);
- VariantInternal::initialize(ret, Variant::OBJECT);
- Object **ret_opaque = VariantInternal::get_object(ret);
- method->ptrcall(base_obj, argptrs, ret_opaque);
- if (method->is_return_type_raw_object_ptr()) {
- // The Variant has to participate in the ref count since the method returns a raw Object *.
- VariantInternal::object_assign(ret, *ret_opaque);
- } else {
- // The method, in case it returns something, returns an already encapsulated object.
- VariantInternal::update_object_id(ret);
- }
+ method->validated_call(base_obj, (const Variant **)argptrs, ret);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
@@ -2114,7 +1960,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
ip += 3;
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_CALL_PTRCALL_NO_RETURN) {
+
+ OPCODE(OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN) {
LOAD_INSTRUCTION_ARGS
CHECK_SPACE(3 + instr_arg_count);
@@ -2140,12 +1987,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#else
Object *base_obj = *VariantInternal::get_object(base);
#endif
- const void **argptrs = call_args_ptr;
-
- for (int i = 0; i < argc; i++) {
- GET_INSTRUCTION_ARG(v, i);
- argptrs[i] = VariantInternal::get_opaque_pointer((const Variant *)v);
- }
+ Variant **argptrs = instruction_args;
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
@@ -2156,7 +1998,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_INSTRUCTION_ARG(ret, argc + 1);
VariantInternal::initialize(ret, Variant::NIL);
- method->ptrcall(base_obj, argptrs, nullptr);
+ method->validated_call(base_obj, (const Variant **)argptrs, nullptr);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
index fd1460a48f..691b611574 100644
--- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
@@ -7,7 +7,7 @@ func test():
test_builtin_call_validated(Vector2.UP, false)
test_object_call(RefCounted.new(), false)
test_object_call_method_bind(Resource.new(), false)
- test_object_call_ptrcall(RefCounted.new(), false)
+ test_object_call_method_bind_validated(RefCounted.new(), false)
print("end")
@@ -40,7 +40,7 @@ func test_object_call_method_bind(v: Resource, f):
v.duplicate() # Native type method call with MethodBind.
assert(not f) # Test unary operator reading from `nil`.
-func test_object_call_ptrcall(v: RefCounted, f):
+func test_object_call_method_bind_validated(v: RefCounted, f):
@warning_ignore("return_value_discarded")
- v.get_reference_count() # Native type method call with ptrcall.
+ v.get_reference_count() # Native type method call with validated MethodBind.
assert(not f) # Test unary operator reading from `nil`.
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 595b14f260..324eb79ea2 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -4340,7 +4340,7 @@ Error GLTFDocument::_expand_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) {
}
Error GLTFDocument::_verify_skin(Ref<GLTFState> p_state, Ref<GLTFSkin> p_skin) {
- // This may seem duplicated from expand_skins, but this is really a sanity check! (so it kinda is)
+ // This may seem duplicated from expand_skins, but this is really a safety check! (so it kinda is)
// In case additional interpolating logic is added to the skins, this will help ensure that you
// do not cause it to self implode into a fiery blaze
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 556b0b4374..953b0634eb 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -35,7 +35,10 @@
#include "lm_raster.glsl.gen.h"
#include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
#include "core/math/geometry_2d.h"
+#include "editor/editor_paths.h"
+#include "editor/editor_settings.h"
#include "servers/rendering/rendering_device_binds.h"
//uncomment this if you want to see textures from all the process saved
@@ -671,6 +674,131 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
return BAKE_OK;
}
+Error LightmapperRD::_store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name) {
+ Vector<uint8_t> data = p_rd->texture_get_data(p_atlas_tex, p_index);
+ Ref<Image> img = Image::create_from_data(p_atlas_size.width, p_atlas_size.height, false, Image::FORMAT_RGBAH, data);
+ img->convert(Image::FORMAT_RGBF);
+ Vector<uint8_t> data_float = img->get_data();
+
+ Error err = OK;
+ Ref<FileAccess> file = FileAccess::open(p_name, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save PFN at path: '%s'.", p_name));
+ file->store_line("PF");
+ file->store_line(vformat("%d %d", img->get_width(), img->get_height()));
+#ifdef BIG_ENDIAN_ENABLED
+ file->store_line("1.0");
+#else
+ file->store_line("-1.0");
+#endif
+ file->store_buffer(data_float);
+ file->close();
+
+ return OK;
+}
+
+Ref<Image> LightmapperRD::_read_pfm(const String &p_name) {
+ Error err = OK;
+ Ref<FileAccess> file = FileAccess::open(p_name, FileAccess::READ, &err);
+ ERR_FAIL_COND_V_MSG(err, Ref<Image>(), vformat("Can't load PFM at path: '%s'.", p_name));
+ ERR_FAIL_COND_V(file->get_line() != "PF", Ref<Image>());
+
+ Vector<String> new_size = file->get_line().split(" ");
+ ERR_FAIL_COND_V(new_size.size() != 2, Ref<Image>());
+ int new_width = new_size[0].to_int();
+ int new_height = new_size[1].to_int();
+
+ float endian = file->get_line().to_float();
+ Vector<uint8_t> new_data = file->get_buffer(file->get_length() - file->get_position());
+ file->close();
+
+#ifdef BIG_ENDIAN_ENABLED
+ if (unlikely(endian < 0.0)) {
+ uint32_t count = new_data.size() / 4;
+ uint16_t *dst = (uint16_t *)new_data.ptrw();
+ for (uint32_t j = 0; j < count; j++) {
+ dst[j * 4] = BSWAP32(dst[j * 4]);
+ }
+ }
+#else
+ if (unlikely(endian > 0.0)) {
+ uint32_t count = new_data.size() / 4;
+ uint16_t *dst = (uint16_t *)new_data.ptrw();
+ for (uint32_t j = 0; j < count; j++) {
+ dst[j * 4] = BSWAP32(dst[j * 4]);
+ }
+ }
+#endif
+ Ref<Image> img = Image::create_from_data(new_width, new_height, false, Image::FORMAT_RGBF, new_data);
+ img->convert(Image::FORMAT_RGBAH);
+ return img;
+}
+
+LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, const String &p_exe) {
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ for (int i = 0; i < p_atlas_slices; i++) {
+ String fname_norm_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_norm_%d.pfm", i));
+ _store_pfm(p_rd, p_source_normal_tex, i, p_atlas_size, fname_norm_in);
+
+ for (int j = 0; j < (p_bake_sh ? 4 : 1); j++) {
+ int index = i * (p_bake_sh ? 4 : 1) + j;
+ String fname_light_in = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_light_%d.pfm", index));
+ String fname_out = EditorPaths::get_singleton()->get_cache_dir().path_join(vformat("temp_denoised_%d.pfm", index));
+
+ _store_pfm(p_rd, p_source_light_tex, index, p_atlas_size, fname_light_in);
+
+ List<String> args;
+ args.push_back("--device");
+ args.push_back("default");
+
+ args.push_back("--filter");
+ args.push_back("RTLightmap");
+
+ args.push_back("--hdr");
+ args.push_back(fname_light_in);
+
+ args.push_back("--nrm");
+ args.push_back(fname_norm_in);
+
+ args.push_back("--output");
+ args.push_back(fname_out);
+
+ String str;
+ int exitcode = 0;
+
+ Error err = OS::get_singleton()->execute(p_exe, args, &str, &exitcode, true);
+
+ da->remove(fname_light_in);
+
+ if (err != OK || exitcode != 0) {
+ da->remove(fname_out);
+ print_verbose(str);
+ ERR_FAIL_V_MSG(BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, vformat(TTR("OIDN denoiser failed, return code: %d"), exitcode));
+ }
+
+ Ref<Image> img = _read_pfm(fname_out);
+ da->remove(fname_out);
+
+ ERR_FAIL_COND_V(img.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
+
+ Vector<uint8_t> old_data = p_rd->texture_get_data(p_source_light_tex, index);
+ Vector<uint8_t> new_data = img->get_data();
+ img.unref(); // Avoid copy on write.
+
+ uint32_t count = old_data.size() / 2;
+ const uint16_t *src = (const uint16_t *)old_data.ptr();
+ uint16_t *dst = (uint16_t *)new_data.ptrw();
+ for (uint32_t k = 0; k < count; k += 4) {
+ dst[k + 3] = src[k + 3];
+ }
+
+ p_rd->texture_update(p_dest_light_tex, index, new_data);
+ }
+ da->remove(fname_norm_in);
+ }
+ return BAKE_OK;
+}
+
LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function) {
RID denoise_params_buffer = p_rd->uniform_buffer_create(sizeof(DenoiseParams));
DenoiseParams denoise_params;
@@ -742,6 +870,23 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
}
LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, float p_denoiser_strength, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata, float p_exposure_normalization) {
+ int denoiser = GLOBAL_GET("rendering/lightmapping/denoising/denoiser");
+ String oidn_path = EDITOR_GET("filesystem/tools/oidn/oidn_denoise_path");
+
+ if (p_use_denoiser && denoiser == 1) {
+ // OIDN (external).
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ if (da->dir_exists(oidn_path)) {
+ if (OS::get_singleton()->get_name() == "Windows") {
+ oidn_path = oidn_path.path_join("oidnDenoise.exe");
+ } else {
+ oidn_path = oidn_path.path_join("oidnDenoise");
+ }
+ }
+ ERR_FAIL_COND_V_MSG(oidn_path.is_empty() || !da->file_exists(oidn_path), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES, TTR("OIDN denoiser is selected in the project settings, but no or invalid OIDN executable path is configured in the editor settings."));
+ }
+
if (p_step_function) {
p_step_function(0.0, RTR("Begin Bake"), p_bake_userdata, true);
}
@@ -1501,8 +1646,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
{
- SWAP(light_accum_tex, light_accum_tex2);
- BakeError error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, atlas_size, atlas_slices, p_bake_sh, p_step_function);
+ BakeError error;
+ if (denoiser == 1) {
+ // OIDN (external).
+ error = _denoise_oidn(rd, light_accum_tex, normal_tex, light_accum_tex, atlas_size, atlas_slices, p_bake_sh, oidn_path);
+ } else {
+ // JNLM (built-in).
+ SWAP(light_accum_tex, light_accum_tex2);
+ error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, atlas_size, atlas_slices, p_bake_sh, p_step_function);
+ }
if (unlikely(error != BAKE_OK)) {
return error;
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index 7120a21b84..9537d5eae6 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -246,6 +246,10 @@ class LightmapperRD : public Lightmapper {
BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function);
+ Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name);
+ Ref<Image> _read_pfm(const String &p_name);
+ BakeError _denoise_oidn(RenderingDevice *p_rd, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, const String &p_exe);
+
public:
virtual void add_mesh(const MeshData &p_mesh) override;
virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) override;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index ce33f2ed1d..cccf7db96e 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -205,6 +205,14 @@ uint trace_ray(vec3 p_from, vec3 p_to
return RAY_ANY; //any hit good
#endif
+ vec3 position = p_from + dir * distance;
+ vec3 hit_cell = (position - params.to_cell_offset) * params.to_cell_size;
+ if (icell != ivec3(hit_cell)) {
+ // It's possible for the ray to hit a triangle in a position outside the bounds of the cell
+ // if it's large enough to cover multiple ones. The hit must be ignored if this is the case.
+ continue;
+ }
+
#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
if (!backface) {
// the case of meshes having both a front and back face in the same plane is more common than
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 984ce88316..a6dd76efc9 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -58,6 +58,8 @@ void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_probe_ray_count", 512);
GLOBAL_DEF("rendering/lightmapping/bake_quality/ultra_quality_probe_ray_count", 2048);
GLOBAL_DEF("rendering/lightmapping/bake_performance/max_rays_per_probe_pass", 64);
+
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lightmapping/denoising/denoiser", PROPERTY_HINT_ENUM, "JNLM,OIDN"), 0);
#ifndef _3D_DISABLED
GDREGISTER_CLASS(LightmapperRD);
Lightmapper::create_gpu = create_lightmapper_rd;
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 9846d60c33..859d77b262 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,6 +1,6 @@
# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "android", "web", "ios"]
# Eventually support for each them should be added back.
-supported_platforms = ["windows", "macos", "linuxbsd", "android"]
+supported_platforms = ["windows", "macos", "linuxbsd", "android", "ios"]
def can_build(env, platform):
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 95bf848cbf..23d0eb8b67 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -328,6 +328,11 @@ void CSharpLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("/* */"); // delimited comment
}
+void CSharpLanguage::get_doc_comment_delimiters(List<String> *p_delimiters) const {
+ p_delimiters->push_back("///"); // single-line doc comment
+ p_delimiters->push_back("/** */"); // delimited doc comment
+}
+
void CSharpLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("' '"); // character literal
p_delimiters->push_back("\" \""); // regular string literal
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 2ab80c132d..e381f0e840 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -419,6 +419,7 @@ public:
void get_reserved_words(List<String> *p_words) const override;
bool is_control_flow_keyword(String p_keyword) const override;
void get_comment_delimiters(List<String> *p_delimiters) const override;
+ void get_doc_comment_delimiters(List<String> *p_delimiters) const override;
void get_string_delimiters(List<String> *p_delimiters) const override;
bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
index 663eb14f07..ad3a10ba49 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -29,5 +29,7 @@
<None Include="$(GodotSdkPackageVersionsFilePath)" Pack="true" PackagePath="Sdk">
<Link>Sdk\SdkPackageVersions.props</Link>
</None>
+ <None Include="Sdk\iOSNativeAOT.props" Pack="true" PackagePath="Sdk" />
+ <None Include="Sdk\iOSNativeAOT.targets" Pack="true" PackagePath="Sdk" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index b35cec64f3..b6c72bce9d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -60,6 +60,18 @@
<!-- Auto-detect the target Godot platform if it was not specified. -->
<PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
+ <GodotTargetPlatform Condition=" $(RuntimeIdentifier.StartsWith('ios')) ">ios</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('android')) ">android</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('browser')) ">web</GodotTargetPlatform>
+
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('linux')) ">linuxbsd</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('freebsd')) ">linuxbsd</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('osx')) ">macos</GodotTargetPlatform>
+ <GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('win')) ">windows</GodotTargetPlatform>
+ </PropertyGroup>
+
+ <!-- Auto-detect the target Godot platform if it was not specified and there's no runtime identifier information. -->
+ <PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(FreeBSD))' ">linuxbsd</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(OSX))' ">macos</GodotTargetPlatform>
@@ -97,4 +109,6 @@
<DefineConstants>$(GodotDefineConstants);$(DefineConstants)</DefineConstants>
</PropertyGroup>
+
+ <Import Project="$(MSBuildThisFileDirectory)\iOSNativeAOT.props" Condition=" '$(GodotTargetPlatform)' == 'ios' " />
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index 4dcc96a1f6..29ef76a5e8 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -20,4 +20,8 @@
<PackageReference Include="GodotSharp" Version="$(PackageVersion_GodotSharp)" />
<PackageReference Include="GodotSharpEditor" Version="$(PackageVersion_GodotSharp)" Condition=" '$(Configuration)' == 'Debug' " />
</ItemGroup>
+
+ <!-- iOS-specific build targets -->
+ <Import Project="$(MSBuildThisFileDirectory)\iOSNativeAOT.targets" Condition=" '$(GodotTargetPlatform)' == 'ios' " />
+
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.props
new file mode 100644
index 0000000000..e3c953ccac
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.props
@@ -0,0 +1,8 @@
+<Project>
+ <PropertyGroup>
+ <PublishAot>true</PublishAot>
+ <PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
+ <UseNativeAOTRuntime>true</UseNativeAOTRuntime>
+ <TrimmerSingleWarn>false</TrimmerSingleWarn>
+ </PropertyGroup>
+</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets
new file mode 100644
index 0000000000..d8129a6652
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets
@@ -0,0 +1,58 @@
+<Project>
+ <ItemGroup>
+ <TrimmerRootAssembly Include="GodotSharp" />
+ <TrimmerRootAssembly Include="$(TargetName)" />
+ <LinkerArg Include="-install_name '@rpath/$(TargetName)$(NativeBinaryExt)'" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <LinkStandardCPlusPlusLibrary>true</LinkStandardCPlusPlusLibrary>
+ <FindXCode Condition=" '$(XCodePath)' == '' and '$([MSBuild]::IsOsPlatform(OSX))' ">true</FindXCode>
+ <XCodePath Condition=" '$(XCodePath)' == '' ">/Applications/Xcode.app/Contents/Developer</XCodePath>
+ <XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
+ </PropertyGroup>
+
+ <Target Name="PrepareBeforeIlcCompile"
+ BeforeTargets="IlcCompile">
+
+ <Copy SourceFiles="%(ResolvedRuntimePack.PackageDirectory)/runtimes/$(RuntimeIdentifier)/native/icudt.dat" DestinationFolder="$(PublishDir)"/>
+
+ <!-- We need to find the path to Xcode so we can set manual linker args to the correct SDKs
+ Once https://github.com/dotnet/runtime/issues/88737 is released, we can take this out
+ -->
+
+ <Exec Command="xcrun xcode-select -p" ConsoleToMSBuild="true" Condition=" '$(FindXCode)' == 'true' ">
+ <Output TaskParameter="ConsoleOutput" PropertyName="XcodeSelect" />
+ </Exec>
+
+ <PropertyGroup Condition=" '$(FindXCode)' == 'true' ">
+ <XCodePath>$(XcodeSelect)</XCodePath>
+ <XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
+ </PropertyGroup>
+
+ <Message Importance="normal" Text="Found XCode at $(XcodeSelect)" Condition=" '$(FindXCode)' == 'true' "/>
+
+ <ItemGroup>
+ <LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22"
+ Condition=" $(RuntimeIdentifier.Contains('simulator')) "/>
+ <LinkerArg Include="-isysroot %22$(XCodePath)Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk%22"
+ Condition=" !$(RuntimeIdentifier.Contains('simulator')) "/>
+ </ItemGroup>
+
+ </Target>
+
+ <Target Name="FixSymbols"
+ AfterTargets="Publish">
+
+ <RemoveDir Directories="$(PublishDir)$(TargetName).framework.dSYM"/>
+
+ <!-- create-xcframework (called from the export plugin wants the symbol files in a directory
+ with a slightly different name from the one created by dotnet publish, so we copy them over
+ to the correctly-named directory -->
+ <ItemGroup>
+ <SymbolFiles Include="$(NativeBinary).dsym\**\*.*"/>
+ </ItemGroup>
+ <Copy SourceFiles="@(SymbolFiles)" DestinationFolder="$(PublishDir)$(TargetName).framework.dSYM"/>
+ </Target>
+
+</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index f3c8e89dff..04ea46e9ef 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -23,6 +23,13 @@ namespace GodotTools.ProjectEditor
var mainGroup = root.AddPropertyGroup();
mainGroup.AddProperty("TargetFramework", "net6.0");
+
+ var net7 = mainGroup.AddProperty("TargetFramework", "net7.0");
+ net7.Condition = " '$(GodotTargetPlatform)' == 'android' ";
+
+ var net8 = mainGroup.AddProperty("TargetFramework", "net8.0");
+ net8.Condition = " '$(GodotTargetPlatform)' == 'ios' ";
+
mainGroup.AddProperty("EnableDynamicLoading", "true");
string sanitizedName = IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index 907511d140..7cf98b8f1f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
@@ -67,7 +68,7 @@ namespace GodotTools.Build
{
BuildStarted?.Invoke(buildInfo);
- // Required in order to update the build tasks list
+ // Required in order to update the build tasks list.
Internal.GodotMainIteration();
try
@@ -162,7 +163,7 @@ namespace GodotTools.Build
{
BuildStarted?.Invoke(buildInfo);
- // Required in order to update the build tasks list
+ // Required in order to update the build tasks list.
Internal.GodotMainIteration();
try
@@ -323,6 +324,45 @@ namespace GodotTools.Build
) => PublishProjectBlocking(CreatePublishBuildInfo(configuration,
platform, runtimeIdentifier, publishOutputDir, includeDebugSymbols));
+ public static bool GenerateXCFrameworkBlocking(
+ List<string> outputPaths,
+ string xcFrameworkPath)
+ {
+ using var pr = new EditorProgress("generate_xcframework", "Generating XCFramework...", 1);
+
+ pr.Step("Running xcodebuild -create-xcframework", 0);
+
+ if (!GenerateXCFramework(outputPaths, xcFrameworkPath))
+ {
+ ShowBuildErrorDialog("Failed to generate XCFramework");
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool GenerateXCFramework(List<string> outputPaths, string xcFrameworkPath)
+ {
+ // Required in order to update the build tasks list.
+ Internal.GodotMainIteration();
+
+ try
+ {
+ int exitCode = BuildSystem.GenerateXCFramework(outputPaths, xcFrameworkPath, StdOutputReceived, StdErrorReceived);
+
+ if (exitCode != 0)
+ PrintVerbose(
+ $"xcodebuild create-xcframework exited with code: {exitCode}.");
+
+ return exitCode == 0;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return false;
+ }
+ }
+
public static bool EditorBuildCallback()
{
if (!File.Exists(GodotSharpDirs.ProjectCsProjPath))
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index 8a292fd73a..57b5598a78 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -9,7 +9,9 @@ using System.Text;
using System.Threading.Tasks;
using Godot;
using GodotTools.BuildLogger;
+using GodotTools.Internals;
using GodotTools.Utils;
+using Directory = GodotTools.Utils.Directory;
namespace GodotTools.Build
{
@@ -293,5 +295,81 @@ namespace GodotTools.Build
foreach (string env in platformEnvironmentVariables)
environmentVariables.Remove(env);
}
+
+ private static Process DoGenerateXCFramework(List<string> outputPaths, string xcFrameworkPath,
+ Action<string> stdOutHandler, Action<string> stdErrHandler)
+ {
+ if (Directory.Exists(xcFrameworkPath))
+ {
+ Directory.Delete(xcFrameworkPath, true);
+ }
+
+ var startInfo = new ProcessStartInfo("xcrun");
+
+ BuildXCFrameworkArguments(outputPaths, xcFrameworkPath, startInfo.ArgumentList);
+
+ string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Packaging: ")).ToString();
+ stdOutHandler?.Invoke(launchMessage);
+ if (Godot.OS.IsStdOutVerbose())
+ Console.WriteLine(launchMessage);
+
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+ startInfo.UseShellExecute = false;
+
+ if (OperatingSystem.IsWindows())
+ {
+ startInfo.StandardOutputEncoding = Encoding.UTF8;
+ startInfo.StandardErrorEncoding = Encoding.UTF8;
+ }
+
+ // Needed when running from Developer Command Prompt for VS.
+ RemovePlatformVariable(startInfo.EnvironmentVariables);
+
+ var process = new Process { StartInfo = startInfo };
+
+ if (stdOutHandler != null)
+ process.OutputDataReceived += (_, e) => stdOutHandler.Invoke(e.Data);
+ if (stdErrHandler != null)
+ process.ErrorDataReceived += (_, e) => stdErrHandler.Invoke(e.Data);
+
+ process.Start();
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ return process;
+ }
+
+ public static int GenerateXCFramework(List<string> outputPaths, string xcFrameworkPath, Action<string> stdOutHandler, Action<string> stdErrHandler)
+ {
+ using (var process = DoGenerateXCFramework(outputPaths, xcFrameworkPath, stdOutHandler, stdErrHandler))
+ {
+ process.WaitForExit();
+
+ return process.ExitCode;
+ }
+ }
+
+ private static void BuildXCFrameworkArguments(List<string> outputPaths,
+ string xcFrameworkPath, Collection<string> arguments)
+ {
+ var baseDylib = $"{GodotSharpDirs.ProjectAssemblyName}.dylib";
+ var baseSym = $"{GodotSharpDirs.ProjectAssemblyName}.framework.dSYM";
+
+ arguments.Add("xcodebuild");
+ arguments.Add("-create-xcframework");
+
+ foreach (var outputPath in outputPaths)
+ {
+ arguments.Add("-library");
+ arguments.Add(Path.Combine(outputPath, baseDylib));
+ arguments.Add("-debug-symbols");
+ arguments.Add(Path.Combine(outputPath, baseSym));
+ }
+
+ arguments.Add("-output");
+ arguments.Add(xcFrameworkPath);
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index b98df190ca..018298cb33 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -6,9 +6,7 @@ using System.Linq;
using System.Security.Cryptography;
using System.Text;
using GodotTools.Build;
-using GodotTools.Core;
using GodotTools.Internals;
-using static GodotTools.Internals.Globals;
using Directory = GodotTools.Utils.Directory;
using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS;
@@ -77,7 +75,7 @@ namespace GodotTools.Export
$"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}",
nameof(path));
- // TODO What if the source file is not part of the game's C# project
+ // TODO: What if the source file is not part of the game's C# project?
bool includeScriptsContent = (bool)GetOption("dotnet/include_scripts_content");
@@ -89,7 +87,7 @@ namespace GodotTools.Export
// Because of this, we add a file which contains a line break.
AddFile(path, System.Text.Encoding.UTF8.GetBytes("\n"), remap: false);
- // Tell the Godot exporter that we already took care of the file
+ // Tell the Godot exporter that we already took care of the file.
Skip();
}
}
@@ -119,7 +117,7 @@ namespace GodotTools.Export
private void _ExportBeginImpl(string[] features, bool isDebug, string path, long flags)
{
- _ = flags; // Unused
+ _ = flags; // Unused.
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return;
@@ -127,115 +125,261 @@ namespace GodotTools.Export
if (!DeterminePlatformFromFeatures(features, out string platform))
throw new NotSupportedException("Target platform not supported.");
- if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS, OS.Platforms.Android }
+ if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS }
.Contains(platform))
{
throw new NotImplementedException("Target platform not yet implemented.");
}
- string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
-
- bool includeDebugSymbols = (bool)GetOption("dotnet/include_debug_symbols");
+ PublishConfig publishConfig = new()
+ {
+ BuildConfig = isDebug ? "ExportDebug" : "ExportRelease",
+ IncludeDebugSymbols = (bool)GetOption("dotnet/include_debug_symbols"),
+ RidOS = DetermineRuntimeIdentifierOS(platform),
+ Archs = new List<string>(),
+ UseTempDir = platform != OS.Platforms.iOS, // xcode project links directly to files in the publish dir, so use one that sticks around.
+ BundleOutputs = true,
+ };
- var archs = new List<string>();
if (features.Contains("x86_64"))
{
- archs.Add("x86_64");
+ publishConfig.Archs.Add("x86_64");
}
+
if (features.Contains("x86_32"))
{
- archs.Add("x86_32");
+ publishConfig.Archs.Add("x86_32");
}
+
if (features.Contains("arm64"))
{
- archs.Add("arm64");
+ publishConfig.Archs.Add("arm64");
}
+
if (features.Contains("arm32"))
{
- archs.Add("arm32");
+ publishConfig.Archs.Add("arm32");
}
+
if (features.Contains("universal"))
{
if (platform == OS.Platforms.MacOS)
{
- archs.Add("x86_64");
- archs.Add("arm64");
+ publishConfig.Archs.Add("x86_64");
+ publishConfig.Archs.Add("arm64");
}
}
- bool embedBuildResults = (bool)GetOption("dotnet/embed_build_outputs") || features.Contains("android");
+ var targets = new List<PublishConfig> { publishConfig };
- foreach (var arch in archs)
+ if (platform == OS.Platforms.iOS)
{
- string ridOS = DetermineRuntimeIdentifierOS(platform);
- string ridArch = DetermineRuntimeIdentifierArch(arch);
- string runtimeIdentifier = $"{ridOS}-{ridArch}";
- string projectDataDirName = $"data_{GodotSharpDirs.CSharpProjectName}_{platform}_{arch}";
- if (platform == OS.Platforms.MacOS)
+ targets.Add(new PublishConfig
{
- projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
- }
+ BuildConfig = publishConfig.BuildConfig,
+ Archs = new List<string> { "arm64", "x86_64" },
+ BundleOutputs = false,
+ IncludeDebugSymbols = publishConfig.IncludeDebugSymbols,
+ RidOS = OS.DotNetOS.iOSSimulator,
+ UseTempDir = true,
+ });
+ }
- // Create temporary publish output directory
+ List<string> outputPaths = new();
- string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
- $"{System.Environment.ProcessId}-{buildConfig}-{runtimeIdentifier}");
+ bool embedBuildResults = (bool)GetOption("dotnet/embed_build_outputs") || platform == OS.Platforms.Android;
- _tempFolders.Add(publishOutputTempDir);
+ foreach (PublishConfig config in targets)
+ {
+ string ridOS = config.RidOS;
+ string buildConfig = config.BuildConfig;
+ bool includeDebugSymbols = config.IncludeDebugSymbols;
- if (!Directory.Exists(publishOutputTempDir))
- Directory.CreateDirectory(publishOutputTempDir);
+ foreach (string arch in config.Archs)
+ {
+ string ridArch = DetermineRuntimeIdentifierArch(arch);
+ string runtimeIdentifier = $"{ridOS}-{ridArch}";
+ string projectDataDirName = $"data_{GodotSharpDirs.CSharpProjectName}_{platform}_{arch}";
+ if (platform == OS.Platforms.MacOS)
+ {
+ projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
+ }
- // Execute dotnet publish
+ // Create temporary publish output directory.
+ string publishOutputDir;
- if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
- runtimeIdentifier, publishOutputTempDir, includeDebugSymbols))
- {
- throw new InvalidOperationException("Failed to build project.");
- }
+ if (config.UseTempDir)
+ {
+ publishOutputDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
+ $"{System.Environment.ProcessId}-{buildConfig}-{runtimeIdentifier}");
+ _tempFolders.Add(publishOutputDir);
+ }
+ else
+ {
+ publishOutputDir = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, "godot-publish-dotnet",
+ $"{buildConfig}-{runtimeIdentifier}");
- string soExt = ridOS switch
- {
- OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
- OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
- _ => "so"
- };
-
- if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
- // NativeAOT shared library output
- && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
- {
- throw new NotSupportedException(
- "Publish succeeded but project assembly not found in the output directory");
- }
+ }
- var manifest = new StringBuilder();
+ outputPaths.Add(publishOutputDir);
- // Add to the exported project shared object list or packed resources.
- foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
- {
- if (embedBuildResults)
+ if (!Directory.Exists(publishOutputDir))
+ Directory.CreateDirectory(publishOutputDir);
+
+ // Execute dotnet publish.
+ if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
+ runtimeIdentifier, publishOutputDir, includeDebugSymbols))
+ {
+ throw new InvalidOperationException("Failed to build project.");
+ }
+
+ string soExt = ridOS switch
{
- var filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputTempDir, file));
- var fileData = File.ReadAllBytes(file);
- var hash = Convert.ToBase64String(SHA512.HashData(fileData));
+ OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
+ OS.DotNetOS.OSX or OS.DotNetOS.iOS or OS.DotNetOS.iOSSimulator => "dylib",
+ _ => "so"
+ };
- manifest.Append($"{filePath}\t{hash}\n");
+ string assemblyPath = Path.Combine(publishOutputDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll");
+ string nativeAotPath = Path.Combine(publishOutputDir,
+ $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}");
- AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
+ if (!File.Exists(assemblyPath) && !File.Exists(nativeAotPath))
+ {
+ throw new NotSupportedException(
+ $"Publish succeeded but project assembly not found at '{assemblyPath}' or '{nativeAotPath}'.");
}
- else
+
+ // For ios simulator builds, skip packaging the build outputs.
+ if (!config.BundleOutputs)
+ continue;
+
+ var manifest = new StringBuilder();
+
+ // Add to the exported project shared object list or packed resources.
+ RecursePublishContents(publishOutputDir,
+ filterDir: dir =>
+ {
+ if (platform == OS.Platforms.iOS)
+ {
+ // Exclude dsym folders.
+ return !dir.EndsWith(".dsym", StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ return true;
+ },
+ filterFile: file =>
+ {
+ if (platform == OS.Platforms.iOS)
+ {
+ // Exclude the dylib artifact, since it's included separately as an xcframework.
+ return Path.GetFileName(file) != $"{GodotSharpDirs.ProjectAssemblyName}.dylib";
+ }
+
+ return true;
+ },
+ recurseDir: dir =>
+ {
+ if (platform == OS.Platforms.iOS)
+ {
+ // Don't recurse into dsym folders.
+ return !dir.EndsWith(".dsym", StringComparison.InvariantCultureIgnoreCase);
+ }
+
+ return true;
+ },
+ addEntry: (path, isFile) =>
+ {
+ // We get called back for both directories and files, but we only package files for now.
+ if (isFile)
+ {
+ if (embedBuildResults)
+ {
+ string filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputDir, path));
+ byte[] fileData = File.ReadAllBytes(path);
+ string hash = Convert.ToBase64String(SHA512.HashData(fileData));
+
+ manifest.Append($"{filePath}\t{hash}\n");
+
+ AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
+ }
+ else
+ {
+ if (platform == OS.Platforms.iOS && path.EndsWith(".dat"))
+ {
+ AddIosBundleFile(path);
+ }
+ else
+ {
+ AddSharedObject(path, tags: null,
+ Path.Join(projectDataDirName,
+ Path.GetRelativePath(publishOutputDir,
+ Path.GetDirectoryName(path))));
+ }
+ }
+ }
+ });
+
+ if (embedBuildResults)
{
- AddSharedObject(file, tags: null,
- Path.Join(projectDataDirName,
- Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
+ byte[] fileData = Encoding.Default.GetBytes(manifest.ToString());
+ AddFile($"res://.godot/mono/publish/{arch}/.dotnet-publish-manifest", fileData, false);
}
}
+ }
+
+ if (platform == OS.Platforms.iOS)
+ {
+ if (outputPaths.Count > 2)
+ {
+ // lipo the simulator binaries together
+ // TODO: Move this to the native lipo implementation we have in the macos export plugin.
+ var lipoArgs = new List<string>();
+ lipoArgs.Add("-create");
+ lipoArgs.AddRange(outputPaths.Skip(1).Select(x => Path.Combine(x, $"{GodotSharpDirs.ProjectAssemblyName}.dylib")));
+ lipoArgs.Add("-output");
+ lipoArgs.Add(Path.Combine(outputPaths[1], $"{GodotSharpDirs.ProjectAssemblyName}.dylib"));
+
+ int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs);
+ if (lipoExitCode != 0)
+ throw new InvalidOperationException($"Command 'lipo' exited with code: {lipoExitCode}.");
+
+ outputPaths.RemoveRange(2, outputPaths.Count - 2);
+ }
+
+ var xcFrameworkPath = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig,
+ $"{GodotSharpDirs.ProjectAssemblyName}.xcframework");
+ if (!BuildManager.GenerateXCFrameworkBlocking(outputPaths,
+ Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig, xcFrameworkPath)))
+ {
+ throw new InvalidOperationException("Failed to generate xcframework.");
+ }
+
+ AddIosEmbeddedFramework(xcFrameworkPath);
+ }
+ }
+
+ private static void RecursePublishContents(string path, Func<string, bool> filterDir,
+ Func<string, bool> filterFile, Func<string, bool> recurseDir,
+ Action<string, bool> addEntry)
+ {
+ foreach (string file in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly))
+ {
+ if (filterFile(file))
+ {
+ addEntry(file, true);
+ }
+ }
- if (embedBuildResults)
+ foreach (string dir in Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly))
+ {
+ if (filterDir(dir))
+ {
+ addEntry(dir, false);
+ }
+ else if (recurseDir(dir))
{
- var fileData = Encoding.Default.GetBytes(manifest.ToString());
- AddFile($"res://.godot/mono/publish/{arch}/.dotnet-publish-manifest", fileData, false);
+ RecursePublishContents(dir, filterDir, filterFile, recurseDir, addEntry);
}
}
}
@@ -304,5 +448,15 @@ namespace GodotTools.Export
platform = null;
return false;
}
+
+ private struct PublishConfig
+ {
+ public bool UseTempDir;
+ public bool BundleOutputs;
+ public string RidOS;
+ public List<string> Archs;
+ public string BuildConfig;
+ public bool IncludeDebugSymbols;
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 55b413453d..67891a0594 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -118,6 +118,16 @@ namespace GodotTools.Internals
}
}
+ public static string ProjectBaseOutputPath
+ {
+ get
+ {
+ if (_projectCsProjPath == null)
+ DetermineProjectLocation();
+ return Path.Combine(Path.GetDirectoryName(_projectCsProjPath)!, ".godot", "mono", "temp", "bin");
+ }
+ }
+
public static string LogsDirPathFor(string solution, string configuration)
=> Path.Combine(BuildLogsDirs, $"{solution.Md5Text()}_{configuration}");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index bff0c0df7c..c24b730c89 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -56,6 +56,7 @@ namespace GodotTools.Utils
public const string Win10 = "win10";
public const string Android = "android";
public const string iOS = "ios";
+ public const string iOSSimulator = "iossimulator";
public const string Browser = "browser";
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs
index 94788ef680..9126495a27 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs
@@ -28,7 +28,7 @@ partial class AnimationNode
partial class AnimationPlayer
{
- /// <inheritdoc cref="CallbackModeMethod"/>
+ /// <inheritdoc cref="AnimationMixer.CallbackModeMethod"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public AnimationMethodCallMode MethodCallMode
{
@@ -36,7 +36,7 @@ partial class AnimationPlayer
set => CallbackModeMethod = (AnimationCallbackModeMethod)value;
}
- /// <inheritdoc cref="Active"/>
+ /// <inheritdoc cref="AnimationMixer.Active"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool PlaybackActive
{
@@ -44,7 +44,7 @@ partial class AnimationPlayer
set => Active = value;
}
- /// <inheritdoc cref="CallbackModeProcess"/>
+ /// <inheritdoc cref="AnimationMixer.CallbackModeProcess"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public AnimationProcessCallback PlaybackProcessMode
{
@@ -55,7 +55,7 @@ partial class AnimationPlayer
partial class AnimationTree
{
- /// <inheritdoc cref="CallbackModeProcess"/>
+ /// <inheritdoc cref="AnimationMixer.CallbackModeProcess"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public AnimationProcessCallback ProcessCallback
{
@@ -120,7 +120,7 @@ partial class GraphEdit
partial class GraphNode
{
- /// <inheritdoc cref="DeleteRequest"/>
+ /// <inheritdoc cref="GraphElement.DeleteRequest"/>
[EditorBrowsable(EditorBrowsableState.Never)]
public event Action CloseRequest
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 10aeeae995..13c0cde1ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -36,6 +36,9 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Array"/> from the given collection's elements.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="collection"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="collection">The collection of elements to construct from.</param>
/// <returns>A new Godot Array.</returns>
public Array(IEnumerable<Variant> collection) : this()
@@ -50,6 +53,9 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Array"/> from the given objects.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="array">The objects to put in the new array.</param>
/// <returns>A new Godot Array.</returns>
public Array(Variant[] array)
@@ -68,6 +74,13 @@ namespace Godot.Collections
this[i] = array[i];
}
+ /// <summary>
+ /// Constructs a new <see cref="Array"/> from the given span's elements.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <returns>A new Godot Array.</returns>
public Array(Span<StringName> array)
{
if (array == null)
@@ -84,6 +97,13 @@ namespace Godot.Collections
this[i] = array[i];
}
+ /// <summary>
+ /// Constructs a new <see cref="Array"/> from the given span's elements.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <returns>A new Godot Array.</returns>
public Array(Span<NodePath> array)
{
if (array == null)
@@ -100,6 +120,13 @@ namespace Godot.Collections
this[i] = array[i];
}
+ /// <summary>
+ /// Constructs a new <see cref="Array"/> from the given span's elements.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <returns>A new Godot Array.</returns>
public Array(Span<Rid> array)
{
if (array == null)
@@ -121,6 +148,13 @@ namespace Godot.Collections
// fine as long as the array is not mutated. However, Span does this type checking at
// instantiation, so it's not possible to use it even when not mutating anything.
// ReSharper disable once RedundantNameQualifier
+ /// <summary>
+ /// Constructs a new <see cref="Array"/> from the given ReadOnlySpan's elements.
+ /// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <returns>A new Godot Array.</returns>
public Array(ReadOnlySpan<GodotObject> array)
{
if (array == null)
@@ -861,9 +895,15 @@ namespace Godot.Collections
/// Copies the elements of this <see cref="Array"/> to the given
/// <see cref="Variant"/> C# array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
/// </exception>
+ /// <exception cref="ArgumentException">
+ /// The destination array was not long enough.
+ /// </exception>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
public void CopyTo(Variant[] array, int arrayIndex)
@@ -1031,6 +1071,7 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new empty <see cref="Array{T}"/>.
/// </summary>
+ /// <returns>A new Godot Array.</returns>
public Array()
{
_underlyingArray = new Array();
@@ -1039,6 +1080,9 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Array{T}"/> from the given collection's elements.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="collection"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="collection">The collection of elements to construct from.</param>
/// <returns>A new Godot Array.</returns>
public Array(IEnumerable<T> collection)
@@ -1055,6 +1099,9 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Array{T}"/> from the given items.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="array">The items to put in the new array.</param>
/// <returns>A new Godot Array.</returns>
public Array(T[] array)
@@ -1071,9 +1118,16 @@ namespace Godot.Collections
/// <summary>
/// Constructs a typed <see cref="Array{T}"/> from an untyped <see cref="Array"/>.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="array">The untyped array to construct from.</param>
+ /// <returns>A new Godot Array.</returns>
public Array(Array array)
{
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
_underlyingArray = array;
}
@@ -1085,6 +1139,7 @@ namespace Godot.Collections
/// Converts this typed <see cref="Array{T}"/> to an untyped <see cref="Array"/>.
/// </summary>
/// <param name="from">The typed array to convert.</param>
+ /// <returns>A new Godot Array, or <see langword="null"/> if <see paramref="from"/> was null.</returns>
public static explicit operator Array(Array<T> from)
{
return from?._underlyingArray;
@@ -1695,9 +1750,15 @@ namespace Godot.Collections
/// Copies the elements of this <see cref="Array{T}"/> to the given
/// C# array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
/// </exception>
+ /// <exception cref="ArgumentException">
+ /// The destination array was not long enough.
+ /// </exception>
/// <param name="array">The C# array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
public void CopyTo(T[] array, int arrayIndex)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 923b2adafd..2a72ebc32b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -385,6 +385,15 @@ namespace Godot.Collections
/// Copies the elements of this <see cref="Dictionary"/> to the given untyped
/// <see cref="KeyValuePair{TKey, TValue}"/> array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// The destination array was not long enough.
+ /// </exception>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
void ICollection<KeyValuePair<Variant, Variant>>.CopyTo(KeyValuePair<Variant, Variant>[] array, int arrayIndex)
@@ -499,6 +508,7 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary()
{
_underlyingDict = new Dictionary();
@@ -507,6 +517,9 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="dictionary"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="dictionary">The dictionary to construct from.</param>
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
@@ -523,10 +536,16 @@ namespace Godot.Collections
/// <summary>
/// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="dictionary"/> is <see langword="null"/>.
+ /// </exception>
/// <param name="dictionary">The dictionary to construct from.</param>
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(Dictionary dictionary)
{
+ if (dictionary == null)
+ throw new ArgumentNullException(nameof(dictionary));
+
_underlyingDict = dictionary;
}
@@ -539,6 +558,7 @@ namespace Godot.Collections
/// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>.
/// </summary>
/// <param name="from">The typed dictionary to convert.</param>
+ /// <returns>A new Godot Dictionary, or <see langword="null"/> if <see paramref="from"/> was null.</returns>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
{
return from?._underlyingDict;
@@ -555,6 +575,8 @@ namespace Godot.Collections
/// elements will be shallow copied regardless of the <paramref name="deep"/>
/// setting.
/// </summary>
+ /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param>
+ /// <returns>A new Godot Dictionary.</returns>
public Dictionary<TKey, TValue> Duplicate(bool deep = false)
{
return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep));
@@ -688,6 +710,9 @@ namespace Godot.Collections
/// <exception cref="InvalidOperationException">
/// The dictionary is read-only.
/// </exception>
+ /// <exception cref="ArgumentException">
+ /// An element with the same <paramref name="key"/> already exists.
+ /// </exception>
/// <param name="key">The key at which to add the object.</param>
/// <param name="value">The object to add.</param>
public void Add(TKey key, TValue value)
@@ -810,6 +835,15 @@ namespace Godot.Collections
/// Copies the elements of this <see cref="Dictionary{TKey, TValue}"/> to the given
/// untyped C# array, starting at the given index.
/// </summary>
+ /// <exception cref="ArgumentNullException">
+ /// The <paramref name="array"/> is <see langword="null"/>.
+ /// </exception>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="arrayIndex"/> is less than 0 or greater than the array's size.
+ /// </exception>
+ /// <exception cref="ArgumentException">
+ /// The destination array was not long enough.
+ /// </exception>
/// <param name="array">The array to copy to.</param>
/// <param name="arrayIndex">The index to start at.</param>
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index faf3ae7b04..c55c5d8111 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -89,7 +89,7 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
- ERR_FAIL_COND(delegate_handle.value == nullptr);
+ ERR_FAIL_NULL(delegate_handle.value);
GDMonoCache::managed_callbacks.DelegateUtils_InvokeWithVariantArgs(
delegate_handle, trampoline, p_arguments, p_argcount, &r_return_value);
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 247968e251..23f2f2ff13 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -322,7 +322,7 @@ godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle)
#if defined(WINDOWS_ENABLED)
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
-#elif defined(MACOS_ENABLED)
+#elif defined(MACOS_ENABLED) || defined(IOS_ENABLED)
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dylib");
#elif defined(UNIX_ENABLED)
String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".so");
@@ -330,23 +330,19 @@ godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle)
#error "Platform not supported (yet?)"
#endif
- if (FileAccess::exists(native_aot_so_path)) {
- Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle);
-
- if (err != OK) {
- return nullptr;
- }
+ Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle);
- void *lib = r_aot_dll_handle;
+ if (err != OK) {
+ return nullptr;
+ }
- void *symbol = nullptr;
+ void *lib = r_aot_dll_handle;
- err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol);
- ERR_FAIL_COND_V(err != OK, nullptr);
- return (godot_plugins_initialize_fn)symbol;
- }
+ void *symbol = nullptr;
- return nullptr;
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol);
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ return (godot_plugins_initialize_fn)symbol;
}
#endif
@@ -376,11 +372,13 @@ void GDMono::initialize() {
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
+#if !defined(IOS_ENABLED)
// Check that the .NET assemblies directory exists before trying to use it.
if (!DirAccess::exists(GodotSharpDirs::get_api_assemblies_dir())) {
OS::get_singleton()->alert(vformat(RTR("Unable to find the .NET assemblies directory.\nMake sure the '%s' directory exists and contains the .NET assemblies."), GodotSharpDirs::get_api_assemblies_dir()), RTR(".NET assemblies not found"));
ERR_FAIL_MSG(".NET: Assemblies not found");
}
+#endif
if (!load_hostfxr(hostfxr_dll_handle)) {
#if !defined(TOOLS_ENABLED)
diff --git a/modules/mono/mono_gd/support/ios_support.h b/modules/mono/mono_gd/support/ios_support.h
deleted file mode 100644
index cb397c8b46..0000000000
--- a/modules/mono/mono_gd/support/ios_support.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/**************************************************************************/
-/* ios_support.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#ifndef IOS_SUPPORT_H
-#define IOS_SUPPORT_H
-
-#if defined(IOS_ENABLED)
-
-#include "core/string/ustring.h"
-
-namespace gdmono {
-namespace ios {
-namespace support {
-
-void initialize();
-void cleanup();
-} // namespace support
-} // namespace ios
-} // namespace gdmono
-
-#endif // IOS_ENABLED
-
-#endif // IOS_SUPPORT_H
diff --git a/modules/mono/mono_gd/support/ios_support.mm b/modules/mono/mono_gd/support/ios_support.mm
deleted file mode 100644
index df8b3e2626..0000000000
--- a/modules/mono/mono_gd/support/ios_support.mm
+++ /dev/null
@@ -1,150 +0,0 @@
-/**************************************************************************/
-/* ios_support.mm */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/**************************************************************************/
-
-#include "ios_support.h"
-
-#if defined(IOS_ENABLED)
-
-#include "../gd_mono_marshal.h"
-
-#include "core/ustring.h"
-
-#import <Foundation/Foundation.h>
-#include <os/log.h>
-
-// Implemented mostly following: https://github.com/mono/mono/blob/master/sdks/ios/app/runtime.m
-
-// Definition generated by the Godot exporter
-extern "C" void gd_mono_setup_aot();
-
-namespace gdmono {
-namespace ios {
-namespace support {
-
-void ios_mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
- os_log_info(OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message);
- if (fatal) {
- os_log_info(OS_LOG_DEFAULT, "Exit code: %d.", 1);
- exit(1);
- }
-}
-
-void initialize() {
- mono_dllmap_insert(nullptr, "System.Native", nullptr, "__Internal", nullptr);
- mono_dllmap_insert(nullptr, "System.IO.Compression.Native", nullptr, "__Internal", nullptr);
- mono_dllmap_insert(nullptr, "System.Security.Cryptography.Native.Apple", nullptr, "__Internal", nullptr);
-
-#ifdef IOS_DEVICE
- // This function is defined in an auto-generated source file
- gd_mono_setup_aot();
-#endif
-
- mono_set_signal_chaining(true);
- mono_set_crash_chaining(true);
-}
-
-void cleanup() {
-}
-} // namespace support
-} // namespace ios
-} // namespace gdmono
-
-// The following are P/Invoke functions required by the monotouch profile of the BCL.
-// These are P/Invoke functions and not internal calls, hence why they use
-// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'.
-
-#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default")))
-
-GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
- NSLocale *locale = [NSLocale currentLocale];
- NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
- if (countryCode == nullptr) {
- return strdup("US");
- }
- return strdup([countryCode UTF8String]);
-}
-
-GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) {
- int length = 0;
- const uint16_t *ptr = p_unicode_message;
- while (*ptr++) {
- length += sizeof(uint16_t);
- }
- NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding];
-
- os_log_info(OS_LOG_DEFAULT, "%{public}@", msg);
-}
-
-GD_PINVOKE_EXPORT const char *xamarin_GetFolderPath(int p_folder) {
- NSSearchPathDirectory dd = (NSSearchPathDirectory)p_folder;
- NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:dd inDomains:NSUserDomainMask] lastObject];
- NSString *path = [url path];
- return strdup([path UTF8String]);
-}
-
-GD_PINVOKE_EXPORT char *xamarin_timezone_get_local_name() {
- NSTimeZone *tz = nil;
- tz = [NSTimeZone localTimeZone];
- NSString *name = [tz name];
- return (name != nil) ? strdup([name UTF8String]) : strdup("Local");
-}
-
-GD_PINVOKE_EXPORT char **xamarin_timezone_get_names(uint32_t *p_count) {
- NSArray *array = [NSTimeZone knownTimeZoneNames];
- *p_count = array.count;
- char **result = (char **)malloc(sizeof(char *) * (*p_count));
- for (uint32_t i = 0; i < *p_count; i++) {
- NSString *s = [array objectAtIndex:i];
- result[i] = strdup(s.UTF8String);
- }
- return result;
-}
-
-GD_PINVOKE_EXPORT void *xamarin_timezone_get_data(const char *p_name, uint32_t *p_size) { // FIXME: uint32_t since Dec 2019, unsigned long before
- NSTimeZone *tz = nil;
- if (p_name) {
- NSString *n = [[NSString alloc] initWithUTF8String:p_name];
- tz = [[NSTimeZone alloc] initWithName:n];
- } else {
- tz = [NSTimeZone localTimeZone];
- }
- NSData *data = [tz data];
- *p_size = [data length];
- void *result = malloc(*p_size);
- memcpy(result, data.bytes, *p_size);
- return result;
-}
-
-GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) {
- // FIXME: What's this for? No idea how to implement.
- os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'");
-}
-
-#endif // IOS_ENABLED
diff --git a/modules/multiplayer/multiplayer_debugger.cpp b/modules/multiplayer/multiplayer_debugger.cpp
index 9b05fa884b..a4d2aed2d6 100644
--- a/modules/multiplayer/multiplayer_debugger.cpp
+++ b/modules/multiplayer/multiplayer_debugger.cpp
@@ -239,8 +239,8 @@ void MultiplayerDebugger::RPCProfiler::tick(double p_frame_time, double p_proces
MultiplayerDebugger::SyncInfo::SyncInfo(MultiplayerSynchronizer *p_sync) {
ERR_FAIL_NULL(p_sync);
synchronizer = p_sync->get_instance_id();
- if (p_sync->get_replication_config().is_valid()) {
- config = p_sync->get_replication_config()->get_instance_id();
+ if (p_sync->get_replication_config_ptr()) {
+ config = p_sync->get_replication_config_ptr()->get_instance_id();
}
if (p_sync->get_root_node()) {
root_node = p_sync->get_root_node()->get_instance_id();
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index 233f15c3a4..21f1f86dbf 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -441,6 +441,10 @@ List<NodePath> MultiplayerSynchronizer::get_delta_properties(uint64_t p_indexes)
return out;
}
+SceneReplicationConfig *MultiplayerSynchronizer::get_replication_config_ptr() const {
+ return replication_config.ptr();
+}
+
MultiplayerSynchronizer::MultiplayerSynchronizer() {
// Publicly visible by default.
peer_visibility.insert(0);
diff --git a/modules/multiplayer/multiplayer_synchronizer.h b/modules/multiplayer/multiplayer_synchronizer.h
index 7b77e691d1..99613de29b 100644
--- a/modules/multiplayer/multiplayer_synchronizer.h
+++ b/modules/multiplayer/multiplayer_synchronizer.h
@@ -118,6 +118,7 @@ public:
List<Variant> get_delta_state(uint64_t p_cur_usec, uint64_t p_last_usec, uint64_t &r_indexes);
List<NodePath> get_delta_properties(uint64_t p_indexes);
+ SceneReplicationConfig *get_replication_config_ptr() const;
MultiplayerSynchronizer();
};
diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp
index 8d102ca981..56cd0bec18 100644
--- a/modules/multiplayer/scene_cache_interface.cpp
+++ b/modules/multiplayer/scene_cache_interface.cpp
@@ -44,9 +44,8 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) {
path_get_cache.erase(p_id);
// Cleanup sent cache.
// Some refactoring is needed to make this faster and do paths GC.
- for (const KeyValue<NodePath, PathSentCache> &E : path_send_cache) {
- PathSentCache *psc = path_send_cache.getptr(E.key);
- psc->confirmed_peers.erase(p_id);
+ for (KeyValue<ObjectID, PathSentCache> &E : path_send_cache) {
+ E.value.confirmed_peers.erase(p_id);
}
}
}
@@ -67,7 +66,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
String paths;
paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs);
- NodePath path = paths;
+ const NodePath path = paths;
if (!path_get_cache.has(p_from)) {
path_get_cache[p_from] = PathGetCache();
@@ -81,7 +80,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
}
PathGetCache::NodeInfo ni;
- ni.path = path;
+ ni.path = node->get_path();
path_get_cache[p_from].nodes[id] = ni;
@@ -106,19 +105,24 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small.");
+ Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path());
+ ERR_FAIL_NULL(root_node);
const bool valid_rpc_checksum = p_packet[1];
String paths;
paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2);
- NodePath path = paths;
+ const NodePath path = paths;
if (valid_rpc_checksum == false) {
ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
}
- PathSentCache *psc = path_send_cache.getptr(path);
+ Node *node = root_node->get_node(path);
+ ERR_FAIL_NULL(node);
+
+ PathSentCache *psc = path_send_cache.getptr(node->get_instance_id());
ERR_FAIL_NULL_MSG(psc, "Invalid packet received. Tries to confirm a path which was not found in cache.");
HashMap<int, bool>::Iterator E = psc->confirmed_peers.find(p_from);
@@ -126,9 +130,9 @@ void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_pack
E->value = true;
}
-Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers) {
+Error SceneCacheInterface::_send_confirm_path(Node *p_node, PathSentCache *psc, const List<int> &p_peers) {
// Encode function name.
- const CharString path = String(p_path).utf8();
+ const CharString path = String(multiplayer->get_root_path().rel_path_to(p_node->get_path())).utf8();
const int path_len = encode_cstring(path.get_data(), nullptr);
// Extract MD5 from rpc methods list.
@@ -163,8 +167,9 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, Pat
return err;
}
-bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) {
- const PathSentCache *psc = path_send_cache.getptr(p_path);
+bool SceneCacheInterface::is_cache_confirmed(Node *p_node, int p_peer) {
+ ERR_FAIL_NULL_V(p_node, false);
+ const PathSentCache *psc = path_send_cache.getptr(p_node->get_instance_id());
ERR_FAIL_NULL_V(psc, false);
HashMap<int, bool>::ConstIterator F = psc->confirmed_peers.find(p_peer);
ERR_FAIL_COND_V(!F, false); // Should never happen.
@@ -174,13 +179,13 @@ bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) {
int SceneCacheInterface::make_object_cache(Object *p_obj) {
Node *node = Object::cast_to<Node>(p_obj);
ERR_FAIL_NULL_V(node, -1);
- NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path());
+ const ObjectID oid = node->get_instance_id();
// See if the path is cached.
- PathSentCache *psc = path_send_cache.getptr(for_path);
+ PathSentCache *psc = path_send_cache.getptr(oid);
if (!psc) {
// Path is not cached, create.
- path_send_cache[for_path] = PathSentCache();
- psc = path_send_cache.getptr(for_path);
+ path_send_cache[oid] = PathSentCache();
+ psc = path_send_cache.getptr(oid);
psc->id = last_send_cache_id++;
}
return psc->id;
@@ -189,11 +194,16 @@ int SceneCacheInterface::make_object_cache(Object *p_obj) {
bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) {
Node *node = Object::cast_to<Node>(p_obj);
ERR_FAIL_NULL_V(node, false);
-
- r_id = make_object_cache(p_obj);
- ERR_FAIL_COND_V(r_id < 0, false);
- NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path());
- PathSentCache *psc = path_send_cache.getptr(for_path);
+ const ObjectID oid = node->get_instance_id();
+ // See if the path is cached.
+ PathSentCache *psc = path_send_cache.getptr(oid);
+ if (!psc) {
+ // Path is not cached, create.
+ path_send_cache[oid] = PathSentCache();
+ psc = path_send_cache.getptr(oid);
+ psc->id = last_send_cache_id++;
+ }
+ r_id = psc->id;
bool has_all_peers = true;
List<int> peers_to_add; // If one is missing, take note to add it.
@@ -225,7 +235,7 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r
}
if (peers_to_add.size()) {
- _send_confirm_path(node, for_path, psc, peers_to_add);
+ _send_confirm_path(node, psc, peers_to_add);
}
return has_all_peers;
diff --git a/modules/multiplayer/scene_cache_interface.h b/modules/multiplayer/scene_cache_interface.h
index 7a7304fde8..e63beb5f84 100644
--- a/modules/multiplayer/scene_cache_interface.h
+++ b/modules/multiplayer/scene_cache_interface.h
@@ -58,12 +58,12 @@ private:
HashMap<int, NodeInfo> nodes;
};
- HashMap<NodePath, PathSentCache> path_send_cache;
+ HashMap<ObjectID, PathSentCache> path_send_cache;
HashMap<int, PathGetCache> path_get_cache;
int last_send_cache_id = 1;
protected:
- Error _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers);
+ Error _send_confirm_path(Node *p_node, PathSentCache *psc, const List<int> &p_peers);
public:
void clear();
@@ -75,7 +75,7 @@ public:
bool send_object_cache(Object *p_obj, int p_target, int &p_id);
int make_object_cache(Object *p_obj);
Object *get_cached_object(int p_from, uint32_t p_cache_id);
- bool is_cache_confirmed(NodePath p_path, int p_peer);
+ bool is_cache_confirmed(Node *p_path, int p_peer);
SceneCacheInterface(SceneMultiplayer *p_multiplayer) { multiplayer = p_multiplayer; }
};
diff --git a/modules/multiplayer/scene_multiplayer.cpp b/modules/multiplayer/scene_multiplayer.cpp
index 3e3118b1cd..04de3dfb7f 100644
--- a/modules/multiplayer/scene_multiplayer.cpp
+++ b/modules/multiplayer/scene_multiplayer.cpp
@@ -680,12 +680,16 @@ void SceneMultiplayer::_bind_methods() {
SceneMultiplayer::SceneMultiplayer() {
relay_buffer.instantiate();
- replicator = Ref<SceneReplicationInterface>(memnew(SceneReplicationInterface(this)));
- rpc = Ref<SceneRPCInterface>(memnew(SceneRPCInterface(this)));
cache = Ref<SceneCacheInterface>(memnew(SceneCacheInterface(this)));
+ replicator = Ref<SceneReplicationInterface>(memnew(SceneReplicationInterface(this, cache.ptr())));
+ rpc = Ref<SceneRPCInterface>(memnew(SceneRPCInterface(this, cache.ptr(), replicator.ptr())));
set_multiplayer_peer(Ref<OfflineMultiplayerPeer>(memnew(OfflineMultiplayerPeer)));
}
SceneMultiplayer::~SceneMultiplayer() {
clear();
+ // Ensure unref in reverse order for safety (we shouldn't use those pointers in the deconstructors anyway).
+ rpc.unref();
+ replicator.unref();
+ cache.unref();
}
diff --git a/modules/multiplayer/scene_multiplayer.h b/modules/multiplayer/scene_multiplayer.h
index a61e505689..e799abeb48 100644
--- a/modules/multiplayer/scene_multiplayer.h
+++ b/modules/multiplayer/scene_multiplayer.h
@@ -201,9 +201,6 @@ public:
void set_max_delta_packet_size(int p_size);
int get_max_delta_packet_size() const;
- Ref<SceneCacheInterface> get_path_cache() { return cache; }
- Ref<SceneReplicationInterface> get_replicator() { return replicator; }
-
SceneMultiplayer();
~SceneMultiplayer();
};
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index e350f2f68b..c95e4ff9c9 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -89,6 +89,10 @@ void SceneReplicationInterface::_free_remotes(const PeerInfo &p_info) {
}
}
+bool SceneReplicationInterface::_has_authority(const Node *p_node) {
+ return multiplayer->has_multiplayer_peer() && p_node->get_multiplayer_authority() == multiplayer->get_unique_id();
+}
+
void SceneReplicationInterface::on_peer_change(int p_id, bool p_connected) {
if (p_connected) {
peers_info[p_id] = PeerInfo();
@@ -184,7 +188,7 @@ void SceneReplicationInterface::_node_ready(const ObjectID &p_oid) {
ERR_CONTINUE(!spawner);
spawned_nodes.insert(oid);
- if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
+ if (_has_authority(spawner)) {
if (tobj.net_id == 0) {
tobj.net_id = ++last_net_id;
}
@@ -248,9 +252,9 @@ Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_c
// Try to apply spawn state (before ready).
if (pending_buffer_size > 0) {
- ERR_FAIL_COND_V(!node || sync->get_replication_config().is_null(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(!node || !sync->get_replication_config_ptr(), ERR_UNCONFIGURED);
int consumed = 0;
- const List<NodePath> props = sync->get_replication_config()->get_spawn_properties();
+ const List<NodePath> props = sync->get_replication_config_ptr()->get_spawn_properties();
Vector<Variant> vars;
vars.resize(props.size());
Error err = MultiplayerAPI::decode_and_decompress_variants(vars, pending_buffer, pending_buffer_size, consumed);
@@ -342,7 +346,7 @@ bool SceneReplicationInterface::is_rpc_visible(const ObjectID &p_oid, int p_peer
Error SceneReplicationInterface::_update_sync_visibility(int p_peer, MultiplayerSynchronizer *p_sync) {
ERR_FAIL_NULL_V(p_sync, ERR_BUG);
- if (!multiplayer->has_multiplayer_peer() || !p_sync->is_multiplayer_authority() || p_peer == multiplayer->get_unique_id()) {
+ if (!_has_authority(p_sync) || p_peer == multiplayer->get_unique_id()) {
return OK;
}
@@ -383,14 +387,16 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
ERR_FAIL_NULL_V(tnode, ERR_BUG);
MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tnode->spawner);
Node *node = get_id_as<Node>(p_oid);
- ERR_FAIL_COND_V(!node || !spawner || !spawner->is_multiplayer_authority(), ERR_BUG);
+ ERR_FAIL_NULL_V(node, ERR_BUG);
+ ERR_FAIL_NULL_V(spawner, ERR_BUG);
+ ERR_FAIL_COND_V(!_has_authority(spawner), ERR_BUG);
ERR_FAIL_COND_V(!tracked_nodes.has(p_oid), ERR_BUG);
const HashSet<ObjectID> synchronizers = tracked_nodes[p_oid].synchronizers;
bool is_visible = true;
for (const ObjectID &sid : synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid);
ERR_CONTINUE(!sync);
- if (!sync->is_multiplayer_authority()) {
+ if (!_has_authority(sync)) {
continue;
}
// Spawn visibility is composed using OR when multiple synchronizers are present.
@@ -435,7 +441,7 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
for (int pid : to_spawn) {
ERR_CONTINUE(!peers_info.has(pid));
int path_id;
- multiplayer->get_path_cache()->send_object_cache(spawner, pid, path_id);
+ multiplayer_cache->send_object_cache(spawner, pid, path_id);
_send_raw(packet_cache.ptr(), len, pid, true);
peers_info[pid].spawn_nodes.insert(p_oid);
}
@@ -454,9 +460,9 @@ Error SceneReplicationInterface::_update_spawn_visibility(int p_peer, const Obje
Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) {
ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!multiplayer->has_multiplayer_peer(), ERR_UNCONFIGURED);
Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer();
+ ERR_FAIL_COND_V(peer.is_null(), ERR_UNCONFIGURED);
peer->set_transfer_channel(0);
peer->set_transfer_mode(p_reliable ? MultiplayerPeer::TRANSFER_MODE_RELIABLE : MultiplayerPeer::TRANSFER_MODE_UNRELIABLE);
return multiplayer->send_command(p_peer, p_buffer, p_size);
@@ -488,12 +494,12 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpa
const HashSet<ObjectID> synchronizers = tnode->synchronizers;
for (const ObjectID &sid : synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(sid);
- if (!sync->is_multiplayer_authority()) {
+ if (!_has_authority(sync)) {
continue;
}
ERR_CONTINUE(!sync);
- ERR_FAIL_COND_V(sync->get_replication_config().is_null(), ERR_BUG);
- for (const NodePath &prop : sync->get_replication_config()->get_spawn_properties()) {
+ ERR_FAIL_NULL_V(sync->get_replication_config_ptr(), ERR_BUG);
+ for (const NodePath &prop : sync->get_replication_config_ptr()->get_spawn_properties()) {
state_props.push_back(prop);
}
// Ensure the synchronizer has an ID.
@@ -513,7 +519,7 @@ Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpa
}
// Encode scene ID, path ID, net ID, node name.
- int path_id = multiplayer->get_path_cache()->make_object_cache(p_spawner);
+ int path_id = multiplayer_cache->make_object_cache(p_spawner);
CharString cname = p_node->get_name().operator String().utf8();
int nlen = encode_cstring(cname.get_data(), nullptr);
MAKE_ROOM(1 + 1 + 4 + 4 + 4 + 4 * sync_ids.size() + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size);
@@ -567,7 +573,7 @@ Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_b
ofs += 1;
uint32_t node_target = decode_uint32(&p_buffer[ofs]);
ofs += 4;
- MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(multiplayer->get_path_cache()->get_cached_object(p_from, node_target));
+ MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(multiplayer_cache->get_cached_object(p_from, node_target));
ERR_FAIL_NULL_V(spawner, ERR_DOES_NOT_EXIST);
ERR_FAIL_COND_V(p_from != spawner->get_multiplayer_authority(), ERR_UNAUTHORIZED);
@@ -678,7 +684,7 @@ bool SceneReplicationInterface::_verify_synchronizer(int p_peer, MultiplayerSync
r_net_id = p_sync->get_net_id();
if (r_net_id == 0 || (r_net_id & 0x80000000)) {
int path_id = 0;
- bool verified = multiplayer->get_path_cache()->send_object_cache(p_sync, p_peer, path_id);
+ bool verified = multiplayer_cache->send_object_cache(p_sync, p_peer, path_id);
ERR_FAIL_COND_V_MSG(path_id < 0, false, "This should never happen!");
if (r_net_id == 0) {
// First time path based ID.
@@ -693,7 +699,7 @@ bool SceneReplicationInterface::_verify_synchronizer(int p_peer, MultiplayerSync
MultiplayerSynchronizer *SceneReplicationInterface::_find_synchronizer(int p_peer, uint32_t p_net_id) {
MultiplayerSynchronizer *sync = nullptr;
if (p_net_id & 0x80000000) {
- sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_path_cache()->get_cached_object(p_peer, p_net_id & 0x7FFFFFFF));
+ sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer_cache->get_cached_object(p_peer, p_net_id & 0x7FFFFFFF));
} else if (peers_info[p_peer].recv_sync_ids.has(p_net_id)) {
const ObjectID &sid = peers_info[p_peer].recv_sync_ids[p_net_id];
sync = get_id_as<MultiplayerSynchronizer>(sid);
@@ -708,7 +714,7 @@ void SceneReplicationInterface::_send_delta(int p_peer, const HashSet<ObjectID>
int ofs = 1;
for (const ObjectID &oid : p_synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(oid);
- ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid() || !sync->is_multiplayer_authority());
+ ERR_CONTINUE(!sync || !sync->get_replication_config_ptr() || !_has_authority(sync));
uint32_t net_id;
if (!_verify_synchronizer(p_peer, sync, net_id)) {
continue;
@@ -803,7 +809,7 @@ void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p
// This is a lazy implementation, we could optimize much more here with by grouping by replication config.
for (const ObjectID &oid : p_synchronizers) {
MultiplayerSynchronizer *sync = get_id_as<MultiplayerSynchronizer>(oid);
- ERR_CONTINUE(!sync || !sync->get_replication_config().is_valid() || !sync->is_multiplayer_authority());
+ ERR_CONTINUE(!sync || !sync->get_replication_config_ptr() || !_has_authority(sync));
if (!sync->update_outbound_sync_time(p_usec)) {
continue; // nothing to sync.
}
@@ -818,7 +824,7 @@ void SceneReplicationInterface::_send_sync(int p_peer, const HashSet<ObjectID> p
int size;
Vector<Variant> vars;
Vector<const Variant *> varp;
- const List<NodePath> props = sync->get_replication_config()->get_sync_properties();
+ const List<NodePath> props = sync->get_replication_config_ptr()->get_sync_properties();
Error err = MultiplayerSynchronizer::get_state(props, node, vars, varp);
ERR_CONTINUE_MSG(err != OK, "Unable to retrieve sync state.");
err = MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), nullptr, size);
@@ -877,7 +883,7 @@ Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_bu
ofs += size;
continue;
}
- const List<NodePath> props = sync->get_replication_config()->get_sync_properties();
+ const List<NodePath> props = sync->get_replication_config_ptr()->get_sync_properties();
Vector<Variant> vars;
vars.resize(props.size());
int consumed;
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index 267d329ca7..3b3ec6a9ef 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -37,6 +37,7 @@
#include "core/object/ref_counted.h"
class SceneMultiplayer;
+class SceneCacheInterface;
class SceneReplicationInterface : public RefCounted {
GDCLASS(SceneReplicationInterface, RefCounted);
@@ -87,6 +88,7 @@ private:
// Replicator config.
SceneMultiplayer *multiplayer = nullptr;
+ SceneCacheInterface *multiplayer_cache = nullptr;
PackedByteArray packet_cache;
int sync_mtu = 1350; // Highly dependent on underlying protocol.
int delta_mtu = 65535;
@@ -95,6 +97,7 @@ private:
void _untrack(const ObjectID &p_id);
void _node_ready(const ObjectID &p_oid);
+ bool _has_authority(const Node *p_node);
bool _verify_synchronizer(int p_peer, MultiplayerSynchronizer *p_sync, uint32_t &r_net_id);
MultiplayerSynchronizer *_find_synchronizer(int p_peer, uint32_t p_net_ida);
@@ -143,8 +146,9 @@ public:
void set_max_delta_packet_size(int p_size);
int get_max_delta_packet_size() const;
- SceneReplicationInterface(SceneMultiplayer *p_multiplayer) {
+ SceneReplicationInterface(SceneMultiplayer *p_multiplayer, SceneCacheInterface *p_cache) {
multiplayer = p_multiplayer;
+ multiplayer_cache = p_cache;
}
};
diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp
index 48e1d13f9c..1463598ddc 100644
--- a/modules/multiplayer/scene_rpc_interface.cpp
+++ b/modules/multiplayer/scene_rpc_interface.cpp
@@ -116,22 +116,6 @@ const SceneRPCInterface::RPCConfigCache &SceneRPCInterface::_get_node_config(con
return rpc_cache[oid];
}
-_FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, int p_remote_id) {
- switch (mode) {
- case MultiplayerAPI::RPC_MODE_DISABLED: {
- return false;
- } break;
- case MultiplayerAPI::RPC_MODE_ANY_PEER: {
- return true;
- } break;
- case MultiplayerAPI::RPC_MODE_AUTHORITY: {
- return !p_node->is_multiplayer_authority() && p_remote_id == p_node->get_multiplayer_authority();
- } break;
- }
-
- return false;
-}
-
String SceneRPCInterface::get_rpc_md5(const Object *p_obj) {
const Node *node = Object::cast_to<Node>(p_obj);
ERR_FAIL_NULL_V(node, "");
@@ -167,7 +151,7 @@ Node *SceneRPCInterface::_process_get_node(int p_from, const uint8_t *p_packet,
return node;
} else {
// Use cached path.
- return Object::cast_to<Node>(multiplayer->get_path_cache()->get_cached_object(p_from, p_node_target));
+ return Object::cast_to<Node>(multiplayer_cache->get_cached_object(p_from, p_node_target));
}
}
@@ -252,7 +236,19 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i
ERR_FAIL_COND(!cache_config.configs.has(p_rpc_method_id));
const RPCConfig &config = cache_config.configs[p_rpc_method_id];
- bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from);
+ bool can_call = false;
+ switch (config.rpc_mode) {
+ case MultiplayerAPI::RPC_MODE_DISABLED: {
+ can_call = false;
+ } break;
+ case MultiplayerAPI::RPC_MODE_ANY_PEER: {
+ can_call = true;
+ } break;
+ case MultiplayerAPI::RPC_MODE_AUTHORITY: {
+ can_call = p_from == p_node->get_multiplayer_authority();
+ } break;
+ }
+
ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", authority is " + itos(p_node->get_multiplayer_authority()) + ".");
int argc = 0;
@@ -313,25 +309,24 @@ void SceneRPCInterface::_send_rpc(Node *p_node, int p_to, uint16_t p_rpc_id, con
// See if all peers have cached path (if so, call can be fast) while building the RPC target list.
HashSet<int> targets;
- Ref<SceneCacheInterface> cache = multiplayer->get_path_cache();
int psc_id = -1;
bool has_all_peers = true;
const ObjectID oid = p_node->get_instance_id();
if (p_to > 0) {
- ERR_FAIL_COND_MSG(!multiplayer->get_replicator()->is_rpc_visible(oid, p_to), "Attempt to call an RPC to a peer that cannot see this node. Peer ID: " + itos(p_to));
+ ERR_FAIL_COND_MSG(!multiplayer_replicator->is_rpc_visible(oid, p_to), "Attempt to call an RPC to a peer that cannot see this node. Peer ID: " + itos(p_to));
targets.insert(p_to);
- has_all_peers = cache->send_object_cache(p_node, p_to, psc_id);
+ has_all_peers = multiplayer_cache->send_object_cache(p_node, p_to, psc_id);
} else {
- bool restricted = !multiplayer->get_replicator()->is_rpc_visible(oid, 0);
+ bool restricted = !multiplayer_replicator->is_rpc_visible(oid, 0);
for (const int &P : multiplayer->get_connected_peers()) {
if (p_to < 0 && P == -p_to) {
continue; // Excluded peer.
}
- if (restricted && !multiplayer->get_replicator()->is_rpc_visible(oid, P)) {
+ if (restricted && !multiplayer_replicator->is_rpc_visible(oid, P)) {
continue; // Not visible to this peer.
}
targets.insert(P);
- bool has_peer = cache->send_object_cache(p_node, P, psc_id);
+ bool has_peer = multiplayer_cache->send_object_cache(p_node, P, psc_id);
has_all_peers = has_all_peers && has_peer;
}
}
@@ -443,15 +438,14 @@ void SceneRPCInterface::_send_rpc(Node *p_node, int p_to, uint16_t p_rpc_id, con
// Not all verified path, so send one by one.
// Append path at the end, since we will need it for some packets.
- NodePath from_path = multiplayer->get_root_path().rel_path_to(p_node->get_path());
- CharString pname = String(from_path).utf8();
+ CharString pname = String(multiplayer->get_root_path().rel_path_to(p_node->get_path())).utf8();
int path_len = encode_cstring(pname.get_data(), nullptr);
MAKE_ROOM(ofs + path_len);
encode_cstring(pname.get_data(), &(packet_cache.write[ofs]));
// Not all verified path, so check which needs the longer packet.
for (const int P : targets) {
- bool confirmed = multiplayer->get_path_cache()->is_cache_confirmed(from_path, P);
+ bool confirmed = multiplayer_cache->is_cache_confirmed(p_node, P);
if (confirmed) {
// This one confirmed path, so use id.
encode_uint32(psc_id, &(packet_cache.write[1]));
diff --git a/modules/multiplayer/scene_rpc_interface.h b/modules/multiplayer/scene_rpc_interface.h
index b40169a63b..5c9b66d5f5 100644
--- a/modules/multiplayer/scene_rpc_interface.h
+++ b/modules/multiplayer/scene_rpc_interface.h
@@ -35,6 +35,8 @@
#include "scene/main/multiplayer_api.h"
class SceneMultiplayer;
+class SceneCacheInterface;
+class SceneReplicationInterface;
class Node;
class SceneRPCInterface : public RefCounted {
@@ -77,6 +79,9 @@ private:
};
SceneMultiplayer *multiplayer = nullptr;
+ SceneCacheInterface *multiplayer_cache = nullptr;
+ SceneReplicationInterface *multiplayer_replicator = nullptr;
+
Vector<uint8_t> packet_cache;
HashMap<ObjectID, RPCConfigCache> rpc_cache;
@@ -99,7 +104,11 @@ public:
void process_rpc(int p_from, const uint8_t *p_packet, int p_packet_len);
String get_rpc_md5(const Object *p_obj);
- SceneRPCInterface(SceneMultiplayer *p_multiplayer) { multiplayer = p_multiplayer; }
+ SceneRPCInterface(SceneMultiplayer *p_multiplayer, SceneCacheInterface *p_cache, SceneReplicationInterface *p_replicator) {
+ multiplayer = p_multiplayer;
+ multiplayer_cache = p_cache;
+ multiplayer_replicator = p_replicator;
+ }
};
#endif // SCENE_RPC_INTERFACE_H
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
index d95bc3bb8e..7488b5cf8e 100644
--- a/modules/openxr/util.h
+++ b/modules/openxr/util.h
@@ -61,13 +61,13 @@
#define GDEXTENSION_INIT_XR_FUNC(name) \
do { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
- ERR_FAIL_COND(name##_ptr == nullptr); \
+ ERR_FAIL_NULL(name##_ptr); \
} while (0)
#define GDEXTENSION_INIT_XR_FUNC_V(name) \
do { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
- ERR_FAIL_COND_V(name##_ptr == nullptr, false); \
+ ERR_FAIL_NULL_V(name##_ptr, false); \
} while (0)
#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index b605b29f84..2e994f277d 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -4084,7 +4084,7 @@ bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const Stri
MutexLock lock(sd->mutex);
for (int i = 0; i < p_fonts.size(); i++) {
- ERR_FAIL_COND_V(!_get_font_data(p_fonts[i]), false);
+ ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);
}
if (p_text.is_empty()) {
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 0cfbf7f530..2d2fe08798 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -2939,7 +2939,7 @@ bool TextServerFallback::_shaped_text_add_string(const RID &p_shaped, const Stri
ERR_FAIL_COND_V(p_size <= 0, false);
for (int i = 0; i < p_fonts.size(); i++) {
- ERR_FAIL_COND_V(!_get_font_data(p_fonts[i]), false);
+ ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);
}
if (p_text.is_empty()) {
diff --git a/modules/webrtc/library_godot_webrtc.js b/modules/webrtc/library_godot_webrtc.js
index 7ece4aa872..eae4120741 100644
--- a/modules/webrtc/library_godot_webrtc.js
+++ b/modules/webrtc/library_godot_webrtc.js
@@ -90,6 +90,7 @@ const GodotRTCDataChannel = {
},
},
+ godot_js_rtc_datachannel_ready_state_get__proxy: 'sync',
godot_js_rtc_datachannel_ready_state_get__sig: 'ii',
godot_js_rtc_datachannel_ready_state_get: function (p_id) {
const ref = IDHandler.get(p_id);
@@ -110,6 +111,7 @@ const GodotRTCDataChannel = {
}
},
+ godot_js_rtc_datachannel_send__proxy: 'sync',
godot_js_rtc_datachannel_send__sig: 'iiiii',
godot_js_rtc_datachannel_send: function (p_id, p_buffer, p_length, p_raw) {
const ref = IDHandler.get(p_id);
@@ -131,16 +133,19 @@ const GodotRTCDataChannel = {
return 0;
},
+ godot_js_rtc_datachannel_is_ordered__proxy: 'sync',
godot_js_rtc_datachannel_is_ordered__sig: 'ii',
godot_js_rtc_datachannel_is_ordered: function (p_id) {
return GodotRTCDataChannel.get_prop(p_id, 'ordered', true);
},
+ godot_js_rtc_datachannel_id_get__proxy: 'sync',
godot_js_rtc_datachannel_id_get__sig: 'ii',
godot_js_rtc_datachannel_id_get: function (p_id) {
return GodotRTCDataChannel.get_prop(p_id, 'id', 65535);
},
+ godot_js_rtc_datachannel_max_packet_lifetime_get__proxy: 'sync',
godot_js_rtc_datachannel_max_packet_lifetime_get__sig: 'ii',
godot_js_rtc_datachannel_max_packet_lifetime_get: function (p_id) {
const ref = IDHandler.get(p_id);
@@ -156,21 +161,25 @@ const GodotRTCDataChannel = {
return 65535;
},
+ godot_js_rtc_datachannel_max_retransmits_get__proxy: 'sync',
godot_js_rtc_datachannel_max_retransmits_get__sig: 'ii',
godot_js_rtc_datachannel_max_retransmits_get: function (p_id) {
return GodotRTCDataChannel.get_prop(p_id, 'maxRetransmits', 65535);
},
+ godot_js_rtc_datachannel_is_negotiated__proxy: 'sync',
godot_js_rtc_datachannel_is_negotiated__sig: 'ii',
godot_js_rtc_datachannel_is_negotiated: function (p_id) {
return GodotRTCDataChannel.get_prop(p_id, 'negotiated', 65535);
},
+ godot_js_rtc_datachannel_get_buffered_amount__proxy: 'sync',
godot_js_rtc_datachannel_get_buffered_amount__sig: 'ii',
godot_js_rtc_datachannel_get_buffered_amount: function (p_id) {
return GodotRTCDataChannel.get_prop(p_id, 'bufferedAmount', 0);
},
+ godot_js_rtc_datachannel_label_get__proxy: 'sync',
godot_js_rtc_datachannel_label_get__sig: 'ii',
godot_js_rtc_datachannel_label_get: function (p_id) {
const ref = IDHandler.get(p_id);
@@ -189,12 +198,14 @@ const GodotRTCDataChannel = {
return GodotRuntime.allocString(ref.protocol);
},
+ godot_js_rtc_datachannel_destroy__proxy: 'sync',
godot_js_rtc_datachannel_destroy__sig: 'vi',
godot_js_rtc_datachannel_destroy: function (p_id) {
GodotRTCDataChannel.close(p_id);
IDHandler.remove(p_id);
},
+ godot_js_rtc_datachannel_connect__proxy: 'sync',
godot_js_rtc_datachannel_connect__sig: 'viiiiii',
godot_js_rtc_datachannel_connect: function (p_id, p_ref, p_on_open, p_on_message, p_on_error, p_on_close) {
const onopen = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
@@ -204,6 +215,7 @@ const GodotRTCDataChannel = {
GodotRTCDataChannel.connect(p_id, onopen, onmessage, onerror, onclose);
},
+ godot_js_rtc_datachannel_close__proxy: 'sync',
godot_js_rtc_datachannel_close__sig: 'vi',
godot_js_rtc_datachannel_close: function (p_id) {
const ref = IDHandler.get(p_id);
@@ -356,6 +368,7 @@ const GodotRTCPeerConnection = {
},
},
+ godot_js_rtc_pc_create__proxy: 'sync',
godot_js_rtc_pc_create__sig: 'iiiiiiii',
godot_js_rtc_pc_create: function (p_config, p_ref, p_on_connection_state_change, p_on_ice_gathering_state_change, p_on_signaling_state_change, p_on_ice_candidate, p_on_datachannel) {
const wrap = function (p_func) {
@@ -371,6 +384,7 @@ const GodotRTCPeerConnection = {
);
},
+ godot_js_rtc_pc_close__proxy: 'sync',
godot_js_rtc_pc_close__sig: 'vi',
godot_js_rtc_pc_close: function (p_id) {
const ref = IDHandler.get(p_id);
@@ -380,11 +394,13 @@ const GodotRTCPeerConnection = {
ref.close();
},
+ godot_js_rtc_pc_destroy__proxy: 'sync',
godot_js_rtc_pc_destroy__sig: 'vi',
godot_js_rtc_pc_destroy: function (p_id) {
GodotRTCPeerConnection.destroy(p_id);
},
+ godot_js_rtc_pc_offer_create__proxy: 'sync',
godot_js_rtc_pc_offer_create__sig: 'viiii',
godot_js_rtc_pc_offer_create: function (p_id, p_obj, p_on_session, p_on_error) {
const ref = IDHandler.get(p_id);
@@ -400,6 +416,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_local_description_set__proxy: 'sync',
godot_js_rtc_pc_local_description_set__sig: 'viiiii',
godot_js_rtc_pc_local_description_set: function (p_id, p_type, p_sdp, p_obj, p_on_error) {
const ref = IDHandler.get(p_id);
@@ -417,6 +434,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_remote_description_set__proxy: 'sync',
godot_js_rtc_pc_remote_description_set__sig: 'viiiiii',
godot_js_rtc_pc_remote_description_set: function (p_id, p_type, p_sdp, p_obj, p_session_created, p_on_error) {
const ref = IDHandler.get(p_id);
@@ -442,6 +460,7 @@ const GodotRTCPeerConnection = {
});
},
+ godot_js_rtc_pc_ice_candidate_add__proxy: 'sync',
godot_js_rtc_pc_ice_candidate_add__sig: 'viiii',
godot_js_rtc_pc_ice_candidate_add: function (p_id, p_mid_name, p_mline_idx, p_sdp) {
const ref = IDHandler.get(p_id);
@@ -458,6 +477,7 @@ const GodotRTCPeerConnection = {
},
godot_js_rtc_pc_datachannel_create__deps: ['$GodotRTCDataChannel'],
+ godot_js_rtc_pc_datachannel_create__proxy: 'sync',
godot_js_rtc_pc_datachannel_create__sig: 'iiii',
godot_js_rtc_pc_datachannel_create: function (p_id, p_label, p_config) {
try {
diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js
index ed01c69725..5e0c6fc576 100644
--- a/modules/websocket/library_godot_websocket.js
+++ b/modules/websocket/library_godot_websocket.js
@@ -144,6 +144,7 @@ const GodotWebSocket = {
},
},
+ godot_js_websocket_create__proxy: 'sync',
godot_js_websocket_create__sig: 'iiiiiiii',
godot_js_websocket_create: function (p_ref, p_url, p_proto, p_on_open, p_on_message, p_on_error, p_on_close) {
const on_open = GodotRuntime.get_func(p_on_open).bind(null, p_ref);
@@ -166,6 +167,7 @@ const GodotWebSocket = {
return GodotWebSocket.create(socket, on_open, on_message, on_error, on_close);
},
+ godot_js_websocket_send__proxy: 'sync',
godot_js_websocket_send__sig: 'iiiii',
godot_js_websocket_send: function (p_id, p_buf, p_buf_len, p_raw) {
const bytes_array = new Uint8Array(p_buf_len);
@@ -180,11 +182,13 @@ const GodotWebSocket = {
return GodotWebSocket.send(p_id, out);
},
+ godot_js_websocket_buffered_amount__proxy: 'sync',
godot_js_websocket_buffered_amount__sig: 'ii',
godot_js_websocket_buffered_amount: function (p_id) {
return GodotWebSocket.bufferedAmount(p_id);
},
+ godot_js_websocket_close__proxy: 'sync',
godot_js_websocket_close__sig: 'viii',
godot_js_websocket_close: function (p_id, p_code, p_reason) {
const code = p_code;
@@ -192,6 +196,7 @@ const GodotWebSocket = {
GodotWebSocket.close(p_id, code, reason);
},
+ godot_js_websocket_destroy__proxy: 'sync',
godot_js_websocket_destroy__sig: 'vi',
godot_js_websocket_destroy: function (p_id) {
GodotWebSocket.destroy(p_id);