diff options
Diffstat (limited to 'modules')
82 files changed, 1386 insertions, 1118 deletions
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp index 093e2f3006..f23c66dbcf 100644 --- a/modules/assimp/editor_scene_importer_assimp.cpp +++ b/modules/assimp/editor_scene_importer_assimp.cpp @@ -854,7 +854,7 @@ Ref<Material> EditorSceneImporterAssimp::_generate_material_from_index(ImportSta if (found) { Ref<Texture> texture = _load_texture(state, path); - if (texture != NULL) { + if (texture.is_valid()) { _set_texture_mapping_mode(map_mode, texture); mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true); mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture); diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index a7e8dec11e..88732dff33 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -47,9 +47,6 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, size_t height = (size_t)p_header.bmp_info_header.bmp_height; size_t bits_per_pixel = (size_t)p_header.bmp_info_header.bmp_bit_count; - if (p_header.bmp_info_header.bmp_compression != BI_RGB) { - err = FAILED; - } // Check whether we can load it if (bits_per_pixel == 1) { @@ -238,11 +235,16 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, bmp_header.bmp_info_header.bmp_colors_used = f->get_32(); bmp_header.bmp_info_header.bmp_important_colors = f->get_32(); - // Compressed bitmaps not supported, stop parsing - if (bmp_header.bmp_info_header.bmp_compression != BI_RGB) { - ERR_EXPLAIN("Unsupported bmp file: " + f->get_path()); - f->close(); - ERR_FAIL_V(ERR_UNAVAILABLE); + switch (bmp_header.bmp_info_header.bmp_compression) { + case BI_RLE8: + case BI_RLE4: + case BI_CMYKRLE8: + case BI_CMYKRLE4: { + // Stop parsing + ERR_EXPLAIN("Compressed BMP files are not supported: " + f->get_path()); + f->close(); + ERR_FAIL_V(ERR_UNAVAILABLE); + } break; } // Don't rely on sizeof(bmp_file_header) as structure padding // adds 2 bytes offset leading to misaligned color table reading @@ -257,8 +259,8 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, if (bmp_header.bmp_info_header.bmp_bit_count <= 8) { // Support 256 colors max color_table_size = 1 << bmp_header.bmp_info_header.bmp_bit_count; + ERR_FAIL_COND_V(color_table_size == 0, ERR_BUG); } - ERR_FAIL_COND_V(color_table_size == 0, ERR_BUG); PoolVector<uint8_t> bmp_color_table; // Color table is usually 4 bytes per color -> [B][G][R][0] diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index 0082cf778a..2debb19a1c 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -42,15 +42,15 @@ protected: enum bmp_compression_s { BI_RGB = 0x00, - BI_RLE8 = 0x01, - BI_RLE4 = 0x02, + BI_RLE8 = 0x01, // compressed + BI_RLE4 = 0x02, // compressed BI_BITFIELDS = 0x03, BI_JPEG = 0x04, BI_PNG = 0x05, BI_ALPHABITFIELDS = 0x06, BI_CMYK = 0x0b, - BI_CMYKRLE8 = 0x0c, - BI_CMYKRLE4 = 0x0d + BI_CMYKRLE8 = 0x0c, // compressed + BI_CMYKRLE4 = 0x0d // compressed }; struct bmp_header_s { diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 085cce9733..8d21b25b20 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -728,12 +728,12 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer::BodyAxis p_axis) const { void RigidBodyBullet::reload_axis_lock() { - btBody->setLinearFactor(btVector3(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_X), !is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Y), !is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Z))); + btBody->setLinearFactor(btVector3(float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_X)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Y)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_LINEAR_Z)))); if (PhysicsServer::BODY_MODE_CHARACTER == mode) { /// When character angular is always locked btBody->setAngularFactor(btVector3(0., 0., 0.)); } else { - btBody->setAngularFactor(btVector3(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_X), !is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Y), !is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Z))); + btBody->setAngularFactor(btVector3(float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_X)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Y)), float(!is_axis_locked(PhysicsServer::BODY_AXIS_ANGULAR_Z)))); } } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 0a714dcc6c..23725c4960 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -436,10 +436,10 @@ void CSGShape::_update_shape() { } // unset write access - surfaces.write[i].verticesw = PoolVector<Vector3>::Write(); - surfaces.write[i].normalsw = PoolVector<Vector3>::Write(); - surfaces.write[i].uvsw = PoolVector<Vector2>::Write(); - surfaces.write[i].tansw = PoolVector<float>::Write(); + surfaces.write[i].verticesw.release(); + surfaces.write[i].normalsw.release(); + surfaces.write[i].uvsw.release(); + surfaces.write[i].tansw.release(); if (surfaces[i].last_added == 0) continue; diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox.xml index d100c01205..14f5a1952e 100644 --- a/modules/csg/doc_classes/CSGBox.xml +++ b/modules/csg/doc_classes/CSGBox.xml @@ -17,7 +17,7 @@ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0"> Height of the box measured from the center of the box. </member> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the box. </member> <member name="width" type="float" setter="set_width" getter="get_width" default="2.0"> diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder.xml index 643eb7c7f4..9fc0281887 100644 --- a/modules/csg/doc_classes/CSGCylinder.xml +++ b/modules/csg/doc_classes/CSGCylinder.xml @@ -17,7 +17,7 @@ <member name="height" type="float" setter="set_height" getter="get_height" default="1.0"> The height of the cylinder. </member> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the cylinder. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml index daa08decb6..afe0bc262d 100644 --- a/modules/csg/doc_classes/CSGMesh.xml +++ b/modules/csg/doc_classes/CSGMesh.xml @@ -11,9 +11,9 @@ <methods> </methods> <members> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> </member> - <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh" default="null"> + <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> The mesh resource to use as a CSG shape. </member> </members> diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml index 48f5d730cc..0ecee92cd5 100644 --- a/modules/csg/doc_classes/CSGPolygon.xml +++ b/modules/csg/doc_classes/CSGPolygon.xml @@ -14,7 +14,7 @@ <member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0"> Extrusion depth when [member mode] is [constant MODE_DEPTH]. </member> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> Material to use for the resulting mesh. </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode" default="0"> diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml index 91f54f8246..755d8df67e 100644 --- a/modules/csg/doc_classes/CSGShape.xml +++ b/modules/csg/doc_classes/CSGShape.xml @@ -92,7 +92,7 @@ Only intersecting geometry remains, the rest is removed. </constant> <constant name="OPERATION_SUBTRACTION" value="2" enum="Operation"> - The second shape is susbtracted from the first, leaving a dent with it's shape. + The second shape is subtracted from the first, leaving a dent with its shape. </constant> </constants> </class> diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere.xml index 0a62644179..714e725acb 100644 --- a/modules/csg/doc_classes/CSGSphere.xml +++ b/modules/csg/doc_classes/CSGSphere.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the sphere. </member> <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12"> diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus.xml index 156fb185e7..5dc6bb8380 100644 --- a/modules/csg/doc_classes/CSGTorus.xml +++ b/modules/csg/doc_classes/CSGTorus.xml @@ -14,7 +14,7 @@ <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0"> The inner radius of the torus. </member> - <member name="material" type="Material" setter="set_material" getter="get_material" default="null"> + <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the torus. </member> <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0"> diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 024e9ffc3b..17b0038780 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -388,8 +388,8 @@ void image_decompress_cvtt(Image *p_image) { h >>= 1; } - rb = PoolVector<uint8_t>::Read(); - wb = PoolVector<uint8_t>::Write(); + rb.release(); + wb.release(); p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); } diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 197b41b30c..4628bd9a5b 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -251,7 +251,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, src_data.resize(size); PoolVector<uint8_t>::Write wb = src_data.write(); f->get_buffer(wb.ptr(), size); - wb = PoolVector<uint8_t>::Write(); } else if (info.palette) { @@ -296,8 +295,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, if (colsize == 4) wb[dst_ofs + 3] = palette[src_ofs + 3]; } - - wb = PoolVector<uint8_t>::Write(); } else { //uncompressed generic... @@ -444,8 +441,6 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, default: { } } - - wb = PoolVector<uint8_t>::Write(); } Ref<Image> img = memnew(Image(width, height, mipmaps - 1, info.format, src_data)); diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp index f302834222..ff925480b8 100644 --- a/modules/etc/texture_loader_pkm.cpp +++ b/modules/etc/texture_loader_pkm.cpp @@ -80,7 +80,7 @@ RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, src_data.resize(size); PoolVector<uint8_t>::Write wb = src_data.write(); f->get_buffer(wb.ptr(), size); - wb = PoolVector<uint8_t>::Write(); + wb.release(); int mipmaps = h.format; int width = h.origWidth; diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml index 95ed1fc048..8750ddc56d 100644 --- a/modules/gdnative/doc_classes/GDNative.xml +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -33,7 +33,7 @@ </method> </methods> <members> - <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library" default="null"> + <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> </member> </members> <constants> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index 460471386d..e34e209374 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -53,7 +53,7 @@ <members> <member name="class_name" type="String" setter="set_class_name" getter="get_class_name" default=""""> </member> - <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library" default="null"> + <member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library"> </member> <member name="script_class_icon_path" type="String" setter="set_script_class_icon_path" getter="get_script_class_icon_path" default=""""> </member> diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 3870a5ea7d..a21b6a2907 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -345,45 +345,78 @@ <method name="fmod"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="a" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="b" type="float"> </argument> <description> - Returns the floating-point remainder of [code]x/y[/code]. + Returns the floating-point remainder of [code]a/b[/code], keeping the sign of [code]a[/code]. [codeblock] # Remainder is 1.5 var remainder = fmod(7, 5.5) [/codeblock] + For the integer remainder operation, use the % operator. </description> </method> <method name="fposmod"> <return type="float"> </return> - <argument index="0" name="x" type="float"> + <argument index="0" name="a" type="float"> </argument> - <argument index="1" name="y" type="float"> + <argument index="1" name="b" type="float"> + </argument> + <description> + Returns the floating-point modulus of [code]a/b[/code] that wraps equally in positive and negative. + [codeblock] + var i = -6 + while i < 5: + prints(i, fposmod(i, 3)) + i += 1 + [/codeblock] + Produces: + [codeblock] + -6 0 + -5 1 + -4 2 + -3 0 + -2 1 + -1 2 + 0 0 + 1 1 + 2 2 + 3 0 + 4 1 + [/codeblock] + </description> + </method> + <method name="posmod"> + <return type="int"> + </return> + <argument index="0" name="a" type="int"> + </argument> + <argument index="1" name="b" type="int"> </argument> <description> - Returns the floating-point remainder of [code]x/y[/code] that wraps equally in positive and negative. + Returns the integer modulus of [code]a/b[/code] that wraps equally in positive and negative. [codeblock] - var i = -10 - while i < 0: - prints(i, fposmod(i, 10)) + var i = -6 + while i < 5: + prints(i, posmod(i, 3)) i += 1 [/codeblock] Produces: [codeblock] - -10 10 - -9 1 - -8 2 - -7 3 - -6 4 - -5 5 - -4 6 - -3 7 - -2 8 - -1 9 + -6 0 + -5 1 + -4 2 + -3 0 + -2 1 + -1 2 + 0 0 + 1 1 + 2 2 + 3 0 + 4 1 [/codeblock] </description> </method> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 62b65fe96b..963b40529d 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -370,8 +370,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { bool default_theme = text_editor_color_theme == "Default"; bool dark_theme = settings->is_dark_theme(); - function_definition_color = Color::html(default_theme ? "#01e1ff" : dark_theme ? "#01e1ff" : "#00a5ba"); - node_path_color = Color::html(default_theme ? "#64c15a" : dark_theme ? "64c15a" : "#518b4b"); + function_definition_color = default_theme ? Color(0.0, 0.88, 1.0) : dark_theme ? Color(0.0, 0.88, 1.0) : Color(0.0, 0.65, 0.73); + node_path_color = default_theme ? Color(0.39, 0.76, 0.35) : dark_theme ? Color(0.39, 0.76, 0.35) : Color(0.32, 0.55, 0.29); EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 78a1bfc99b..521b5ed538 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -159,7 +159,11 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & for (int i = 0; i < cl->subclasses.size(); i++) { for (int j = 0; j < cl->subclasses[i]->functions.size(); j++) { - funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + String(cl->subclasses[i]->functions[j]->name); + funcs[cl->subclasses[i]->functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->functions[j]->name; + } + for (int j = 0; j < cl->subclasses[i]->static_functions.size(); j++) { + + funcs[cl->subclasses[i]->static_functions[j]->line] = String(cl->subclasses[i]->name) + "." + cl->subclasses[i]->static_functions[j]->name; } } diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index d5e74c07c9..42f349ffc0 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -1784,20 +1784,9 @@ GDScriptFunction::~GDScriptFunction() { Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) { -#ifdef DEBUG_ENABLED - ERR_EXPLAIN("Resumed function '" + String(function->get_name()) + "()' after yield, but class instance is gone. At script: " + state.script->get_path() + ":" + itos(state.line)); - ERR_FAIL_V(Variant()); -#else - return Variant(); -#endif - } - Variant arg; r_error.error = Variant::CallError::CALL_OK; - ERR_FAIL_COND_V(!function, Variant()); - if (p_argcount == 0) { r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; r_error.argument = 1; @@ -1823,44 +1812,7 @@ Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_ar return Variant(); } - state.result = arg; - Variant ret = function->call(NULL, NULL, 0, r_error, &state); - - bool completed = true; - - // If the return value is a GDScriptFunctionState reference, - // then the function did yield again after resuming. - if (ret.is_ref()) { - GDScriptFunctionState *gdfs = Object::cast_to<GDScriptFunctionState>(ret); - if (gdfs && gdfs->function == function) { - completed = false; - gdfs->first_state = first_state.is_valid() ? first_state : Ref<GDScriptFunctionState>(this); - } - } - - function = NULL; //cleaned up; - state.result = Variant(); - - if (completed) { - if (first_state.is_valid()) { - first_state->emit_signal("completed", ret); - } else { - emit_signal("completed", ret); - } - } - -#ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->exit_function(); - if (state.stack_size) { - //free stack - Variant *stack = (Variant *)state.stack.ptr(); - for (int i = 0; i < state.stack_size; i++) - stack[i].~Variant(); - } -#endif - - return ret; + return resume(arg); } bool GDScriptFunctionState::is_valid(bool p_extended_check) const { diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index 0736f3d010..8c33d6613c 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -58,6 +58,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) { "sqrt", "fmod", "fposmod", + "posmod", "floor", "ceil", "round", @@ -243,6 +244,12 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ VALIDATE_ARG_NUM(1); r_ret = Math::fposmod((double)*p_args[0], (double)*p_args[1]); } break; + case MATH_POSMOD: { + VALIDATE_ARG_COUNT(2); + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + r_ret = Math::posmod((int)*p_args[0], (int)*p_args[1]); + } break; case MATH_FLOOR: { VALIDATE_ARG_COUNT(1); VALIDATE_ARG_NUM(0); @@ -1456,6 +1463,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) { case MATH_SQRT: case MATH_FMOD: case MATH_FPOSMOD: + case MATH_POSMOD: case MATH_FLOOR: case MATH_CEIL: case MATH_ROUND: @@ -1568,15 +1576,20 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case MATH_FMOD: { - MethodInfo mi("fmod", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("fmod", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); mi.return_val.type = Variant::REAL; return mi; } break; case MATH_FPOSMOD: { - MethodInfo mi("fposmod", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("fposmod", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); mi.return_val.type = Variant::REAL; return mi; } break; + case MATH_POSMOD: { + MethodInfo mi("posmod", PropertyInfo(Variant::INT, "a"), PropertyInfo(Variant::INT, "b")); + mi.return_val.type = Variant::INT; + return mi; + } break; case MATH_FLOOR: { MethodInfo mi("floor", PropertyInfo(Variant::REAL, "s")); mi.return_val.type = Variant::REAL; @@ -1603,7 +1616,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case MATH_POW: { - MethodInfo mi("pow", PropertyInfo(Variant::REAL, "x"), PropertyInfo(Variant::REAL, "y")); + MethodInfo mi("pow", PropertyInfo(Variant::REAL, "base"), PropertyInfo(Variant::REAL, "exp")); mi.return_val.type = Variant::REAL; return mi; } break; diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h index 6ad70f2eb4..d52b9118d3 100644 --- a/modules/gdscript/gdscript_functions.h +++ b/modules/gdscript/gdscript_functions.h @@ -49,6 +49,7 @@ public: MATH_SQRT, MATH_FMOD, MATH_FPOSMOD, + MATH_POSMOD, MATH_FLOOR, MATH_CEIL, MATH_ROUND, diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index c5c86fda0a..fa430b5364 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2211,6 +2211,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran p_block->has_return = true; + bool catch_all_appeared = false; + while (true) { while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) @@ -2221,7 +2223,7 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran return; if (indent_level > tab_level.back()->get()) { - return; // go back a level + break; // go back a level } if (pending_newline != -1) { @@ -2236,12 +2238,20 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran branch->patterns.push_back(_parse_pattern(p_static)); if (!branch->patterns[0]) { - return; + break; } bool has_binding = branch->patterns[0]->pt_type == PatternNode::PT_BIND; bool catch_all = has_binding || branch->patterns[0]->pt_type == PatternNode::PT_WILDCARD; +#ifdef DEBUG_ENABLED + // Branches after a wildcard or binding are unreachable + if (catch_all_appeared && !current_function->has_unreachable_code) { + _add_warning(GDScriptWarning::UNREACHABLE_CODE, -1, current_function->name.operator String()); + current_function->has_unreachable_code = true; + } +#endif + while (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); branch->patterns.push_back(_parse_pattern(p_static)); @@ -2259,6 +2269,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran catch_all = catch_all || pt == PatternNode::PT_WILDCARD; } + catch_all_appeared = catch_all_appeared || catch_all; + if (!_enter_indent_block()) { _set_error("Expected block in pattern branch"); return; @@ -2274,6 +2286,11 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran p_branches.push_back(branch); } + + // Even if all branches return, there is possibility of default fallthrough + if (!catch_all_appeared) { + p_block->has_return = false; + } } void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings) { @@ -5077,6 +5094,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); + } else if (tokenizer->is_token_literal(0, true)) { + _set_error("Unexpected identifier"); + return; } if (enum_name != "") { diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 325432579f..1bd3d72066 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -210,7 +210,7 @@ </member> <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> </member> - <member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library" default="null"> + <member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library"> The assigned [MeshLibrary]. </member> <member name="theme" type="MeshLibrary" setter="set_theme" getter="get_theme"> diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 20e454c218..5a21833ffa 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -345,7 +345,7 @@ void GridMapEditor::_validate_selection() { _update_selection_transform(); } -void GridMapEditor::_set_selection(bool p_active, const Vector3 p_begin, const Vector3 p_end) { +void GridMapEditor::_set_selection(bool p_active, const Vector3 &p_begin, const Vector3 &p_end) { selection.active = p_active; selection.begin = p_begin; @@ -578,7 +578,7 @@ void GridMapEditor::_update_paste_indicator() { return; } - Vector3 center = 0.5 * Vector3(node->get_center_x(), node->get_center_y(), node->get_center_z()); + Vector3 center = 0.5 * Vector3(float(node->get_center_x()), float(node->get_center_y()), float(node->get_center_z())); Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size(); Transform xf; xf.scale(scale); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index da36165d4e..b9be925ff7 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -222,7 +222,7 @@ class GridMapEditor : public VBoxContainer { void _do_paste(); void _update_selection_transform(); void _validate_selection(); - void _set_selection(bool p_active, const Vector3 p_begin = Vector3(), const Vector3 p_end = Vector3()); + void _set_selection(bool p_active, const Vector3 &p_begin = Vector3(), const Vector3 &p_end = Vector3()); void _floor_changed(float p_value); void _floor_mouse_exited(); diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 5493223cb0..dcd8b8aebd 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -96,7 +96,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p else fmt = Image::FORMAT_RGB8; - dw = PoolVector<uint8_t>::Write(); + dw.release(); p_image->create(image_width, image_height, 0, fmt, data); return OK; @@ -117,8 +117,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force Error err = jpeg_load_image_from_buffer(p_image.ptr(), w.ptr(), src_image_len); - w = PoolVector<uint8_t>::Write(); - return err; } diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py index f66ffdb573..c47cfc8a38 100644 --- a/modules/mono/build_scripts/godot_tools_build.py +++ b/modules/mono/build_scripts/godot_tools_build.py @@ -87,7 +87,7 @@ def build(env_mono): target_filenames = ['GodotTools.dll', 'GodotTools.BuildLogger.dll', 'GodotTools.ProjectEditor.dll', 'DotNet.Glob.dll', 'GodotTools.Core.dll'] if env_mono['target'] == 'debug': - target_filenames += ['GodotTools.pdb', 'GodotTools.BuildLogger.dll', 'GodotTools.ProjectEditor.dll', 'GodotTools.Core.dll'] + target_filenames += ['GodotTools.pdb', 'GodotTools.BuildLogger.pdb', 'GodotTools.ProjectEditor.pdb', 'GodotTools.Core.pdb'] targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames] @@ -102,6 +102,10 @@ def build_project_editor_only(env_mono): editor_tools_dir = os.path.join(output_dir, 'GodotSharp', 'Tools') target_filenames = ['GodotTools.ProjectEditor.dll', 'DotNet.Glob.dll', 'GodotTools.Core.dll'] + + if env_mono['target'] == 'debug': + target_filenames += ['GodotTools.ProjectEditor.pdb', 'GodotTools.Core.pdb'] + targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames] cmd = env_mono.CommandNoCache(targets, [], build_godot_tools_project_editor, module_dir=os.getcwd()) diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py index 583708bf07..b2c48f0a61 100644 --- a/modules/mono/build_scripts/mono_reg_utils.py +++ b/modules/mono/build_scripts/mono_reg_utils.py @@ -116,5 +116,3 @@ def find_msbuild_tools_path_reg(): return value except (WindowsError, OSError): return '' - - return '' diff --git a/modules/mono/build_scripts/solution_builder.py b/modules/mono/build_scripts/solution_builder.py index 9f549a10ed..d1529a64d2 100644 --- a/modules/mono/build_scripts/solution_builder.py +++ b/modules/mono/build_scripts/solution_builder.py @@ -108,10 +108,14 @@ def find_msbuild_windows(env): if not mono_root: raise RuntimeError('Cannot find mono root directory') - framework_path = os.path.join(mono_root, 'lib', 'mono', '4.5') mono_bin_dir = os.path.join(mono_root, 'bin') msbuild_mono = os.path.join(mono_bin_dir, 'msbuild.bat') + msbuild_tools_path = find_msbuild_tools_path_reg() + + if msbuild_tools_path: + return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), {}) + if os.path.isfile(msbuild_mono): # The (Csc/Vbc/Fsc)ToolExe environment variables are required when # building with Mono's MSBuild. They must point to the batch files @@ -121,12 +125,7 @@ def find_msbuild_windows(env): 'VbcToolExe': os.path.join(mono_bin_dir, 'vbc.bat'), 'FscToolExe': os.path.join(mono_bin_dir, 'fsharpc.bat') } - return (msbuild_mono, framework_path, mono_msbuild_env) - - msbuild_tools_path = find_msbuild_tools_path_reg() - - if msbuild_tools_path: - return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), framework_path, {}) + return (msbuild_mono, mono_msbuild_env) return None @@ -172,7 +171,6 @@ def build_solution(env, solution_path, build_config, extra_msbuild_args=[]): global verbose verbose = env['verbose'] - framework_path = '' msbuild_env = os.environ.copy() # Needed when running from Developer Command Prompt for VS @@ -185,8 +183,7 @@ def build_solution(env, solution_path, build_config, extra_msbuild_args=[]): if msbuild_info is None: raise RuntimeError('Cannot find MSBuild executable') msbuild_path = msbuild_info[0] - framework_path = msbuild_info[1] - msbuild_env.update(msbuild_info[2]) + msbuild_env.update(msbuild_info[1]) else: msbuild_path = find_msbuild_unix('msbuild') if msbuild_path is None: @@ -212,7 +209,6 @@ def build_solution(env, solution_path, build_config, extra_msbuild_args=[]): # Build solution msbuild_args = [solution_path, '/p:Configuration=' + build_config] - msbuild_args += ['/p:FrameworkPathOverride=' + framework_path] if framework_path else [] msbuild_args += extra_msbuild_args run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name='msbuild') diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp new file mode 100644 index 0000000000..71ccdb7aab --- /dev/null +++ b/modules/mono/class_db_api_json.cpp @@ -0,0 +1,242 @@ +/*************************************************************************/ +/* class_db_api_json.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#include "class_db_api_json.h" + +#include "core/io/json.h" +#include "core/os/file_access.h" +#include "core/project_settings.h" +#include "core/version.h" + +void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { + Dictionary classes_dict; + + List<StringName> names; + + const StringName *k = NULL; + + while ((k = ClassDB::classes.next(k))) { + + names.push_back(*k); + } + //must be alphabetically sorted for hash to compute + names.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + + ClassDB::ClassInfo *t = ClassDB::classes.getptr(E->get()); + ERR_FAIL_COND(!t); + if (t->api != p_api || !t->exposed) + continue; + + Dictionary class_dict; + classes_dict[t->name] = class_dict; + + class_dict["inherits"] = t->inherits; + + { //methods + + List<StringName> snames; + + k = NULL; + + while ((k = t->method_map.next(k))) { + + snames.push_back(*k); + } + + snames.sort_custom<StringName::AlphCompare>(); + + Array methods; + + for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + Dictionary method_dict; + methods.push_back(method_dict); + + MethodBind *mb = t->method_map[F->get()]; + method_dict["name"] = mb->get_name(); + method_dict["argument_count"] = mb->get_argument_count(); + method_dict["return_type"] = mb->get_argument_type(-1); + + Array arguments; + method_dict["arguments"] = arguments; + + for (int i = 0; i < mb->get_argument_count(); i++) { + Dictionary argument_dict; + arguments.push_back(argument_dict); + const PropertyInfo info = mb->get_argument_info(i); + argument_dict["type"] = info.type; + argument_dict["name"] = info.name; + argument_dict["hint"] = info.hint; + argument_dict["hint_string"] = info.hint_string; + } + + method_dict["default_argument_count"] = mb->get_default_argument_count(); + + Array default_arguments; + method_dict["default_arguments"] = default_arguments; + + for (int i = 0; i < mb->get_default_argument_count(); i++) { + Dictionary default_argument_dict; + default_arguments.push_back(default_argument_dict); + //hash should not change, i hope for tis + Variant da = mb->get_default_argument(i); + default_argument_dict["value"] = da; + } + + method_dict["hint_flags"] = mb->get_hint_flags(); + } + + if (!methods.empty()) { + class_dict["methods"] = methods; + } + } + + { //constants + + List<StringName> snames; + + k = NULL; + + while ((k = t->constant_map.next(k))) { + + snames.push_back(*k); + } + + snames.sort_custom<StringName::AlphCompare>(); + + Array constants; + + for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + Dictionary constant_dict; + constants.push_back(constant_dict); + + constant_dict["name"] = F->get(); + constant_dict["value"] = t->constant_map[F->get()]; + } + + if (!constants.empty()) { + class_dict["constants"] = constants; + } + } + + { //signals + + List<StringName> snames; + + k = NULL; + + while ((k = t->signal_map.next(k))) { + + snames.push_back(*k); + } + + snames.sort_custom<StringName::AlphCompare>(); + + Array signals; + + for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + Dictionary signal_dict; + signals.push_back(signal_dict); + + MethodInfo &mi = t->signal_map[F->get()]; + signal_dict["name"] = F->get(); + + Array arguments; + signal_dict["arguments"] = arguments; + for (int i = 0; i < mi.arguments.size(); i++) { + Dictionary argument_dict; + arguments.push_back(argument_dict); + argument_dict["type"] = mi.arguments[i].type; + } + } + + if (!signals.empty()) { + class_dict["signals"] = signals; + } + } + + { //properties + + List<StringName> snames; + + k = NULL; + + while ((k = t->property_setget.next(k))) { + + snames.push_back(*k); + } + + snames.sort_custom<StringName::AlphCompare>(); + + Array properties; + + for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + Dictionary property_dict; + properties.push_back(property_dict); + + ClassDB::PropertySetGet *psg = t->property_setget.getptr(F->get()); + + property_dict["name"] = F->get(); + property_dict["setter"] = psg->setter; + property_dict["getter"] = psg->getter; + } + + if (!properties.empty()) { + class_dict["property_setget"] = properties; + } + } + + Array property_list; + + //property list + for (List<PropertyInfo>::Element *F = t->property_list.front(); F; F = F->next()) { + Dictionary property_dict; + property_list.push_back(property_dict); + + property_dict["name"] = F->get().name; + property_dict["type"] = F->get().type; + property_dict["hint"] = F->get().hint; + property_dict["hint_string"] = F->get().hint_string; + property_dict["usage"] = F->get().usage; + } + + if (!property_list.empty()) { + class_dict["property_list"] = property_list; + } + } + + FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); + ERR_FAIL_COND(!f); + f->store_string(JSON::print(classes_dict, /*indent: */ "\t")); + f->close(); + + print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); +} diff --git a/modules/mono/class_db_api_json.h b/modules/mono/class_db_api_json.h new file mode 100644 index 0000000000..0aa9c20930 --- /dev/null +++ b/modules/mono/class_db_api_json.h @@ -0,0 +1,39 @@ +/*************************************************************************/ +/* class_db_api_json.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 CLASS_DB_API_JSON_H +#define CLASS_DB_API_JSON_H + +#include "core/class_db.h" +#include "core/ustring.h" + +void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api); + +#endif // CLASS_DB_API_JSON_H diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b5c91a8585..078a490b22 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -44,6 +44,10 @@ #include "editor/editor_node.h" #endif +#ifdef DEBUG_METHODS_ENABLED +#include "class_db_api_json.h" +#endif + #include "editor/editor_internal_calls.h" #include "godotsharp_dirs.h" #include "mono_gd/gd_mono_class.h" @@ -98,18 +102,32 @@ Error CSharpLanguage::execute_file(const String &p_path) { void CSharpLanguage::init() { +#ifdef DEBUG_METHODS_ENABLED + if (OS::get_singleton()->get_cmdline_args().find("--class_db_to_json")) { + class_db_api_to_json("user://class_db_api.json", ClassDB::API_CORE); +#ifdef TOOLS_ENABLED + class_db_api_to_json("user://class_db_api_editor.json", ClassDB::API_EDITOR); +#endif + } +#endif + gdmono = memnew(GDMono); gdmono->initialize(); -#ifndef MONO_GLUE_ENABLED - WARN_PRINT("This binary is built with `mono_glue=no` and cannot be used for scripting"); -#endif - #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) + // Generate bindings here, before loading assemblies. `initialize_load_assemblies` aborts + // the applications if the api assemblies or the main tools assembly is missing, but this + // is not a problem for BindingsGenerator as it only needs the tools project editor assembly. List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); BindingsGenerator::handle_cmdline_args(cmdline_args); #endif +#ifndef MONO_GLUE_ENABLED + print_line("Run this binary with `--generate-mono-glue path/to/modules/mono/glue`"); +#endif + + gdmono->initialize_load_assemblies(); + #ifdef TOOLS_ENABLED EditorNode::add_init_callback(&_editor_init_callback); @@ -697,14 +715,6 @@ bool CSharpLanguage::is_assembly_reloading_needed() { return false; // No assembly to load } -#ifdef TOOLS_ENABLED - if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) - return false; // The core API assembly to load is invalidated - - if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) - return false; // The editor API assembly to load is invalidated -#endif - return true; } @@ -867,17 +877,26 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { script->reload(p_soft_reload); script->update_exports(); + + if (!script->valid) { + script->pending_reload_instances.clear(); + continue; + } } else { const StringName &class_namespace = script->tied_class_namespace_for_reload; const StringName &class_name = script->tied_class_name_for_reload; GDMonoAssembly *project_assembly = gdmono->get_project_assembly(); - GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly(); // Search in project and tools assemblies first as those are the most likely to have the class GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : NULL); + +#ifdef TOOLS_ENABLED if (!script_class) { + GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly(); script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : NULL); } +#endif + if (!script_class) { script_class = gdmono->get_class(class_namespace, class_name); } @@ -897,12 +916,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class); - Ref<CSharpScript> new_script = CSharpScript::create_for_managed_type(script_class, native); - CRASH_COND(new_script.is_null()); - - new_script->pending_reload_instances = script->pending_reload_instances; - new_script->pending_reload_state = script->pending_reload_state; - script = new_script; + CSharpScript::initialize_for_managed_type(script, script_class, native); } String native_name = NATIVE_GDMONOCLASS_NAME(script->native); @@ -953,7 +967,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { CRASH_COND(si != NULL); #endif // Re-create script instance - obj->set_script(script.get_ref_ptr()); // will create the script instance as well } } @@ -1203,7 +1216,9 @@ CSharpLanguage::CSharpLanguage() { scripts_metadata_invalidated = true; +#ifdef TOOLS_ENABLED godotsharp_editor = NULL; +#endif } CSharpLanguage::~CSharpLanguage() { @@ -2144,7 +2159,6 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List propnames.push_back(E->get()); } } -#endif void CSharpScript::_update_member_info_no_exports() { @@ -2191,6 +2205,7 @@ void CSharpScript::_update_member_info_no_exports() { } } } +#endif bool CSharpScript::_update_exports() { @@ -2673,35 +2688,46 @@ void CSharpScript::_bind_methods() { Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) { - // This method should not fail + // This method should not fail, only assertions allowed CRASH_COND(p_class == NULL); // TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time Ref<CSharpScript> script = memnew(CSharpScript); - script->name = p_class->get_name(); - script->script_class = p_class; - script->native = p_native; + initialize_for_managed_type(script, p_class, p_native); - CRASH_COND(script->native == NULL); + return script; +} - GDMonoClass *base = script->script_class->get_parent_class(); +void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native) { - if (base != script->native) - script->base = base; + // This method should not fail, only assertions allowed - script->valid = true; - script->tool = script->script_class->has_attribute(CACHED_CLASS(ToolAttribute)); + CRASH_COND(p_class == NULL); - if (!script->tool) { - GDMonoClass *nesting_class = script->script_class->get_nesting_class(); - script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute)); + p_script->name = p_class->get_name(); + p_script->script_class = p_class; + p_script->native = p_native; + + CRASH_COND(p_script->native == NULL); + + GDMonoClass *base = p_script->script_class->get_parent_class(); + + if (base != p_script->native) + p_script->base = base; + + p_script->valid = true; + p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute)); + + if (!p_script->tool) { + GDMonoClass *nesting_class = p_script->script_class->get_nesting_class(); + p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute)); } #if TOOLS_ENABLED - if (!script->tool) { - script->tool = script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly(); + if (!p_script->tool) { + p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly(); } #endif @@ -2710,10 +2736,10 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD // Native base methods must be fetched before the current class. // Not needed if the script class itself is a native class. - if (script->script_class != script->native) { - GDMonoClass *native_top = script->native; + if (p_script->script_class != p_script->native) { + GDMonoClass *native_top = p_script->native; while (native_top) { - native_top->fetch_methods_with_godot_api_checks(script->native); + native_top->fetch_methods_with_godot_api_checks(p_script->native); if (native_top == CACHED_CLASS(GodotObject)) break; @@ -2723,19 +2749,19 @@ Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GD } #endif - script->script_class->fetch_methods_with_godot_api_checks(script->native); + p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native); // Need to fetch method from base classes as well - GDMonoClass *top = script->script_class; - while (top && top != script->native) { - top->fetch_methods_with_godot_api_checks(script->native); + GDMonoClass *top = p_script->script_class; + while (top && top != p_script->native) { + top->fetch_methods_with_godot_api_checks(p_script->native); top = top->get_parent_class(); } - script->load_script_signals(script->script_class, script->native); - script->_update_member_info_no_exports(); - - return script; + p_script->load_script_signals(p_script->script_class, p_script->native); +#ifdef TOOLS_ENABLED + p_script->_update_member_info_no_exports(); +#endif } bool CSharpScript::can_instance() const { diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index d31a1c35d2..eb168f344d 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -121,6 +121,7 @@ class CSharpScript : public Script { bool placeholder_fallback_enabled; bool exports_invalidated; void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames); + void _update_member_info_no_exports(); virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); #endif @@ -131,7 +132,6 @@ class CSharpScript : public Script { void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class); bool _get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms); - void _update_member_info_no_exports(); bool _update_exports(); #ifdef TOOLS_ENABLED bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported); @@ -144,6 +144,7 @@ class CSharpScript : public Script { // Do not use unless you know what you are doing friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *); static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native); + static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native); protected: static void _bind_methods(); @@ -354,7 +355,9 @@ public: _FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; } +#ifdef TOOLS_ENABLED _FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const { return godotsharp_editor; } +#endif static void release_script_gchandle(Ref<MonoGCHandle> &p_gchandle); static void release_script_gchandle(MonoObject *p_expected_obj, Ref<MonoGCHandle> &p_gchandle); diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs index 7cf58b6755..4f21871f1a 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs @@ -91,13 +91,11 @@ namespace GodotTools.ProjectEditor var coreApiRef = root.AddItem("Reference", CoreApiProjectName); coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll")); - coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll")); coreApiRef.AddMetadata("Private", "False"); var editorApiRef = root.AddItem("Reference", EditorApiProjectName); editorApiRef.Condition = " '$(Configuration)' == 'Tools' "; editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll")); - editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll")); editorApiRef.AddMetadata("Private", "False"); GenAssemblyInfoFile(root, dir, name); diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 22cf89695d..1edc426e00 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -1,6 +1,8 @@ using GodotTools.Core; using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Linq; using DotNet.Globbing; using Microsoft.Build.Construction; @@ -12,6 +14,8 @@ namespace GodotTools.ProjectEditor { var dir = Directory.GetParent(projectPath).FullName; var root = ProjectRootElement.Open(projectPath); + Debug.Assert(root != null); + var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\"); if (root.AddItemChecked(itemType, normalizedInclude)) @@ -23,7 +27,8 @@ namespace GodotTools.ProjectEditor string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories); // We want relative paths - for (int i = 0; i < files.Length; i++) { + for (int i = 0; i < files.Length; i++) + { files[i] = files[i].RelativeToPath(rootDirectory); } @@ -35,7 +40,7 @@ namespace GodotTools.ProjectEditor var result = new List<string>(); var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs"); - GlobOptions globOptions = new GlobOptions(); + var globOptions = new GlobOptions(); globOptions.Evaluation.CaseInsensitive = false; var root = ProjectRootElement.Open(projectPath); @@ -68,5 +73,103 @@ namespace GodotTools.ProjectEditor return result.ToArray(); } + + /// Simple function to make sure the Api assembly references are configured correctly + public static void FixApiHintPath(string projectPath) + { + var root = ProjectRootElement.Open(projectPath); + Debug.Assert(root != null); + + bool dirty = false; + + void AddPropertyIfNotPresent(string name, string condition, string value) + { + if (root.PropertyGroups + .Any(g => g.Condition == string.Empty || g.Condition == condition && + g.Properties + .Any(p => p.Name == name && + p.Value == value && + (p.Condition == condition || g.Condition == condition)))) + { + return; + } + + root.AddProperty(name, value).Condition = condition; + dirty = true; + } + + AddPropertyIfNotPresent(name: "ApiConfiguration", + condition: " '$(Configuration)' != 'Release' ", + value: "Debug"); + AddPropertyIfNotPresent(name: "ApiConfiguration", + condition: " '$(Configuration)' == 'Release' ", + value: "Release"); + + void SetReferenceHintPath(string referenceName, string condition, string hintPath) + { + foreach (var itemGroup in root.ItemGroups.Where(g => + g.Condition == string.Empty || g.Condition == condition)) + { + var references = itemGroup.Items.Where(item => + item.ItemType == "Reference" && + item.Include == referenceName && + (item.Condition == condition || itemGroup.Condition == condition)); + + var referencesWithHintPath = references.Where(reference => + reference.Metadata.Any(m => m.Name == "HintPath")); + + if (referencesWithHintPath.Any(reference => reference.Metadata + .Any(m => m.Name == "HintPath" && m.Value == hintPath))) + { + // Found a Reference item with the right HintPath + return; + } + + var referenceWithHintPath = referencesWithHintPath.FirstOrDefault(); + if (referenceWithHintPath != null) + { + // Found a Reference item with a wrong HintPath + foreach (var metadata in referenceWithHintPath.Metadata.ToList() + .Where(m => m.Name == "HintPath")) + { + // Safe to remove as we duplicate with ToList() to loop + referenceWithHintPath.RemoveChild(metadata); + } + + referenceWithHintPath.AddMetadata("HintPath", hintPath); + dirty = true; + return; + } + + var referenceWithoutHintPath = references.FirstOrDefault(); + if (referenceWithoutHintPath != null) + { + // Found a Reference item without a HintPath + referenceWithoutHintPath.AddMetadata("HintPath", hintPath); + dirty = true; + return; + } + } + + // Found no Reference item at all. Add it. + root.AddItem("Reference", referenceName).Condition = condition; + dirty = true; + } + + const string coreProjectName = "GodotSharp"; + const string editorProjectName = "GodotSharpEditor"; + + const string coreCondition = ""; + const string editorCondition = " '$(Configuration)' == 'Tools' "; + + var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll"; + var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll"; + + SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath); + SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath); + + if (dirty) + root.Save(); + } } } diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln new file mode 100644 index 0000000000..6f7d44bec2 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.ProjectEditor", "GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools", "GodotTools\GodotTools.csproj", "{27B00618-A6F2-4828-B922-05CAEB08C286}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.Core", "GodotTools.Core\GodotTools.Core.csproj", "{639E48BD-44E5-4091-8EDD-22D36DC0768D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.BuildLogger", "GodotTools.BuildLogger\GodotTools.BuildLogger.csproj", "{6CE9A984-37B1-4F8A-8FE9-609F05F071B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}.Release|Any CPU.Build.0 = Release|Any CPU + {27B00618-A6F2-4828-B922-05CAEB08C286}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27B00618-A6F2-4828-B922-05CAEB08C286}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27B00618-A6F2-4828-B922-05CAEB08C286}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27B00618-A6F2-4828-B922-05CAEB08C286}.Release|Any CPU.Build.0 = Release|Any CPU + {639E48BD-44E5-4091-8EDD-22D36DC0768D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {639E48BD-44E5-4091-8EDD-22D36DC0768D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {639E48BD-44E5-4091-8EDD-22D36DC0768D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {639E48BD-44E5-4091-8EDD-22D36DC0768D}.Release|Any CPU.Build.0 = Release|Any CPU + {6CE9A984-37B1-4F8A-8FE9-609F05F071B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6CE9A984-37B1-4F8A-8FE9-609F05F071B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6CE9A984-37B1-4F8A-8FE9-609F05F071B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6CE9A984-37B1-4F8A-8FE9-609F05F071B3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs index a0d14c43c9..f0068385f4 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs @@ -172,7 +172,7 @@ namespace GodotTools.Build if (outputArray.Count == 0) return string.Empty; - var lines = outputArray[1].Split('\n'); + var lines = outputArray[0].Split('\n'); foreach (string line in lines) { diff --git a/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs b/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs index 0426f0ac5a..4535ed7247 100644 --- a/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs +++ b/modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs @@ -1,9 +1,9 @@ using Godot; using System; -using System.Collections.Generic; using Godot.Collections; using GodotTools.Internals; using GodotTools.ProjectEditor; +using static GodotTools.Internals.Globals; using File = GodotTools.Utils.File; using Directory = GodotTools.Utils.Directory; @@ -11,11 +11,11 @@ namespace GodotTools { public static class CSharpProject { - public static string GenerateGameProject(string dir, string name, IEnumerable<string> files = null) + public static string GenerateGameProject(string dir, string name) { try { - return ProjectGenerator.GenGameProject(dir, name, files); + return ProjectGenerator.GenGameProject(dir, name, compileItems: new string[] { }); } catch (Exception e) { @@ -26,12 +26,24 @@ namespace GodotTools public static void AddItem(string projectPath, string itemType, string include) { - if (!(bool) Internal.GlobalDef("mono/project/auto_update_project", true)) + if (!(bool) GlobalDef("mono/project/auto_update_project", true)) return; ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include); } + public static void FixApiHintPath(string projectPath) + { + try + { + ProjectUtils.FixApiHintPath(projectPath); + } + catch (Exception e) + { + GD.PushError(e.ToString()); + } + } + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static ulong ConvertToTimestamp(this DateTime value) @@ -58,7 +70,7 @@ namespace GodotTools { var oldFileDict = (Dictionary) oldFileVar; - if (ulong.TryParse((string) oldFileDict["modified_time"], out ulong storedModifiedTime)) + if (ulong.TryParse(oldFileDict["modified_time"] as string, out ulong storedModifiedTime)) { if (storedModifiedTime == modifiedTime) { diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs index 433a931941..a884b0ead0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using GodotTools.Build; using GodotTools.Internals; using GodotTools.Utils; +using static GodotTools.Internals.Globals; using Error = Godot.Error; using File = GodotTools.Utils.File; using Directory = GodotTools.Utils.Directory; @@ -192,134 +193,14 @@ namespace GodotTools return false; } - private static bool CopyApiAssembly(string srcDir, string dstDir, string assemblyName, ApiAssemblyType apiType) - { - // Create destination directory if needed - if (!Directory.Exists(dstDir)) - { - try - { - Directory.CreateDirectory(dstDir); - } - catch (IOException e) - { - ShowBuildErrorDialog($"Failed to create destination directory for the API assemblies. Exception message: {e.Message}"); - return false; - } - } - - string assemblyFile = assemblyName + ".dll"; - string assemblySrc = Path.Combine(srcDir, assemblyFile); - string assemblyDst = Path.Combine(dstDir, assemblyFile); - - if (!File.Exists(assemblyDst) || File.GetLastWriteTime(assemblySrc) > File.GetLastWriteTime(assemblyDst) || - Internal.MetadataIsApiAssemblyInvalidated(apiType)) - { - string xmlFile = $"{assemblyName}.xml"; - string pdbFile = $"{assemblyName}.pdb"; - - try - { - File.Copy(Path.Combine(srcDir, xmlFile), Path.Combine(dstDir, xmlFile)); - } - catch (IOException e) - { - Godot.GD.PushWarning(e.ToString()); - } - - try - { - File.Copy(Path.Combine(srcDir, pdbFile), Path.Combine(dstDir, pdbFile)); - } - catch (IOException e) - { - Godot.GD.PushWarning(e.ToString()); - } - - try - { - File.Copy(assemblySrc, assemblyDst); - } - catch (IOException e) - { - ShowBuildErrorDialog($"Failed to copy {assemblyFile}. Exception message: {e.Message}"); - return false; - } - - Internal.MetadataSetApiAssemblyInvalidated(apiType, false); - } - - return true; - } - - public static bool MakeApiAssembly(ApiAssemblyType apiType, string config) - { - string apiName = apiType == ApiAssemblyType.Core ? ApiAssemblyNames.Core : ApiAssemblyNames.Editor; - - string editorPrebuiltApiDir = Path.Combine(GodotSharpDirs.DataEditorPrebuiltApiDir, config); - string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, config); - - if (File.Exists(Path.Combine(editorPrebuiltApiDir, $"{apiName}.dll"))) - { - using (var copyProgress = new EditorProgress("mono_copy_prebuilt_api_assembly", $"Copying prebuilt {apiName} assembly...", 1)) - { - copyProgress.Step($"Copying {apiName} assembly", 0); - return CopyApiAssembly(editorPrebuiltApiDir, resAssembliesDir, apiName, apiType); - } - } - - const string apiSolutionName = ApiAssemblyNames.SolutionName; - - using (var pr = new EditorProgress($"mono_build_release_{apiSolutionName}", $"Building {apiSolutionName} solution...", 3)) - { - pr.Step($"Generating {apiSolutionName} solution", 0); - - string apiSlnDir = Path.Combine(GodotSharpDirs.MonoSolutionsDir, _ApiFolderName(ApiAssemblyType.Core)); - string apiSlnFile = Path.Combine(apiSlnDir, $"{apiSolutionName}.sln"); - - if (!Directory.Exists(apiSlnDir) || !File.Exists(apiSlnFile)) - { - var bindingsGenerator = new BindingsGenerator(); - - if (!Godot.OS.IsStdoutVerbose()) - bindingsGenerator.LogPrintEnabled = false; - - Error err = bindingsGenerator.GenerateCsApi(apiSlnDir); - if (err != Error.Ok) - { - ShowBuildErrorDialog($"Failed to generate {apiSolutionName} solution. Error: {err}"); - return false; - } - } - - pr.Step($"Building {apiSolutionName} solution", 1); - - if (!BuildApiSolution(apiSlnDir, config)) - return false; - - pr.Step($"Copying {apiName} assembly", 2); - - // Copy the built assembly to the assemblies directory - string apiAssemblyDir = Path.Combine(apiSlnDir, apiName, "bin", config); - if (!CopyApiAssembly(apiAssemblyDir, resAssembliesDir, apiName, apiType)) - return false; - } - - return true; - } - public static bool BuildProjectBlocking(string config, IEnumerable<string> godotDefines) { if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) return true; // No solution to build - string apiConfig = config == "Release" ? "Release" : "Debug"; - - if (!MakeApiAssembly(ApiAssemblyType.Core, apiConfig)) - return false; - - if (!MakeApiAssembly(ApiAssemblyType.Editor, apiConfig)) - return false; + // Make sure to update the API assemblies if they happen to be missing. Just in + // case the user decided to delete them at some point after they were loaded. + Internal.UpdateApiAssembliesFromPrebuilt(); using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1)) { @@ -376,7 +257,7 @@ namespace GodotTools { // Build tool settings - Internal.EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono); + EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono); var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings(); @@ -390,7 +271,7 @@ namespace GodotTools $"{PropNameMsbuildMono},{PropNameXbuild}" }); - Internal.EditorDef("mono/builds/print_build_output", false); + EditorDef("mono/builds/print_build_output", false); } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 955574d5fe..90dec43412 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using GodotTools.Internals; using GodotTools.ProjectEditor; +using static GodotTools.Internals.Globals; using File = GodotTools.Utils.File; using Path = System.IO.Path; using OS = GodotTools.Utils.OS; @@ -26,13 +27,15 @@ namespace GodotTools private MonoDevelopInstance monoDevelopInstance; private MonoDevelopInstance visualStudioForMacInstance; + private WeakRef exportPluginWeak; // TODO Use WeakReference once we have proper serialization + public MonoBottomPanel MonoBottomPanel { get; private set; } private bool CreateProjectSolution() { - using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...", 2)) // TTR("Generating solution...") + using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2)) { - pr.Step("Generating C# project..."); // TTR("Generating C# project...") + pr.Step("Generating C# project...".TTR()); string resourceDir = ProjectSettings.GlobalizePath("res://"); @@ -65,96 +68,28 @@ namespace GodotTools } catch (IOException e) { - ShowErrorDialog($"Failed to save solution. Exception message: {e.Message}"); // TTR + ShowErrorDialog("Failed to save solution. Exception message: ".TTR() + e.Message); return false; } - string apiConfig = "Debug"; - - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, apiConfig)) - return false; - - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, apiConfig)) - return false; + // Make sure to update the API assemblies if they happen to be missing. Just in + // case the user decided to delete them at some point after they were loaded. + Internal.UpdateApiAssembliesFromPrebuilt(); - pr.Step("Done"); // TTR("Done") + pr.Step("Done".TTR()); // Here, after all calls to progress_task_step CallDeferred(nameof(_RemoveCreateSlnMenuOption)); } else { - ShowErrorDialog("Failed to create C# project."); // TTR + ShowErrorDialog("Failed to create C# project.".TTR()); } return true; } } - private static int _makeApiSolutionsAttempts = 100; - private static bool _makeApiSolutionsRecursionGuard = false; - - private void _MakeApiSolutionsIfNeeded() - { - // I'm sick entirely of ProgressDialog - - if (Internal.IsMessageQueueFlushing() || Engine.GetMainLoop() == null) - { - if (_makeApiSolutionsAttempts == 0) // This better never happen or I swear... - throw new TimeoutException(); - - if (Engine.GetMainLoop() != null) - { - if (!Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded))) - Engine.GetMainLoop().Connect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)); - } - else - { - CallDeferred(nameof(_MakeApiSolutionsIfNeededImpl)); - } - - _makeApiSolutionsAttempts--; - return; - } - - // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike - // the message queue, with signals the collateral damage should be minimal in the worst case. - if (!_makeApiSolutionsRecursionGuard) - { - _makeApiSolutionsRecursionGuard = true; - - // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead - if (Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded))) - Engine.GetMainLoop().Disconnect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)); - - _MakeApiSolutionsIfNeededImpl(); - - _makeApiSolutionsRecursionGuard = false; - } - } - - private void _MakeApiSolutionsIfNeededImpl() - { - // If the project has a solution and C# project make sure the API assemblies are present and up to date - - string api_config = "Debug"; - string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, api_config); - - if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Core}.dll")) || - Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Core)) - { - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, api_config)) - return; - } - - if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Editor}.dll")) || - Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Editor)) - { - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, api_config)) - return; // Redundant? I don't think so! - } - } - private void _RemoveCreateSlnMenuOption() { menuPopup.RemoveItem(menuPopup.GetItemIndex((int) MenuOptions.CreateSln)); @@ -405,7 +340,7 @@ namespace GodotTools MonoBottomPanel = new MonoBottomPanel(); - bottomPanelBtn = AddControlToBottomPanel(MonoBottomPanel, "Mono"); // TTR("Mono") + bottomPanelBtn = AddControlToBottomPanel(MonoBottomPanel, "Mono".TTR()); AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"}); @@ -417,7 +352,7 @@ namespace GodotTools // TODO: Remove or edit this info dialog once Mono support is no longer in alpha { - menuPopup.AddItem("About C# support", (int) MenuOptions.AboutCSharp); // TTR("About C# support") + menuPopup.AddItem("About C# support".TTR(), (int) MenuOptions.AboutCSharp); aboutDialog = new AcceptDialog(); editorBaseControl.AddChild(aboutDialog); aboutDialog.WindowTitle = "Important: C# support is not feature-complete"; @@ -439,7 +374,7 @@ namespace GodotTools var aboutLabel = new Label(); aboutHBox.AddChild(aboutLabel); - aboutLabel.RectMinSize = new Vector2(600, 150) * Internal.EditorScale; + aboutLabel.RectMinSize = new Vector2(600, 150) * EditorScale; aboutLabel.SizeFlagsVertical = (int) Control.SizeFlags.ExpandFill; aboutLabel.Autowrap = true; aboutLabel.Text = @@ -452,7 +387,7 @@ namespace GodotTools " 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!"; - Internal.EditorDef("mono/editor/show_info_on_start", true); + EditorDef("mono/editor/show_info_on_start", true); // CheckBox in main container aboutDialogCheckBox = new CheckBox {Text = "Show this warning when starting the editor"}; @@ -462,13 +397,13 @@ namespace GodotTools if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath)) { - // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized. - CallDeferred(nameof(_MakeApiSolutionsIfNeeded)); + // Make sure the existing project has Api assembly references configured correctly + CSharpProject.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath); } else { bottomPanelBtn.Hide(); - menuPopup.AddItem("Create C# solution", (int) MenuOptions.CreateSln); // TTR("Create C# solution") + menuPopup.AddItem("Create C# solution".TTR(), (int) MenuOptions.CreateSln); } menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed)); @@ -483,7 +418,7 @@ namespace GodotTools AddControlToContainer(CustomControlContainer.Toolbar, buildButton); // External editor settings - Internal.EditorDef("mono/editor/external_editor", ExternalEditor.None); + EditorDef("mono/editor/external_editor", ExternalEditor.None); string settingsHintStr = "Disabled"; @@ -513,11 +448,29 @@ namespace GodotTools }); // Export plugin - AddExportPlugin(new GodotSharpExport()); + var exportPlugin = new GodotSharpExport(); + AddExportPlugin(exportPlugin); + exportPluginWeak = WeakRef(exportPlugin); GodotSharpBuilds.Initialize(); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (exportPluginWeak != null) + { + // We need to dispose our export plugin before the editor destroys EditorSettings. + // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid + // will be freed after EditorSettings already was, and its device polling thread + // will try to access the EditorSettings singleton, resulting in null dereferencing. + (exportPluginWeak.GetRef() as GodotSharpExport)?.Dispose(); + + exportPluginWeak.Dispose(); + } + } + public void OnBeforeSerialize() { } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index a0ff8a0df1..01e8c87d14 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -44,6 +44,7 @@ <Compile Include="Internals\GodotSharpDirs.cs" /> <Compile Include="Internals\Internal.cs" /> <Compile Include="Internals\ScriptClassParser.cs" /> + <Compile Include="Internals\Globals.cs" /> <Compile Include="MonoDevelopInstance.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Build\BuildSystem.cs" /> diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs index aa52079cf4..0f6f5ffadc 100644 --- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs +++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs @@ -1,5 +1,6 @@ using Godot; using GodotTools.Internals; +using static GodotTools.Internals.Globals; namespace GodotTools { @@ -37,7 +38,7 @@ namespace GodotTools watchTimer = new Timer { OneShot = false, - WaitTime = (float) Internal.EditorDef("mono/assembly_watch_interval_sec", 0.5) + WaitTime = (float) EditorDef("mono/assembly_watch_interval_sec", 0.5) }; watchTimer.Connect("timeout", this, nameof(TimerTimeout)); AddChild(watchTimer); diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs new file mode 100644 index 0000000000..793f84fd77 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs @@ -0,0 +1,33 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace GodotTools.Internals +{ + public static class Globals + { + public static float EditorScale => internal_EditorScale(); + + public static object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) => + internal_GlobalDef(setting, defaultValue, restartIfChanged); + + public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) => + internal_EditorDef(setting, defaultValue, restartIfChanged); + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public static string TTR(this string text) => internal_TTR(text); + + // Internal Calls + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern float internal_EditorScale(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern object internal_GlobalDef(string setting, object defaultValue, bool restartIfChanged); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern string internal_TTR(string text); + } +} diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index 5c7ce832cd..9526dd3c6f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -10,13 +10,8 @@ namespace GodotTools.Internals public const string CSharpLanguageType = "CSharpScript"; public const string CSharpLanguageExtension = "cs"; - public static float EditorScale => internal_EditorScale(); - - public static object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) => - internal_GlobalDef(setting, defaultValue, restartIfChanged); - - public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) => - internal_EditorDef(setting, defaultValue, restartIfChanged); + public static string UpdateApiAssembliesFromPrebuilt() => + internal_UpdateApiAssembliesFromPrebuilt(); public static string FullTemplatesDir => internal_FullTemplatesDir(); @@ -25,14 +20,6 @@ namespace GodotTools.Internals public static bool IsOsxAppBundleInstalled(string bundleId) => internal_IsOsxAppBundleInstalled(bundleId); - public static bool MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType) => - internal_MetadataIsApiAssemblyInvalidated(apiType); - - public static void MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated) => - internal_MetadataSetApiAssemblyInvalidated(apiType, invalidated); - - public static bool IsMessageQueueFlushing() => internal_IsMessageQueueFlushing(); - public static bool GodotIs32Bits() => internal_GodotIs32Bits(); public static bool GodotIsRealTDouble() => internal_GodotIsRealTDouble(); @@ -62,13 +49,7 @@ namespace GodotTools.Internals // Internal Calls [MethodImpl(MethodImplOptions.InternalCall)] - private static extern float internal_EditorScale(); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern object internal_GlobalDef(string setting, object defaultValue, bool restartIfChanged); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged); + private static extern string internal_UpdateApiAssembliesFromPrebuilt(); [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_FullTemplatesDir(); @@ -80,15 +61,6 @@ namespace GodotTools.Internals private static extern bool internal_IsOsxAppBundleInstalled(string bundleId); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool internal_MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void internal_MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool internal_IsMessageQueueFlushing(); - - [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool internal_GodotIs32Bits(); [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs b/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs index 300cf7fcb9..53ff0891d5 100644 --- a/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/MonoBottomPanel.cs @@ -3,6 +3,7 @@ using System; using System.IO; using Godot.Collections; using GodotTools.Internals; +using static GodotTools.Internals.Globals; using File = GodotTools.Utils.File; using Path = System.IO.Path; @@ -254,7 +255,7 @@ namespace GodotTools panelTabs = new TabContainer { TabAlign = TabContainer.TabAlignEnum.Left, - RectMinSize = new Vector2(0, 228) * Internal.EditorScale, + RectMinSize = new Vector2(0, 228) * EditorScale, SizeFlagsVertical = (int) SizeFlags.ExpandFill }; panelTabs.AddStyleboxOverride("panel", editorBaseControl.GetStylebox("DebuggerPanel", "EditorStyles")); @@ -266,7 +267,7 @@ namespace GodotTools // Builds tab panelBuildsTab = new VBoxContainer { - Name = "Builds", // TTR + Name = "Builds".TTR(), SizeFlagsHorizontal = (int) SizeFlags.ExpandFill }; panelTabs.AddChild(panelBuildsTab); @@ -276,7 +277,7 @@ namespace GodotTools var buildProjectBtn = new Button { - Text = "Build Project", // TTR + Text = "Build Project".TTR(), FocusMode = FocusModeEnum.None }; buildProjectBtn.Connect("pressed", this, nameof(BuildProjectPressed)); @@ -286,7 +287,7 @@ namespace GodotTools warningsBtn = new ToolButton { - Text = "Warnings", // TTR + Text = "Warnings".TTR(), ToggleMode = true, Pressed = true, Visible = false, @@ -297,7 +298,7 @@ namespace GodotTools errorsBtn = new ToolButton { - Text = "Errors", // TTR + Text = "Errors".TTR(), ToggleMode = true, Pressed = true, Visible = false, @@ -310,7 +311,7 @@ namespace GodotTools viewLogBtn = new Button { - Text = "View log", // TTR + Text = "View log".TTR(), FocusMode = FocusModeEnum.None, Visible = false }; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 1a440e5ced..45037bf637 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -875,14 +875,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect da->make_dir("Core"); da->make_dir("ObjectType"); - String core_dir = path_join(p_proj_dir, "Core"); - String obj_type_dir = path_join(p_proj_dir, "ObjectType"); + String core_dir = path::join(p_proj_dir, "Core"); + String obj_type_dir = path::join(p_proj_dir, "ObjectType"); // Generate source file for global scope constants and enums { StringBuilder constants_source; _generate_global_constants(constants_source); - String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs"); + String output_file = path::join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs"); Error save_err = _save_file(output_file, constants_source); if (save_err != OK) return save_err; @@ -896,7 +896,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect if (itype.api_type == ClassDB::API_EDITOR) continue; - String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs"); + String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs"); Error err = _generate_cs_type(itype, output_file); if (err == ERR_SKIP) @@ -917,7 +917,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect const String &file_name = E->key(); const GodotCsCompressedFile &file_data = E->value(); - String output_file = path_join(core_dir, file_name); + String output_file = path::join(core_dir, file_name); Vector<uint8_t> data; data.resize(file_data.uncompressed_size); @@ -971,7 +971,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK); - String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs"); + String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs"); Error err = _save_file(internal_methods_file, cs_icalls_content); if (err != OK) @@ -996,8 +996,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve da->make_dir("Core"); da->make_dir("ObjectType"); - String core_dir = path_join(p_proj_dir, "Core"); - String obj_type_dir = path_join(p_proj_dir, "ObjectType"); + String core_dir = path::join(p_proj_dir, "Core"); + String obj_type_dir = path::join(p_proj_dir, "ObjectType"); for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { const TypeInterface &itype = E.get(); @@ -1005,7 +1005,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve if (itype.api_type != ClassDB::API_EDITOR) continue; - String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs"); + String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs"); Error err = _generate_cs_type(itype, output_file); if (err == ERR_SKIP) @@ -1051,7 +1051,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK); - String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs"); + String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs"); Error err = _save_file(internal_methods_file, cs_icalls_content); if (err != OK) @@ -1064,7 +1064,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve Error BindingsGenerator::generate_cs_api(const String &p_output_dir) { - String output_dir = DirAccess::get_full_path(p_output_dir, DirAccess::ACCESS_FILESYSTEM); + String output_dir = path::abspath(path::realpath(p_output_dir)); DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); @@ -1862,7 +1862,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { output.append("\n#endif // MONO_GLUE_ENABLED\n"); - Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output); + Error save_err = _save_file(path::join(p_output_dir, "mono_glue.gen.cpp"), output); if (save_err != OK) return save_err; @@ -2192,7 +2192,7 @@ void BindingsGenerator::_populate_object_type_interfaces() { itype.base_name = ClassDB::get_parent_class(type_cname); itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name); - itype.is_instantiable = ClassDB::can_instance(type_cname) && !itype.is_singleton; + itype.is_instantiable = class_info->creation_func && !itype.is_singleton; itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference); itype.memory_own = itype.is_reference; diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index a3b5b450ef..0014aaca70 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -30,7 +30,6 @@ #include "editor_internal_calls.h" -#include "core/message_queue.h" #include "core/os/os.h" #include "core/version.h" #include "editor/editor_node.h" @@ -231,24 +230,34 @@ uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies); } -float godot_icall_Internal_EditorScale() { +float godot_icall_Globals_EditorScale() { return EDSCALE; } -MonoObject *godot_icall_Internal_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) { +MonoObject *godot_icall_Globals_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) { String setting = GDMonoMarshal::mono_string_to_godot(p_setting); Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value); Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed); return GDMonoMarshal::variant_to_mono_object(result); } -MonoObject *godot_icall_Internal_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) { +MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) { String setting = GDMonoMarshal::mono_string_to_godot(p_setting); Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value); - Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed); + Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed); return GDMonoMarshal::variant_to_mono_object(result); } +MonoString *godot_icall_Globals_TTR(MonoString *p_text) { + String text = GDMonoMarshal::mono_string_to_godot(p_text); + return GDMonoMarshal::mono_string_from_godot(TTR(text)); +} + +MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt() { + String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt(); + return GDMonoMarshal::mono_string_from_godot(error_str); +} + MonoString *godot_icall_Internal_FullTemplatesDir() { String full_templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); return GDMonoMarshal::mono_string_from_godot(full_templates_dir); @@ -269,18 +278,6 @@ MonoBoolean godot_icall_Internal_IsOsxAppBundleInstalled(MonoString *p_bundle_id #endif } -MonoBoolean godot_icall_Internal_MetadataIsApiAssemblyInvalidated(int32_t p_api_type) { - return GDMono::get_singleton()->metadata_is_api_assembly_invalidated((APIAssembly::Type)p_api_type); -} - -void godot_icall_Internal_MetadataSetApiAssemblyInvalidated(int32_t p_api_type, MonoBoolean p_invalidated) { - GDMono::get_singleton()->metadata_set_api_assembly_invalidated((APIAssembly::Type)p_api_type, (bool)p_invalidated); -} - -MonoBoolean godot_icall_Internal_IsMessageQueueFlushing() { - return (MonoBoolean)MessageQueue::get_singleton()->is_flushing(); -} - MonoBoolean godot_icall_Internal_GodotIs32Bits() { return sizeof(void *) == 4; } @@ -402,15 +399,10 @@ void register_editor_internal_calls() { mono_add_internal_call("GodotTools.GodotSharpExport::internal_GetExportedAssemblyDependencies", (void *)godot_icall_GodotSharpExport_GetExportedAssemblyDependencies); // Internals - mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorScale", (void *)godot_icall_Internal_EditorScale); - mono_add_internal_call("GodotTools.Internals.Internal::internal_GlobalDef", (void *)godot_icall_Internal_GlobalDef); - mono_add_internal_call("GodotTools.Internals.Internal::internal_EditorDef", (void *)godot_icall_Internal_EditorDef); + mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt); mono_add_internal_call("GodotTools.Internals.Internal::internal_FullTemplatesDir", (void *)godot_icall_Internal_FullTemplatesDir); mono_add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", (void *)godot_icall_Internal_SimplifyGodotPath); mono_add_internal_call("GodotTools.Internals.Internal::internal_IsOsxAppBundleInstalled", (void *)godot_icall_Internal_IsOsxAppBundleInstalled); - mono_add_internal_call("GodotTools.Internals.Internal::internal_MetadataIsApiAssemblyInvalidated", (void *)godot_icall_Internal_MetadataIsApiAssemblyInvalidated); - mono_add_internal_call("GodotTools.Internals.Internal::internal_MetadataSetApiAssemblyInvalidated", (void *)godot_icall_Internal_MetadataSetApiAssemblyInvalidated); - mono_add_internal_call("GodotTools.Internals.Internal::internal_IsMessageQueueFlushing", (void *)godot_icall_Internal_IsMessageQueueFlushing); mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", (void *)godot_icall_Internal_GodotIs32Bits); mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", (void *)godot_icall_Internal_GodotIsRealTDouble); mono_add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", (void *)godot_icall_Internal_GodotMainIteration); @@ -424,6 +416,12 @@ void register_editor_internal_calls() { mono_add_internal_call("GodotTools.Internals.Internal::internal_GetScriptsMetadataOrNothing", (void *)godot_icall_Internal_GetScriptsMetadataOrNothing); mono_add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", (void *)godot_icall_Internal_MonoWindowsInstallRoot); + // Globals + mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", (void *)godot_icall_Globals_EditorScale); + mono_add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", (void *)godot_icall_Globals_GlobalDef); + mono_add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", (void *)godot_icall_Globals_EditorDef); + mono_add_internal_call("GodotTools.Internals.Globals::internal_TTR", (void *)godot_icall_Globals_TTR); + // Utils.OS mono_add_internal_call("GodotTools.Utils.OS::GetPlatformName", (void *)godot_icall_Utils_OS_GetPlatformName); } diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 75b2dfce9a..6d85f55b97 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -219,7 +219,18 @@ MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString * } MonoString *godot_icall_Object_ToString(Object *p_ptr) { - return GDMonoMarshal::mono_string_from_godot(Variant(p_ptr).operator String()); +#ifdef DEBUG_ENABLED + // Cannot happen in C#; would get an ObjectDisposedException instead. + CRASH_COND(p_ptr == NULL); + + if (ScriptDebugger::get_singleton() && !Object::cast_to<Reference>(p_ptr)) { // Only if debugging! + // Cannot happen either in C#; the handle is nullified when the object is destroyed + CRASH_COND(!ObjectDB::instance_validate(p_ptr)); + } +#endif + + String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]"; + return GDMonoMarshal::mono_string_from_godot(result); } void godot_register_object_icalls() { diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 7ae991eeaa..096ad0f5e3 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -59,10 +59,6 @@ #include "android_mono_config.gen.h" #endif -#define OUT_OF_SYNC_ERR_MESSAGE(m_assembly_name) "The assembly '" m_assembly_name "' is out of sync. " \ - "This error is expected if you just upgraded to a newer Godot version. " \ - "Building the project will update the assembly to the correct version." - GDMono *GDMono::singleton = NULL; namespace { @@ -241,9 +237,9 @@ void GDMono::initialize() { locations.push_back("/usr/local/var/homebrew/linked/mono/"); for (int i = 0; i < locations.size(); i++) { - String hint_assembly_rootdir = path_join(locations[i], "lib"); - String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll"); - String hint_config_dir = path_join(locations[i], "etc"); + String hint_assembly_rootdir = path::join(locations[i], "lib"); + String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll"); + String hint_config_dir = path::join(locations[i], "etc"); if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) { assembly_rootdir = hint_assembly_rootdir; @@ -304,26 +300,9 @@ void GDMono::initialize() { mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL); #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#). - - String mscorlib_fname("mscorlib.dll"); - - Vector<String> search_dirs; - GDMonoAssembly::fill_search_dirs(search_dirs); - - bool found = false; - for (int i = 0; i < search_dirs.size(); i++) { - if (FileAccess::exists(search_dirs[i].plus_file(mscorlib_fname))) { - found = true; - break; - } - } - - if (!found) - return; // mscorlib is missing, do not initialize mono - } + // Export templates only load the Mono runtime if the project uses it + if (!DirAccess::exists("res://.mono")) + return; #endif root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319"); @@ -354,63 +333,48 @@ void GDMono::initialize() { _register_internal_calls(); - // The following assemblies are not required at initialization -#ifdef MONO_GLUE_ENABLED - if (_load_api_assemblies()) { - // Everything is fine with the api assemblies, load the tools and project assemblies - -#if defined(TOOLS_ENABLED) - ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies"); - ERR_FAIL_COND(!_load_tools_assemblies()); -#endif + print_verbose("Mono: INITIALIZED"); +} - _load_project_assembly(); +void GDMono::initialize_load_assemblies() { - } else { - if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) -#ifdef TOOLS_ENABLED - || (editor_api_assembly && editor_api_assembly_out_of_sync) +#ifndef MONO_GLUE_ENABLED + ERR_EXPLAIN("Mono: This binary was built with `mono_glue=no`; cannot load assemblies"); + CRASH_NOW(); #endif - ) { -#ifdef TOOLS_ENABLED - // The assembly was successfully loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the - // metadata, so we invalidate the version in the metadata and unload the script domain. - - if (core_api_assembly_out_of_sync) { - ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME)); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { - ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } - if (editor_api_assembly_out_of_sync) { - ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME)); - metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); - } + // Load assemblies. The API and tools assemblies are required, + // the application is aborted if these assemblies cannot be loaded. - print_line("Mono: Proceeding to unload scripts domain because of invalid API assemblies."); + _load_api_assemblies(); - Error err = _unload_scripts_domain(); - if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); - } -#else - ERR_PRINT("The loaded API assembly is invalid"); - CRASH_NOW(); -#endif // TOOLS_ENABLED - } +#if defined(TOOLS_ENABLED) + if (!_load_tools_assemblies()) { + ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies"); + CRASH_NOW(); } -#else - print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif // MONO_GLUE_ENABLED +#endif - print_verbose("Mono: INITIALIZED"); + // Load the project's main assembly. This doesn't necessarily need to succeed. + // The game may not be using .NET at all, or if the project does use .NET and + // we're running in the editor, it may just happen to be it wasn't built yet. + if (!_load_project_assembly()) { + if (OS::get_singleton()->is_stdout_verbose()) + print_error("Mono: Failed to load project assembly"); + } +} + +bool GDMono::_are_api_assemblies_out_of_sync() { + bool out_of_sync = core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated); +#ifdef TOOLS_ENABLED + if (!out_of_sync) + out_of_sync = editor_api_assembly && editor_api_assembly_out_of_sync; +#endif + return out_of_sync; } -#ifdef MONO_GLUE_ENABLED namespace GodotSharpBindings { +#ifdef MONO_GLUE_ENABLED uint64_t get_core_api_hash(); #ifdef TOOLS_ENABLED @@ -419,13 +383,33 @@ uint64_t get_editor_api_hash(); uint32_t get_bindings_version(); void register_generated_icalls(); -} // namespace GodotSharpBindings + +#else + +uint64_t get_core_api_hash() { + CRASH_NOW(); + GD_UNREACHABLE(); +} +#ifdef TOOLS_ENABLED +uint64_t get_editor_api_hash() { + CRASH_NOW(); + GD_UNREACHABLE(); +} #endif +uint32_t get_bindings_version() { + CRASH_NOW(); + GD_UNREACHABLE(); +} + +void register_generated_icalls() { + /* Fine, just do nothing */ +} + +#endif // MONO_GLUE_ENABLED +} // namespace GodotSharpBindings void GDMono::_register_internal_calls() { -#ifdef MONO_GLUE_ENABLED GodotSharpBindings::register_generated_icalls(); -#endif } void GDMono::_initialize_and_check_api_hashes() { @@ -564,12 +548,22 @@ bool GDMono::_load_corlib_assembly() { return success; } -static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) { +#ifdef TOOLS_ENABLED +bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) { + + bool &api_assembly_out_of_sync = (p_api_type == APIAssembly::API_CORE) ? + GDMono::get_singleton()->core_api_assembly_out_of_sync : + GDMono::get_singleton()->editor_api_assembly_out_of_sync; + + String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); + String dst_dir = GodotSharpDirs::get_res_assemblies_dir(); + + String assembly_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; // Create destination directory if needed - if (!DirAccess::exists(p_dst_dir)) { - DirAccess *da = DirAccess::create_for_path(p_dst_dir); - Error err = da->make_dir_recursive(p_dst_dir); + if (!DirAccess::exists(dst_dir)) { + DirAccess *da = DirAccess::create_for_path(dst_dir); + Error err = da->make_dir_recursive(dst_dir); memdelete(da); if (err != OK) { @@ -578,21 +572,19 @@ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, } } - String assembly_file = p_assembly_name + ".dll"; - String assembly_src = p_src_dir.plus_file(assembly_file); - String assembly_dst = p_dst_dir.plus_file(assembly_file); + String assembly_file = assembly_name + ".dll"; + String assembly_src = src_dir.plus_file(assembly_file); + String assembly_dst = dst_dir.plus_file(assembly_file); - if (!FileAccess::exists(assembly_dst) || - FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) || - GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) { + if (!FileAccess::exists(assembly_dst) || api_assembly_out_of_sync) { DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - String xml_file = p_assembly_name + ".xml"; - if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK) + String xml_file = assembly_name + ".xml"; + if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) WARN_PRINTS("Failed to copy " + xml_file); - String pdb_file = p_assembly_name + ".pdb"; - if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK) + String pdb_file = assembly_name + ".pdb"; + if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK) WARN_PRINTS("Failed to copy " + pdb_file); Error err = da->copy(assembly_src, assembly_dst); @@ -602,47 +594,63 @@ static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, return false; } - GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false); + api_assembly_out_of_sync = false; } return true; } +String GDMono::update_api_assemblies_from_prebuilt() { + +#define FAIL_REASON(m_out_of_sync, m_prebuilt_exist) \ + ( \ + (m_out_of_sync ? \ + String("The assembly is invalidated") : \ + String("The assembly was not found")) + \ + (m_prebuilt_exist ? \ + String(" and the prebuilt assemblies are missing") : \ + String(" and we failed to copy the prebuilt assemblies"))) + + bool api_assembly_out_of_sync = core_api_assembly_out_of_sync || editor_api_assembly_out_of_sync; + + String core_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll"); + String editor_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + + if (!api_assembly_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) + return String(); // No update needed + + String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); + String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); + String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); + + if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ false); + + // Copy the prebuilt Api + if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE) || !copy_prebuilt_api_assembly(APIAssembly::API_EDITOR)) + return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exist: */ true); + + return String(); // Updated successfully + +#undef FAIL_REASON +} +#endif + bool GDMono::_load_core_api_assembly() { if (core_api_assembly) return true; #ifdef TOOLS_ENABLED - if (metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) { - String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); - String prebuilt_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll"); - String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_CORE); - - if (!FileAccess::exists(prebuilt_dll_path) || - FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) { - print_verbose("Mono: Skipping loading of Core API assembly because it was invalidated"); - return false; - } else { - // Copy the prebuilt Api - String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); - if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, CORE_API_ASSEMBLY_NAME, APIAssembly::API_CORE) || - !copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) { - print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Core API assembly because it was invalidated"); - return false; - } - } - } -#endif - + // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll"); - - bool success = (FileAccess::exists(assembly_path) && - load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly)) || - load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly); + bool success = FileAccess::exists(assembly_path) && + load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &core_api_assembly); +#else + bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly); +#endif if (success) { -#ifdef MONO_GLUE_ENABLED APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE); core_api_assembly_out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash || GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || @@ -652,9 +660,8 @@ bool GDMono::_load_core_api_assembly() { _install_trace_listener(); } -#else - GDMonoUtils::update_godot_api_cache(); -#endif + } else { + core_api_assembly_out_of_sync = false; } return success; @@ -666,44 +673,100 @@ bool GDMono::_load_editor_api_assembly() { if (editor_api_assembly) return true; - if (metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { - String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"); - String prebuilt_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); - String invalidated_dll_path = get_invalidated_api_assembly_path(APIAssembly::API_EDITOR); - - if (!FileAccess::exists(prebuilt_dll_path) || - FileAccess::get_modified_time(invalidated_dll_path) == FileAccess::get_modified_time(prebuilt_dll_path)) { - print_verbose("Mono: Skipping loading of Editor API assembly because it was invalidated"); - return false; - } else { - // Copy the prebuilt editor Api (no need to copy the core api if we got to this point) - String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); - if (!copy_api_assembly(prebuilt_api_dir, res_assemblies_dir, EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) { - print_verbose("Mono: Failed to copy prebuilt API. Skipping loading of Editor API assembly because it was invalidated"); - return false; - } - } - } - + // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"); - - bool success = (FileAccess::exists(assembly_path) && - load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly)) || - load_assembly(EDITOR_API_ASSEMBLY_NAME, &editor_api_assembly); + bool success = FileAccess::exists(assembly_path) && + load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &editor_api_assembly); if (success) { -#ifdef MONO_GLUE_ENABLED APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR); editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash || GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version || CS_GLUE_VERSION != api_assembly_ver.cs_glue_version; -#endif + } else { + editor_api_assembly_out_of_sync = false; } return success; } #endif +bool GDMono::_try_load_api_assemblies() { + + if (!_load_core_api_assembly()) { + if (OS::get_singleton()->is_stdout_verbose()) + print_error("Mono: Failed to load Core API assembly"); + return false; + } + + if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) + return false; + +#ifdef TOOLS_ENABLED + if (!_load_editor_api_assembly()) { + if (OS::get_singleton()->is_stdout_verbose()) + print_error("Mono: Failed to load Editor API assembly"); + return false; + } + + if (editor_api_assembly_out_of_sync) + return false; +#endif + + return true; +} + +void GDMono::_load_api_assemblies() { + + if (!_try_load_api_assemblies()) { + // The API assemblies are out of sync. Fine, try one more time, but this time + // update them from the prebuilt assemblies directory before trying to load them. + + // 1. Unload the scripts domain + if (_unload_scripts_domain() != OK) { + ERR_EXPLAIN("Mono: Failed to unload scripts domain"); + CRASH_NOW(); + } + + // 2. Update the API assemblies + String update_error = update_api_assemblies_from_prebuilt(); + if (!update_error.empty()) { + ERR_EXPLAIN(update_error); + CRASH_NOW(); + } + + // 3. Load the scripts domain again + if (_load_scripts_domain() != OK) { + ERR_EXPLAIN("Mono: Failed to load scripts domain"); + CRASH_NOW(); + } + + // 4. Try loading the updated assemblies + if (!_try_load_api_assemblies()) { + // welp... too bad + + if (_are_api_assemblies_out_of_sync()) { + if (core_api_assembly_out_of_sync) { + ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync"); + } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed"); + } + +#ifdef TOOLS_ENABLED + if (editor_api_assembly_out_of_sync) { + ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync"); + } +#endif + + CRASH_NOW(); + } else { + ERR_EXPLAIN("Failed to load one of the API assemblies"); + CRASH_NOW(); + } + } + } +} + #ifdef TOOLS_ENABLED bool GDMono::_load_tools_assemblies() { @@ -732,39 +795,11 @@ bool GDMono::_load_project_assembly() { if (success) { mono_assembly_set_main(project_assembly->get_assembly()); - } else { - if (OS::get_singleton()->is_stdout_verbose()) - print_error("Mono: Failed to load project assembly"); } return success; } -bool GDMono::_load_api_assemblies() { - - if (!_load_core_api_assembly()) { - if (OS::get_singleton()->is_stdout_verbose()) - print_error("Mono: Failed to load Core API assembly"); - return false; - } - - if (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated) - return false; - -#ifdef TOOLS_ENABLED - if (!_load_editor_api_assembly()) { - if (OS::get_singleton()->is_stdout_verbose()) - print_error("Mono: Failed to load Editor API assembly"); - return false; - } - - if (editor_api_assembly_out_of_sync) - return false; -#endif - - return true; -} - void GDMono::_install_trace_listener() { #ifdef DEBUG_ENABLED @@ -782,78 +817,6 @@ void GDMono::_install_trace_listener() { #endif } -#ifdef TOOLS_ENABLED -String GDMono::_get_api_assembly_metadata_path() { - - return GodotSharpDirs::get_res_metadata_dir().plus_file("api_assemblies.cfg"); -} - -void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated) { - - String section = APIAssembly::to_string(p_api_type); - String path = _get_api_assembly_metadata_path(); - - Ref<ConfigFile> metadata; - metadata.instance(); - metadata->load(path); - - metadata->set_value(section, "invalidated", p_invalidated); - - String assembly_path = GodotSharpDirs::get_res_assemblies_dir() - .plus_file(p_api_type == APIAssembly::API_CORE ? - CORE_API_ASSEMBLY_NAME ".dll" : - EDITOR_API_ASSEMBLY_NAME ".dll"); - - ERR_FAIL_COND(!FileAccess::exists(assembly_path)); - - uint64_t modified_time = FileAccess::get_modified_time(assembly_path); - - metadata->set_value(section, "invalidated_asm_modified_time", String::num_uint64(modified_time)); - - String dir = path.get_base_dir(); - if (!DirAccess::exists(dir)) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND(!da); - Error err = da->make_dir_recursive(ProjectSettings::get_singleton()->globalize_path(dir)); - ERR_FAIL_COND(err != OK); - } - - Error save_err = metadata->save(path); - ERR_FAIL_COND(save_err != OK); -} - -bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type) { - - String section = APIAssembly::to_string(p_api_type); - - Ref<ConfigFile> metadata; - metadata.instance(); - metadata->load(_get_api_assembly_metadata_path()); - - String assembly_path = GodotSharpDirs::get_res_assemblies_dir() - .plus_file(p_api_type == APIAssembly::API_CORE ? - CORE_API_ASSEMBLY_NAME ".dll" : - EDITOR_API_ASSEMBLY_NAME ".dll"); - - if (!FileAccess::exists(assembly_path)) - return false; - - uint64_t modified_time = FileAccess::get_modified_time(assembly_path); - - uint64_t stored_modified_time = metadata->get_value(section, "invalidated_asm_modified_time", 0); - - return metadata->get_value(section, "invalidated", false) && modified_time <= stored_modified_time; -} - -String GDMono::get_invalidated_api_assembly_path(APIAssembly::Type p_api_type) { - - return GodotSharpDirs::get_res_assemblies_dir() - .plus_file(p_api_type == APIAssembly::API_CORE ? - CORE_API_ASSEMBLY_NAME ".dll" : - EDITOR_API_ASSEMBLY_NAME ".dll"); -} -#endif - Error GDMono::_load_scripts_domain() { ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG); @@ -901,11 +864,6 @@ Error GDMono::_unload_scripts_domain() { tools_project_editor_assembly = NULL; #endif - core_api_assembly_out_of_sync = false; -#ifdef TOOLS_ENABLED - editor_api_assembly_out_of_sync = false; -#endif - MonoDomain *domain = scripts_domain; scripts_domain = NULL; @@ -942,57 +900,25 @@ Error GDMono::reload_scripts_domain() { return err; } -#ifdef MONO_GLUE_ENABLED - if (!_load_api_assemblies()) { - if ((core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated)) -#ifdef TOOLS_ENABLED - || (editor_api_assembly && editor_api_assembly_out_of_sync) -#endif - ) { -#ifdef TOOLS_ENABLED - // The assembly was successfully loaded, but the full api could not be cached. - // This is most likely an outdated assembly loaded because of an invalid version in the - // metadata, so we invalidate the version in the metadata and unload the script domain. - - if (core_api_assembly_out_of_sync) { - ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(CORE_API_ASSEMBLY_NAME)); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { - ERR_PRINT("The loaded Core API assembly is in sync, but the cache update failed"); - metadata_set_api_assembly_invalidated(APIAssembly::API_CORE, true); - } - - if (editor_api_assembly_out_of_sync) { - ERR_PRINT(OUT_OF_SYNC_ERR_MESSAGE(EDITOR_API_ASSEMBLY_NAME)); - metadata_set_api_assembly_invalidated(APIAssembly::API_EDITOR, true); - } + // Load assemblies. The API and tools assemblies are required, + // the application is aborted if these assemblies cannot be loaded. - err = _unload_scripts_domain(); - if (err != OK) { - WARN_PRINT("Mono: Failed to unload scripts domain"); - } + _load_api_assemblies(); - return ERR_CANT_RESOLVE; -#else - ERR_PRINT("The loaded API assembly is invalid"); - CRASH_NOW(); -#endif - } else { - return ERR_CANT_OPEN; - } +#if defined(TOOLS_ENABLED) + if (!_load_tools_assemblies()) { + ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies"); + CRASH_NOW(); } - -#ifdef TOOLS_ENABLED - ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies"); - ERR_FAIL_COND_V(!_load_tools_assemblies(), ERR_CANT_OPEN); #endif + // Load the project's main assembly. Here, during hot-reloading, we do + // consider failing to load the project's main assembly to be an error. + // However, unlike the API and tools assemblies, the application can continue working. if (!_load_project_assembly()) { + print_error("Mono: Failed to load project assembly"); return ERR_CANT_OPEN; } -#else - print_verbose("Mono: Glue disabled, ignoring script assemblies."); -#endif // MONO_GLUE_ENABLED return OK; } diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h index a926bf4126..deebe5fd50 100644 --- a/modules/mono/mono_gd/gd_mono.h +++ b/modules/mono/mono_gd/gd_mono.h @@ -104,6 +104,8 @@ class GDMono { void _domain_assemblies_cleanup(uint32_t p_domain_id); + bool _are_api_assemblies_out_of_sync(); + bool _load_corlib_assembly(); bool _load_core_api_assembly(); #ifdef TOOLS_ENABLED @@ -112,11 +114,8 @@ class GDMono { #endif bool _load_project_assembly(); - bool _load_api_assemblies(); - -#ifdef TOOLS_ENABLED - String _get_api_assembly_metadata_path(); -#endif + bool _try_load_api_assemblies(); + void _load_api_assemblies(); void _install_trace_listener(); @@ -157,9 +156,8 @@ public: #endif #ifdef TOOLS_ENABLED - void metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type, bool p_invalidated); - bool metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type); - String get_invalidated_api_assembly_path(APIAssembly::Type p_api_type); + bool copy_prebuilt_api_assembly(APIAssembly::Type p_api_type); + String update_api_assemblies_from_prebuilt(); #endif static GDMono *get_singleton() { return singleton; } @@ -203,6 +201,7 @@ public: Error finalize_and_unload_domain(MonoDomain *p_domain); void initialize(); + void initialize_load_assemblies(); GDMono(); ~GDMono(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 8e63ef3563..761c7f6fcb 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -46,20 +46,6 @@ bool GDMonoAssembly::in_preload = false; Vector<String> GDMonoAssembly::search_dirs; -static String _get_expected_api_build_config() { -#ifdef TOOLS_ENABLED - return "Debug"; -#else - -#ifdef DEBUG_ENABLED - return "Debug"; -#else - return "Release"; -#endif - -#endif -} - void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) { String framework_dir; @@ -81,11 +67,14 @@ void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const Strin r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir()); } - String api_config = p_custom_config.empty() ? _get_expected_api_build_config() : - (p_custom_config == "Release" ? "Release" : "Debug"); - r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config)); + if (p_custom_config.empty()) { + r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); + } else { + String api_config = p_custom_config == "Release" ? "Release" : "Debug"; + r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config)); + } - r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir()); + r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir()); r_search_dirs.push_back(OS::get_singleton()->get_resource_dir()); r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir()); diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index 6e431f51e7..20863b1afe 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -36,16 +36,21 @@ #include "core/project_settings.h" #ifdef WINDOWS_ENABLED +#include <windows.h> + #define ENV_PATH_SEP ";" #else -#define ENV_PATH_SEP ":" #include <limits.h> +#include <unistd.h> + +#define ENV_PATH_SEP ":" #endif #include <stdlib.h> -String path_which(const String &p_name) { +namespace path { +String find_executable(const String &p_name) { #ifdef WINDOWS_ENABLED Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false); #endif @@ -55,7 +60,7 @@ String path_which(const String &p_name) { return String(); for (int i = 0; i < env_path.size(); i++) { - String p = path_join(env_path[i], p_name); + String p = path::join(env_path[i], p_name); #ifdef WINDOWS_ENABLED for (int j = 0; j < exts.size(); j++) { @@ -73,42 +78,96 @@ String path_which(const String &p_name) { return String(); } -void fix_path(const String &p_path, String &r_out) { - r_out = p_path.replace("\\", "/"); +String cwd() { +#ifdef WINDOWS_ENABLED + const DWORD expected_size = ::GetCurrentDirectoryW(0, NULL); + + String buffer; + buffer.resize((int)expected_size); + if (::GetCurrentDirectoryW(expected_size, buffer.ptrw()) == 0) + return "."; + + return buffer.simplify_path(); +#else + char buffer[PATH_MAX]; + if (::getcwd(buffer, sizeof(buffer)) == NULL) + return "."; + + String result; + if (result.parse_utf8(buffer)) + return "."; - while (true) { // in case of using 2 or more slash - String compare = r_out.replace("//", "/"); - if (r_out == compare) - break; - else - r_out = compare; + return result.simplify_path(); +#endif +} + +String abspath(const String &p_path) { + if (p_path.is_abs_path()) { + return p_path.simplify_path(); + } else { + return path::join(path::cwd(), p_path).simplify_path(); } } -bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) { +String realpath(const String &p_path) { #ifdef WINDOWS_ENABLED - CharType ret[_MAX_PATH]; - if (::_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) { - String abspath = String(ret).replace("\\", "/"); - int pos = abspath.find(":/"); - if (pos != -1) { - r_abs_path = abspath.substr(pos - 1, abspath.length()); - } else { - r_abs_path = abspath; - } - return true; - } -#else - char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL); - if (resolved_path) { - String retstr; - bool success = !retstr.parse_utf8(resolved_path); - ::free(resolved_path); - if (success) { - r_abs_path = retstr; - return true; - } + // Open file without read/write access + HANDLE hFile = ::CreateFileW(p_path.c_str(), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == INVALID_HANDLE_VALUE) + return p_path; + + const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, NULL, 0, FILE_NAME_NORMALIZED); + + if (expected_size == 0) { + ::CloseHandle(hFile); + return p_path; } + + String buffer; + buffer.resize((int)expected_size); + ::GetFinalPathNameByHandleW(hFile, buffer.ptrw(), expected_size, FILE_NAME_NORMALIZED); + + ::CloseHandle(hFile); + return buffer.simplify_path(); +#elif UNIX_ENABLED + char *resolved_path = ::realpath(p_path.utf8().get_data(), NULL); + + if (!resolved_path) + return p_path; + + String result; + bool parse_ok = result.parse_utf8(resolved_path); + ::free(resolved_path); + + if (parse_ok) + return p_path; + + return result.simplify_path(); #endif - return false; } + +String join(const String &p_a, const String &p_b) { + if (p_a.empty()) + return p_b; + + const CharType a_last = p_a[p_a.length() - 1]; + if ((a_last == '/' || a_last == '\\') || + (p_b.size() > 0 && (p_b[0] == '/' || p_b[0] == '\\'))) { + return p_a + p_b; + } + + return p_a + "/" + p_b; +} + +String join(const String &p_a, const String &p_b, const String &p_c) { + return path::join(path::join(p_a, p_b), p_c); +} + +String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d) { + return path::join(path::join(path::join(p_a, p_b), p_c), p_d); +} + +} // namespace path diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h index 69edf4deb7..ca25bc09f7 100644 --- a/modules/mono/utils/path_utils.h +++ b/modules/mono/utils/path_utils.h @@ -31,24 +31,32 @@ #ifndef PATH_UTILS_H #define PATH_UTILS_H +#include "core/string_builder.h" #include "core/ustring.h" -_FORCE_INLINE_ String path_join(const String &e1, const String &e2) { - return e1.plus_file(e2); -} +namespace path { -_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3) { - return e1.plus_file(e2).plus_file(e3); -} +String join(const String &p_a, const String &p_b); +String join(const String &p_a, const String &p_b, const String &p_c); +String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d); -_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3, const String &e4) { - return e1.plus_file(e2).plus_file(e3).plus_file(e4); -} +String find_executable(const String &p_name); -String path_which(const String &p_name); +/// Returns a normalized absolute path to the current working directory +String cwd(); -void fix_path(const String &p_path, String &r_out); +/** + * Obtains a normalized absolute path to p_path. Symbolic links are + * not resolved. The path p_path might not exist in the file system. + */ +String abspath(const String &p_path); -bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path); +/** + * Obtains a normalized path to p_path with symbolic links resolved. + * The resulting path might be either a relative or an absolute path. + */ +String realpath(const String &p_path); + +} // namespace path #endif // PATH_UTILS_H diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index 877122985d..2b014c2a45 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -44,7 +44,7 @@ int sfind(const String &p_text, int p_from) { int src_len = 2; int len = p_text.length(); - if (src_len == 0 || len == 0) + if (len == 0) return -1; const CharType *src = p_text.c_str(); diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index 4826b6cd2a..4b59a380f5 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -20,7 +20,7 @@ <member name="height" type="int" setter="set_height" getter="get_height" default="512"> Height of the generated texture. </member> - <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise" default="null"> + <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise"> The [OpenSimplexNoise] instance used to generate the noise. </member> <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false"> diff --git a/modules/opus/audio_stream_opus.cpp b/modules/opus/audio_stream_opus.cpp index 70d0f770d8..615081d818 100644 --- a/modules/opus/audio_stream_opus.cpp +++ b/modules/opus/audio_stream_opus.cpp @@ -280,7 +280,7 @@ int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) { int todo = p_frames; - if (todo == 0 || todo < MIN_MIX) { + if (todo < MIN_MIX) { break; } diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 8f6ffcc83f..8b1f21d95d 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -153,7 +153,7 @@ RES ResourceFormatPVR::load(const String &p_path, const String &p_original_path, ERR_FAIL_V(RES()); } - w = PoolVector<uint8_t>::Write(); + w.release(); int tex_flags = Texture::FLAG_FILTER | Texture::FLAG_REPEAT; @@ -655,8 +655,8 @@ static void _pvrtc_decompress(Image *p_img) { decompress_pvrtc((PVRTCBlock *)r.ptr(), _2bit, p_img->get_width(), p_img->get_height(), 0, (unsigned char *)w.ptr()); - w = PoolVector<uint8_t>::Write(); - r = PoolVector<uint8_t>::Read(); + w.release(); + r.release(); bool make_mipmaps = p_img->has_mipmaps(); p_img->create(p_img->get_width(), p_img->get_height(), false, Image::FORMAT_RGBA8, newdata); diff --git a/modules/recast/register_types.cpp b/modules/recast/register_types.cpp index 247d7f6144..44129fbb61 100644 --- a/modules/recast/register_types.cpp +++ b/modules/recast/register_types.cpp @@ -40,7 +40,14 @@ void register_recast_types() { #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); _nav_mesh_generator = memnew(EditorNavigationMeshGenerator); + + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + ClassDB::register_class<EditorNavigationMeshGenerator>(); + + ClassDB::set_current_api(prev_api); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", EditorNavigationMeshGenerator::get_singleton())); #endif } diff --git a/modules/regex/SCsub b/modules/regex/SCsub index acbe4a5a01..1be5af02a5 100644 --- a/modules/regex/SCsub +++ b/modules/regex/SCsub @@ -33,6 +33,7 @@ if env['builtin_pcre2']: "pcre2_newline.c", "pcre2_ord2utf.c", "pcre2_pattern_info.c", + "pcre2_script_run.c", "pcre2_serialize.c", "pcre2_string_utils.c", "pcre2_study.c", diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml index e279607d13..6dec9fc516 100644 --- a/modules/regex/doc_classes/RegExMatch.xml +++ b/modules/regex/doc_classes/RegExMatch.xml @@ -48,9 +48,7 @@ </method> </methods> <members> - <member name="names" type="Dictionary" setter="" getter="get_names" default="{ - -}"> + <member name="names" type="Dictionary" setter="" getter="get_names" default="{}"> A dictionary of named groups and its corresponding group number. Only groups with that were matched are included. If multiple groups have the same name, that name would refer to the first matching one. </member> <member name="strings" type="Array" setter="" getter="get_strings" default="[ ]"> diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp index 4f38357aa1..64f4c169cb 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_compress_squish.cpp @@ -198,8 +198,8 @@ void image_compress_squish(Image *p_image, float p_lossy_quality, Image::Compres h = MAX(h / 2, 1); } - rb = PoolVector<uint8_t>::Read(); - wb = PoolVector<uint8_t>::Write(); + rb.release(); + wb.release(); p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); } diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index b5f4718c72..0922471500 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -188,7 +188,7 @@ void AudioStreamOGGVorbis::set_data(const PoolVector<uint8_t> &p_data) { ogg_stream = stb_vorbis_open_memory((const unsigned char *)src_datar.ptr(), src_data_len, &error, &ogg_alloc); if (!ogg_stream && error == VORBIS_outofmem) { - w = PoolVector<char>::Write(); + w.release(); alloc_try *= 2; } else { diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index e36844a1bc..b0cd648734 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -123,7 +123,7 @@ Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const PoolVector<uint8_t rasterizer.rasterize(svg_image, 0, 0, p_scale * upscale, (unsigned char *)dw.ptr(), w, h, w * 4); - dw = PoolVector<uint8_t>::Write(); + dw.release(); p_image->create(w, h, false, Image::FORMAT_RGBA8, dst_image); if (upsample) p_image->shrink_x2(); diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index a3c0f5ded7..6ee408d472 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -199,7 +199,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } } - image_data_w = PoolVector<uint8_t>::Write(); + image_data_w.release(); p_image->create(width, height, 0, Image::FORMAT_RGBA8, image_data); diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index a9340b1498..74a584821a 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -235,7 +235,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f p_image->create(exr_image.width, exr_image.height, false, format, imgdata); - w = PoolVector<uint8_t>::Write(); + w.release(); FreeEXRHeader(&exr_header); FreeEXRImage(&exr_image); diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml index 05ed0ad1e5..b3b39691c9 100644 --- a/modules/visual_script/doc_classes/VisualScriptPreload.xml +++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml @@ -15,7 +15,7 @@ <methods> </methods> <members> - <member name="resource" type="Resource" setter="set_preload" getter="get_preload" default="null"> + <member name="resource" type="Resource" setter="set_preload" getter="get_preload"> The [Resource] to load. </member> </members> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index df5bb9ca2e..b816e37936 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1487,7 +1487,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p Variant **output_args = (Variant **)(input_args + max_input_args); int flow_max = f->flow_stack_size; int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)NULL; - int *pass_stack = flow_stack + flow_max; + int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)NULL; String error_str; @@ -1905,7 +1905,7 @@ Variant VisualScriptInstance::call(const StringName &p_method, const Variant **p Variant **output_args = (Variant **)(input_args + max_input_args); int flow_max = f->flow_stack_size; int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)NULL; - int *pass_stack = flow_stack + flow_max; + int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)NULL; for (int i = 0; i < f->node_count; i++) { sequence_bits[i] = false; //all starts as false diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 75b79f8929..6c9c6b0fc8 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -104,6 +104,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "bytes2var", "color_named", "smoothstep", + "posmod", }; VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) { @@ -192,6 +193,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case MATH_ATAN2: case MATH_FMOD: case MATH_FPOSMOD: + case MATH_POSMOD: case MATH_POW: case MATH_EASE: case MATH_STEPIFY: @@ -261,7 +263,16 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const case MATH_ASIN: case MATH_ACOS: case MATH_ATAN: - case MATH_SQRT: { + case MATH_SQRT: + case MATH_FLOOR: + case MATH_CEIL: + case MATH_ROUND: + case MATH_ABS: + case MATH_SIGN: + case MATH_LOG: + case MATH_EXP: + case MATH_ISNAN: + case MATH_ISINF: { return PropertyInfo(Variant::REAL, "s"); } break; case MATH_ATAN2: { @@ -271,32 +282,25 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::REAL, "x"); } break; case MATH_FMOD: - case MATH_FPOSMOD: { + case MATH_FPOSMOD: + case LOGIC_MAX: + case LOGIC_MIN: { if (p_idx == 0) - return PropertyInfo(Variant::REAL, "x"); + return PropertyInfo(Variant::REAL, "a"); else - return PropertyInfo(Variant::REAL, "y"); + return PropertyInfo(Variant::REAL, "b"); } break; - case MATH_FLOOR: - case MATH_CEIL: - case MATH_ROUND: - case MATH_ABS: - case MATH_SIGN: { - return PropertyInfo(Variant::REAL, "s"); - + case MATH_POSMOD: { + if (p_idx == 0) + return PropertyInfo(Variant::INT, "a"); + else + return PropertyInfo(Variant::INT, "b"); } break; - case MATH_POW: { if (p_idx == 0) - return PropertyInfo(Variant::REAL, "x"); + return PropertyInfo(Variant::REAL, "base"); else - return PropertyInfo(Variant::REAL, "y"); - } break; - case MATH_LOG: - case MATH_EXP: - case MATH_ISNAN: - case MATH_ISINF: { - return PropertyInfo(Variant::REAL, "s"); + return PropertyInfo(Variant::REAL, "exp"); } break; case MATH_EASE: { if (p_idx == 0) @@ -313,14 +317,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const else return PropertyInfo(Variant::REAL, "steps"); } break; - case MATH_LERP: { - if (p_idx == 0) - return PropertyInfo(Variant::REAL, "from"); - else if (p_idx == 1) - return PropertyInfo(Variant::REAL, "to"); - else - return PropertyInfo(Variant::REAL, "weight"); - } break; + case MATH_LERP: case MATH_INVERSE_LERP: { if (p_idx == 0) return PropertyInfo(Variant::REAL, "from"); @@ -365,12 +362,8 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const else return PropertyInfo(Variant::REAL, "step"); } break; - case MATH_RANDOMIZE: { - - } break; - case MATH_RAND: { - - } break; + case MATH_RANDOMIZE: + case MATH_RAND: case MATH_RANDF: { } break; @@ -380,9 +373,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const else return PropertyInfo(Variant::REAL, "to"); } break; - case MATH_SEED: { - return PropertyInfo(Variant::INT, "seed"); - } break; + case MATH_SEED: case MATH_RANDSEED: { return PropertyInfo(Variant::INT, "seed"); } break; @@ -418,26 +409,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const else return PropertyInfo(Variant::INT, "max"); } break; - case MATH_WRAPF: { - if (p_idx == 0) - return PropertyInfo(Variant::REAL, "value"); - else if (p_idx == 1) - return PropertyInfo(Variant::REAL, "min"); - else - return PropertyInfo(Variant::REAL, "max"); - } break; - case LOGIC_MAX: { - if (p_idx == 0) - return PropertyInfo(Variant::REAL, "a"); - else - return PropertyInfo(Variant::REAL, "b"); - } break; - case LOGIC_MIN: { - if (p_idx == 0) - return PropertyInfo(Variant::REAL, "a"); - else - return PropertyInfo(Variant::REAL, "b"); - } break; + case MATH_WRAPF: case LOGIC_CLAMP: { if (p_idx == 0) return PropertyInfo(Variant::REAL, "value"); @@ -450,20 +422,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::INT, "value"); } break; case OBJ_WEAKREF: { - return PropertyInfo(Variant::OBJECT, "source"); - } break; case FUNC_FUNCREF: { - if (p_idx == 0) return PropertyInfo(Variant::OBJECT, "instance"); else return PropertyInfo(Variant::STRING, "funcname"); - } break; case TYPE_CONVERT: { - if (p_idx == 0) return PropertyInfo(Variant::NIL, "what"); else @@ -471,45 +438,24 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const } break; case TYPE_OF: { return PropertyInfo(Variant::NIL, "what"); - } break; case TYPE_EXISTS: { - return PropertyInfo(Variant::STRING, "type"); - } break; case TEXT_CHAR: { - return PropertyInfo(Variant::INT, "ascii"); - - } break; - case TEXT_STR: { - - return PropertyInfo(Variant::NIL, "value"); - - } break; - case TEXT_PRINT: { - - return PropertyInfo(Variant::NIL, "value"); - - } break; - case TEXT_PRINTERR: { - return PropertyInfo(Variant::NIL, "value"); - } break; + case TEXT_STR: + case TEXT_PRINT: + case TEXT_PRINTERR: case TEXT_PRINTRAW: { - return PropertyInfo(Variant::NIL, "value"); - - } break; - case VAR_TO_STR: { - return PropertyInfo(Variant::NIL, "var"); - } break; case STR_TO_VAR: { return PropertyInfo(Variant::STRING, "string"); } break; + case VAR_TO_STR: case VAR_TO_BYTES: { if (p_idx == 0) return PropertyInfo(Variant::NIL, "var"); @@ -525,12 +471,10 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::BOOL, "allow_objects"); } break; case COLORN: { - if (p_idx == 0) return PropertyInfo(Variant::STRING, "name"); else return PropertyInfo(Variant::REAL, "alpha"); - } break; case FUNC_MAX: { } @@ -561,6 +505,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case MATH_CEIL: { t = Variant::REAL; } break; + case MATH_POSMOD: case MATH_ROUND: { t = Variant::INT; } break; @@ -806,6 +751,12 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(1); *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]); } break; + case VisualScriptBuiltinFunc::MATH_POSMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]); + } break; case VisualScriptBuiltinFunc::MATH_FLOOR: { VALIDATE_ARG_NUM(0); @@ -1365,6 +1316,7 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_SQRT); BIND_ENUM_CONSTANT(MATH_FMOD); BIND_ENUM_CONSTANT(MATH_FPOSMOD); + BIND_ENUM_CONSTANT(MATH_POSMOD); BIND_ENUM_CONSTANT(MATH_FLOOR); BIND_ENUM_CONSTANT(MATH_CEIL); BIND_ENUM_CONSTANT(MATH_ROUND); @@ -1454,6 +1406,7 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/posmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POSMOD>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/round", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index f009f49b5b..7821e0eb2d 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -104,6 +104,7 @@ public: BYTES_TO_VAR, COLORN, MATH_SMOOTHSTEP, + MATH_POSMOD, FUNC_MAX }; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 4579644d49..31d5e4665a 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -341,74 +341,74 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { Color color; if (dark_theme) switch (p_type) { - case Variant::NIL: color = Color::html("#69ecbd"); break; - - case Variant::BOOL: color = Color::html("#8da6f0"); break; - case Variant::INT: color = Color::html("#7dc6ef"); break; - case Variant::REAL: color = Color::html("#61daf4"); break; - case Variant::STRING: color = Color::html("#6ba7ec"); break; - - case Variant::VECTOR2: color = Color::html("#bd91f1"); break; - case Variant::RECT2: color = Color::html("#f191a5"); break; - case Variant::VECTOR3: color = Color::html("#d67dee"); break; - case Variant::TRANSFORM2D: color = Color::html("#c4ec69"); break; - case Variant::PLANE: color = Color::html("#f77070"); break; - case Variant::QUAT: color = Color::html("#ec69a3"); break; - case Variant::AABB: color = Color::html("#ee7991"); break; - case Variant::BASIS: color = Color::html("#e3ec69"); break; - case Variant::TRANSFORM: color = Color::html("#f6a86e"); break; - - case Variant::COLOR: color = Color::html("#9dff70"); break; - case Variant::NODE_PATH: color = Color::html("#6993ec"); break; - case Variant::_RID: color = Color::html("#69ec9a"); break; - case Variant::OBJECT: color = Color::html("#79f3e8"); break; - case Variant::DICTIONARY: color = Color::html("#77edb1"); break; - - case Variant::ARRAY: color = Color::html("#e0e0e0"); break; - case Variant::POOL_BYTE_ARRAY: color = Color::html("#aaf4c8"); break; - case Variant::POOL_INT_ARRAY: color = Color::html("#afdcf5"); break; - case Variant::POOL_REAL_ARRAY: color = Color::html("#97e7f8"); break; - case Variant::POOL_STRING_ARRAY: color = Color::html("#9dc4f2"); break; - case Variant::POOL_VECTOR2_ARRAY: color = Color::html("#d1b3f5"); break; - case Variant::POOL_VECTOR3_ARRAY: color = Color::html("#df9bf2"); break; - case Variant::POOL_COLOR_ARRAY: color = Color::html("#e9ff97"); break; + case Variant::NIL: color = Color(0.41, 0.93, 0.74); break; + + case Variant::BOOL: color = Color(0.55, 0.65, 0.94); break; + case Variant::INT: color = Color(0.49, 0.78, 0.94); break; + case Variant::REAL: color = Color(0.38, 0.85, 0.96); break; + case Variant::STRING: color = Color(0.42, 0.65, 0.93); break; + + case Variant::VECTOR2: color = Color(0.74, 0.57, 0.95); break; + case Variant::RECT2: color = Color(0.95, 0.57, 0.65); break; + case Variant::VECTOR3: color = Color(0.84, 0.49, 0.93); break; + case Variant::TRANSFORM2D: color = Color(0.77, 0.93, 0.41); break; + case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; + case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break; + case Variant::AABB: color = Color(0.93, 0.47, 0.57); break; + case Variant::BASIS: color = Color(0.89, 0.93, 0.41); break; + case Variant::TRANSFORM: color = Color(0.96, 0.66, 0.43); break; + + case Variant::COLOR: color = Color(0.62, 1.0, 0.44); break; + case Variant::NODE_PATH: color = Color(0.41, 0.58, 0.93); break; + case Variant::_RID: color = Color(0.41, 0.93, 0.6); break; + case Variant::OBJECT: color = Color(0.47, 0.95, 0.91); break; + case Variant::DICTIONARY: color = Color(0.47, 0.93, 0.69); break; + + case Variant::ARRAY: color = Color(0.88, 0.88, 0.88); break; + case Variant::POOL_BYTE_ARRAY: color = Color(0.67, 0.96, 0.78); break; + case Variant::POOL_INT_ARRAY: color = Color(0.69, 0.86, 0.96); break; + case Variant::POOL_REAL_ARRAY: color = Color(0.59, 0.91, 0.97); break; + case Variant::POOL_STRING_ARRAY: color = Color(0.62, 0.77, 0.95); break; + case Variant::POOL_VECTOR2_ARRAY: color = Color(0.82, 0.7, 0.96); break; + case Variant::POOL_VECTOR3_ARRAY: color = Color(0.87, 0.61, 0.95); break; + case Variant::POOL_COLOR_ARRAY: color = Color(0.91, 1.0, 0.59); break; default: color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7); } else switch (p_type) { - case Variant::NIL: color = Color::html("#25e3a0"); break; - - case Variant::BOOL: color = Color::html("#6d8eeb"); break; - case Variant::INT: color = Color::html("#4fb2e9"); break; - case Variant::REAL: color = Color::html("#27ccf0"); break; - case Variant::STRING: color = Color::html("#4690e7"); break; - - case Variant::VECTOR2: color = Color::html("#ad76ee"); break; - case Variant::RECT2: color = Color::html("#ee758e"); break; - case Variant::VECTOR3: color = Color::html("#dc6aed"); break; - case Variant::TRANSFORM2D: color = Color::html("#96ce1a"); break; - case Variant::PLANE: color = Color::html("#f77070"); break; - case Variant::QUAT: color = Color::html("#ec69a3"); break; - case Variant::AABB: color = Color::html("#ee7991"); break; - case Variant::BASIS: color = Color::html("#b2bb19"); break; - case Variant::TRANSFORM: color = Color::html("#f49047"); break; - - case Variant::COLOR: color = Color::html("#3cbf00"); break; - case Variant::NODE_PATH: color = Color::html("#6993ec"); break; - case Variant::_RID: color = Color::html("#2ce573"); break; - case Variant::OBJECT: color = Color::html("#12d5c3"); break; - case Variant::DICTIONARY: color = Color::html("#57e99f"); break; - - case Variant::ARRAY: color = Color::html("#737373"); break; - case Variant::POOL_BYTE_ARRAY: color = Color::html("#61ea98"); break; - case Variant::POOL_INT_ARRAY: color = Color::html("#61baeb"); break; - case Variant::POOL_REAL_ARRAY: color = Color::html("#40d3f2"); break; - case Variant::POOL_STRING_ARRAY: color = Color::html("#609fea"); break; - case Variant::POOL_VECTOR2_ARRAY: color = Color::html("#9d5dea"); break; - case Variant::POOL_VECTOR3_ARRAY: color = Color::html("#ca5aea"); break; - case Variant::POOL_COLOR_ARRAY: color = Color::html("#92ba00"); break; + case Variant::NIL: color = Color(0.15, 0.89, 0.63); break; + + case Variant::BOOL: color = Color(0.43, 0.56, 0.92); break; + case Variant::INT: color = Color(0.31, 0.7, 0.91); break; + case Variant::REAL: color = Color(0.15, 0.8, 0.94); break; + case Variant::STRING: color = Color(0.27, 0.56, 0.91); break; + + case Variant::VECTOR2: color = Color(0.68, 0.46, 0.93); break; + case Variant::RECT2: color = Color(0.93, 0.46, 0.56); break; + case Variant::VECTOR3: color = Color(0.86, 0.42, 0.93); break; + case Variant::TRANSFORM2D: color = Color(0.59, 0.81, 0.1); break; + case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; + case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break; + case Variant::AABB: color = Color(0.93, 0.47, 0.57); break; + case Variant::BASIS: color = Color(0.7, 0.73, 0.1); break; + case Variant::TRANSFORM: color = Color(0.96, 0.56, 0.28); break; + + case Variant::COLOR: color = Color(0.24, 0.75, 0.0); break; + case Variant::NODE_PATH: color = Color(0.41, 0.58, 0.93); break; + case Variant::_RID: color = Color(0.17, 0.9, 0.45); break; + case Variant::OBJECT: color = Color(0.07, 0.84, 0.76); break; + case Variant::DICTIONARY: color = Color(0.34, 0.91, 0.62); break; + + case Variant::ARRAY: color = Color(0.45, 0.45, 0.45); break; + case Variant::POOL_BYTE_ARRAY: color = Color(0.38, 0.92, 0.6); break; + case Variant::POOL_INT_ARRAY: color = Color(0.38, 0.73, 0.92); break; + case Variant::POOL_REAL_ARRAY: color = Color(0.25, 0.83, 0.95); break; + case Variant::POOL_STRING_ARRAY: color = Color(0.38, 0.62, 0.92); break; + case Variant::POOL_VECTOR2_ARRAY: color = Color(0.62, 0.36, 0.92); break; + case Variant::POOL_VECTOR3_ARRAY: color = Color(0.79, 0.35, 0.92); break; + case Variant::POOL_COLOR_ARRAY: color = Color(0.57, 0.73, 0.0); break; default: color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3); @@ -3054,19 +3054,19 @@ void VisualScriptEditor::_notification(int p_what) { List<Pair<String, Color> > colors; if (dark_theme) { - colors.push_back(Pair<String, Color>("flow_control", Color::html("#f4f4f4"))); - colors.push_back(Pair<String, Color>("functions", Color::html("#f58581"))); - colors.push_back(Pair<String, Color>("data", Color::html("#80f6cf"))); - colors.push_back(Pair<String, Color>("operators", Color::html("#ab97df"))); - colors.push_back(Pair<String, Color>("custom", Color::html("#80bbf6"))); - colors.push_back(Pair<String, Color>("constants", Color::html("#f680b0"))); + colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96))); + colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51))); + colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81))); + colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87))); + colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96))); + colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69))); } else { - colors.push_back(Pair<String, Color>("flow_control", Color::html("#424242"))); - colors.push_back(Pair<String, Color>("functions", Color::html("#f26661"))); - colors.push_back(Pair<String, Color>("data", Color::html("#13bb83"))); - colors.push_back(Pair<String, Color>("operators", Color::html("#8265d0"))); - colors.push_back(Pair<String, Color>("custom", Color::html("#4ea0f2"))); - colors.push_back(Pair<String, Color>("constants", Color::html("#f02f7d"))); + colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26))); + colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38))); + colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51))); + colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82))); + colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95))); + colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49))); } for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) { diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index f8cb6cfa3c..c330fa1bc0 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -570,7 +570,6 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const Node *bnode = _get_base_node(); if (bnode) { property.hint_string = bnode->get_path(); //convert to loong string - } else { } } } @@ -1027,7 +1026,6 @@ void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const { } PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const { - if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) { if (p_idx == 0) { PropertyInfo pi; @@ -1035,8 +1033,16 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); _adjust_input_index(pi); return pi; - } else { - p_idx--; + } + } + + List<PropertyInfo> props; + ClassDB::get_property_list(_get_base_type(), &props, true); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (E->get().name == property) { + PropertyInfo pinfo = PropertyInfo(E->get().type, "value", PROPERTY_HINT_TYPE_STRING, E->get().hint_string); + _adjust_input_index(pinfo); + return pinfo; } } @@ -1050,6 +1056,13 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons if (call_mode == CALL_MODE_BASIC_TYPE) { return PropertyInfo(basic_type, "out"); } else if (call_mode == CALL_MODE_INSTANCE) { + List<PropertyInfo> props; + ClassDB::get_property_list(_get_base_type(), &props, true); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (E->get().name == property) { + return PropertyInfo(E->get().type, "pass", PROPERTY_HINT_TYPE_STRING, E->get().hint_string); + } + } return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); } else { return PropertyInfo(); @@ -1352,7 +1365,6 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { Node *bnode = _get_base_node(); if (bnode) { property.hint_string = bnode->get_path(); //convert to loong string - } else { } } } @@ -1794,22 +1806,18 @@ PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type); pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower()); return pi; - } else { - p_idx--; } } return PropertyInfo(); } PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const { - - if (index != StringName()) { - - Variant v; - Variant::CallError ce; - v = Variant::construct(type_cache, NULL, 0, ce); - Variant i = v.get(index); - return PropertyInfo(i.get_type(), "value." + String(index)); + List<PropertyInfo> props; + ClassDB::get_property_list(_get_base_type(), &props, true); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (E->get().name == property) { + return PropertyInfo(E->get().type, "value." + String(index)); + } } return PropertyInfo(type_cache, "value"); @@ -2073,7 +2081,6 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { Node *bnode = _get_base_node(); if (bnode) { property.hint_string = bnode->get_path(); //convert to loong string - } else { } } } diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 962560cc96..ebd0f0b3cb 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -431,7 +431,6 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { Node *bnode = _get_base_node(); if (bnode) { property.hint_string = bnode->get_path(); //convert to loong string - } else { } } } diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index e652abbe6a..2f4a45f108 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -103,7 +103,7 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) { int todo = p_frames; - if (todo == 0 || todo < MIN_MIX) { + if (todo < MIN_MIX) { break; } diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 928a0dcbd3..630c15f140 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -71,7 +71,7 @@ static PoolVector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_q w[3] = 'P'; copymem(&w[4], dst_buff, dst_size); free(dst_buff); - w = PoolVector<uint8_t>::Write(); + w.release(); return dst; } @@ -110,7 +110,7 @@ static Ref<Image> _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) { //ERR_EXPLAIN("Error decoding webp! - "+p_file); ERR_FAIL_COND_V(errdec, Ref<Image>()); - dst_w = PoolVector<uint8_t>::Write(); + dst_w.release(); Ref<Image> img = memnew(Image(features.width, features.height, 0, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image)); return img; @@ -137,7 +137,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p } else { errdec = WebPDecodeRGBInto(p_buffer, p_buffer_len, dst_w.ptr(), datasize, 3 * features.width) == NULL; } - dst_w = PoolVector<uint8_t>::Write(); + dst_w.release(); //ERR_EXPLAIN("Error decoding webp!"); ERR_FAIL_COND_V(errdec, ERR_FILE_CORRUPT); @@ -171,8 +171,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc Error err = webp_load_image_from_buffer(p_image.ptr(), w.ptr(), src_image_len); - w = PoolVector<uint8_t>::Write(); - return err; } diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 23cbf916eb..e24cb850ec 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -191,7 +191,7 @@ void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_ty p_peer->put_packet(&(message.read()[0]), message.size()); } -PoolVector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) { +PoolVector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) { PoolVector<uint8_t> out; out.resize(PROTO_SIZE + p_data_size); diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 7fd97a6595..e3ab0784ab 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -41,7 +41,7 @@ class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer { GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer); private: - PoolVector<uint8_t> _make_pkt(uint32_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); + PoolVector<uint8_t> _make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); void _store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size); Error _server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size); diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index b2d865a58f..86374e8f80 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -92,6 +92,7 @@ void WSLClient::_do_handshake() { data->id = 1; _peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size); _on_connect(protocol); + break; } _resp_pos += 1; } diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index 1e140a716f..0d09a4d74e 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -42,7 +42,7 @@ WSLServer::PendingPeer::PendingPeer() { memset(req_buf, 0, sizeof(req_buf)); } -bool WSLServer::PendingPeer::_parse_request(String &r_key) { +bool WSLServer::PendingPeer::_parse_request(const PoolStringArray p_protocols) { Vector<String> psa = String((char *)req_buf).split("\r\n"); int len = psa.size(); if (len < 4) { @@ -87,11 +87,29 @@ bool WSLServer::PendingPeer::_parse_request(String &r_key) { _WLS_CHECK_EX("connection"); #undef _WLS_CHECK_EX #undef _WLS_CHECK - r_key = headers["sec-websocket-key"]; + key = headers["sec-websocket-key"]; + if (headers.has("sec-websocket-protocol")) { + Vector<String> protos = headers["sec-websocket-protocol"].split(","); + for (int i = 0; i < protos.size(); i++) { + // Check if we have the given protocol + for (int j = 0; j < p_protocols.size(); j++) { + if (protos[i] != p_protocols[j]) + continue; + protocol = protos[i]; + break; + } + // Found a protocol + if (protocol != "") + break; + } + if (protocol == "") // Invalid protocol(s) requested + return false; + } else if (p_protocols.size() > 0) // No protocol requested, but we need one + return false; return true; } -Error WSLServer::PendingPeer::do_handshake() { +Error WSLServer::PendingPeer::do_handshake(PoolStringArray p_protocols) { if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT) return ERR_TIMEOUT; if (!has_request) { @@ -111,13 +129,15 @@ Error WSLServer::PendingPeer::do_handshake() { int l = req_pos; if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') { r[l - 3] = '\0'; - if (!_parse_request(key)) { + if (!_parse_request(p_protocols)) { return FAILED; } String s = "HTTP/1.1 101 Switching Protocols\r\n"; s += "Upgrade: websocket\r\n"; s += "Connection: Upgrade\r\n"; s += "Sec-WebSocket-Accept: " + WSLPeer::compute_key_response(key) + "\r\n"; + if (protocol != "") + s += "Sec-WebSocket-Protocol: " + protocol + "\r\n"; s += "\r\n"; response = s.utf8(); has_request = true; @@ -143,6 +163,7 @@ Error WSLServer::listen(int p_port, PoolVector<String> p_protocols, bool gd_mp_a ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE); _is_multiplayer = gd_mp_api; + _protocols = p_protocols; _server->listen(p_port); return OK; @@ -167,7 +188,7 @@ void WSLServer::poll() { List<Ref<PendingPeer> > remove_peers; for (List<Ref<PendingPeer> >::Element *E = _pending.front(); E; E = E->next()) { Ref<PendingPeer> ppeer = E->get(); - Error err = ppeer->do_handshake(); + Error err = ppeer->do_handshake(_protocols); if (err == ERR_BUSY) { continue; } else if (err != OK) { @@ -188,7 +209,7 @@ void WSLServer::poll() { _peer_map[id] = ws_peer; remove_peers.push_back(ppeer); - _on_connect(id, ""); + _on_connect(id, ppeer->protocol); } for (List<Ref<PendingPeer> >::Element *E = remove_peers.front(); E; E = E->next()) { _pending.erase(E->get()); diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h index b0520bd731..2ceb941073 100644 --- a/modules/websocket/wsl_server.h +++ b/modules/websocket/wsl_server.h @@ -49,7 +49,7 @@ private: class PendingPeer : public Reference { private: - bool _parse_request(String &r_key); + bool _parse_request(const PoolStringArray p_protocols); public: Ref<StreamPeer> connection; @@ -58,13 +58,14 @@ private: uint8_t req_buf[WSL_MAX_HEADER_SIZE]; int req_pos; String key; + String protocol; bool has_request; CharString response; int response_sent; PendingPeer(); - Error do_handshake(); + Error do_handshake(const PoolStringArray p_protocols); }; int _in_buf_size; @@ -74,6 +75,7 @@ private: List<Ref<PendingPeer> > _pending; Ref<TCP_Server> _server; + PoolStringArray _protocols; public: Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets); diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index 903b57f017..c18aa04336 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -39,57 +39,37 @@ extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const flo bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) { //set up input mesh - xatlas::InputMesh input_mesh; - input_mesh.indexData = malloc(sizeof(int) * p_index_count); + xatlas::MeshDecl input_mesh; + input_mesh.indexData = p_indices; input_mesh.indexCount = p_index_count; - input_mesh.indexFormat = xatlas::IndexFormat::Float; //really xatlas? - input_mesh.faceMaterialData = (uint16_t *)malloc(sizeof(uint16_t) * p_index_count); - - for (int i = 0; i < p_index_count; i++) { - int *index = (int *)input_mesh.indexData; - index[i] = p_indices[i]; - } - for (int i = 0; i < p_index_count / 3; i++) { - uint16_t *mat_index = (uint16_t *)input_mesh.faceMaterialData; - mat_index[i] = p_face_materials[i]; - } + input_mesh.indexFormat = xatlas::IndexFormat::UInt32; input_mesh.vertexCount = p_vertex_count; - input_mesh.vertexPositionData = malloc(sizeof(float) * p_vertex_count * 3); + input_mesh.vertexPositionData = p_vertices; input_mesh.vertexPositionStride = sizeof(float) * 3; - input_mesh.vertexNormalData = malloc(sizeof(float) * p_vertex_count * 3); - input_mesh.vertexNormalStride = sizeof(float) * 3; - - //material is a better hint than this i guess? + input_mesh.vertexNormalData = p_normals; + input_mesh.vertexNormalStride = sizeof(uint32_t) * 3; input_mesh.vertexUvData = NULL; input_mesh.vertexUvStride = 0; - for (int i = 0; i < p_vertex_count * 3; i++) { - float *vertex_ptr = (float *)input_mesh.vertexPositionData; - float *normal_ptr = (float *)input_mesh.vertexNormalData; + xatlas::ChartOptions chart_options; + xatlas::PackOptions pack_options; - vertex_ptr[i] = p_vertices[i]; - normal_ptr[i] = p_normals[i]; - } - - xatlas::CharterOptions chart_options; - xatlas::PackerOptions pack_options; - - pack_options.method = xatlas::PackMethod::TexelArea; - pack_options.texelArea = 1.0 / p_texel_size; - pack_options.quality = 3; + pack_options.maxChartSize = 4096; + pack_options.bruteForce = true; + pack_options.texelsPerUnit = 1.0 / p_texel_size; xatlas::Atlas *atlas = xatlas::Create(); - printf("adding mesh..\n"); - xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh); - ERR_EXPLAINC(xatlas::StringForEnum(err.code)); - ERR_FAIL_COND_V(err.code != xatlas::AddMeshErrorCode::Success, false); + printf("Adding mesh..\n"); + xatlas::AddMeshError::Enum err = xatlas::AddMesh(atlas, input_mesh, 1); + ERR_EXPLAINC(xatlas::StringForEnum(err)); + ERR_FAIL_COND_V(err != xatlas::AddMeshError::Enum::Success, false); - printf("generate..\n"); - xatlas::Generate(atlas, chart_options, pack_options); + printf("Generate..\n"); + xatlas::Generate(atlas, chart_options, NULL, pack_options); - *r_size_hint_x = xatlas::GetWidth(atlas); - *r_size_hint_y = xatlas::GetHeight(atlas); + *r_size_hint_x = atlas->width; + *r_size_hint_y = atlas->height; float w = *r_size_hint_x; float h = *r_size_hint_y; @@ -98,39 +78,33 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver return false; //could not bake } - const xatlas::OutputMesh *const *output_meshes = xatlas::GetOutputMeshes(atlas); - - const xatlas::OutputMesh *output = output_meshes[0]; + const xatlas::Mesh &output = atlas->meshes[0]; - *r_vertex = (int *)malloc(sizeof(int) * output->vertexCount); - *r_uv = (float *)malloc(sizeof(float) * output->vertexCount * 2); - *r_index = (int *)malloc(sizeof(int) * output->indexCount); + *r_vertex = (int *)malloc(sizeof(int) * output.vertexCount); + *r_uv = (float *)malloc(sizeof(float) * output.vertexCount * 2); + *r_index = (int *)malloc(sizeof(int) * output.indexCount); float max_x = 0; float max_y = 0; - for (uint32_t i = 0; i < output->vertexCount; i++) { - (*r_vertex)[i] = output->vertexArray[i].xref; - (*r_uv)[i * 2 + 0] = output->vertexArray[i].uv[0] / w; - (*r_uv)[i * 2 + 1] = output->vertexArray[i].uv[1] / h; - max_x = MAX(max_x, output->vertexArray[i].uv[0]); - max_y = MAX(max_y, output->vertexArray[i].uv[1]); + for (uint32_t i = 0; i < output.vertexCount; i++) { + (*r_vertex)[i] = output.vertexArray[i].xref; + (*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w; + (*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h; + max_x = MAX(max_x, output.vertexArray[i].uv[0]); + max_y = MAX(max_y, output.vertexArray[i].uv[1]); } - printf("final texsize: %f,%f - max %f,%f\n", w, h, max_x, max_y); - *r_vertex_count = output->vertexCount; + printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y); + *r_vertex_count = output.vertexCount; - for (uint32_t i = 0; i < output->indexCount; i++) { - (*r_index)[i] = output->indexArray[i]; + for (uint32_t i = 0; i < output.indexCount; i++) { + (*r_index)[i] = output.indexArray[i]; } - *r_index_count = output->indexCount; + *r_index_count = output.indexCount; //xatlas::Destroy(atlas); - free((void *)input_mesh.indexData); - free((void *)input_mesh.vertexPositionData); - free((void *)input_mesh.vertexNormalData); - free((void *)input_mesh.faceMaterialData); - printf("done"); + printf("Done\n"); return true; } |