diff options
Diffstat (limited to 'modules')
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); |
