diff options
Diffstat (limited to 'modules')
44 files changed, 1385 insertions, 399 deletions
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 3044887ef5..d4069b901f 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -283,6 +283,10 @@ String CSGShapeSpatialGizmoPlugin::get_name() const { return "CSGShapes"; } +int CSGShapeSpatialGizmoPlugin::get_priority() const { + return -1; +} + bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const { return true; } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index b208c39938..0915d05111 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -42,6 +42,7 @@ class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { public: bool has_gizmo(Spatial *p_spatial); String get_name() const; + int get_priority() const; bool is_selectable_when_hidden() const; void redraw(EditorSpatialGizmo *p_gizmo); diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 34325db9fd..e8278825bc 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -414,6 +414,7 @@ bool GDNative::terminate() { if (error || !library_terminate) { OS::get_singleton()->close_dynamic_library(native_handle); native_handle = NULL; + initialized = false; return true; } diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index b99c5d31ab..7eb4294732 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -279,7 +279,7 @@ List<ClassAPI> generate_c_api_classes() { MethodInfo &method_info = m->get(); //method name - method_api.method_name = m->get().name; + method_api.method_name = method_info.name; //method return type if (method_api.method_name.find(":") != -1) { method_api.return_type = method_api.method_name.get_slice(":", 1); @@ -321,6 +321,8 @@ List<ClassAPI> generate_c_api_classes() { arg_type = arg_info.hint_string; } else if (arg_info.type == Variant::NIL) { arg_type = "Variant"; + } else if (arg_info.type == Variant::OBJECT) { + arg_type = arg_info.class_name; } else { arg_type = Variant::get_type_name(arg_info.type); } diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index c2b772df85..5cf144d4fe 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -160,8 +160,10 @@ bool NativeScript::can_instance() const { NativeScriptDesc *script_data = get_script_desc(); #ifdef TOOLS_ENABLED - - return script_data || (!is_tool() && !ScriptServer::is_scripting_enabled()); + // Only valid if this is either a tool script or a "regular" script. + // (so an environment whre scripting is disabled (and not the editor) would not + // create objects). + return script_data && (is_tool() || ScriptServer::is_scripting_enabled()); #else return script_data; #endif @@ -199,25 +201,6 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) { return NULL; } -#ifdef TOOLS_ENABLED - if (!ScriptServer::is_scripting_enabled() && !is_tool()) { - // placeholder for nodes. For tools we want the rool thing. - - PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); - placeholders.insert(sins); - - if (script_data->create_func.create_func) { - script_data->create_func.create_func( - (godot_object *)p_this, - script_data->create_func.method_data); - } - - _update_placeholder(sins); - - return sins; - } -#endif - NativeScriptInstance *nsi = memnew(NativeScriptInstance); nsi->owner = p_this; @@ -246,6 +229,19 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) { return nsi; } +PlaceHolderScriptInstance *NativeScript::placeholder_instance_create(Object *p_this) { +#ifdef TOOLS_ENABLED + PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(NSL, Ref<Script>(this), p_this)); + placeholders.insert(sins); + + _update_placeholder(sins); + + return sins; +#else + return NULL; +#endif +} + bool NativeScript::instance_has(const Object *p_this) const { return instance_owners.has((Object *)p_this); } @@ -1036,8 +1032,16 @@ NativeScriptLanguage::~NativeScriptLanguage() { for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { - if (L->get().is_valid()) - L->get()->terminate(); + Ref<GDNative> lib = L->get(); + // only shut down valid libs, duh! + if (lib.is_valid()) { + + // If it's a singleton-library then the gdnative module + // manages the destruction at engine shutdown, not NativeScript. + if (!lib->get_library()->is_singleton()) { + lib->terminate(); + } + } } NSL->library_classes.clear(); @@ -1641,10 +1645,19 @@ void NativeReloadNode::_notification(int p_what) { continue; } + // Don't unload what should not be reloaded! if (!gdn->get_library()->is_reloadable()) { continue; } + // singleton libraries might have alive pointers living inside the + // editor. Also reloading a singleton library would mean that + // the singleton entry will not be called again, as this only + // happens at engine startup. + if (gdn->get_library()->is_singleton()) { + continue; + } + gdn->terminate(); } @@ -1672,6 +1685,12 @@ void NativeReloadNode::_notification(int p_what) { continue; } + // since singleton libraries are not unloaded there is no point + // in loading them again. + if (gdn->get_library()->is_singleton()) { + continue; + } + if (!gdn->initialize()) { libs_to_remove.insert(L->key()); continue; diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 8dd5ba3b9c..a6865c6243 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -149,6 +149,7 @@ public: virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index d1794b6c36..8fcebe7855 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -117,18 +117,20 @@ bool VideoStreamPlaybackGDNative::open_file(const String &p_file) { file = FileAccess::open(p_file, FileAccess::READ); bool file_opened = interface->open_file(data_struct, file); - num_channels = interface->get_channels(data_struct); - mix_rate = interface->get_mix_rate(data_struct); + if (file_opened) { + num_channels = interface->get_channels(data_struct); + mix_rate = interface->get_mix_rate(data_struct); - godot_vector2 vec = interface->get_texture_size(data_struct); - texture_size = *(Vector2 *)&vec; + godot_vector2 vec = interface->get_texture_size(data_struct); + texture_size = *(Vector2 *)&vec; - pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float)); - memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); - pcm_write_idx = -1; - samples_decoded = 0; + pcm = (float *)memalloc(num_channels * AUX_BUFFER_SIZE * sizeof(float)); + memset(pcm, 0, num_channels * AUX_BUFFER_SIZE * sizeof(float)); + pcm_write_idx = -1; + samples_decoded = 0; - texture->create((int)texture_size.width, (int)texture_size.height, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); + texture->create((int)texture_size.width, (int)texture_size.height, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); + } return file_opened; } @@ -355,9 +357,9 @@ RES ResourceFormatLoaderVideoStreamGDNative::load(const String &p_path, const St if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } + memdelete(f); VideoStreamGDNative *stream = memnew(VideoStreamGDNative); stream->set_file(p_path); Ref<VideoStreamGDNative> ogv_stream = Ref<VideoStreamGDNative>(stream); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 670aabc34c..4385cf12ad 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1965,7 +1965,7 @@ String GDScriptWarning::get_message() const { return "Assignment operation, but the function '" + symbols[0] + "()' returns void."; } break; case NARROWING_CONVERSION: { - return "Narrowing coversion (float is converted to int and lose precision)."; + return "Narrowing conversion (float is converted to int and loses precision)."; } break; case FUNCTION_MAY_YIELD: { CHECK_SYMBOLS(1); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index b2b7b1c260..ae67521749 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -139,17 +139,32 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.native_type = result.script_type->get_instance_base_type(); } break; case GDScriptParser::DataType::CLASS: { - result.kind = GDScriptDataType::GDSCRIPT; - if (!p_datatype.class_type->owner) { - result.script_type = Ref<GDScript>(main_script); - } else { - result.script_type = class_map[p_datatype.class_type->name]; + // Locate class by constructing the path to it and following that path + GDScriptParser::ClassNode *class_type = p_datatype.class_type; + List<StringName> names; + while (class_type->owner) { + names.push_back(class_type->name); + class_type = class_type->owner; } - result.native_type = result.script_type->get_instance_base_type(); + + Ref<GDScript> script = Ref<GDScript>(main_script); + while (names.back()) { + if (!script->subclasses.has(names.back()->get())) { + ERR_PRINT("Parser bug: Cannot locate datatype class."); + result.has_type = false; + return GDScriptDataType(); + } + script = script->subclasses[names.back()->get()]; + names.pop_back(); + } + + result.kind = GDScriptDataType::GDSCRIPT; + result.script_type = script; + result.native_type = script->get_instance_base_type(); } break; default: { ERR_PRINT("Parser bug: converting unresolved type."); - result.has_type = false; + return GDScriptDataType(); } } @@ -460,12 +475,14 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.alloc_stack(slevel); } - switch (cn->cast_type.kind) { - case GDScriptParser::DataType::BUILTIN: { + GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type); + + switch (cast_type.kind) { + case GDScriptDataType::BUILTIN: { codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN); codegen.opcodes.push_back(cn->cast_type.builtin_type); } break; - case GDScriptParser::DataType::NATIVE: { + case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) { @@ -478,32 +495,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator codegen.opcodes.push_back(class_idx); // variable type } break; - case GDScriptParser::DataType::CLASS: { - - Variant script; - int idx = -1; - if (!cn->cast_type.class_type->owner) { - script = codegen.script; - } else { - StringName name = cn->cast_type.class_type->name; - if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) { - idx = codegen.get_name_map_pos(name); - idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; - } else { - script = class_map[name]; - } - } - - if (idx < 0) { - idx = codegen.get_constant_pos(script); - idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) - } - - codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator - codegen.opcodes.push_back(idx); // variable type - } break; - case GDScriptParser::DataType::SCRIPT: - case GDScriptParser::DataType::GDSCRIPT: { + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { Variant script = cn->cast_type.script_type; int idx = codegen.get_constant_pos(script); @@ -1149,18 +1142,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: if (src_address_b < 0) return -1; - GDScriptParser::DataType assign_type = on->arguments[0]->get_datatype(); + GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype()); if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) { // Typed assignment switch (assign_type.kind) { - case GDScriptParser::DataType::BUILTIN: { + case GDScriptDataType::BUILTIN: { codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator codegen.opcodes.push_back(assign_type.builtin_type); // variable type codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 } break; - case GDScriptParser::DataType::NATIVE: { + case GDScriptDataType::NATIVE: { int class_idx; if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) { @@ -1175,34 +1168,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(dst_address_a); // argument 1 codegen.opcodes.push_back(src_address_b); // argument 2 } break; - case GDScriptParser::DataType::CLASS: { - - Variant script; - int idx = -1; - if (!assign_type.class_type->owner) { - script = codegen.script; - } else { - StringName name = assign_type.class_type->name; - if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) { - idx = codegen.get_name_map_pos(name); - idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; - } else { - script = class_map[name]; - } - } - - if (idx < 0) { - idx = codegen.get_constant_pos(script); - idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) - } - - codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator - codegen.opcodes.push_back(idx); // variable type - codegen.opcodes.push_back(dst_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 - } break; - case GDScriptParser::DataType::SCRIPT: - case GDScriptParser::DataType::GDSCRIPT: { + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { Variant script = assign_type.script_type; int idx = codegen.get_constant_pos(script); @@ -1396,11 +1363,6 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo case GDScriptParser::ControlFlowNode::CF_IF: { -#ifdef DEBUG_ENABLED - codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE); - codegen.opcodes.push_back(cf->line); - codegen.current_line = cf->line; -#endif int ret2 = _parse_expression(codegen, cf->arguments[0], p_stack_level, false); if (ret2 < 0) return ERR_PARSE_ERROR; @@ -1850,22 +1812,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return OK; } -Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { +Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { + + parsing_classes.insert(p_script); if (p_class->owner && p_class->owner->owner) { // Owner is not root - StringName owner_name = p_class->owner->name; - if (!parsed_classes.has(owner_name)) { - if (parsing_classes.has(owner_name)) { - _set_error("Cyclic class reference for '" + String(owner_name) + "'.", p_class); + if (!parsed_classes.has(p_script->_owner)) { + if (parsing_classes.has(p_script->_owner)) { + _set_error("Cyclic class reference for '" + String(p_class->name) + "'.", p_class); return ERR_PARSE_ERROR; } - parsing_classes.insert(owner_name); - Error err = _parse_class_level(class_map[owner_name].ptr(), class_map[owner_name]->_owner, p_class->owner, p_keep_state); + Error err = _parse_class_level(p_script->_owner, p_class->owner, p_keep_state); if (err) { return err; } - parsing_classes.erase(owner_name); } } @@ -1883,47 +1844,26 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner p_script->_signals.clear(); p_script->initializer = NULL; - p_script->subclasses.clear(); - p_script->_owner = p_owner; p_script->tool = p_class->tool; p_script->name = p_class->name; Ref<GDScriptNativeClass> native; + GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type); // Inheritance - switch (p_class->base_type.kind) { - case GDScriptParser::DataType::CLASS: { - StringName base_name = p_class->base_type.class_type->name; - // Make sure dependency is parsed first - if (!parsed_classes.has(base_name)) { - if (parsing_classes.has(base_name)) { - _set_error("Cyclic class reference for '" + String(base_name) + "'.", p_class); - return ERR_PARSE_ERROR; - } - parsing_classes.insert(base_name); - Error err = _parse_class_level(class_map[base_name].ptr(), class_map[base_name]->_owner, p_class->base_type.class_type, p_keep_state); - if (err) { - return err; - } - parsing_classes.erase(base_name); - } - Ref<GDScript> base = class_map[base_name]; - p_script->base = base; - p_script->_base = p_script->base.ptr(); - p_script->member_indices = base->member_indices; - } break; - case GDScriptParser::DataType::GDSCRIPT: { - Ref<GDScript> base = p_class->base_type.script_type; - p_script->base = base; - p_script->_base = p_script->base.ptr(); - p_script->member_indices = base->member_indices; - } break; - case GDScriptParser::DataType::NATIVE: { - int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_class->base_type.native_type]; + switch (base_type.kind) { + case GDScriptDataType::NATIVE: { + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type]; native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; ERR_FAIL_COND_V(native.is_null(), ERR_BUG); p_script->native = native; } break; + case GDScriptDataType::GDSCRIPT: { + Ref<GDScript> base = base_type.script_type; + p_script->base = base; + p_script->_base = base.ptr(); + p_script->member_indices = base->member_indices; + } break; default: { _set_error("Parser bug: invalid inheritance.", p_class); return ERR_BUG; @@ -2017,24 +1957,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner p_script->_signals[name] = p_class->_signals[i].arguments; } - if (p_class->owner) { - parsed_classes.insert(p_class->name); - if (parsing_classes.has(p_class->name)) { - parsing_classes.erase(p_class->name); - } - } + parsed_classes.insert(p_script); + parsing_classes.erase(p_script); //parse sub-classes for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; - Ref<GDScript> subclass = class_map[name]; + GDScript *subclass = p_script->subclasses[name].ptr(); // Subclass might still be parsing, just skip it - if (!parsed_classes.has(name) && !parsing_classes.has(name)) { - parsing_classes.insert(name); - Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state); + if (!parsed_classes.has(subclass) && !parsing_classes.has(subclass)) { + Error err = _parse_class_level(subclass, p_class->subclasses[i], p_keep_state); if (err) return err; } @@ -2045,7 +1980,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner #endif p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants - p_script->subclasses.insert(name, subclass); } return OK; @@ -2144,9 +2078,9 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; - Ref<GDScript> subclass = class_map[name]; + GDScript *subclass = p_script->subclasses[name].ptr(); - Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state); + Error err = _parse_class_blocks(subclass, p_class->subclasses[i], p_keep_state); if (err) { return err; } @@ -2156,7 +2090,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa return OK; } -void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { +void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { Map<StringName, Ref<GDScript> > old_subclasses; @@ -2164,6 +2098,8 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar old_subclasses = p_script->subclasses; } + p_script->subclasses.clear(); + for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; @@ -2175,10 +2111,10 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar subclass.instance(); } - subclass->_owner = const_cast<GDScript *>(p_script); - class_map.insert(name, subclass); + subclass->_owner = p_script; + p_script->subclasses.insert(name, subclass); - _make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state); + _make_scripts(subclass.ptr(), p_class->subclasses[i], false); } } @@ -2197,7 +2133,8 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri // Create scripts for subclasses beforehand so they can be referenced _make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); - Error err = _parse_class_level(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); + p_script->_owner = NULL; + Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); if (err) return err; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 8440807a56..2cf630ba72 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -38,9 +38,8 @@ class GDScriptCompiler { const GDScriptParser *parser; - Map<StringName, Ref<GDScript> > class_map; - Set<StringName> parsed_classes; - Set<StringName> parsing_classes; + Set<GDScript *> parsed_classes; + Set<GDScript *> parsing_classes; GDScript *main_script; struct CodeGen { @@ -149,9 +148,9 @@ class GDScriptCompiler { int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false); Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); - Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); - void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + void _make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); int err_line; int err_column; StringName source; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 5619729c13..da69181a43 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -815,6 +815,16 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (!dependencies_only) { + if (!bfn && ScriptServer::is_global_class(identifier)) { + Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(identifier)); + if (scr.is_valid() && scr->is_valid()) { + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = scr; + expr = constant; + bfn = true; + } + } + // Check parents for the constant if (!bfn && cln->extends_file != StringName()) { Ref<GDScript> parent = ResourceLoader::load(cln->extends_file); @@ -2731,6 +2741,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } break; case GDScriptTokenizer::TK_NEWLINE: { + int line = tokenizer->get_token_line(); + if (!_parse_newline()) { if (!error_set) { p_block->end_line = tokenizer->get_token_line(); @@ -2740,7 +2752,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } NewLineNode *nl2 = alloc_node<NewLineNode>(); - nl2->line = tokenizer->get_token_line(); + nl2->line = line; p_block->statements.push_back(nl2); } break; @@ -7247,6 +7259,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType DataType result; result.has_type = true; result.script_type = scr; + result.is_constant = true; result.is_meta_type = true; Ref<GDScript> gds = scr; if (gds.is_valid()) { @@ -7297,6 +7310,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType if (singleton.is_valid()) { DataType result; result.has_type = true; + result.is_constant = true; result.script_type = singleton; Ref<GDScript> gds = singleton; diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index fe1eac6dc9..32a014e76d 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -517,7 +517,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Ref<NavigationMesh> navmesh = mesh_library->get_item_navmesh(c.item); if (navmesh.is_valid()) { Octant::NavMesh nm; - nm.xform = xform; + nm.xform = xform * mesh_library->get_item_navmesh_transform(c.item); if (navigation) { nm.id = navigation->navmesh_add(navmesh, xform, this); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index bc7a576785..17eb6f674c 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -717,6 +717,26 @@ void GridMapEditor::_set_display_mode(int p_mode) { update_palette(); } +void GridMapEditor::_text_changed(const String &p_text) { + update_palette(); +} + +void GridMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) { + + Ref<InputEventKey> k = p_ie; + + if (k.is_valid() && (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_PAGEUP || k->get_scancode() == KEY_PAGEDOWN)) { + + mesh_library_palette->call("_gui_input", k); + search_box->accept_event(); + } +} + +void GridMapEditor::_icon_size_changed(float p_value) { + mesh_library_palette->set_icon_scale(p_value); + update_palette(); +} + void GridMapEditor::update_palette() { int selected = mesh_library_palette->get_current(); @@ -730,8 +750,9 @@ void GridMapEditor::update_palette() { } float min_size = EDITOR_DEF("editors/grid_map/preview_size", 64); + min_size *= EDSCALE; mesh_library_palette->set_fixed_icon_size(Size2(min_size, min_size)); - mesh_library_palette->set_fixed_column_width(min_size * 3 / 2); + mesh_library_palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1.5)); mesh_library_palette->set_max_text_lines(2); Ref<MeshLibrary> mesh_library = node->get_mesh_library(); @@ -754,23 +775,28 @@ void GridMapEditor::update_palette() { } il.sort(); + String filter = search_box->get_text().strip_edges(); + int item = 0; for (List<_CGMEItemSort>::Element *E = il.front(); E; E = E->next()) { int id = E->get().id; - - mesh_library_palette->add_item(""); - String name = mesh_library->get_item_name(id); Ref<Texture> preview = mesh_library->get_item_preview(id); + if (name == "") { + name = "#" + itos(id); + } + + if (filter != "" && !filter.is_subsequence_ofi(name)) + continue; + + mesh_library_palette->add_item(""); if (!preview.is_null()) { mesh_library_palette->set_item_icon(item, preview); mesh_library_palette->set_item_tooltip(item, name); } - if (name != "") { - mesh_library_palette->set_item_text(item, name); - } + mesh_library_palette->set_item_text(item, name); mesh_library_palette->set_item_metadata(item, id); item++; @@ -985,6 +1011,7 @@ void GridMapEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { options->set_icon(get_icon("GridMap", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); } break; } } @@ -1031,6 +1058,9 @@ void GridMapEditor::_floor_changed(float p_value) { void GridMapEditor::_bind_methods() { + ClassDB::bind_method("_text_changed", &GridMapEditor::_text_changed); + ClassDB::bind_method("_sbox_input", &GridMapEditor::_sbox_input); + ClassDB::bind_method("_icon_size_changed", &GridMapEditor::_icon_size_changed); ClassDB::bind_method("_menu_option", &GridMapEditor::_menu_option); ClassDB::bind_method("_configure", &GridMapEditor::_configure); ClassDB::bind_method("_item_selected_cbk", &GridMapEditor::_item_selected_cbk); @@ -1132,6 +1162,12 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { add_child(hb); hb->set_h_size_flags(SIZE_EXPAND_FILL); + search_box = memnew(LineEdit); + search_box->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(search_box); + search_box->connect("text_changed", this, "_text_changed"); + search_box->connect("gui_input", this, "_sbox_input"); + mode_thumbnail = memnew(ToolButton); mode_thumbnail->set_toggle_mode(true); mode_thumbnail->set_pressed(true); @@ -1146,6 +1182,15 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { hb->add_child(mode_list); mode_list->connect("pressed", this, "_set_display_mode", varray(DISPLAY_LIST)); + size_slider = memnew(HSlider); + size_slider->set_h_size_flags(SIZE_EXPAND_FILL); + size_slider->set_min(0.1f); + size_slider->set_max(4.0f); + size_slider->set_step(0.1f); + size_slider->set_value(1.0f); + size_slider->connect("value_changed", this, "_icon_size_changed"); + add_child(size_slider); + EDITOR_DEF("editors/grid_map/preview_size", 64); display_mode = DISPLAY_THUMBNAIL; diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 81a21a76ae..59b8ac13da 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -79,6 +79,8 @@ class GridMapEditor : public VBoxContainer { double accumulated_floor_delta; ToolButton *mode_thumbnail; ToolButton *mode_list; + LineEdit *search_box; + HSlider *size_slider; HBoxContainer *spatial_editor_hb; ConfirmationDialog *settings_dialog; VBoxContainer *settings_vbc; @@ -193,6 +195,11 @@ class GridMapEditor : public VBoxContainer { void _update_cursor_instance(); void _update_clip(); + void _text_changed(const String &p_text); + void _sbox_input(const Ref<InputEvent> &p_ie); + + void _icon_size_changed(float p_value); + void _update_duplicate_indicator(); void _duplicate_paste(); void _update_selection_transform(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 47be3a9959..e33b238f45 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -499,6 +499,47 @@ String CSharpLanguage::_get_indentation() const { return "\t"; } +String CSharpLanguage::debug_get_error() const { + + return _debug_error; +} + +int CSharpLanguage::debug_get_stack_level_count() const { + + if (_debug_parse_err_line >= 0) + return 1; + + // TODO: StackTrace + return 1; +} + +int CSharpLanguage::debug_get_stack_level_line(int p_level) const { + + if (_debug_parse_err_line >= 0) + return _debug_parse_err_line; + + // TODO: StackTrace + return 1; +} + +String CSharpLanguage::debug_get_stack_level_function(int p_level) const { + + if (_debug_parse_err_line >= 0) + return String(); + + // TODO: StackTrace + return String(); +} + +String CSharpLanguage::debug_get_stack_level_source(int p_level) const { + + if (_debug_parse_err_line >= 0) + return _debug_parse_err_file; + + // TODO: StackTrace + return String(); +} + Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() { #ifdef DEBUG_ENABLED @@ -958,12 +999,11 @@ void CSharpLanguage::thread_exit() { bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { - // Break because of parse error + // Not a parser error in our case, but it's still used for other type of errors if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - // TODO - //_debug_parse_err_line = p_line; - //_debug_parse_err_file = p_file; - //_debug_error = p_error; + _debug_parse_err_line = p_line; + _debug_parse_err_file = p_file; + _debug_error = p_error; ScriptDebugger::get_singleton()->debug(this, false); return true; } else { @@ -974,10 +1014,9 @@ bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const S bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { if (ScriptDebugger::get_singleton() && Thread::get_caller_id() == Thread::get_main_id()) { - // TODO - //_debug_parse_err_line = -1; - //_debug_parse_err_file = ""; - //_debug_error = p_error; + _debug_parse_err_line = -1; + _debug_parse_err_file = ""; + _debug_error = p_error; ScriptDebugger::get_singleton()->debug(this, p_allow_continue); return true; } else { @@ -985,6 +1024,13 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { } } +void CSharpLanguage::_uninitialize_script_bindings() { + for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { + CSharpScriptBinding &script_binding = E->value(); + script_binding.inited = false; + } +} + void CSharpLanguage::set_language_index(int p_idx) { ERR_FAIL_COND(lang_idx != -1); @@ -1269,14 +1315,14 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) { GDMonoClass *top = script->script_class; while (top && top != script->native) { - GDMonoField *field = script->script_class->get_field(p_name); + GDMonoField *field = top->get_field(p_name); if (field) { field->set_value_from_variant(mono_object, p_value); return true; } - GDMonoProperty *property = script->script_class->get_property(p_name); + GDMonoProperty *property = top->get_property(p_name); if (property) { property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type())); @@ -1887,6 +1933,9 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED + if (!Engine::get_singleton()->is_editor_hint()) + return false; + placeholder_fallback_enabled = true; // until proven otherwise if (!valid) @@ -2203,8 +2252,11 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, IMonoClassMember *p_ hint_string = name_only_hint_string; } } else if (variant_type == Variant::OBJECT && CACHED_CLASS(GodotReference)->is_assignable_from(type.type_class)) { + GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(type.type_class); + CRASH_COND(field_native_class == NULL); + hint = PROPERTY_HINT_RESOURCE_TYPE; - hint_string = NATIVE_GDMONOCLASS_NAME(type.type_class); + hint_string = NATIVE_GDMONOCLASS_NAME(field_native_class); } else { hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)); hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr); @@ -2699,6 +2751,7 @@ Error CSharpScript::reload(bool p_keep_state) { } load_script_signals(script_class, native); + _update_exports(); } return OK; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 8b1a4b5f7e..99877a4379 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -162,7 +162,7 @@ public: virtual bool has_script_signal(const StringName &p_signal) const; virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; - /* TODO */ virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; + virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const; virtual void get_script_property_list(List<PropertyInfo> *p_list) const; virtual void update_exports(); @@ -309,6 +309,14 @@ class CSharpLanguage : public ScriptLanguage { Dictionary scripts_metadata; + // For debug_break and debug_break_parse + int _debug_parse_err_line; + String _debug_parse_err_file; + String _debug_error; + + friend class GDMono; + void _uninitialize_script_bindings(); + public: StringNameCache string_names; @@ -365,11 +373,11 @@ public: /* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {} /* DEBUGGER FUNCTIONS */ - /* TODO */ virtual String debug_get_error() const { return ""; } - /* TODO */ virtual int debug_get_stack_level_count() const { return 1; } - /* TODO */ virtual int debug_get_stack_level_line(int p_level) const { return 1; } - /* TODO */ virtual String debug_get_stack_level_function(int p_level) const { return ""; } - /* TODO */ virtual String debug_get_stack_level_source(int p_level) const { return ""; } + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; /* TODO */ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} /* TODO */ virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {} diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs index 79ef46ebb5..967e3bcc19 100644 --- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -92,6 +92,9 @@ namespace GodotSharpTools.Build bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput; + if (!redirectOutput) // TODO: or if stdout verbose + Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}"); + startInfo.RedirectStandardOutput = redirectOutput; startInfo.RedirectStandardError = redirectOutput; startInfo.UseShellExecute = false; @@ -145,6 +148,9 @@ namespace GodotSharpTools.Build bool redirectOutput = !IsDebugMSBuildRequested() && !PrintBuildOutput; + if (!redirectOutput) // TODO: or if stdout verbose + Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}"); + startInfo.RedirectStandardOutput = redirectOutput; startInfo.RedirectStandardError = redirectOutput; startInfo.UseShellExecute = false; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 890bea0d1d..35a89956a8 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -38,6 +38,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/os.h" +#include "core/string_builder.h" #include "core/ucaps.h" #include "../glue/cs_compressed.gen.h" @@ -97,7 +98,7 @@ #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array" -#define BINDINGS_GENERATOR_VERSION UINT32_C(7) +#define BINDINGS_GENERATOR_VERSION UINT32_C(8) const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n"; @@ -105,6 +106,16 @@ bool BindingsGenerator::verbose_output = false; BindingsGenerator *BindingsGenerator::singleton = NULL; +static String fix_doc_description(const String &p_bbcode) { + + // This seems to be the correct way to do this. It's the same EditorHelp does. + + return p_bbcode.dedent() + .replace("\t", "") + .replace("\r", "") + .strip_edges(); +} + static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) { String ret; @@ -173,6 +184,366 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up return ret; } +String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) { + + // Based on the version in EditorHelp + + if (p_bbcode.empty()) + return String(); + + DocData *doc = EditorHelp::get_doc_data(); + + String bbcode = p_bbcode; + + StringBuilder xml_output; + + xml_output.append("<para>"); + + List<String> tag_stack; + bool code_tag = false; + + int pos = 0; + while (pos < bbcode.length()) { + int brk_pos = bbcode.find("[", pos); + + if (brk_pos < 0) + brk_pos = bbcode.length(); + + if (brk_pos > pos) { + String text = bbcode.substr(pos, brk_pos - pos); + if (code_tag || tag_stack.size() > 0) { + xml_output.append(text.xml_escape()); + } else { + Vector<String> lines = text.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (i != 0) + xml_output.append("<para>"); + + xml_output.append(lines[i].xml_escape()); + + if (i != lines.size() - 1) + xml_output.append("</para>\n"); + } + } + } + + if (brk_pos == bbcode.length()) + break; // nothing else to add + + int brk_end = bbcode.find("]", brk_pos + 1); + + if (brk_end == -1) { + String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos); + if (code_tag || tag_stack.size() > 0) { + xml_output.append(text.xml_escape()); + } else { + Vector<String> lines = text.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (i != 0) + xml_output.append("<para>"); + + xml_output.append(lines[i].xml_escape()); + + if (i != lines.size() - 1) + xml_output.append("</para>\n"); + } + } + + break; + } + + String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1); + + if (tag.begins_with("/")) { + bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length()); + + if (!tag_ok) { + xml_output.append("["); + pos = brk_pos + 1; + continue; + } + + tag_stack.pop_front(); + pos = brk_end + 1; + code_tag = false; + + if (tag == "/url") { + xml_output.append("</a>"); + } else if (tag == "/code") { + xml_output.append("</c>"); + } else if (tag == "/codeblock") { + xml_output.append("</code>"); + } + } else if (code_tag) { + xml_output.append("["); + pos = brk_pos + 1; + } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ")) { + String link_target = tag.substr(tag.find(" ") + 1, tag.length()); + String link_tag = tag.substr(0, tag.find(" ")); + + Vector<String> link_target_parts = link_target.split("."); + + if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) { + ERR_PRINTS("Invalid reference format: " + tag); + + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + + pos = brk_end + 1; + continue; + } + + const TypeInterface *target_itype; + StringName target_cname; + + if (link_target_parts.size() == 2) { + target_itype = _get_type_or_null(TypeReference(link_target_parts[0])); + if (!target_itype) { + target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0])); + } + target_cname = link_target_parts[1]; + } else { + target_itype = p_itype; + target_cname = link_target_parts[0]; + } + + if (link_tag == "method") { + if (!target_itype || !target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else { + const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); + + if (target_imethod) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_imethod->proxy_name); + xml_output.append("\"/>"); + } + } + } else if (link_tag == "member") { + if (!target_itype || !target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else { + const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname); + + if (target_iprop) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("."); + xml_output.append(target_iprop->proxy_name); + xml_output.append("\"/>"); + } + } + } else if (link_tag == "signal") { + // We do not declare signals in any way in C#, so there is nothing to reference + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } else if (link_tag == "enum") { + StringName search_cname = !target_itype ? target_cname : + StringName(target_itype->name + "." + (String)target_cname); + + const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname); + + if (!enum_match && search_cname != target_cname) { + enum_match = enum_types.find(target_cname); + } + + if (enum_match) { + const TypeInterface &target_enum_itype = enum_match->value(); + + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve enum reference in documentation: " + link_target); + + xml_output.append("<c>"); + xml_output.append(link_target); + xml_output.append("</c>"); + } + } + + pos = brk_end + 1; + } else if (doc->class_list.has(tag)) { + if (tag == "Array" || tag == "Dictionary") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE_COLLECTIONS "."); + xml_output.append(tag); + xml_output.append("\"/>"); + } else if (tag == "bool" || tag == "int") { + xml_output.append("<see cref=\""); + xml_output.append(tag); + xml_output.append("\"/>"); + } else if (tag == "float") { + xml_output.append("<see cref=\"" +#ifdef REAL_T_IS_DOUBLE + "double" +#else + "float" +#endif + "\"/>"); + } else if (tag == "Variant") { + // We use System.Object for Variant, so there is no Variant type in C# + xml_output.append("<c>Variant</c>"); + } else if (tag == "String") { + xml_output.append("<see cref=\"string\"/>"); + } else if (tag == "Nil") { + xml_output.append("<see langword=\"null\"/>"); + } else if (tag.begins_with("@")) { + // @Global Scope, @GDScript, etc + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + } else if (tag == "PoolByteArray") { + xml_output.append("<see cref=\"byte\"/>"); + } else if (tag == "PoolIntArray") { + xml_output.append("<see cref=\"int\"/>"); + } else if (tag == "PoolRealArray") { +#ifdef REAL_T_IS_DOUBLE + xml_output.append("<see cref=\"double\"/>"); +#else + xml_output.append("<see cref=\"float\"/>"); +#endif + } else if (tag == "PoolStringArray") { + xml_output.append("<see cref=\"string\"/>"); + } else if (tag == "PoolVector2Array") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>"); + } else if (tag == "PoolVector3Array") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>"); + } else if (tag == "PoolColorArray") { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>"); + } else { + const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag)); + + if (!target_itype) { + target_itype = _get_type_or_null(TypeReference("_" + tag)); + } + + if (target_itype) { + xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); + xml_output.append(target_itype->proxy_name); + xml_output.append("\"/>"); + } else { + ERR_PRINTS("Cannot resolve type reference in documentation: " + tag); + + xml_output.append("<c>"); + xml_output.append(tag); + xml_output.append("</c>"); + } + } + + pos = brk_end + 1; + } else if (tag == "b") { + // bold is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "i") { + // italics is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "code") { + xml_output.append("<c>"); + + code_tag = true; + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "codeblock") { + xml_output.append("<code>"); + + code_tag = true; + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "center") { + // center is alignment not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "br") { + xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now. + pos = brk_end + 1; + } else if (tag == "u") { + // underline is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "s") { + // strikethrough is not supported in xml comments + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag == "url") { + int end = bbcode.find("[", brk_end); + if (end == -1) + end = bbcode.length(); + String url = bbcode.substr(brk_end + 1, end - brk_end - 1); + xml_output.append("<a href=\""); + xml_output.append(url); + xml_output.append("\">"); + xml_output.append(url); + + pos = brk_end + 1; + tag_stack.push_front(tag); + } else if (tag.begins_with("url=")) { + String url = tag.substr(4, tag.length()); + xml_output.append("<a href=\""); + xml_output.append(url); + xml_output.append("\">"); + + pos = brk_end + 1; + tag_stack.push_front("url"); + } else if (tag == "img") { + int end = bbcode.find("[", brk_end); + if (end == -1) + end = bbcode.length(); + String image = bbcode.substr(brk_end + 1, end - brk_end - 1); + + // Not supported. Just append the bbcode. + xml_output.append("[img]"); + xml_output.append(image); + xml_output.append("[/img]"); + + pos = end; + tag_stack.push_front(tag); + } else if (tag.begins_with("color=")) { + // Not supported. + pos = brk_end + 1; + tag_stack.push_front("color"); + } else if (tag.begins_with("font=")) { + // Not supported. + pos = brk_end + 1; + tag_stack.push_front("font"); + } else { + xml_output.append("["); // ignore + pos = brk_pos + 1; + } + } + + xml_output.append("</para>"); + + return xml_output.as_string(); +} + int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { CRASH_COND(p_ienum.constants.empty()); @@ -299,6 +670,9 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { // Constants (in partial GD class) + p_output.push_back("\n#pragma warning disable CS1591 // Disable warning: " + "'Missing XML comment for publicly visible type or member'\n"); + p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{"); @@ -306,20 +680,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { const ConstantInterface &iconstant = E->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } p_output.push_back(MEMBER_BEGIN "public const int "); @@ -369,20 +743,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { const ConstantInterface &iconstant = F->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - p_output.push_back(INDENT2 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(INDENT2 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>\n"); + p_output.push_back(INDENT2 "/// </summary>\n"); + } } p_output.push_back(INDENT2); @@ -399,6 +773,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) { } p_output.push_back(CLOSE_BLOCK); // end of namespace + + p_output.push_back("\n#pragma warning restore CS1591\n"); } Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) { @@ -712,28 +1088,31 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back("using System;\n"); // IntPtr output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable - output.push_back("\n#pragma warning disable CS1591 // Disable warning: " - "'Missing XML comment for publicly visible type or member'\n"); + output.push_back("\n" + "#pragma warning disable CS1591 // Disable warning: " + "'Missing XML comment for publicly visible type or member'\n" + "#pragma warning disable CS1573 // Disable warning: " + "'Parameter has no matching param tag in the XML comment'\n"); output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); const DocData::ClassDoc *class_doc = itype.class_doc; if (class_doc && class_doc->description.size()) { - output.push_back(INDENT1 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(class_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = class_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(INDENT1 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT1 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT1 "/// </summary>\n"); + output.push_back(INDENT1 "/// </summary>\n"); + } } output.push_back(INDENT1 "public "); @@ -767,20 +1146,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str const ConstantInterface &iconstant = E->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT2 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT2 "/// </summary>"); + output.push_back(INDENT2 "/// </summary>"); + } } output.push_back(MEMBER_BEGIN "public const int "); @@ -808,20 +1187,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str const ConstantInterface &iconstant = F->get(); if (iconstant.const_doc && iconstant.const_doc->description.size()) { - output.push_back(INDENT3 "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = iconstant.const_doc->description.split("\n"); + if (summary_lines.size()) { + output.push_back(INDENT3 "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { output.push_back(INDENT3 "/// "); - output.push_back(description_line.xml_escape()); + output.push_back(summary_lines[i]); output.push_back("\n"); } - } - output.push_back(INDENT3 "/// </summary>\n"); + output.push_back(INDENT3 "/// </summary>\n"); + } } output.push_back(INDENT3); @@ -928,7 +1307,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(INDENT1 CLOSE_BLOCK /* class */ CLOSE_BLOCK /* namespace */); - output.push_back("\n#pragma warning restore CS1591\n"); + output.push_back("\n" + "#pragma warning restore CS1591\n" + "#pragma warning restore CS1573\n"); return _save_file(p_output_file, output); } @@ -978,33 +1359,21 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte const TypeInterface *prop_itype = _get_type_or_null(proptype_name); ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found - String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname)); - - // Prevent property and enclosing type from sharing the same name - if (prop_proxy_name == p_itype.proxy_name) { - if (verbose_output) { - WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" + - p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`"); - } - - prop_proxy_name += "_"; - } - if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = p_iprop.prop_doc->description.split("\n"); + if (summary_lines.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } p_output.push_back(MEMBER_BEGIN "public "); @@ -1014,7 +1383,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.push_back(prop_itype->cs_type); p_output.push_back(" "); - p_output.push_back(prop_proxy_name.replace("/", "__")); + p_output.push_back(p_iprop.proxy_name); p_output.push_back("\n" INDENT2 OPEN_BLOCK); if (getter) { @@ -1135,7 +1504,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in); - default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n"); + // Apparently the name attribute must not include the @ + String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name; + + default_args_doc.push_back(INDENT2 "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>\n"); } else { icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name); } @@ -1151,24 +1523,24 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf } if (p_imethod.method_doc && p_imethod.method_doc->description.size()) { - p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); + String xml_summary = bbcode_to_xml(fix_doc_description(p_imethod.method_doc->description), &p_itype); + Vector<String> summary_lines = xml_summary.split("\n"); - Vector<String> description_lines = p_imethod.method_doc->description.split("\n"); + if (summary_lines.size() || default_args_doc.size()) { + p_output.push_back(MEMBER_BEGIN "/// <summary>\n"); - for (int i = 0; i < description_lines.size(); i++) { - String description_line = description_lines[i].strip_edges(); - if (description_line.size()) { + for (int i = 0; i < summary_lines.size(); i++) { p_output.push_back(INDENT2 "/// "); - p_output.push_back(description_line.xml_escape()); + p_output.push_back(summary_lines[i]); p_output.push_back("\n"); } - } - for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) { - p_output.push_back(E->get().xml_escape()); - } + for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) { + p_output.push_back(E->get()); + } - p_output.push_back(INDENT2 "/// </summary>"); + p_output.push_back(INDENT2 "/// </summary>"); + } } if (!p_imethod.is_internal) { @@ -1540,20 +1912,13 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte String vararg_arg = "arg" + argc_str; String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg - p_output.push_back("\tVector<Variant> varargs;\n" - "\tint vararg_length = mono_array_length("); + p_output.push_back("\tint vararg_length = mono_array_length("); p_output.push_back(vararg_arg); p_output.push_back(");\n\tint total_length = "); p_output.push_back(real_argc_str); - p_output.push_back(" + vararg_length;\n\t"); - p_output.push_back(err_fail_macro); - p_output.push_back("(varargs.resize(vararg_length) != OK"); - p_output.push_back(fail_ret); - p_output.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t"); - p_output.push_back(err_fail_macro); - p_output.push_back("(call_args.resize(total_length) != OK"); - p_output.push_back(fail_ret); - p_output.push_back(");\n"); + p_output.push_back(" + vararg_length;\n" + "\tArgumentsVector<Variant> varargs(vararg_length);\n" + "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n"); p_output.push_back(c_in_statements); p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK "\t\tMonoObject* elem = mono_array_get("); @@ -1562,7 +1927,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n" "\t\t" C_LOCAL_PTRCALL_ARGS ".set("); p_output.push_back(real_argc_str); - p_output.push_back(" + i, &varargs.write[i]);\n\t" CLOSE_BLOCK); + p_output.push_back(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK); } else { p_output.push_back(c_in_statements); p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "["); @@ -1584,7 +1949,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", "); - p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL"); + p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL"); p_output.push_back(", total_length, vcall_error);\n"); // See the comment on the C_LOCAL_VARARG_RET declaration @@ -1728,7 +2093,6 @@ void BindingsGenerator::_populate_object_type_interfaces() { PropertyInterface iprop; iprop.cname = property.name; - iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname); iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname); @@ -1736,6 +2100,8 @@ void BindingsGenerator::_populate_object_type_interfaces() { iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid); ERR_FAIL_COND(!valid); + iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname)); + // Prevent property and enclosing type from sharing the same name if (iprop.proxy_name == itype.proxy_name) { if (verbose_output) { @@ -1746,6 +2112,8 @@ void BindingsGenerator::_populate_object_type_interfaces() { iprop.proxy_name += "_"; } + iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash... + iprop.prop_doc = NULL; for (int i = 0; i < itype.class_doc->properties.size(); i++) { diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 8a1c942f6b..7eaebeabbd 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -87,8 +87,13 @@ class BindingsGenerator { StringName cname; bool is_enum; - TypeReference() { - is_enum = false; + TypeReference() : + is_enum(false) { + } + + TypeReference(const StringName &p_cname) : + cname(p_cname), + is_enum(false) { } }; @@ -321,6 +326,15 @@ class BindingsGenerator { return NULL; } + const PropertyInterface *find_property_by_name(const StringName &p_cname) const { + for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().cname == p_cname) + return &E->get(); + } + + return NULL; + } + const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const { for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { if (E->get().proxy_name == p_proxy_name) @@ -482,6 +496,7 @@ class BindingsGenerator { StringName type_VarArg; StringName type_Object; StringName type_Reference; + StringName type_String; StringName enum_Error; NameCache() { @@ -493,6 +508,7 @@ class BindingsGenerator { type_VarArg = StaticCString::create("VarArg"); type_Object = StaticCString::create("Object"); type_Reference = StaticCString::create("Reference"); + type_String = StaticCString::create("String"); enum_Error = StaticCString::create("Error"); } @@ -522,6 +538,8 @@ class BindingsGenerator { return p_type.name; } + String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype); + int _determine_enum_prefix(const EnumInterface &p_ienum); void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length); diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 5b68810017..921b9f987b 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -185,6 +185,16 @@ void GodotSharpEditor::_toggle_about_dialog_on_start(bool p_enabled) { } } +void GodotSharpEditor::_build_solution_pressed() { + + if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) { + if (!_create_project_solution()) + return; // Failed to create solution + } + + MonoBottomPanel::get_singleton()->call("_build_project_pressed"); +} + void GodotSharpEditor::_menu_option_pressed(int p_id) { switch (p_id) { @@ -220,6 +230,7 @@ void GodotSharpEditor::_notification(int p_notification) { void GodotSharpEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_build_solution_pressed"), &GodotSharpEditor::_build_solution_pressed); ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution); ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed); ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option); @@ -446,12 +457,12 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { about_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); about_label->set_autowrap(true); String about_text = - String("C# support in Godot Engine is a brand new feature and a work in progress.\n") + - "It is currently in an alpha stage and is not suitable for use in production.\n\n" + - "As of Godot 3.1, C# support is not feature-complete and may crash in some situations. " + - "Bugs and usability issues will be addressed gradually over future 3.x releases, " + - "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + - "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc:\n\n" + + String("C# support in Godot Engine is in late alpha stage and, while already usable, ") + + "it is not meant for use in production.\n\n" + + "Projects can be exported to Linux, macOS and Windows, but not yet to mobile or web platforms. " + + "Bugs and usability issues will be addressed gradually over future releases, " + + "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + + "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" + " https://github.com/godotengine/godot/issues\n\n" + "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!"; about_label->set_text(about_text); @@ -482,7 +493,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { build_button->set_text("Build"); build_button->set_tooltip("Build solution"); build_button->set_focus_mode(Control::FOCUS_NONE); - build_button->connect("pressed", MonoBottomPanel::get_singleton(), "_build_project_pressed"); + build_button->connect("pressed", this, "_build_solution_pressed"); editor->get_menu_hb()->add_child(build_button); // External editor settings diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index c9744a9eed..cf0d2aec84 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -65,6 +65,8 @@ class GodotSharpEditor : public Node { void _menu_option_pressed(int p_id); + void _build_solution_pressed(); + static GodotSharpEditor *singleton; protected: diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp index 6b2ec5cc20..dfb652a7aa 100644 --- a/modules/mono/editor/script_class_parser.cpp +++ b/modules/mono/editor/script_class_parser.cpp @@ -266,6 +266,20 @@ Error ScriptClassParser::_skip_generic_type_params() { if (tk == TK_IDENTIFIER) { tk = get_token(); + // Type specifications can end with "?" to denote nullable types, such as IList<int?> + if (tk == TK_SYMBOL) { + tk = get_token(); + if (value.operator String() != "?") { + error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found unexpected symbol '" + value + "'"; + error = true; + return ERR_PARSE_ERROR; + } + if (tk != TK_OP_GREATER && tk != TK_COMMA) { + error_str = "Nullable type symbol '?' is only allowed after an identifier, but found " + get_token_name(tk) + " next."; + error = true; + return ERR_PARSE_ERROR; + } + } if (tk == TK_PERIOD) { while (true) { diff --git a/modules/mono/glue/Managed/Files/DebuggingUtils.cs b/modules/mono/glue/Managed/Files/DebuggingUtils.cs index b27816084e..edfe3464ec 100644 --- a/modules/mono/glue/Managed/Files/DebuggingUtils.cs +++ b/modules/mono/glue/Managed/Files/DebuggingUtils.cs @@ -19,6 +19,12 @@ namespace Godot sb.Append(" "); } + public static void InstallTraceListener() + { + Trace.Listeners.Clear(); + Trace.Listeners.Add(new GodotTraceListener()); + } + public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl) { fileName = frame.GetFileName(); diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs new file mode 100644 index 0000000000..9504415664 --- /dev/null +++ b/modules/mono/glue/Managed/Files/DynamicObject.cs @@ -0,0 +1,213 @@ + +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; + +namespace Godot +{ + /// <summary> + /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API. + /// </summary> + /// <remarks> + /// <para> + /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant + /// members of a <see cref="Godot.Object"/> instance at runtime. + /// </para> + /// <para> + /// This allows accessing the class members using their original names in the engine as well as the members from the + /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in. + /// </para> + /// </remarks> + /// <example> + /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>. + /// <code> + /// dynamic sprite = GetNode("Sprite").DynamicGodotObject; + /// sprite.add_child(this); + /// + /// if ((sprite.hframes * sprite.vframes) > 0) + /// sprite.frame = 0; + /// </code> + /// </example> + /// <example> + /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>. + /// <code> + /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject; + /// + /// if (childNode.print_allowed) + /// { + /// childNode.message = "Hello from C#"; + /// childNode.print_message(3); + /// } + /// </code> + /// The <c>ChildNode</c> node has the following GDScript script attached: + /// <code> + /// // # ChildNode.gd + /// // var print_allowed = true + /// // var message = "" + /// // + /// // func print_message(times): + /// // for i in times: + /// // print(message) + /// </code> + /// </example> + public class DynamicGodotObject : DynamicObject + { + /// <summary> + /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>. + /// </summary> + public Object Value { get; } + + /// <summary> + /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class. + /// </summary> + /// <param name="godotObject"> + /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>. + /// </param> + /// <exception cref="System.ArgumentNullException"> + /// Thrown when the <paramref name="godotObject"/> parameter is null. + /// </exception> + public DynamicGodotObject(Object godotObject) + { + if (godotObject == null) + throw new ArgumentNullException(nameof(godotObject)); + + this.Value = godotObject; + } + + public override IEnumerable<string> GetDynamicMemberNames() + { + return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value)); + } + + public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) + { + switch (binder.Operation) + { + case ExpressionType.Equal: + case ExpressionType.NotEqual: + if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool))) + { + if (arg == null) + { + bool boolResult = Object.IsInstanceValid(Value); + + if (binder.Operation == ExpressionType.Equal) + boolResult = !boolResult; + + result = boolResult; + return true; + } + + if (arg is Object other) + { + bool boolResult = (Value == other); + + if (binder.Operation == ExpressionType.NotEqual) + boolResult = !boolResult; + + result = boolResult; + return true; + } + } + + break; + default: + // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual). + // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly. + break; + } + + return base.TryBinaryOperation(binder, arg, out result); + } + + public override bool TryConvert(ConvertBinder binder, out object result) + { + if (binder.Type == typeof(Object)) + { + result = Value; + return true; + } + + if (typeof(Object).IsAssignableFrom(binder.Type)) + { + // Throws InvalidCastException when the cast fails + result = Convert.ChangeType(Value, binder.Type); + return true; + } + + return base.TryConvert(binder, out result); + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + { + if (indexes.Length == 1) + { + if (indexes[0] is string name) + { + return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result); + } + } + + return base.TryGetIndex(binder, indexes, out result); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result); + } + + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result); + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + if (indexes.Length == 1) + { + if (indexes[0] is string name) + { + return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value); + } + } + + return base.TrySetIndex(binder, indexes, value); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value); + + #region We don't override these methods + + // Looks like this is not usable from C# + //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result); + + // Object members cannot be deleted + //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes); + //public override bool TryDeleteMember(DeleteMemberBinder binder); + + // Invokation on the object itself, e.g.: obj(param) + //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result); + + // No unnary operations to handle + //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result); + + #endregion + } +} diff --git a/modules/mono/glue/Managed/Files/GodotTraceListener.cs b/modules/mono/glue/Managed/Files/GodotTraceListener.cs new file mode 100644 index 0000000000..f1a00ae0fa --- /dev/null +++ b/modules/mono/glue/Managed/Files/GodotTraceListener.cs @@ -0,0 +1,37 @@ +using System; +using System.Diagnostics; + +namespace Godot +{ + internal class GodotTraceListener : TraceListener + { + public override void Write(string message) + { + GD.PrintRaw(message); + } + + public override void WriteLine(string message) + { + GD.Print(message); + } + + public override void Fail(string message, string detailMessage) + { + GD.PrintErr("Assertion failed: ", message); + if (detailMessage != null) + { + GD.PrintErr(" Details: ", detailMessage); + } + + try + { + var stackTrace = new StackTrace(true).ToString(); + GD.PrintErr(stackTrace); + } + catch + { + // ignored + } + } + } +} diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs index dcab3c1ffc..5f5de12959 100644 --- a/modules/mono/glue/Managed/Files/Mathf.cs +++ b/modules/mono/glue/Managed/Files/Mathf.cs @@ -289,13 +289,13 @@ namespace Godot public static int Wrap(int value, int min, int max) { int rng = max - min; - return min + ((value - min) % rng + rng) % rng; + return rng != 0 ? min + ((value - min) % rng + rng) % rng : min; } public static real_t Wrap(real_t value, real_t min, real_t max) { real_t rng = max - min; - return min + ((value - min) % rng + rng) % rng; + return !IsEqualApprox(rng, default(real_t)) ? min + ((value - min) % rng + rng) % rng : min; } } } diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs index 2ef02cc288..414762f7b1 100644 --- a/modules/mono/glue/Managed/Files/MathfEx.cs +++ b/modules/mono/glue/Managed/Files/MathfEx.cs @@ -35,5 +35,10 @@ namespace Godot { return (int)Math.Round(s); } + + public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon) + { + return Abs(a - b) < ratio; + } } }
\ No newline at end of file diff --git a/modules/mono/glue/Managed/Files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs index 41fc43996f..e152d56871 100644 --- a/modules/mono/glue/Managed/Files/Object.base.cs +++ b/modules/mono/glue/Managed/Files/Object.base.cs @@ -73,11 +73,39 @@ namespace Godot disposed = true; } + /// <summary> + /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance + /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter. + /// </summary> + /// <param name="source"> + /// The instance the awaiter will be listening to. + /// </param> + /// <param name="signal"> + /// The signal the awaiter will be waiting for. + /// </param> + /// <example> + /// This sample prints a message once every frame up to 100 times. + /// <code> + /// public override void _Ready() + /// { + /// for (int i = 0; i < 100; i++) + /// { + /// await ToSignal(GetTree(), "idle_frame"); + /// GD.Print($"Frame {i}"); + /// } + /// } + /// </code> + /// </example> public SignalAwaiter ToSignal(Object source, string signal) { return new SignalAwaiter(source, signal, this); } + /// <summary> + /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance. + /// </summary> + public dynamic DynamicObject => new DynamicGodotObject(this); + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static IntPtr godot_icall_Object_Ctor(Object obj); diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h new file mode 100644 index 0000000000..cb558235d8 --- /dev/null +++ b/modules/mono/glue/arguments_vector.h @@ -0,0 +1,60 @@ +/*************************************************************************/ +/* arguments_vector.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* 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 ARGUMENTS_VECTOR_H +#define ARGUMENTS_VECTOR_H + +#include "core/os/memory.h" + +template <typename T, int POOL_SIZE = 5> +struct ArgumentsVector { + +private: + T pool[POOL_SIZE]; + T *_ptr; + + ArgumentsVector(); + ArgumentsVector(const ArgumentsVector &); + +public: + T *ptr() { return _ptr; } + T &get(int p_idx) { return _ptr[p_idx]; } + void set(int p_idx, const T &p_value) { _ptr[p_idx] = p_value; } + + explicit ArgumentsVector(int size) { + if (size <= POOL_SIZE) { + _ptr = pool; + } else { + _ptr = memnew_arr(T, size); + } + } +}; + +#endif // ARGUMENTS_VECTOR_H diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index fad02b01d3..b690de0d20 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -36,9 +36,11 @@ #include "core/string_name.h" #include "../csharp_script.h" +#include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_internals.h" #include "../mono_gd/gd_mono_utils.h" #include "../signal_awaiter_utils.h" +#include "arguments_vector.h" Object *godot_icall_Object_Ctor(MonoObject *p_obj) { Object *instance = memnew(Object); @@ -75,7 +77,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer) { +void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == NULL); // This is only called with Reference derived classes @@ -155,6 +157,67 @@ Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter); } +MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) { + List<PropertyInfo> property_list; + p_ptr->get_property_list(&property_list); + + MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size()); + + int i = 0; + for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name); + mono_array_set(result, MonoString *, i, boxed); + i++; + } + + return result; +} + +MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + + int argc = mono_array_length(p_args); + + ArgumentsVector<Variant> arg_store(argc); + ArgumentsVector<const Variant *> args(argc); + + for (int i = 0; i < argc; i++) { + MonoObject *elem = mono_array_get(p_args, MonoObject *, i); + arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem)); + args.set(i, &arg_store.get(i)); + } + + Variant::CallError error; + Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error); + + *r_result = GDMonoMarshal::variant_to_mono_object(result); + + return error.error == OK; +} + +MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + + bool valid; + Variant value = p_ptr->get(StringName(name), &valid); + + if (valid) { + *r_result = GDMonoMarshal::variant_to_mono_object(value); + } + + return valid; +} + +MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) { + String name = GDMonoMarshal::mono_string_to_godot(p_name); + Variant value = GDMonoMarshal::mono_object_to_variant(p_value); + + bool valid; + p_ptr->set(StringName(name), value, &valid); + + return valid; +} + void godot_register_object_icalls() { mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor); mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed); @@ -162,6 +225,10 @@ void godot_register_object_icalls() { mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method); mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref); mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect); + mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList); + mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember); + mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember); + mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember); } #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h index e126fac6ca..9b5224a347 100644 --- a/modules/mono/glue/base_object_glue.h +++ b/modules/mono/glue/base_object_glue.h @@ -42,7 +42,7 @@ Object *godot_icall_Object_Ctor(MonoObject *p_obj); void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr); -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer); +void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer); MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method); @@ -50,6 +50,16 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj); Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter); +// DynamicGodotObject + +MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr); + +MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result); + +MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result); + +MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value); + // Register internal calls void godot_register_object_icalls(); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 1065ff0868..1aad1c53bc 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -81,7 +81,7 @@ void godot_icall_Array_Clear(Array *ptr) { ptr->clear(); } -bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) { +MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) { return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1; } @@ -113,7 +113,7 @@ void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) { ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item)); } -bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) { +MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) { int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item)); if (idx >= 0) { ptr->remove(idx); @@ -208,21 +208,21 @@ void godot_icall_Dictionary_Clear(Dictionary *ptr) { ptr->clear(); } -bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) { +MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) { // no dupes Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value); } -bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { +MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { return ptr->has(GDMonoMarshal::mono_object_to_variant(key)); } -bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { +MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { return ptr->erase(GDMonoMarshal::mono_object_to_variant(key)); } -bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { +MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); // no dupes @@ -235,7 +235,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject return false; } -bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { +MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == NULL) { *value = NULL; @@ -245,7 +245,7 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb return true; } -bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { +MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) { Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); if (ret == NULL) { *value = NULL; diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h index c0056d3bce..85a2e243a2 100644 --- a/modules/mono/glue/collections_glue.h +++ b/modules/mono/glue/collections_glue.h @@ -55,7 +55,7 @@ void godot_icall_Array_Add(Array *ptr, MonoObject *item); void godot_icall_Array_Clear(Array *ptr); -bool godot_icall_Array_Contains(Array *ptr, MonoObject *item); +MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item); void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index); @@ -63,7 +63,7 @@ int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item); void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item); -bool godot_icall_Array_Remove(Array *ptr, MonoObject *item); +MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item); void godot_icall_Array_RemoveAt(Array *ptr, int index); @@ -93,17 +93,17 @@ void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *va void godot_icall_Dictionary_Clear(Dictionary *ptr); -bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value); +MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value); -bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key); +MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key); -bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key); +MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key); -bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value); +MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value); -bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); +MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); -bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); +MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class); void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class); diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index 5edf49d2bf..af022dae81 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -175,7 +175,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) { return GDMonoMarshal::variant_to_mono_object(ret); } -bool godot_icall_GD_type_exists(MonoString *p_type) { +MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) { return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type)); } diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h index ba75d85343..2632639169 100644 --- a/modules/mono/glue/gd_glue.h +++ b/modules/mono/glue/gd_glue.h @@ -69,7 +69,7 @@ MonoString *godot_icall_GD_str(MonoArray *p_what); MonoObject *godot_icall_GD_str2var(MonoString *p_str); -bool godot_icall_GD_type_exists(MonoString *p_type); +MonoBoolean godot_icall_GD_type_exists(MonoString *p_type); MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var); diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index b6e8ac6909..1836130b76 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -74,4 +74,6 @@ void godot_register_glue_header_icalls() { } \ Object *m_instance = ci->creation_func(); +#include "arguments_vector.h" + #endif // MONO_GLUE_ENABLED diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index acd8a3b73b..bba7df2c6a 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -288,7 +288,7 @@ void GDMono::initialize() { mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL); -#ifdef TOOLS_ENABLED +#ifndef TOOLS_ENABLED if (!DirAccess::exists("res://.mono")) { // 'res://.mono/' is missing so there is nothing to load. We don't need to initialize mono, but // we still do so unless mscorlib is missing (which is the case for projects that don't use C#). @@ -587,6 +587,8 @@ bool GDMono::_load_core_api_assembly() { CS_GLUE_VERSION != api_assembly_ver.cs_glue_version; if (!core_api_assembly_out_of_sync) { GDMonoUtils::update_godot_api_cache(); + + _install_trace_listener(); } #else GDMonoUtils::update_godot_api_cache(); @@ -690,6 +692,23 @@ bool GDMono::_load_api_assemblies() { return true; } +void GDMono::_install_trace_listener() { + +#ifdef DEBUG_ENABLED + // Install the trace listener now before the project assembly is loaded + typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **); + MonoException *exc = NULL; + GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils"); + DebuggingUtils_InstallTraceListener install_func = + (DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener"); + install_func((MonoObject **)&exc); + if (exc) { + ERR_PRINT("Failed to install System.Diagnostics.Trace listener"); + GDMonoUtils::debug_print_unhandled_exception(exc); + } +#endif +} + #ifdef TOOLS_ENABLED String GDMono::_get_api_assembly_metadata_path() { @@ -779,8 +798,6 @@ Error GDMono::_unload_scripts_domain() { if (mono_domain_get() != root_domain) mono_domain_set(root_domain, true); - mono_gc_collect(mono_gc_max_generation()); - finalizing_scripts_domain = true; if (!mono_domain_finalize(scripts_domain, 2000)) { @@ -848,6 +865,8 @@ Error GDMono::reload_scripts_domain() { } } + CSharpLanguage::get_singleton()->_uninitialize_script_bindings(); + Error err = _load_scripts_domain(); if (err != OK) { ERR_PRINT("Mono: Failed to load scripts domain"); @@ -916,14 +935,20 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) { if (mono_domain_get() == p_domain) mono_domain_set(root_domain, true); - mono_gc_collect(mono_gc_max_generation()); if (!mono_domain_finalize(p_domain, 2000)) { ERR_PRINT("Mono: Domain finalization timeout"); } + mono_gc_collect(mono_gc_max_generation()); _domain_assemblies_cleanup(mono_domain_get_id(p_domain)); +#ifdef TOOLS_ENABLED + if (p_domain == tools_domain) { + editor_tools_assembly = NULL; + } +#endif + MonoException *exc = NULL; mono_domain_try_unload(p_domain, (MonoObject **)&exc); @@ -1025,11 +1050,19 @@ GDMono::~GDMono() { if (is_runtime_initialized()) { - if (scripts_domain) { +#ifdef TOOLS_ENABLED + if (tools_domain) { + Error err = finalize_and_unload_domain(tools_domain); + if (err != OK) { + ERR_PRINT("Mono: Failed to unload tools domain"); + } + } +#endif + if (scripts_domain) { Error err = _unload_scripts_domain(); if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); + ERR_PRINT("Mono: Failed to unload scripts domain"); } } @@ -1050,6 +1083,8 @@ GDMono::~GDMono() { mono_jit_cleanup(root_domain); + print_verbose("Mono: Finalized"); + runtime_initialized = false; } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index 785b65ce13..216c96a612 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -125,6 +125,8 @@ class GDMono { String _get_api_assembly_metadata_path(); #endif + void _install_trace_listener(); + void _register_internal_calls(); Error _load_scripts_domain(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 85273bfdb4..8fec28b186 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -50,7 +50,7 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin const char *rootdir = mono_assembly_getrootdir(); if (rootdir) { - String framework_dir = String(rootdir).plus_file("mono").plus_file("4.5"); + String framework_dir = String::utf8(rootdir).plus_file("mono").plus_file("4.5"); r_search_dirs.push_back(framework_dir); r_search_dirs.push_back(framework_dir.plus_file("Facades")); } @@ -277,6 +277,7 @@ Error GDMonoAssembly::load(bool p_refonly) { ERR_FAIL_NULL_V(image, ERR_FILE_CANT_OPEN); #ifdef DEBUG_ENABLED + Vector<uint8_t> pdb_data; String pdb_path(path + ".pdb"); if (!FileAccess::exists(pdb_path)) { @@ -286,8 +287,9 @@ Error GDMonoAssembly::load(bool p_refonly) { goto no_pdb; } - pdb_data.clear(); pdb_data = FileAccess::get_file_as_array(pdb_path); + + // mono_debug_close_image doesn't seem to be needed mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size()); no_pdb: @@ -306,6 +308,9 @@ no_pdb: ERR_FAIL_COND_V(status != MONO_IMAGE_OK || assembly == NULL, ERR_FILE_CANT_OPEN); + // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name + mono_image_close(image); + loaded = true; modified_time = last_modified_time; @@ -321,8 +326,6 @@ Error GDMonoAssembly::wrapper_for_image(MonoImage *p_image) { image = p_image; - mono_image_addref(image); - loaded = true; return OK; @@ -332,13 +335,6 @@ void GDMonoAssembly::unload() { ERR_FAIL_COND(!loaded); -#ifdef DEBUG_ENABLED - if (pdb_data.size()) { - mono_debug_close_image(image); - pdb_data.clear(); - } -#endif - for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) { memdelete(E->value()); } @@ -346,8 +342,6 @@ void GDMonoAssembly::unload() { cached_classes.clear(); cached_raw.clear(); - mono_image_close(image); - assembly = NULL; image = NULL; loaded = false; diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index 8f47ee26f8..32432af37d 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -84,10 +84,6 @@ class GDMonoAssembly { bool gdobject_class_cache_updated; Map<StringName, GDMonoClass *> gdobject_class_cache; -#ifdef DEBUG_ENABLED - Vector<uint8_t> pdb_data; -#endif - static bool no_search; static bool in_preload; static Vector<String> search_dirs; diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index 0eb4b3b8b3..d7f9b22c31 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "mono_reg_utils.h" +#include "core/os/dir_access.h" #ifdef WINDOWS_ENABLED @@ -200,6 +201,13 @@ String find_msbuild_tools_path() { val += "\\"; } + // Since VS2019, the directory is simply named "Current" + String msBuildDirectory = val + "MSBuild\\Current\\Bin"; + if (DirAccess::exists(msBuildDirectory)) { + return msBuildDirectory; + } + + // Directory name "15.0" is used in VS 2017 return val + "MSBuild\\15.0\\Bin"; } } diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index ba54160a90..a91114b2f7 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -17,6 +17,8 @@ <member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap"> If true, the resulting texture contains a normal map created from the original noise interpreted as a bump map. </member> + <member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength"> + </member> <member name="height" type="int" setter="set_height" getter="get_height"> Height of the generated texture. </member> diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index b67a836fe8..0345e533bc 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -9,85 +9,90 @@ env_lws = env_modules.Clone() if env['builtin_libwebsockets'] and not env["platform"] == "javascript": # already builtin for javascript thirdparty_dir = "#thirdparty/libwebsockets/" - helper_dir = "win32helpers/" + helper_dir = "#thirdparty/libwebsockets/win32helpers/" thirdparty_sources = [ - "core/alloc.c", - "core/context.c", - "core/libwebsockets.c", - "core/output.c", - "core/pollfd.c", - "core/service.c", - - "event-libs/poll/poll.c", - - "misc/base64-decode.c", - "misc/lejp.c", - "misc/sha-1.c", - - "roles/h1/ops-h1.c", - "roles/http/header.c", - "roles/http/client/client.c", - "roles/http/client/client-handshake.c", - "roles/http/server/fops-zip.c", - "roles/http/server/lejp-conf.c", - "roles/http/server/parsers.c", - "roles/http/server/server.c", - "roles/listen/ops-listen.c", - "roles/pipe/ops-pipe.c", - "roles/raw/ops-raw.c", - - "roles/ws/client-ws.c", - "roles/ws/client-parser-ws.c", - "roles/ws/ops-ws.c", - "roles/ws/server-ws.c", - - "tls/tls.c", - "tls/tls-client.c", - "tls/tls-server.c", - - "tls/mbedtls/wrapper/library/ssl_cert.c", - "tls/mbedtls/wrapper/library/ssl_pkey.c", - "tls/mbedtls/wrapper/library/ssl_stack.c", - "tls/mbedtls/wrapper/library/ssl_methods.c", - "tls/mbedtls/wrapper/library/ssl_lib.c", - "tls/mbedtls/wrapper/library/ssl_x509.c", - "tls/mbedtls/wrapper/platform/ssl_port.c", - "tls/mbedtls/wrapper/platform/ssl_pm.c", - "tls/mbedtls/lws-genhash.c", - "tls/mbedtls/mbedtls-client.c", - "tls/mbedtls/lws-genrsa.c", - "tls/mbedtls/ssl.c", - "tls/mbedtls/mbedtls-server.c" + "lib/core/adopt.c", + "lib/core/alloc.c", + "lib/core/connect.c", + "lib/core/context.c", + "lib/core/dummy-callback.c", + "lib/core/libwebsockets.c", + "lib/core/output.c", + "lib/core/pollfd.c", + "lib/core/service.c", + + "lib/event-libs/poll/poll.c", + + "lib/misc/base64-decode.c", + "lib/misc/lejp.c", + "lib/misc/sha-1.c", + + "lib/roles/h1/ops-h1.c", + "lib/roles/http/header.c", + "lib/roles/http/client/client.c", + "lib/roles/http/client/client-handshake.c", + "lib/roles/http/server/fops-zip.c", + "lib/roles/http/server/lejp-conf.c", + "lib/roles/http/server/parsers.c", + "lib/roles/http/server/server.c", + "lib/roles/listen/ops-listen.c", + "lib/roles/pipe/ops-pipe.c", + "lib/roles/raw-skt/ops-raw-skt.c", + "lib/roles/raw-file/ops-raw-file.c", + + "lib/roles/ws/client-ws.c", + "lib/roles/ws/client-parser-ws.c", + "lib/roles/ws/ops-ws.c", + "lib/roles/ws/server-ws.c", + + "lib/tls/tls.c", + "lib/tls/tls-client.c", + "lib/tls/tls-server.c", + + "lib/tls/mbedtls/wrapper/library/ssl_cert.c", + "lib/tls/mbedtls/wrapper/library/ssl_pkey.c", + "lib/tls/mbedtls/wrapper/library/ssl_stack.c", + "lib/tls/mbedtls/wrapper/library/ssl_methods.c", + "lib/tls/mbedtls/wrapper/library/ssl_lib.c", + "lib/tls/mbedtls/wrapper/library/ssl_x509.c", + "lib/tls/mbedtls/wrapper/platform/ssl_port.c", + "lib/tls/mbedtls/wrapper/platform/ssl_pm.c", + "lib/tls/mbedtls/lws-genhash.c", + "lib/tls/mbedtls/mbedtls-client.c", + "lib/tls/mbedtls/lws-genrsa.c", + "lib/tls/mbedtls/ssl.c", + "lib/tls/mbedtls/mbedtls-server.c" ] if env["platform"] == "android": # Builtin getifaddrs - thirdparty_sources += ["misc/getifaddrs.c"] + thirdparty_sources += ["lib/misc/getifaddrs.c"] + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] if env["platform"] == "windows" or env["platform"] == "uwp": # Winsock - thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] + thirdparty_sources += Glob(thirdparty_dir + "lib/plat/windows/*.c") + [helper_dir + src for src in ["getopt.c", "getopt_long.c", "gettimeofday.c"]] else: # Unix socket - thirdparty_sources += ["plat/lws-plat-unix.c"] - - thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + thirdparty_sources += Glob(thirdparty_dir + "lib/plat/unix/*.c") - env_lws.Append(CPPPATH=[thirdparty_dir]) + env_lws.Append(CPPPATH=[thirdparty_dir + 'include/']) if env['builtin_mbedtls']: mbedtls_includes = "#thirdparty/mbedtls/include" env_lws.Prepend(CPPPATH=[mbedtls_includes]) - wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] + wrapper_includes = ["#thirdparty/libwebsockets/lib/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] env_lws.Prepend(CPPPATH=wrapper_includes) if env["platform"] == "windows" or env["platform"] == "uwp": - env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) + env_lws.Append(CPPPATH=[helper_dir]) if env["platform"] == "uwp": env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) env_thirdparty = env_lws.Clone() env_thirdparty.disable_warnings() + env_thirdparty.Append(CPPPATH=[thirdparty_dir + 'lib/']) env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources) env_lws.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp index 2dce0ed1f5..d09558ab22 100644 --- a/modules/websocket/lws_client.cpp +++ b/modules/websocket/lws_client.cpp @@ -34,7 +34,10 @@ #include "core/io/ip.h" #include "core/io/stream_peer_ssl.h" #include "core/project_settings.h" -#include "tls/mbedtls/wrapper/include/openssl/ssl.h" +#if defined(LWS_OPENSSL_SUPPORT) +// Not openssl, just the mbedtls wrapper +#include "openssl/ssl.h" +#endif Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) { @@ -121,6 +124,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi LWSPeer::PeerData *peer_data = (LWSPeer::PeerData *)user; switch (reason) { +#if defined(LWS_OPENSSL_SUPPORT) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: { PoolByteArray arr = StreamPeerSSL::get_project_cert_array(); if (arr.size() > 0) @@ -128,7 +132,7 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi else if (verify_ssl) WARN_PRINTS("No CA cert specified in project settings, SSL will not work"); } break; - +#endif case LWS_CALLBACK_CLIENT_ESTABLISHED: peer->set_wsi(wsi, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size); peer_data->peer_id = 0; |