diff options
Diffstat (limited to 'modules')
164 files changed, 2070 insertions, 1480 deletions
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 760ee0846d..93533e1690 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -194,7 +194,7 @@ void CSGBrush::_regen_face_aabbs() { } } -void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces) { +void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_flip_faces) { faces.clear(); int vc = p_vertices.size(); @@ -208,10 +208,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< const bool *rs = p_smooth.ptr(); int mc = p_materials.size(); const Ref<Material> *rm = p_materials.ptr(); - int ic = p_invert_faces.size(); - const bool *ri = p_invert_faces.ptr(); + int ic = p_flip_faces.size(); + const bool *ri = p_flip_faces.ptr(); - Map<Ref<Material>, int> material_map; + HashMap<Ref<Material>, int> material_map; faces.resize(p_vertices.size() / 3); @@ -242,10 +242,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< if (mc == vc / 3) { Ref<Material> mat = rm[i]; if (mat.is_valid()) { - const Map<Ref<Material>, int>::Element *E = material_map.find(mat); + HashMap<Ref<Material>, int>::ConstIterator E = material_map.find(mat); if (E) { - f.material = E->get(); + f.material = E->value; } else { f.material = material_map.size(); material_map[mat] = f.material; @@ -1387,13 +1387,13 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face } // Ensure B has points either side of or in the plane of A. - int in_plane_count = 0, over_count = 0, under_count = 0; + int over_count = 0, under_count = 0; Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]); ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face."); for (int i = 0; i < 3; i++) { if (plane_a.has_point(vertices_b[i])) { - in_plane_count++; + // In plane. } else if (plane_a.is_point_over(vertices_b[i])) { over_count++; } else { @@ -1406,7 +1406,6 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face } // Ensure A has points either side of or in the plane of B. - in_plane_count = 0; over_count = 0; under_count = 0; Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]); @@ -1414,7 +1413,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face for (int i = 0; i < 3; i++) { if (plane_b.has_point(vertices_a[i])) { - in_plane_count++; + // In plane. } else if (plane_b.is_point_over(vertices_a[i])) { over_count++; } else { diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 9ff7b13a44..53a9e5d722 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -38,8 +38,8 @@ #include "core/math/vector3.h" #include "core/object/ref_counted.h" #include "core/templates/list.h" -#include "core/templates/map.h" #include "core/templates/oa_hash_map.h" +#include "core/templates/rb_map.h" #include "core/templates/vector.h" #include "scene/resources/material.h" @@ -139,8 +139,8 @@ struct CSGBrushOperation { Vector<Vector3> points; Vector<Face> faces; - Map<Ref<Material>, int> materials; - Map<Vector3, int> vertex_map; + HashMap<Ref<Material>, int> materials; + HashMap<Vector3, int> vertex_map; OAHashMap<VertexKey, int, VertexKeyHash> snap_cache; float vertex_snap = 0.0; @@ -184,8 +184,8 @@ struct CSGBrushOperation { }; struct Build2DFaceCollection { - Map<int, Build2DFaces> build2DFacesA; - Map<int, Build2DFaces> build2DFacesB; + HashMap<int, Build2DFaces> build2DFacesA; + HashMap<int, Build2DFaces> build2DFacesB; }; void update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 0a2427e4e6..25772bebbe 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -682,7 +682,7 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver int ic = invert.size(); bool *w = invert.ptrw(); for (int i = 0; i < ic; i++) { - w[i] = invert_faces; + w[i] = flip_faces; } } brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert); @@ -691,28 +691,28 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver } void CSGPrimitive3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces); - ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces); + ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &CSGPrimitive3D::set_flip_faces); + ClassDB::bind_method(D_METHOD("get_flip_faces"), &CSGPrimitive3D::get_flip_faces); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); } -void CSGPrimitive3D::set_invert_faces(bool p_invert) { - if (invert_faces == p_invert) { +void CSGPrimitive3D::set_flip_faces(bool p_invert) { + if (flip_faces == p_invert) { return; } - invert_faces = p_invert; + flip_faces = p_invert; _make_dirty(); } -bool CSGPrimitive3D::is_inverting_faces() { - return invert_faces; +bool CSGPrimitive3D::get_flip_faces() { + return flip_faces; } CSGPrimitive3D::CSGPrimitive3D() { - invert_faces = false; + flip_faces = false; } ///////////////////// @@ -921,7 +921,7 @@ CSGBrush *CSGSphere3D::_build_brush() { int face_count = rings * radial_segments * 2 - radial_segments * 2; - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1052,7 +1052,7 @@ void CSGSphere3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere3D::set_material); ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere3D::get_material); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); @@ -1125,7 +1125,7 @@ CSGBrush *CSGBox3D::_build_brush() { int face_count = 12; //it's a cube.. - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1225,7 +1225,7 @@ void CSGBox3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material); ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } @@ -1258,7 +1258,7 @@ CSGBrush *CSGCylinder3D::_build_brush() { int face_count = sides * (cone ? 1 : 2) + sides + (cone ? 0 : sides); - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1405,8 +1405,8 @@ void CSGCylinder3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); @@ -1503,7 +1503,7 @@ CSGBrush *CSGTorus3D::_build_brush() { int face_count = ring_sides * sides * 2; - bool invert_val = is_inverting_faces(); + bool invert_val = get_flip_faces(); Ref<Material> material = get_material(); Vector<Vector3> faces; @@ -1630,8 +1630,8 @@ void CSGTorus3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_inner_radius", "get_inner_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp,suffix:m"), "set_outer_radius", "get_outer_radius"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); @@ -1881,7 +1881,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { smoothw[face] = false; materialsw[face] = material; - invertw[face] = invert_faces; + invertw[face] = flip_faces; face++; } } @@ -1986,7 +1986,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { uvsw[face * 3 + 2] = u[2]; smoothw[face] = smooth_faces; - invertw[face] = invert_faces; + invertw[face] = flip_faces; materialsw[face] = material; face++; @@ -2001,7 +2001,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { uvsw[face * 3 + 2] = u[0]; smoothw[face] = smooth_faces; - invertw[face] = invert_faces; + invertw[face] = flip_faces; materialsw[face] = material; face++; @@ -2026,7 +2026,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { smoothw[face] = false; materialsw[face] = material; - invertw[face] = invert_faces; + invertw[face] = flip_faces; face++; } } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index b5d5f97cf3..0eaf5c3727 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -171,13 +171,13 @@ class CSGPrimitive3D : public CSGShape3D { GDCLASS(CSGPrimitive3D, CSGShape3D); protected: - bool invert_faces; + bool flip_faces; CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials); static void _bind_methods(); public: - void set_invert_faces(bool p_invert); - bool is_inverting_faces(); + void set_flip_faces(bool p_invert); + bool get_flip_faces(); CSGPrimitive3D(); }; diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml index 39f4fa320d..6ea413c991 100644 --- a/modules/csg/doc_classes/CSGPrimitive3D.xml +++ b/modules/csg/doc_classes/CSGPrimitive3D.xml @@ -11,8 +11,8 @@ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link> </tutorials> <members> - <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false"> - Invert the faces of the mesh. + <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false"> + If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn. </member> </members> </class> diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 4d972e46c6..6442ff71fc 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -349,9 +349,11 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { if (cs->is_root_shape()) { Array csg_meshes = cs->get_meshes(); - Ref<Mesh> csg_mesh = csg_meshes[1]; - if (csg_mesh.is_valid()) { - p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh()); + if (csg_meshes.size() == 2) { + Ref<Mesh> csg_mesh = csg_meshes[1]; + if (csg_mesh.is_valid()) { + p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh()); + } } } diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index e7b61169fb..18eca18e51 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -70,8 +70,8 @@ private: ConnectionStatus connection_status = CONNECTION_DISCONNECTED; - Map<int, Ref<ENetConnection>> hosts; - Map<int, Ref<ENetPacketPeer>> peers; + HashMap<int, Ref<ENetConnection>> hosts; + HashMap<int, Ref<ENetPacketPeer>> peers; struct Packet { ENetPacket *packet = nullptr; diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index d23c4b637c..4b2ea6faa5 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -49,6 +49,7 @@ if env["builtin_freetype"]: "src/psnames/psnames.c", "src/raster/raster.c", "src/sdf/sdf.c", + "src/svg/svg.c", "src/smooth/smooth.c", "src/truetype/truetype.c", "src/type1/type1.c", @@ -87,7 +88,7 @@ if env["builtin_freetype"]: # Also needed in main env for scene/ env.Prepend(CPPPATH=[thirdparty_dir + "/include"]) - env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG"]) + env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", "FT_CONFIG_OPTION_SYSTEM_ZLIB"]) if env["target"] == "debug": env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index d0926d317b..70151c4d21 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -184,27 +184,24 @@ <method name="range" qualifiers="vararg"> <return type="Array" /> <description> - Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]). - Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run. - [code]range()[/code] converts all arguments to [int] before processing. + Returns an array with the given range. [method range] can be called in three ways: + [code]range(n: int)[/code]: Starts from 0, increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The argument [code]n[/code] is [b]exclusive[/b]. + [code]range(b: int, n: int)[/code]: Starts from [code]b[/code], increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. + [code]range(b: int, n: int, s: int)[/code]: Starts from [code]b[/code], increases/decreases by steps of [code]s[/code], and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. The argument [code]s[/code] [b]can[/b] be negative, but not [code]0[/code]. If [code]s[/code] is [code]0[/code], an error message is printed. + [method range] converts all arguments to [int] before processing. + [b]Note:[/b] Returns an empty array if no value meets the value constraint (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]). + Examples: [codeblock] - print(range(4)) - print(range(2, 5)) - print(range(0, 6, 2)) - [/codeblock] - Output: - [codeblock] - [0, 1, 2, 3] - [2, 3, 4] - [0, 2, 4] + print(range(4)) # Prints [0, 1, 2, 3] + print(range(2, 5)) # Prints [2, 3, 4] + print(range(0, 6, 2)) # Prints [0, 2, 4] + print(range(4, 1, -1)) # Prints [4, 3, 2] [/codeblock] To iterate over an [Array] backwards, use: [codeblock] var array = [3, 6, 9] - var i := array.size() - 1 - while i >= 0: - print(array[i]) - i -= 1 + for i in range(array.size(), 0, -1): + print(array[i - 1]) [/codeblock] Output: [codeblock] diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index e3f0ddfc35..b86e9b386d 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -387,9 +387,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_member_variable = false; } - if (!in_node_path && in_region == -1 && str[j] == '$') { + if (!in_node_path && in_region == -1 && (str[j] == '$' || str[j] == '%')) { in_node_path = true; - } else if (in_region != -1 || (is_a_symbol && str[j] != '/')) { + } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { in_node_path = false; } @@ -510,9 +510,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { } /* Autoloads. */ - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.value(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { keywords[info.name] = usertype_color; } diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 1ae0d72896..92764e3891 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -45,7 +45,7 @@ private: bool line_only = false; }; Vector<ColorRegion> color_regions; - Map<int, int> color_region_cache; + HashMap<int, int> color_region_cache; HashMap<StringName, Color> keywords; HashMap<StringName, Color> member_keywords; diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index e7b40aa367..969a50f48c 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H #define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H -#include "core/templates/set.h" +#include "core/templates/hash_set.h" #include "editor/editor_translation_parser.h" #include "modules/gdscript/gdscript_parser.h" @@ -44,9 +44,9 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug // List of patterns used for extracting translation strings. StringName tr_func = "tr"; StringName trn_func = "tr_n"; - Set<StringName> assignment_patterns; - Set<StringName> first_arg_patterns; - Set<StringName> second_arg_patterns; + HashSet<StringName> assignment_patterns; + HashSet<StringName> first_arg_patterns; + HashSet<StringName> second_arg_patterns; // FileDialog patterns. StringName fd_add_filter = "add_filter"; StringName fd_set_filter = "set_filters"; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 1b4711804c..55a7e39dec 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -340,14 +340,14 @@ bool GDScript::has_method(const StringName &p_method) const { } MethodInfo GDScript::get_method_info(const StringName &p_method) const { - const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method); + HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method); if (!E) { return MethodInfo(); } - GDScriptFunction *func = E->get(); + GDScriptFunction *func = E->value; MethodInfo mi; - mi.name = E->key(); + mi.name = E->key; for (int i = 0; i < func->get_argument_count(); i++) { mi.arguments.push_back(func->get_argument_type(i)); } @@ -359,9 +359,9 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const { bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { #ifdef TOOLS_ENABLED - const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property); + HashMap<StringName, Variant>::ConstIterator E = member_default_values_cache.find(p_property); if (E) { - r_value = E->get(); + r_value = E->value; return true; } @@ -427,7 +427,7 @@ void GDScript::set_source_code(const String &p_code) { } #ifdef TOOLS_ENABLED -void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) { +void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) { if (base_cache.is_valid()) { base_cache->_update_exports_values(values, propnames); } @@ -759,13 +759,13 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc if ((changed || p_instance_to_update) && placeholders.size()) { //hm :( // update placeholders if any - Map<StringName, Variant> values; + HashMap<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); if (changed) { - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); + for (PlaceHolderScriptInstance *E : placeholders) { + E->update(propnames, values); } } else { p_instance_to_update->update(propnames, values); @@ -788,10 +788,10 @@ void GDScript::update_exports() { return; } - Set<ObjectID> copy = inheriters_cache; //might get modified + HashSet<ObjectID> copy = inheriters_cache; //might get modified - for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) { - Object *id = ObjectDB::get_instance(E->get()); + for (const ObjectID &E : copy) { + Object *id = ObjectDB::get_instance(E); GDScript *s = Object::cast_to<GDScript>(id); if (!s) { continue; @@ -929,7 +929,7 @@ ScriptLanguage *GDScript::get_language() const { return GDScriptLanguage::get_singleton(); } -void GDScript::get_constants(Map<StringName, Variant> *p_constants) { +void GDScript::get_constants(HashMap<StringName, Variant> *p_constants) { if (p_constants) { for (const KeyValue<StringName, Variant> &E : constants) { (*p_constants)[E.key] = E.value; @@ -937,10 +937,10 @@ void GDScript::get_constants(Map<StringName, Variant> *p_constants) { } } -void GDScript::get_members(Set<StringName> *p_members) { +void GDScript::get_members(HashSet<StringName> *p_members) { if (p_members) { - for (Set<StringName>::Element *E = members.front(); E; E = E->next()) { - p_members->insert(E->get()); + for (const StringName &E : members) { + p_members->insert(E); } } } @@ -952,11 +952,11 @@ const Vector<Multiplayer::RPCConfig> GDScript::get_rpc_methods() const { Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *top = this; while (top) { - Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method); + HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method); if (E) { - ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script."); + ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script."); - return E->get()->call(nullptr, p_args, p_argcount, r_error); + return E->value->call(nullptr, p_args, p_argcount, r_error); } top = top->_base; } @@ -971,17 +971,17 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const { const GDScript *top = this; while (top) { { - const Map<StringName, Variant>::Element *E = top->constants.find(p_name); + HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name); if (E) { - r_ret = E->get(); + r_ret = E->value; return true; } } { - const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name); + HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name); if (E) { - r_ret = E->get(); + r_ret = E->value; return true; } } @@ -1061,7 +1061,7 @@ Error GDScript::load_source_code(const String &p_path) { return OK; } -const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const { +const HashMap<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const { return member_functions; } @@ -1209,7 +1209,7 @@ void GDScript::_init_rpc_methods_properties() { } GDScript *cscript = this; - Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front(); + HashMap<StringName, Ref<GDScript>>::Iterator sub_E = subclasses.begin(); while (cscript) { // RPC Methods for (KeyValue<StringName, GDScriptFunction *> &E : cscript->member_functions) { @@ -1223,11 +1223,11 @@ void GDScript::_init_rpc_methods_properties() { } if (cscript != this) { - sub_E = sub_E->next(); + ++sub_E; } if (sub_E) { - cscript = sub_E->get().ptr(); + cscript = sub_E->value.ptr(); } else { cscript = nullptr; } @@ -1282,9 +1282,9 @@ GDScript::~GDScript() { bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { //member { - const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); + HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name); if (E) { - const GDScript::MemberInfo *member = &E->get(); + const GDScript::MemberInfo *member = &E->value; if (member->setter) { const Variant *val = &p_value; Callable::CallError err; @@ -1325,13 +1325,13 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { GDScript *sptr = script.ptr(); while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); + HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); if (E) { Variant name = p_name; const Variant *args[2] = { &name, &p_value }; Callable::CallError err; - Variant ret = E->get()->call(this, (const Variant **)args, 2, err); + Variant ret = E->value->call(this, (const Variant **)args, 2, err); if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { return true; } @@ -1346,16 +1346,16 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { const GDScript *sptr = script.ptr(); while (sptr) { { - const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name); + HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name); if (E) { - if (E->get().getter) { + if (E->value.getter) { Callable::CallError err; - r_ret = const_cast<GDScriptInstance *>(this)->callp(E->get().getter, nullptr, 0, err); + r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err); if (err.error == Callable::CallError::CALL_OK) { return true; } } - r_ret = members[E->get().index]; + r_ret = members[E->value.index]; return true; //index found } } @@ -1363,9 +1363,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { { const GDScript *sl = sptr; while (sl) { - const Map<StringName, Variant>::Element *E = sl->constants.find(p_name); + HashMap<StringName, Variant>::ConstIterator E = sl->constants.find(p_name); if (E) { - r_ret = E->get(); + r_ret = E->value; return true; //index found } sl = sl->_base; @@ -1376,9 +1376,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { // Signals. const GDScript *sl = sptr; while (sl) { - const Map<StringName, Vector<StringName>>::Element *E = sl->_signals.find(p_name); + HashMap<StringName, Vector<StringName>>::ConstIterator E = sl->_signals.find(p_name); if (E) { - r_ret = Signal(this->owner, E->key()); + r_ret = Signal(this->owner, E->key); return true; //index found } sl = sl->_base; @@ -1389,14 +1389,14 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { // Methods. const GDScript *sl = sptr; while (sl) { - const Map<StringName, GDScriptFunction *>::Element *E = sl->member_functions.find(p_name); + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sl->member_functions.find(p_name); if (E) { Multiplayer::RPCConfig config; config.name = p_name; if (sptr->rpc_functions.find(config) != -1) { - r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key()))); + r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key))); } else { - r_ret = Callable(this->owner, E->key()); + r_ret = Callable(this->owner, E->key); } return true; //index found } @@ -1405,13 +1405,13 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } { - const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); if (E) { Variant name = p_name; const Variant *args[1] = { &name }; Callable::CallError err; - Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err); + Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err); if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) { r_ret = ret; return true; @@ -1449,10 +1449,10 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const List<PropertyInfo> props; while (sptr) { - const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); if (E) { Callable::CallError err; - Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err); + Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err); if (err.error == Callable::CallError::CALL_OK) { ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries."); @@ -1525,7 +1525,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { bool GDScriptInstance::has_method(const StringName &p_method) const { const GDScript *sptr = script.ptr(); while (sptr) { - const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method); if (E) { return true; } @@ -1538,9 +1538,9 @@ bool GDScriptInstance::has_method(const StringName &p_method) const { Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method); + HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method); if (E) { - return E->get()->call(this, p_args, p_argcount, r_error); + return E->value->call(this, p_args, p_argcount, r_error); } sptr = sptr->_base; } @@ -1555,10 +1555,10 @@ void GDScriptInstance::notification(int p_notification) { GDScript *sptr = script.ptr(); while (sptr) { - Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); + HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); if (E) { Callable::CallError err; - E->get()->call(this, args, 1, err); + E->value->call(this, args, 1, err); if (err.error != Callable::CallError::CALL_OK) { //print error about notification call } @@ -1882,7 +1882,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //when someone asks you why dynamically typed languages are easier to write.... - Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> to_reload; + HashMap<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> to_reload; //as scripts are going to be reloaded, must proceed without locking here @@ -1895,11 +1895,11 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so continue; } - to_reload.insert(script, Map<ObjectID, List<Pair<StringName, Variant>>>()); + to_reload.insert(script, HashMap<ObjectID, List<Pair<StringName, Variant>>>()); if (!p_soft_reload) { //save state and remove script from instances - Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script]; + HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script]; while (script->instances.front()) { Object *obj = script->instances.front()->get(); @@ -1916,7 +1916,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so #ifdef TOOLS_ENABLED while (script->placeholders.size()) { - Object *obj = script->placeholders.front()->get()->get_owner(); + Object *obj = (*script->placeholders.begin())->get_owner(); //save instance info if (obj->get_script_instance()) { @@ -1926,7 +1926,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so obj->set_script(Variant()); } else { // no instance found. Let's remove it so we don't loop forever - script->placeholders.erase(script->placeholders.front()->get()); + script->placeholders.erase(*script->placeholders.begin()); } } @@ -1938,7 +1938,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so } } - for (KeyValue<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) { + for (KeyValue<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) { Ref<GDScript> scr = E.key; scr->reload(p_soft_reload); @@ -2232,9 +2232,13 @@ GDScriptLanguage::GDScriptLanguage() { GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { - String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); - bool default_enabled = !warning.begins_with("unsafe_"); - GLOBAL_DEF("debug/gdscript/warnings/" + warning, default_enabled); + GDScriptWarning::Code code = (GDScriptWarning::Code)i; + Variant default_enabled = GDScriptWarning::get_default_value(code); + String path = GDScriptWarning::get_settings_path_from_code(code); + GLOBAL_DEF(path, default_enabled); + + PropertyInfo property_info = GDScriptWarning::get_property_info(code); + ProjectSettings::get_singleton()->set_custom_property_info(path, property_info); } #endif // DEBUG_ENABLED } @@ -2277,13 +2281,13 @@ void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const } Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) { - Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name); + HashMap<String, ObjectID>::Iterator orphan_subclass_element = orphan_subclasses.find(p_qualified_name); if (!orphan_subclass_element) { return Ref<GDScript>(); } - ObjectID orphan_subclass = orphan_subclass_element->get(); + ObjectID orphan_subclass = orphan_subclass_element->value; Object *obj = ObjectDB::get_instance(orphan_subclass); - orphan_subclasses.erase(orphan_subclass_element); + orphan_subclasses.remove(orphan_subclass_element); if (!obj) { return Ref<GDScript>(); } @@ -2372,7 +2376,7 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const Ref<Resource } if (ScriptServer::is_reload_scripts_on_save_enabled()) { - GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false); + GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true); } return OK; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index a20f3b2fca..80f187a375 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -37,6 +37,7 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/script_language.h" +#include "core/templates/rb_set.h" #include "gdscript_function.h" class GDScriptNativeClass : public RefCounted { @@ -80,48 +81,48 @@ class GDScript : public Script { GDScript *_base = nullptr; //fast pointer access GDScript *_owner = nullptr; //for subclasses - Set<StringName> members; //members are just indices to the instantiated script. - Map<StringName, Variant> constants; - Map<StringName, GDScriptFunction *> member_functions; - Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. - Map<StringName, Ref<GDScript>> subclasses; - Map<StringName, Vector<StringName>> _signals; + HashSet<StringName> members; //members are just indices to the instantiated script. + HashMap<StringName, Variant> constants; + HashMap<StringName, GDScriptFunction *> member_functions; + HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. + HashMap<StringName, Ref<GDScript>> subclasses; + HashMap<StringName, Vector<StringName>> _signals; Vector<Multiplayer::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED - Map<StringName, int> member_lines; - Map<StringName, Variant> member_default_values; + HashMap<StringName, int> member_lines; + HashMap<StringName, Variant> member_default_values; List<PropertyInfo> members_cache; - Map<StringName, Variant> member_default_values_cache; + HashMap<StringName, Variant> member_default_values_cache; Ref<GDScript> base_cache; - Set<ObjectID> inheriters_cache; + HashSet<ObjectID> inheriters_cache; bool source_changed_cache = false; bool placeholder_fallback_enabled = false; - void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames); + void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames); DocData::ClassDoc doc; Vector<DocData::ClassDoc> docs; String doc_brief_description; String doc_description; Vector<DocData::TutorialDoc> doc_tutorials; - Map<String, String> doc_functions; - Map<String, String> doc_variables; - Map<String, String> doc_constants; - Map<String, String> doc_signals; - Map<String, DocData::EnumDoc> doc_enums; + HashMap<String, String> doc_functions; + HashMap<String, String> doc_variables; + HashMap<String, String> doc_constants; + HashMap<String, String> doc_signals; + HashMap<String, DocData::EnumDoc> doc_enums; void _clear_doc(); void _update_doc(); void _add_doc(const DocData::ClassDoc &p_inner_class); #endif - Map<StringName, PropertyInfo> member_info; + HashMap<StringName, PropertyInfo> member_info; GDScriptFunction *implicit_initializer = nullptr; GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate int subclass_count = 0; - Set<Object *> instances; + RBSet<Object *> instances; //exported members String source; String path; @@ -139,14 +140,14 @@ class GDScript : public Script { String _get_debug_path() const; #ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; + HashSet<PlaceHolderScriptInstance *> placeholders; //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; #endif #ifdef DEBUG_ENABLED - Map<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state; + HashMap<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state; #endif @@ -176,14 +177,14 @@ public: bool inherits_script(const Ref<Script> &p_script) const override; - const Map<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; } - const Map<StringName, Variant> &get_constants() const { return constants; } - const Set<StringName> &get_members() const { return members; } + const HashMap<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; } + const HashMap<StringName, Variant> &get_constants() const { return constants; } + const HashSet<StringName> &get_members() const { return members; } const GDScriptDataType &get_member_type(const StringName &p_member) const { CRASH_COND(!member_indices.has(p_member)); return member_indices[p_member].data_type; } - const Map<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; } + const HashMap<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; } const Ref<GDScriptNativeClass> &get_native() const { return native; } const String &get_script_class_name() const { return name; } @@ -193,8 +194,8 @@ public: bool is_tool() const override { return tool; } Ref<GDScript> get_base() const; - const Map<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; } - const Map<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only + const HashMap<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; } + const HashMap<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only StringName debug_get_member_by_index(int p_idx) const; Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -245,8 +246,8 @@ public: return -1; } - virtual void get_constants(Map<StringName, Variant> *p_constants) override; - virtual void get_members(Set<StringName> *p_members) override; + virtual void get_constants(HashMap<StringName, Variant> *p_constants) override; + virtual void get_members(HashSet<StringName> *p_members) override; virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; @@ -270,7 +271,7 @@ class GDScriptInstance : public ScriptInstance { Object *owner = nullptr; Ref<GDScript> script; #ifdef DEBUG_ENABLED - Map<StringName, int> member_indices_cache; //used only for hot script reloading + HashMap<StringName, int> member_indices_cache; //used only for hot script reloading #endif Vector<Variant> members; bool base_ref_counted; @@ -315,8 +316,8 @@ class GDScriptLanguage : public ScriptLanguage { Variant *_global_array = nullptr; Vector<Variant> global_array; - Map<StringName, int> globals; - Map<StringName, Variant> named_globals; + HashMap<StringName, int> globals; + HashMap<StringName, Variant> named_globals; struct CallLevel { Variant *stack = nullptr; @@ -348,7 +349,7 @@ class GDScriptLanguage : public ScriptLanguage { bool profiling; uint64_t script_frame_time; - Map<String, ObjectID> orphan_subclasses; + HashMap<String, ObjectID> orphan_subclasses; public: int calls; @@ -427,8 +428,8 @@ public: _FORCE_INLINE_ int get_global_array_size() const { return global_array.size(); } _FORCE_INLINE_ Variant *get_global_array() { return _global_array; } - _FORCE_INLINE_ const Map<StringName, int> &get_global_map() const { return globals; } - _FORCE_INLINE_ const Map<StringName, Variant> &get_named_globals_map() const { return named_globals; } + _FORCE_INLINE_ const HashMap<StringName, int> &get_global_map() const { return globals; } + _FORCE_INLINE_ const HashMap<StringName, Variant> &get_named_globals_map() const { return named_globals; } _FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; } @@ -449,7 +450,7 @@ public: virtual bool is_using_templates() override; virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; - virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override; virtual Script *create_script() const override; virtual bool has_named_classes() const override; virtual bool supports_builtin_mode() const override; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index d346264933..9fa518ca0b 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -898,7 +898,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { } #ifdef DEBUG_ENABLED - Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes; for (uint32_t ignored_warning : member.function->ignored_warnings) { parser->ignored_warning_codes.insert(ignored_warning); } @@ -947,7 +947,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { GDScriptParser::ClassNode::Member member = p_class->members[i]; if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { #ifdef DEBUG_ENABLED - Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes; for (uint32_t ignored_warning : member.function->ignored_warnings) { parser->ignored_warning_codes.insert(ignored_warning); } @@ -1160,8 +1160,16 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * } } } else { - GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type); - p_function->set_datatype(return_type); + if (p_function->return_type != nullptr) { + p_function->set_datatype(resolve_datatype(p_function->return_type)); + } else { + // In case the function is not typed, we can safely assume it's a Variant, so it's okay to mark as "inferred" here. + // It's not "undetected" to not mix up with unknown functions. + GDScriptParser::DataType return_type; + return_type.type_source = GDScriptParser::DataType::INFERRED; + return_type.kind = GDScriptParser::DataType::VARIANT; + p_function->set_datatype(return_type); + } #ifdef TOOLS_ENABLED // Check if the function signature matches the parent. If not it's an error since it breaks polymorphism. @@ -1231,7 +1239,7 @@ void GDScriptAnalyzer::resolve_function_body(GDScriptParser::FunctionNode *p_fun GDScriptParser::DataType return_type = p_function->body->get_datatype(); - if (p_function->get_datatype().has_no_type() && return_type.is_set()) { + if (!p_function->get_datatype().is_hard_type() && return_type.is_set()) { // Use the suite inferred type if return isn't explicitly set. return_type.type_source = GDScriptParser::DataType::INFERRED; p_function->set_datatype(p_function->body->get_datatype()); @@ -1279,7 +1287,7 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) { } #ifdef DEBUG_ENABLED - Set<uint32_t> previously_ignored = parser->ignored_warning_codes; + HashSet<uint32_t> previously_ignored = parser->ignored_warning_codes; for (uint32_t ignored_warning : stmt->ignored_warnings) { parser->ignored_warning_codes.insert(ignored_warning); } @@ -1514,10 +1522,22 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant) { GDScriptParser::DataType type; + GDScriptParser::DataType explicit_type; + if (p_constant->datatype_specifier != nullptr) { + explicit_type = resolve_datatype(p_constant->datatype_specifier); + explicit_type.is_meta_type = false; + } + if (p_constant->initializer != nullptr) { reduce_expression(p_constant->initializer); if (p_constant->initializer->type == GDScriptParser::Node::ARRAY) { - const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer)); + GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_constant->initializer); + const_fold_array(array); + + // Can only infer typed array if it has elements. + if (array->elements.size() > 0 || (p_constant->datatype_specifier != nullptr && explicit_type.has_container_element_type())) { + update_array_literal_element_type(explicit_type, array); + } } else if (p_constant->initializer->type == GDScriptParser::Node::DICTIONARY) { const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_constant->initializer)); } @@ -1536,8 +1556,6 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant } if (p_constant->datatype_specifier != nullptr) { - GDScriptParser::DataType explicit_type = resolve_datatype(p_constant->datatype_specifier); - explicit_type.is_meta_type = false; if (!is_type_compatible(explicit_type, type)) { push_error(vformat(R"(Assigned value for constant "%s" has type %s which is not compatible with defined type %s.)", p_constant->identifier->name, type.to_string(), explicit_type.to_string()), p_constant->initializer); #ifdef DEBUG_ENABLED @@ -2057,7 +2075,8 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) { p_await->set_datatype(awaiting_type); #ifdef DEBUG_ENABLED - if (!awaiting_type.is_coroutine && awaiting_type.builtin_type != Variant::SIGNAL) { + awaiting_type = p_await->to_await->get_datatype(); + if (!(awaiting_type.has_no_type() || awaiting_type.is_coroutine || awaiting_type.builtin_type == Variant::SIGNAL)) { parser->push_warning(p_await, GDScriptWarning::REDUNDANT_AWAIT); } #endif @@ -2174,7 +2193,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await, bool p_is_root) { bool all_is_constant = true; - Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing. + HashMap<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing. for (int i = 0; i < p_call->arguments.size(); i++) { reduce_expression(p_call->arguments[i]); if (p_call->arguments[i]->type == GDScriptParser::Node::ARRAY) { @@ -4218,13 +4237,11 @@ Error GDScriptAnalyzer::resolve_program() { resolve_class_interface(parser->head); resolve_class_body(parser->head); - List<String> parser_keys; - depended_parsers.get_key_list(&parser_keys); - for (const String &E : parser_keys) { - if (depended_parsers[E].is_null()) { + for (KeyValue<String, Ref<GDScriptParserRef>> &K : depended_parsers) { + if (K.value.is_null()) { return ERR_PARSE_ERROR; } - depended_parsers[E]->raise_status(GDScriptParserRef::FULLY_SOLVED); + K.value->raise_status(GDScriptParserRef::FULLY_SOLVED); } return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR; } diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 519e1975c4..3966b81b6e 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -33,7 +33,7 @@ #include "core/object/object.h" #include "core/object/ref_counted.h" -#include "core/templates/set.h" +#include "core/templates/hash_set.h" #include "gdscript_cache.h" #include "gdscript_parser.h" diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index e72069bcd5..3d5a39bf38 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -196,10 +196,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_constant_count = constant_map.size(); function->constants.resize(constant_map.size()); function->_constants_ptr = function->constants.ptrw(); - const Variant *K = nullptr; - while ((K = constant_map.next(K))) { - int idx = constant_map[*K]; - function->constants.write[idx] = *K; + for (const KeyValue<Variant, int> &K : constant_map) { + function->constants.write[K.value] = K.key; } } else { function->_constants_ptr = nullptr; diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 0503f66161..6ee8fda533 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -53,19 +53,19 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { bool debug_stack = false; Vector<int> opcodes; - List<Map<StringName, int>> stack_id_stack; - Map<StringName, int> stack_identifiers; + List<RBMap<StringName, int>> stack_id_stack; + RBMap<StringName, int> stack_identifiers; List<int> stack_identifiers_counts; - Map<StringName, int> local_constants; + RBMap<StringName, int> local_constants; Vector<StackSlot> locals; Vector<StackSlot> temporaries; List<int> used_temporaries; - Map<Variant::Type, List<int>> temporaries_pool; + RBMap<Variant::Type, List<int>> temporaries_pool; List<GDScriptFunction::StackDebug> stack_debug; - List<Map<StringName, int>> block_identifier_stack; - Map<StringName, int> block_identifiers; + List<RBMap<StringName, int>> block_identifier_stack; + RBMap<StringName, int> block_identifiers; int max_locals = 0; int current_line = 0; @@ -77,23 +77,23 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { #endif HashMap<Variant, int, VariantHasher, VariantComparator> constant_map; - Map<StringName, int> name_map; + RBMap<StringName, int> name_map; #ifdef TOOLS_ENABLED Vector<StringName> named_globals; #endif - Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map; - Map<Variant::ValidatedSetter, int> setters_map; - Map<Variant::ValidatedGetter, int> getters_map; - Map<Variant::ValidatedKeyedSetter, int> keyed_setters_map; - Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map; - Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map; - Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map; - Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map; - Map<Variant::ValidatedConstructor, int> constructors_map; - Map<Variant::ValidatedUtilityFunction, int> utilities_map; - Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map; - Map<MethodBind *, int> method_bind_map; - Map<GDScriptFunction *, int> lambdas_map; + RBMap<Variant::ValidatedOperatorEvaluator, int> operator_func_map; + RBMap<Variant::ValidatedSetter, int> setters_map; + RBMap<Variant::ValidatedGetter, int> getters_map; + RBMap<Variant::ValidatedKeyedSetter, int> keyed_setters_map; + RBMap<Variant::ValidatedKeyedGetter, int> keyed_getters_map; + RBMap<Variant::ValidatedIndexedSetter, int> indexed_setters_map; + RBMap<Variant::ValidatedIndexedGetter, int> indexed_getters_map; + RBMap<Variant::ValidatedBuiltInMethod, int> builtin_method_map; + RBMap<Variant::ValidatedConstructor, int> constructors_map; + RBMap<Variant::ValidatedUtilityFunction, int> utilities_map; + RBMap<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map; + RBMap<MethodBind *, int> method_bind_map; + RBMap<GDScriptFunction *, int> lambdas_map; // Lists since these can be nested. List<int> if_jmp_addrs; @@ -135,7 +135,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { stack_identifiers_counts.push_back(locals.size()); stack_id_stack.push_back(stack_identifiers); if (debug_stack) { - Map<StringName, int> block_ids(block_identifiers); + RBMap<StringName, int> block_ids(block_identifiers); block_identifier_stack.push_back(block_ids); block_identifiers.clear(); } diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 8c198345c2..4c15fca91e 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -223,13 +223,13 @@ Error GDScriptCache::finish_compiling(const String &p_owner) { singleton->full_gdscript_cache[p_owner] = script.ptr(); singleton->shallow_gdscript_cache.erase(p_owner); - Set<String> depends = singleton->dependencies[p_owner]; + HashSet<String> depends = singleton->dependencies[p_owner]; Error err = OK; - for (const Set<String>::Element *E = depends.front(); E != nullptr; E = E->next()) { + for (const String &E : depends) { Error this_err = OK; // No need to save the script. We assume it's already referenced in the owner. - get_full_script(E->get(), this_err); + get_full_script(E, this_err); if (this_err != OK) { err = this_err; diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index 3ce976ee14..b971bdd984 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -34,7 +34,7 @@ #include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/templates/hash_map.h" -#include "core/templates/set.h" +#include "core/templates/hash_set.h" #include "gdscript.h" class GDScriptAnalyzer; @@ -74,7 +74,7 @@ class GDScriptCache { HashMap<String, GDScriptParserRef *> parser_map; HashMap<String, GDScript *> shallow_gdscript_cache; HashMap<String, GDScript *> full_gdscript_cache; - HashMap<String, Set<String>> dependencies; + HashMap<String, HashSet<String>> dependencies; friend class GDScript; friend class GDScriptParserRef; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 37a988ee4c..910f94a936 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -108,11 +108,15 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D result.native_type = result.script_type->get_instance_base_type(); } break; case GDScriptParser::DataType::CLASS: { - // Locate class by constructing the path to it and following that path + // Locate class by constructing the path to it and following that path. GDScriptParser::ClassNode *class_type = p_datatype.class_type; if (class_type) { - const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->path); - const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->name); + result.kind = GDScriptDataType::GDSCRIPT; + result.builtin_type = p_datatype.builtin_type; + + String class_name = class_type->fqcn.split("::")[0]; + const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_name == main_script->path); + const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_name == main_script->name); if (is_inner_by_path || is_inner_by_name) { // Local class. List<StringName> names; @@ -131,16 +135,41 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D script = script->subclasses[names.back()->get()]; names.pop_back(); } - result.kind = GDScriptDataType::GDSCRIPT; result.script_type = script.ptr(); result.native_type = script->get_instance_base_type(); - result.builtin_type = p_datatype.builtin_type; } else { - result.kind = GDScriptDataType::GDSCRIPT; - result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path); + // Inner class. + PackedStringArray classes = class_type->fqcn.split("::"); + if (!classes.is_empty()) { + for (GDScript *script : parsed_classes) { + // Checking of inheritance structure of inner class to find a correct script link. + if (script->name == classes[classes.size() - 1]) { + PackedStringArray classes2 = script->fully_qualified_name.split("::"); + bool valid = true; + if (classes.size() != classes2.size()) { + valid = false; + } else { + for (int i = 0; i < classes.size(); i++) { + if (classes[i] != classes2[i]) { + valid = false; + break; + } + } + } + if (!valid) { + continue; + } + result.script_type_ref = Ref<GDScript>(script); + break; + } + } + } + if (result.script_type_ref.is_null()) { + result.script_type_ref = GDScriptCache::get_shallow_script(p_datatype.script_path, main_script->path); + } + result.script_type = result.script_type_ref.ptr(); result.native_type = p_datatype.native_type; - result.builtin_type = p_datatype.builtin_type; } } } break; @@ -336,7 +365,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { // If it's an autoload singleton, we postpone to load it at runtime. // This is so one autoload doesn't try to load another before it's compiled. - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); if (autoloads.has(identifier) && autoloads[identifier].is_singleton) { GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype())); int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; @@ -638,20 +667,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::GET_NODE: { const GDScriptParser::GetNodeNode *get_node = static_cast<const GDScriptParser::GetNodeNode *>(p_expression); - String node_name; - if (get_node->string != nullptr) { - node_name += String(get_node->string->value); - } else { - for (int i = 0; i < get_node->chain.size(); i++) { - if (i > 0) { - node_name += "/"; - } - node_name += get_node->chain[i]->name; - } - } - Vector<GDScriptCodeGenerator::Address> args; - args.push_back(codegen.add_constant(NodePath(node_name))); + args.push_back(codegen.add_constant(NodePath(get_node->full_path))); GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype())); @@ -703,10 +720,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } else if (subscript->is_attribute) { if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) { GDScriptParser::IdentifierNode *identifier = subscript->attribute; - const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(identifier->name); + HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(identifier->name); #ifdef DEBUG_ENABLED - if (MI && MI->get().getter == codegen.function_name) { + if (MI && MI->value.getter == codegen.function_name) { String n = identifier->name; _set_error("Must use '" + n + "' instead of 'self." + n + "' in getter.", identifier); r_error = ERR_COMPILATION_FAILED; @@ -714,11 +731,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } #endif - if (MI && MI->get().getter == "") { + if (MI && MI->value.getter == "") { // Remove result temp as we don't need it. gen->pop_temporary(); // Faster than indexing self (as if no self. had been used). - return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->get().index, _gdtype_from_datatype(subscript->get_datatype())); + return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->value.index, _gdtype_from_datatype(subscript->get_datatype())); } } @@ -894,8 +911,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code const GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(assignment->assignee); #ifdef DEBUG_ENABLED if (subscript->is_attribute && subscript->base->type == GDScriptParser::Node::SELF && codegen.script) { - const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(subscript->attribute->name); - if (MI && MI->get().setter == codegen.function_name) { + HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(subscript->attribute->name); + if (MI && MI->value.setter == codegen.function_name) { String n = subscript->attribute->name; _set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript); r_error = ERR_COMPILATION_FAILED; @@ -2500,8 +2517,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa //validate instances if keeping state if (p_keep_state) { - for (Set<Object *>::Element *E = p_script->instances.front(); E;) { - Set<Object *>::Element *N = E->next(); + for (RBSet<Object *>::Element *E = p_script->instances.front(); E;) { + RBSet<Object *>::Element *N = E->next(); ScriptInstance *si = E->get()->get_script_instance(); if (si->is_placeholder()) { @@ -2563,7 +2580,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa } void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - Map<StringName, Ref<GDScript>> old_subclasses; + HashMap<StringName, Ref<GDScript>> old_subclasses; if (p_keep_state) { old_subclasses = p_script->subclasses; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 8d71437344..4841884e2d 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_COMPILER_H #define GDSCRIPT_COMPILER_H -#include "core/templates/set.h" +#include "core/templates/hash_set.h" #include "gdscript.h" #include "gdscript_codegen.h" #include "gdscript_function.h" @@ -39,8 +39,8 @@ class GDScriptCompiler { const GDScriptParser *parser = nullptr; - Set<GDScript *> parsed_classes; - Set<GDScript *> parsing_classes; + HashSet<GDScript *> parsed_classes; + HashSet<GDScript *> parsing_classes; GDScript *main_script = nullptr; struct CodeGen { @@ -49,9 +49,9 @@ class GDScriptCompiler { const GDScriptParser::FunctionNode *function_node = nullptr; StringName function_name; GDScriptCodeGenerator *generator = nullptr; - Map<StringName, GDScriptCodeGenerator::Address> parameters; - Map<StringName, GDScriptCodeGenerator::Address> locals; - List<Map<StringName, GDScriptCodeGenerator::Address>> locals_stack; + HashMap<StringName, GDScriptCodeGenerator::Address> parameters; + HashMap<StringName, GDScriptCodeGenerator::Address> locals; + List<HashMap<StringName, GDScriptCodeGenerator::Address>> locals_stack; GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) { uint32_t addr = generator->add_local(p_name, p_type); @@ -101,7 +101,7 @@ class GDScriptCompiler { } void start_block() { - Map<StringName, GDScriptCodeGenerator::Address> old_locals = locals; + HashMap<StringName, GDScriptCodeGenerator::Address> old_locals = locals; locals_stack.push_back(old_locals); generator->start_block(); } diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 0197bf9ea3..202d1dcdf4 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -98,7 +98,7 @@ Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates( return templates; } -static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, Map<int, String> &r_funcs) { +static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, HashMap<int, String> &r_funcs) { for (int i = 0; i < p_class->members.size(); i++) { if (p_class->members[i].type == GDScriptParser::ClassNode::Member::FUNCTION) { const GDScriptParser::FunctionNode *function = p_class->members[i].function; @@ -110,7 +110,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl } } -bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const { GDScriptParser parser; GDScriptAnalyzer analyzer(&parser); @@ -148,7 +148,7 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li return false; } else { const GDScriptParser::ClassNode *cl = parser.get_tree(); - Map<int, String> funcs; + HashMap<int, String> funcs; get_function_names_recursively(cl, "", funcs); @@ -159,7 +159,7 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li #ifdef DEBUG_ENABLED if (r_safe_lines) { - const Set<int> &unsafe_lines = parser.get_unsafe_lines(); + const HashSet<int> &unsafe_lines = parser.get_unsafe_lines(); for (int i = 1; i <= parser.get_last_line_number(); i++) { if (!unsafe_lines.has(i)) { r_safe_lines->insert(i); @@ -321,7 +321,7 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> * Ref<GDScript> script = instance->get_script(); ERR_FAIL_COND(script.is_null()); - const Map<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices(); + const HashMap<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices(); for (const KeyValue<StringName, GDScript::MemberInfo> &E : mi) { p_members->push_back(E.key); @@ -343,7 +343,7 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) { } void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map(); + const HashMap<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map(); const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array(); List<Pair<String, Variant>> cinfo; @@ -722,7 +722,7 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio return arghint; } -static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptLanguage::CodeCompletionOption> &r_list) { +static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list) { const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; for (int i = 0; i < p_dir->get_file_count(); i++) { @@ -736,7 +736,7 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String } } -static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { +static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) { if (p_annotation->name == SNAME("@export_range")) { if (p_argument == 3 || p_argument == 4) { // Slider hint. @@ -777,7 +777,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a } } -static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) { +static void _find_built_in_variants(HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) { for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) { ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); @@ -789,7 +789,7 @@ static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOp } } -static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { +static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) { // Built-in Variant Types _find_built_in_variants(r_result, true); @@ -851,9 +851,10 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio } // Autoload singletons - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") { continue; } @@ -862,7 +863,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio } } -static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { +static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) { for (int i = 0; i < p_suite->locals.size(); i++) { ScriptLanguage::CodeCompletionOption option; if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) { @@ -878,9 +879,9 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, } } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth); +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth); -static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); if (!p_parent_only) { @@ -965,7 +966,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, _find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1); } -static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT); GDScriptParser::DataType base_type = p_base.type; @@ -997,7 +998,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base r_result.insert(option.display, option); } } - Map<StringName, Variant> constants; + HashMap<StringName, Variant> constants; scr->get_constants(&constants); for (const KeyValue<StringName, Variant> &E : constants) { int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key); @@ -1056,6 +1057,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base r_result.insert(option.display, option); } + List<MethodInfo> signals; + ClassDB::get_signal_list(type, &signals); + for (const MethodInfo &E : signals) { + int location = p_recursion_depth + _get_signal_location(type, StringName(E.name)); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location); + r_result.insert(option.display, option); + } + if (!_static || Engine::get_singleton()->has_singleton(type)) { List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); @@ -1140,7 +1149,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } -static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { +static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) { if (!p_only_functions && p_context.current_suite) { // This includes function parameters, since they are also locals. _find_identifiers_in_suite(p_context.current_suite, r_result); @@ -1219,12 +1228,11 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context r_result.insert(option.display, option); } - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - if (!E.value().is_singleton) { + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + if (!E.value.is_singleton) { continue; } - ScriptLanguage::CodeCompletionOption option(E.key(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); + ScriptLanguage::CodeCompletionOption option(E.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT); r_result.insert(option.display, option); } @@ -1517,12 +1525,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]); found = true; } else { - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - String name = E.key(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + String name = E.key; if (name == which) { - String script = E.value().path; + String script = E.value.path; if (!script.begins_with("res://")) { script = "res://" + script; @@ -2083,7 +2089,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & case GDScriptParser::DataType::SCRIPT: { Ref<Script> scr = base_type.script_type; if (scr.is_valid()) { - Map<StringName, Variant> constants; + HashMap<StringName, Variant> constants; scr->get_constants(&constants); if (constants.has(p_identifier)) { r_type = _type_from_variant(constants[p_identifier]); @@ -2312,7 +2318,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex return false; } -static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { +static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) { if (!p_enum_hint.contains(".")) { // Global constant or in the current class. StringName current_enum = p_enum_hint; @@ -2349,7 +2355,7 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co } } -static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) { +static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) { Variant base = p_base.value; GDScriptParser::DataType base_type = p_base.type; @@ -2468,7 +2474,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } } -static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { +static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) { if (p_call->type == GDScriptParser::Node::PRELOAD) { if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result); @@ -2583,7 +2589,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c analyzer.analyze(); r_forced = false; - Map<String, ScriptLanguage::CodeCompletionOption> options; + HashMap<String, ScriptLanguage::CodeCompletionOption> options; GDScriptParser::CompletionContext completion_context = parser.get_completion_context(); completion_context.base = p_owner; @@ -2882,10 +2888,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } // Get autoloads. - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - String path = "/root/" + E.key(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + String path = "/root/" + E.key; ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH); options.insert(option.display, option); } @@ -3062,6 +3066,13 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } + if (ClassDB::has_signal(class_name, p_symbol, true)) { + r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL; + r_result.class_name = base_type.native_type; + r_result.class_member = p_symbol; + return OK; + } + StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true); if (enum_name != StringName()) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM; @@ -3144,7 +3155,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } ::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { - // Before parsing, try the usual stuff + // Before parsing, try the usual stuff. if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS; r_result.class_name = p_symbol; @@ -3160,7 +3171,9 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } } - if (GDScriptUtilityFunctions::function_exists(p_symbol)) { + // Need special checks for assert and preload as they are technically + // keywords, so are not registered in GDScriptUtilityFunctions. + if (GDScriptUtilityFunctions::function_exists(p_symbol) || "assert" == p_symbol || "preload" == p_symbol) { r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_METHOD; r_result.class_name = "@GDScript"; r_result.class_member = p_symbol; @@ -3216,6 +3229,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co is_function = true; [[fallthrough]]; } + case GDScriptParser::COMPLETION_ASSIGN: case GDScriptParser::COMPLETION_CALL_ARGUMENTS: case GDScriptParser::COMPLETION_IDENTIFIER: { GDScriptParser::DataType base_type; @@ -3268,7 +3282,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co } // Global. - Map<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map(); + HashMap<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map(); if (classes.has(p_symbol)) { Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]]; if (value.get_type() == Variant::OBJECT) { diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 3d708955ed..cd3b7d69c5 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -93,7 +93,7 @@ struct _GDFKCS { void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const { int oc = 0; - Map<StringName, _GDFKC> sdmap; + HashMap<StringName, _GDFKC> sdmap; for (const StackDebug &sd : stack_debug) { if (sd.line >= p_line) { break; @@ -270,6 +270,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); } + + _clear_stack(); #endif } @@ -279,7 +281,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) { void GDScriptFunctionState::_clear_stack() { if (state.stack_size) { Variant *stack = (Variant *)state.stack.ptr(); - for (int i = 0; i < state.stack_size; i++) { + // The first 3 are special addresses and not copied to the state, so we skip them here. + for (int i = 3; i < state.stack_size; i++) { stack[i].~Variant(); } state.stack_size = 0; @@ -300,8 +303,6 @@ GDScriptFunctionState::GDScriptFunctionState() : } GDScriptFunctionState::~GDScriptFunctionState() { - _clear_stack(); - { MutexLock lock(GDScriptLanguage::singleton->lock); scripts_list.remove_from_list(); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index ba0d51c5cc..d2ca795977 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -495,7 +495,7 @@ private: Vector<GDScriptDataType> argument_types; GDScriptDataType return_type; - Map<int, Variant::Type> temporary_slots; + HashMap<int, Variant::Type> temporary_slots; #ifdef TOOLS_ENABLED Vector<StringName> arg_names; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 67f6b61f14..bc225850c9 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -100,10 +100,8 @@ void GDScriptParser::cleanup() { } void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const { - List<StringName> keys; - valid_annotations.get_key_list(&keys); - for (const StringName &E : keys) { - r_annotations->push_back(valid_annotations[E].info); + for (const KeyValue<StringName, AnnotationInfo> &E : valid_annotations) { + r_annotations->push_back(E.value.info); } } @@ -205,7 +203,8 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ if (ignored_warnings.has(warn_name)) { return; } - if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) { + int warn_level = (int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code)); + if (!warn_level) { return; } @@ -217,6 +216,11 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ warning.leftmost_column = p_source->leftmost_column; warning.rightmost_column = p_source->rightmost_column; + if (warn_level == GDScriptWarning::WarnLevel::ERROR) { + push_error(warning.get_message(), p_source); + return; + } + List<GDScriptWarning>::Element *before = nullptr; for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { if (E->get().start_line > warning.start_line) { @@ -1626,6 +1630,10 @@ GDScriptParser::Node *GDScriptParser::parse_statement() { case Node::AWAIT: // Fine. break; + case Node::LAMBDA: + // Standalone lambdas can't be used, so make this an error. + push_error("Standalone lambdas cannot be accessed. Consider assigning it to a variable.", expression); + break; default: push_warning(expression, GDScriptWarning::STANDALONE_EXPRESSION); } @@ -1810,7 +1818,6 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { #ifdef DEBUG_ENABLED bool all_have_return = true; bool have_wildcard = false; - bool wildcard_has_return = false; bool have_wildcard_without_continue = false; #endif @@ -1828,9 +1835,6 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { if (branch->has_wildcard) { have_wildcard = true; - if (branch->block->has_return) { - wildcard_has_return = true; - } if (!branch->block->has_continue) { have_wildcard_without_continue = true; } @@ -1845,7 +1849,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() { consume(GDScriptTokenizer::Token::DEDENT, R"(Expected an indented block after "match" statement.)"); #ifdef DEBUG_ENABLED - if (wildcard_has_return || (all_have_return && have_wildcard)) { + if (all_have_return && have_wildcard) { current_suite->has_return = true; } #endif @@ -1863,7 +1867,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { if (pattern == nullptr) { continue; } - if (pattern->pattern_type == PatternNode::PT_BIND) { + if (pattern->binds.size() > 0) { has_bind = true; } if (branch->patterns.size() > 0 && has_bind) { @@ -1894,11 +1898,9 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { SuiteNode *suite = alloc_node<SuiteNode>(); if (branch->patterns.size() > 0) { - List<StringName> binds; - branch->patterns[0]->binds.get_key_list(&binds); - - for (const StringName &E : binds) { - SuiteNode::Local local(branch->patterns[0]->binds[E], current_function); + for (const KeyValue<StringName, IdentifierNode *> &E : branch->patterns[0]->binds) { + SuiteNode::Local local(E.value, current_function); + local.type = SuiteNode::Local::PATTERN_BIND; suite->add_local(local); } } @@ -2107,7 +2109,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign); while (p_precedence <= get_rule(current.type)->precedence) { - if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL)) { + if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || (previous_operand->type == Node::LAMBDA && lambda_ended)) { return previous_operand; } // Also switch multiline mode on here for infix operators. @@ -2319,6 +2321,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression operation->operation = BinaryOpNode::OP_MODULO; operation->variant_op = Variant::OP_MODULE; break; + case GDScriptTokenizer::Token::STAR_STAR: + operation->operation = BinaryOpNode::OP_POWER; + operation->variant_op = Variant::OP_POWER; + break; case GDScriptTokenizer::Token::LESS_LESS: operation->operation = BinaryOpNode::OP_BIT_LEFT_SHIFT; operation->variant_op = Variant::OP_SHIFT_LEFT; @@ -2482,6 +2488,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode assignment->operation = AssignmentNode::OP_MULTIPLICATION; assignment->variant_op = Variant::OP_MULTIPLY; break; + case GDScriptTokenizer::Token::STAR_STAR_EQUAL: + assignment->operation = AssignmentNode::OP_POWER; + assignment->variant_op = Variant::OP_POWER; + break; case GDScriptTokenizer::Token::SLASH_EQUAL: assignment->operation = AssignmentNode::OP_DIVISION; assignment->variant_op = Variant::OP_DIVIDE; @@ -2820,51 +2830,97 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_call(ExpressionNode *p_pre } GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p_previous_operand, bool p_can_assign) { - if (match(GDScriptTokenizer::Token::LITERAL)) { - if (previous.literal.get_type() != Variant::STRING) { - push_error(R"(Expect node path as string or identifier after "$".)"); + if (!current.is_node_name() && !check(GDScriptTokenizer::Token::LITERAL) && !check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) { + push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous.get_name())); + return nullptr; + } + + if (check(GDScriptTokenizer::Token::LITERAL)) { + if (current.literal.get_type() != Variant::STRING) { + push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous.get_name())); return nullptr; } - GetNodeNode *get_node = alloc_node<GetNodeNode>(); - make_completion_context(COMPLETION_GET_NODE, get_node); - get_node->string = parse_literal(); - return get_node; - } else if (current.is_node_name()) { - GetNodeNode *get_node = alloc_node<GetNodeNode>(); - int chain_position = 0; - do { - make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++); - if (!current.is_node_name()) { - push_error(R"(Expect node path after "/".)"); + } + + GetNodeNode *get_node = alloc_node<GetNodeNode>(); + + // Store the last item in the path so the parser knows what to expect. + // Allow allows more specific error messages. + enum PathState { + PATH_STATE_START, + PATH_STATE_SLASH, + PATH_STATE_PERCENT, + PATH_STATE_NODE_NAME, + } path_state = PATH_STATE_START; + + if (previous.type == GDScriptTokenizer::Token::DOLLAR) { + // Detect initial slash, which will be handled in the loop if it matches. + match(GDScriptTokenizer::Token::SLASH); +#ifdef DEBUG_ENABLED + } else { + get_node->use_dollar = false; +#endif + } + + int context_argument = 0; + + do { + if (previous.type == GDScriptTokenizer::Token::PERCENT) { + if (path_state != PATH_STATE_START && path_state != PATH_STATE_SLASH) { + push_error(R"("%" is only valid in the beginning of a node name (either after "$" or after "/"))"); return nullptr; } - advance(); - IdentifierNode *identifier = alloc_node<IdentifierNode>(); - identifier->name = previous.get_identifier(); - get_node->chain.push_back(identifier); - } while (match(GDScriptTokenizer::Token::SLASH)); - return get_node; - } else if (match(GDScriptTokenizer::Token::SLASH)) { - GetNodeNode *get_node = alloc_node<GetNodeNode>(); - IdentifierNode *identifier_root = alloc_node<IdentifierNode>(); - get_node->chain.push_back(identifier_root); - int chain_position = 0; - do { - make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++); - if (!current.is_node_name()) { - push_error(R"(Expect node path after "/".)"); + get_node->full_path += "%"; + + path_state = PATH_STATE_PERCENT; + } else if (previous.type == GDScriptTokenizer::Token::SLASH) { + if (path_state != PATH_STATE_START && path_state != PATH_STATE_NODE_NAME) { + push_error(R"("/" is only valid at the beginning of the path or after a node name.)"); return nullptr; } + + get_node->full_path += "/"; + + path_state = PATH_STATE_SLASH; + } + + make_completion_context(COMPLETION_GET_NODE, get_node, context_argument++); + + if (match(GDScriptTokenizer::Token::LITERAL)) { + if (previous.literal.get_type() != Variant::STRING) { + String previous_token; + switch (path_state) { + case PATH_STATE_START: + previous_token = "$"; + break; + case PATH_STATE_PERCENT: + previous_token = "%"; + break; + case PATH_STATE_SLASH: + previous_token = "/"; + break; + default: + break; + } + push_error(vformat(R"(Expected node path as string or identifier after "%s".)", previous_token)); + return nullptr; + } + + get_node->full_path += previous.literal.operator String(); + + path_state = PATH_STATE_NODE_NAME; + } else if (current.is_node_name()) { advance(); - IdentifierNode *identifier = alloc_node<IdentifierNode>(); - identifier->name = previous.get_identifier(); - get_node->chain.push_back(identifier); - } while (match(GDScriptTokenizer::Token::SLASH)); - return get_node; - } else { - push_error(R"(Expect node path as string or identifier after "$".)"); - return nullptr; - } + get_node->full_path += previous.get_identifier(); + + path_state = PATH_STATE_NODE_NAME; + } else if (!check(GDScriptTokenizer::Token::SLASH) && !check(GDScriptTokenizer::Token::PERCENT)) { + push_error(vformat(R"(Unexpected "%s" in node path.)", current.get_name())); + return nullptr; + } + } while (match(GDScriptTokenizer::Token::SLASH) || match(GDScriptTokenizer::Token::PERCENT)); + + return get_node; } GDScriptParser::ExpressionNode *GDScriptParser::parse_preload(ExpressionNode *p_previous_operand, bool p_can_assign) { @@ -2922,6 +2978,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p current_function = function; SuiteNode *body = alloc_node<SuiteNode>(); + body->parent_function = current_function; + body->parent_block = current_suite; + SuiteNode *previous_suite = current_suite; current_suite = body; @@ -3049,7 +3108,7 @@ bool GDScriptParser::has_comment(int p_line) { } String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) { - const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments(); + const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments(); ERR_FAIL_COND_V(!comments.has(p_line), String()); if (p_single_line) { @@ -3101,7 +3160,7 @@ String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) { } void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class) { - const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments(); + const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments(); if (!comments.has(p_line)) { return; } @@ -3134,24 +3193,23 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & String title, link; // For tutorials. String doc_line = comments[line++].comment.trim_prefix("##"); - String striped_line = doc_line.strip_edges(); + String stripped_line = doc_line.strip_edges(); // Set the read mode. - if (striped_line.begins_with("@desc:") && p_desc.is_empty()) { + if (stripped_line.is_empty() && mode == BRIEF && !p_brief.is_empty()) { mode = DESC; - striped_line = striped_line.trim_prefix("@desc:"); - in_codeblock = _in_codeblock(doc_line, in_codeblock); + continue; - } else if (striped_line.begins_with("@tutorial")) { + } else if (stripped_line.begins_with("@tutorial")) { int begin_scan = String("@tutorial").length(); - if (begin_scan >= striped_line.length()) { + if (begin_scan >= stripped_line.length()) { continue; // invalid syntax. } - if (striped_line[begin_scan] == ':') { // No title. + if (stripped_line[begin_scan] == ':') { // No title. // Syntax: ## @tutorial: https://godotengine.org/ // The title argument is optional. title = ""; - link = striped_line.trim_prefix("@tutorial:").strip_edges(); + link = stripped_line.trim_prefix("@tutorial:").strip_edges(); } else { /* Syntax: @@ -3159,35 +3217,35 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & * ^ open ^ close ^ colon ^ url */ int open_bracket_pos = begin_scan, close_bracket_pos = 0; - while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) { + while (open_bracket_pos < stripped_line.length() && (stripped_line[open_bracket_pos] == ' ' || stripped_line[open_bracket_pos] == '\t')) { open_bracket_pos++; } - if (open_bracket_pos == striped_line.length() || striped_line[open_bracket_pos++] != '(') { + if (open_bracket_pos == stripped_line.length() || stripped_line[open_bracket_pos++] != '(') { continue; // invalid syntax. } close_bracket_pos = open_bracket_pos; - while (close_bracket_pos < striped_line.length() && striped_line[close_bracket_pos] != ')') { + while (close_bracket_pos < stripped_line.length() && stripped_line[close_bracket_pos] != ')') { close_bracket_pos++; } - if (close_bracket_pos == striped_line.length()) { + if (close_bracket_pos == stripped_line.length()) { continue; // invalid syntax. } int colon_pos = close_bracket_pos + 1; - while (colon_pos < striped_line.length() && (striped_line[colon_pos] == ' ' || striped_line[colon_pos] == '\t')) { + while (colon_pos < stripped_line.length() && (stripped_line[colon_pos] == ' ' || stripped_line[colon_pos] == '\t')) { colon_pos++; } - if (colon_pos == striped_line.length() || striped_line[colon_pos++] != ':') { + if (colon_pos == stripped_line.length() || stripped_line[colon_pos++] != ':') { continue; // invalid syntax. } - title = striped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges(); - link = striped_line.substr(colon_pos).strip_edges(); + title = stripped_line.substr(open_bracket_pos, close_bracket_pos - open_bracket_pos).strip_edges(); + link = stripped_line.substr(colon_pos).strip_edges(); } mode = TUTORIALS; in_codeblock = false; - } else if (striped_line.is_empty()) { + } else if (stripped_line.is_empty()) { continue; } else { // Tutorial docs are single line, we need a @tag after it. @@ -3207,7 +3265,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String & } doc_line = doc_line.substr(i); } else { - doc_line = striped_line; + doc_line = stripped_line; } String line_join = (in_codeblock) ? "\n" : " "; @@ -3264,13 +3322,15 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // PLUS, { &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // MINUS, { nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR, + { nullptr, &GDScriptParser::parse_binary_operator, PREC_POWER }, // STAR_STAR, { nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH, - { nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT, + { &GDScriptParser::parse_get_node, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT, // Assignment { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PLUS_EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // MINUS_EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_EQUAL, + { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_STAR_EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // SLASH_EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PERCENT_EQUAL, { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // LESS_LESS_EQUAL, @@ -3555,14 +3615,16 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node variable->export_info.hint = PROPERTY_HINT_ENUM; String enum_hint_string; - for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) { - enum_hint_string += E.key().operator String().capitalize().xml_escape(); - enum_hint_string += ":"; - enum_hint_string += String::num_int64(E.value()).xml_escape(); - - if (E.next()) { + bool first = true; + for (const KeyValue<StringName, int> &E : export_type.enum_values) { + if (!first) { enum_hint_string += ","; + } else { + first = false; } + enum_hint_string += E.key.operator String().capitalize().xml_escape(); + enum_hint_string += ":"; + enum_hint_string += String::num_int64(E.value).xml_escape(); } variable->export_info.hint_string = enum_hint_string; @@ -3895,6 +3957,9 @@ void GDScriptParser::TreePrinter::print_assignment(AssignmentNode *p_assignment) case AssignmentNode::OP_MODULO: push_text("%"); break; + case AssignmentNode::OP_POWER: + push_text("**"); + break; case AssignmentNode::OP_BIT_SHIFT_LEFT: push_text("<<"); break; @@ -3943,6 +4008,9 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) { case BinaryOpNode::OP_MODULO: push_text(" % "); break; + case BinaryOpNode::OP_POWER: + push_text(" ** "); + break; case BinaryOpNode::OP_BIT_LEFT_SHIFT: push_text(" << "); break; @@ -4236,17 +4304,10 @@ void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const } void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) { - push_text("$"); - if (p_get_node->string != nullptr) { - print_literal(p_get_node->string); - } else { - for (int i = 0; i < p_get_node->chain.size(); i++) { - if (i > 0) { - push_text("/"); - } - print_identifier(p_get_node->chain[i]); - } + if (p_get_node->use_dollar) { + push_text("$"); } + push_text(p_get_node->full_path); } void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 10474db02f..e3f8d4b8ba 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -39,7 +39,7 @@ #include "core/string/ustring.h" #include "core/templates/hash_map.h" #include "core/templates/list.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "core/templates/vector.h" #include "core/variant/variant.h" #include "gdscript_cache.h" @@ -132,7 +132,7 @@ public: ClassNode *class_type = nullptr; MethodInfo method_info; // For callable/signals. - OrderedHashMap<StringName, int> enum_values; // For enums. + HashMap<StringName, int> enum_values; // For enums. _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; } _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } @@ -360,6 +360,7 @@ public: OP_MULTIPLICATION, OP_DIVISION, OP_MODULO, + OP_POWER, OP_BIT_SHIFT_LEFT, OP_BIT_SHIFT_RIGHT, OP_BIT_AND, @@ -393,6 +394,7 @@ public: OP_MULTIPLICATION, OP_DIVISION, OP_MODULO, + OP_POWER, OP_BIT_LEFT_SHIFT, OP_BIT_RIGHT_SHIFT, OP_BIT_AND, @@ -747,8 +749,10 @@ public: }; struct GetNodeNode : public ExpressionNode { - LiteralNode *string = nullptr; - Vector<IdentifierNode *> chain; + String full_path; +#ifdef DEBUG_ENABLED + bool use_dollar = true; +#endif GetNodeNode() { type = GET_NODE; @@ -800,7 +804,7 @@ public: FunctionNode *function = nullptr; FunctionNode *parent_function = nullptr; Vector<IdentifierNode *> captures; - Map<StringName, int> captures_indices; + HashMap<StringName, int> captures_indices; bool use_self = false; bool has_name() const { @@ -1203,9 +1207,9 @@ private: List<ParserError> errors; #ifdef DEBUG_ENABLED List<GDScriptWarning> warnings; - Set<String> ignored_warnings; - Set<uint32_t> ignored_warning_codes; - Set<int> unsafe_lines; + HashSet<String> ignored_warnings; + HashSet<uint32_t> ignored_warning_codes; + HashSet<int> unsafe_lines; #endif GDScriptTokenizer tokenizer; @@ -1263,6 +1267,7 @@ private: PREC_FACTOR, PREC_SIGN, PREC_BIT_NOT, + PREC_POWER, PREC_TYPE_TEST, PREC_AWAIT, PREC_CALL, @@ -1416,7 +1421,7 @@ public: } #ifdef DEBUG_ENABLED const List<GDScriptWarning> &get_warnings() const { return warnings; } - const Set<int> &get_unsafe_lines() const { return unsafe_lines; } + const HashSet<int> &get_unsafe_lines() const { return unsafe_lines; } int get_last_line_number() const { return current.end_line; } #endif diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 63fad0d9bb..6c17afe939 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -67,6 +67,7 @@ static const char *token_names[] = { "+", // PLUS, "-", // MINUS, "*", // STAR, + "**", // STAR_STAR, "/", // SLASH, "%", // PERCENT, // Assignment @@ -74,6 +75,7 @@ static const char *token_names[] = { "+=", // PLUS_EQUAL, "-=", // MINUS_EQUAL, "*=", // STAR_EQUAL, + "**=", // STAR_STAR_EQUAL, "/=", // SLASH_EQUAL, "%=", // PERCENT_EQUAL, "<<=", // LESS_LESS_EQUAL, @@ -1403,6 +1405,14 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() { if (_peek() == '=') { _advance(); return make_token(Token::STAR_EQUAL); + } else if (_peek() == '*') { + if (_peek(1) == '=') { + _advance(); + _advance(); // Advance both '*' and '=' + return make_token(Token::STAR_STAR_EQUAL); + } + _advance(); + return make_token(Token::STAR_STAR); } else { return make_token(Token::STAR); } diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index abd090e381..7fb715f2c8 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -31,9 +31,9 @@ #ifndef GDSCRIPT_TOKENIZER_H #define GDSCRIPT_TOKENIZER_H +#include "core/templates/hash_map.h" +#include "core/templates/hash_set.h" #include "core/templates/list.h" -#include "core/templates/map.h" -#include "core/templates/set.h" #include "core/templates/vector.h" #include "core/variant/variant.h" @@ -78,6 +78,7 @@ public: PLUS, MINUS, STAR, + STAR_STAR, SLASH, PERCENT, // Assignment @@ -85,6 +86,7 @@ public: PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL, + STAR_STAR_EQUAL, SLASH_EQUAL, PERCENT_EQUAL, LESS_LESS_EQUAL, @@ -191,7 +193,7 @@ public: new_line = p_new_line; } }; - const Map<int, CommentData> &get_comments() const { + const HashMap<int, CommentData> &get_comments() const { return comments; } #endif // TOOLS_ENABLED @@ -224,7 +226,7 @@ private: int length = 0; #ifdef TOOLS_ENABLED - Map<int, CommentData> comments; + HashMap<int, CommentData> comments; #endif // TOOLS_ENABLED _FORCE_INLINE_ bool _is_at_end() { return position >= length; } diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index e28dd26c28..55f4ebb1c5 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -546,33 +546,32 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a memnew_placement(&stack[i], Variant); } - memnew_placement(&stack[ADDR_STACK_NIL], Variant); - if (_instruction_args_size) { instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; } else { instruction_args = nullptr; } - if (p_instance) { - memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner)); - script = p_instance->script.ptr(); - } else { - memnew_placement(&stack[ADDR_STACK_SELF], Variant); - script = _script; + for (const KeyValue<int, Variant::Type> &E : temporary_slots) { + type_init_function_table[E.value](&stack[E.key]); } } + if (_ptrcall_args_size) { call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *)); } else { call_args_ptr = nullptr; } - memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); - - for (const KeyValue<int, Variant::Type> &E : temporary_slots) { - type_init_function_table[E.value](&stack[E.key]); + if (p_instance) { + memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner)); + script = p_instance->script.ptr(); + } else { + memnew_placement(&stack[ADDR_STACK_SELF], Variant); + script = _script; } + memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); + memnew_placement(&stack[ADDR_STACK_NIL], Variant); String err_text; @@ -2104,7 +2103,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a const GDScript *gds = _script; - const Map<StringName, GDScriptFunction *>::Element *E = nullptr; + HashMap<StringName, GDScriptFunction *>::ConstIterator E; while (gds->base.ptr()) { gds = gds->base.ptr(); E = gds->member_functions.find(*methodname); @@ -2116,7 +2115,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a Callable::CallError err; if (E) { - *dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err); + *dst = E->value->call(p_instance, (const Variant **)argptrs, argc, err); } else if (gds->native.ptr()) { if (*methodname != GDScriptLanguage::get_singleton()->strings._init) { MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname); @@ -2171,8 +2170,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a // Is this even possible to be null at this point? if (obj) { if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) { - static StringName completed = _scs_create("completed"); - result = Signal(obj, completed); + result = Signal(obj, "completed"); } } } @@ -2193,8 +2191,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a gdfs->function = this; gdfs->state.stack.resize(alloca_size); - //copy variant stack - for (int i = 0; i < _stack_size; i++) { + + // First 3 stack addresses are special, so we just skip them here. + for (int i = 3; i < _stack_size; i++) { memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i])); } gdfs->state.stack_size = _stack_size; @@ -3451,26 +3450,27 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time; } - // Check if this is the last time the function is resuming from await - // Will be true if never awaited as well - // When it's the last resume it will postpone the exit from stack, - // so the debugger knows which function triggered the resume of the next function (if any) + // Check if this is not the last time it was interrupted by `await` or if it's the first time executing. + // If that is the case then we exit the function as normal. Otherwise we postpone it until the last `await` is completed. + // This ensures the call stack can be properly shown when using `await`, showing what resumed the function. if (!p_state || awaited) { if (EngineDebugger::is_active()) { GDScriptLanguage::get_singleton()->exit_function(); } #endif - if (_stack_size) { - //free stack - for (int i = 0; i < _stack_size; i++) { - stack[i].~Variant(); - } + // Free stack, except reserved addresses. + for (int i = 3; i < _stack_size; i++) { + stack[i].~Variant(); } - #ifdef DEBUG_ENABLED } #endif + // Always free reserved addresses, since they are never copied. + for (int i = 0; i < 3; i++) { + stack[i].~Variant(); + } + return retvalue; } diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index ad96e36640..1cae7bdfac 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -163,6 +163,18 @@ String GDScriptWarning::get_message() const { #undef CHECK_SYMBOLS } +int GDScriptWarning::get_default_value(Code p_code) { + if (get_name_from_code(p_code).to_lower().begins_with("unsafe_")) { + return WarnLevel::IGNORE; + } + return WarnLevel::WARN; +} + +PropertyInfo GDScriptWarning::get_property_info(Code p_code) { + // Making this a separate function in case a warning needs different PropertyInfo in the future. + return PropertyInfo(Variant::INT, get_settings_path_from_code(p_code), PROPERTY_HINT_ENUM, "Ignore,Warn,Error"); +} + String GDScriptWarning::get_name() const { return get_name_from_code(code); } @@ -210,6 +222,10 @@ String GDScriptWarning::get_name_from_code(Code p_code) { return names[(int)p_code]; } +String GDScriptWarning::get_settings_path_from_code(Code p_code) { + return "debug/gdscript/warnings/" + get_name_from_code(p_code).to_lower(); +} + GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) { for (int i = 0; i < WARNING_MAX; i++) { if (get_name_from_code((Code)i) == p_name) { diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 82efe3568f..f47f31aedf 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -33,11 +33,18 @@ #ifdef DEBUG_ENABLED +#include "core/object/object.h" #include "core/string/ustring.h" #include "core/templates/vector.h" class GDScriptWarning { public: + enum WarnLevel { + IGNORE, + WARN, + ERROR + }; + enum Code { UNASSIGNED_VARIABLE, // Variable used but never assigned. UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc). @@ -81,7 +88,10 @@ public: String get_name() const; String get_message() const; + static int get_default_value(Code p_code); + static PropertyInfo get_property_info(Code p_code); static String get_name_from_code(Code p_code); + static String get_settings_path_from_code(Code p_code); static Code get_code_from_name(const String &p_name); }; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 5516f59fe9..d3c5fed95a 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -89,16 +89,16 @@ void ExtendGDScriptParser::update_symbols() { for (int i = 0; i < class_symbol.children.size(); i++) { const lsp::DocumentSymbol &symbol = class_symbol.children[i]; - members.set(symbol.name, &symbol); + members.insert(symbol.name, &symbol); // cache level one inner classes if (symbol.kind == lsp::SymbolKind::Class) { ClassMembers inner_class; for (int j = 0; j < symbol.children.size(); j++) { const lsp::DocumentSymbol &s = symbol.children[j]; - inner_class.set(s.name, &s); + inner_class.insert(s.name, &s); } - inner_classes.set(symbol.name, inner_class); + inner_classes.insert(symbol.name, inner_class); } } } @@ -216,8 +216,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p if (res.is_valid() && !res->get_path().is_empty()) { value_text = "preload(\"" + res->get_path() + "\")"; if (symbol.documentation.is_empty()) { - if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) { - symbol.documentation = S->get()->class_symbol.documentation; + if (HashMap<String, ExtendGDScriptParser *>::Iterator S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) { + symbol.documentation = S->value->class_symbol.documentation; } } } else { @@ -661,30 +661,22 @@ const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const const Array &ExtendGDScriptParser::get_member_completions() { if (member_completions.is_empty()) { - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); + for (const KeyValue<String, const lsp::DocumentSymbol *> &E : members) { + const lsp::DocumentSymbol *symbol = E.value; lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, *name); + item.data = JOIN_SYMBOLS(path, E.key); member_completions.push_back(item.to_json()); - - name = members.next(name); } - const String *_class = inner_classes.next(nullptr); - while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); - const String *member_name = inner_class->next(nullptr); - while (member_name) { - const lsp::DocumentSymbol *symbol = inner_class->get(*member_name); + for (const KeyValue<String, ClassMembers> &E : inner_classes) { + const ClassMembers *inner_class = &E.value; + + for (const KeyValue<String, const lsp::DocumentSymbol *> &F : *inner_class) { + const lsp::DocumentSymbol *symbol = F.value; lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(*_class, *member_name)); + item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(E.key, F.key)); member_completions.push_back(item.to_json()); - - member_name = inner_class->next(member_name); } - - _class = inner_classes.next(_class); } } diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index cdddab319d..7460f8edff 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -126,7 +126,7 @@ Error GDScriptLanguageProtocol::on_client_connected() { ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached"); Ref<LSPeer> peer = memnew(LSPeer); peer->connection = tcp_peer; - clients.set(next_client_id, peer); + clients.insert(next_client_id, peer); next_client_id++; EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR); return OK; @@ -229,28 +229,33 @@ void GDScriptLanguageProtocol::poll() { if (server->is_connection_available()) { on_client_connected(); } - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref<LSPeer> peer = clients.get(*id); + + HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin(); + while (E != clients.end()) { + Ref<LSPeer> peer = E->value; StreamPeerTCP::Status status = peer->connection->get_status(); if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } else { if (peer->connection->get_available_bytes() > 0) { - latest_client_id = *id; + latest_client_id = E->key; Error err = peer->handle_data(); if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } } Error err = peer->send_data(); if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; + on_client_disconnected(E->key); + E = clients.begin(); + continue; } } + ++E; } } @@ -259,9 +264,8 @@ Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) { } void GDScriptLanguageProtocol::stop() { - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref<LSPeer> peer = clients.get(*id); + for (const KeyValue<int, Ref<LSPeer>> &E : clients) { + Ref<LSPeer> peer = clients.get(E.key); peer->connection->disconnect_from_host(); } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index c42bd58aeb..d763701911 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -109,23 +109,15 @@ void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol * void GDScriptTextDocument::initialize() { if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - const HashMap<StringName, ClassMembers> &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members; + for (const KeyValue<StringName, ClassMembers> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members) { + const ClassMembers &members = E.value; - const StringName *class_ptr = native_members.next(nullptr); - while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); - - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); + for (const KeyValue<String, const lsp::DocumentSymbol *> &F : members) { + const lsp::DocumentSymbol *symbol = members.get(F.key); lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(String(*class_ptr), *name); + item.data = JOIN_SYMBOLS(String(E.key), F.key); native_member_completions.push_back(item.to_json()); - - name = members.next(name); } - - class_ptr = native_members.next(class_ptr); } } } @@ -149,9 +141,9 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) { String uri = params["uri"]; String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(uri); Array arr; - if (const Map<String, ExtendGDScriptParser *>::Element *parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) { + if (HashMap<String, ExtendGDScriptParser *>::ConstIterator parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) { Vector<lsp::DocumentedSymbolInformation> list; - parser->get()->get_symbols().symbol_tree_as_list(uri, list); + parser->value->get_symbols().symbol_tree_as_list(uri, list); for (int i = 0; i < list.size(); i++) { arr.push_back(list[i].to_json()); } @@ -275,8 +267,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { } if (!symbol) { - if (const Map<String, ExtendGDScriptParser *>::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) { - symbol = E->get()->get_member_symbol(member_name, inner_class_name); + if (HashMap<String, ExtendGDScriptParser *>::ConstIterator E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) { + symbol = E->value->get_member_symbol(member_name, inner_class_name); } } } diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 89ee6b35e5..8d484a43b3 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -116,22 +116,22 @@ void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) { } void GDScriptWorkspace::remove_cache_parser(const String &p_path) { - Map<String, ExtendGDScriptParser *>::Element *parser = parse_results.find(p_path); - Map<String, ExtendGDScriptParser *>::Element *script = scripts.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator parser = parse_results.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator script = scripts.find(p_path); if (parser && script) { - if (script->get() && script->get() == parser->get()) { - memdelete(script->get()); + if (script->value && script->value == parser->value) { + memdelete(script->value); } else { - memdelete(script->get()); - memdelete(parser->get()); + memdelete(script->value); + memdelete(parser->value); } parse_results.erase(p_path); scripts.erase(p_path); } else if (parser) { - memdelete(parser->get()); + memdelete(parser->value); parse_results.erase(p_path); } else if (script) { - memdelete(script->get()); + memdelete(script->value); scripts.erase(p_path); } } @@ -141,8 +141,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_ StringName empty; while (class_name != empty) { - if (const Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(class_name)) { - const lsp::DocumentSymbol &class_symbol = E->value(); + if (HashMap<StringName, lsp::DocumentSymbol>::ConstIterator E = native_symbols.find(class_name)) { + const lsp::DocumentSymbol &class_symbol = E->value; if (p_member.is_empty()) { return &class_symbol; @@ -162,9 +162,9 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_ } const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_path) const { - const Map<String, ExtendGDScriptParser *>::Element *S = scripts.find(p_path); + HashMap<String, ExtendGDScriptParser *>::ConstIterator S = scripts.find(p_path); if (S) { - return &(S->get()->get_symbols()); + return &(S->value->get_symbols()); } return nullptr; } @@ -209,10 +209,10 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { err = parse_script(path, content); if (err != OK) { - Map<String, ExtendGDScriptParser *>::Element *S = parse_results.find(path); + HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(path); String err_msg = "Failed parse script " + path; if (S) { - err_msg += "\n" + S->get()->get_errors()[0].message; + err_msg += "\n" + S->value->get_errors()[0].message; } ERR_CONTINUE_MSG(err != OK, err_msg); } @@ -238,25 +238,25 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> } ExtendGDScriptParser *GDScriptWorkspace::get_parse_successed_script(const String &p_path) { - const Map<String, ExtendGDScriptParser *>::Element *S = scripts.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator S = scripts.find(p_path); if (!S) { parse_local_script(p_path); S = scripts.find(p_path); } if (S) { - return S->get(); + return S->value; } return nullptr; } ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) { - const Map<String, ExtendGDScriptParser *>::Element *S = parse_results.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(p_path); if (!S) { parse_local_script(p_path); S = parse_results.find(p_path); } if (S) { - return S->get(); + return S->value; } return nullptr; } @@ -404,9 +404,9 @@ Error GDScriptWorkspace::initialize() { const lsp::DocumentSymbol &class_symbol = E.value; for (int i = 0; i < class_symbol.children.size(); i++) { const lsp::DocumentSymbol &symbol = class_symbol.children[i]; - members.set(symbol.name, &symbol); + members.insert(symbol.name, &symbol); } - native_members.set(E.key, members); + native_members.insert(E.key, members); } // cache member completions @@ -424,8 +424,8 @@ Error GDScriptWorkspace::initialize() { Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_content) { ExtendGDScriptParser *parser = memnew(ExtendGDScriptParser); Error err = parser->parse(p_content, p_path); - Map<String, ExtendGDScriptParser *>::Element *last_parser = parse_results.find(p_path); - Map<String, ExtendGDScriptParser *>::Element *last_script = scripts.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator last_parser = parse_results.find(p_path); + HashMap<String, ExtendGDScriptParser *>::Iterator last_script = scripts.find(p_path); if (err == OK) { remove_cache_parser(p_path); @@ -433,8 +433,8 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont scripts[p_path] = parser; } else { - if (last_parser && last_script && last_parser->get() != last_script->get()) { - memdelete(last_parser->get()); + if (last_parser && last_script && last_parser->value != last_script->value) { + memdelete(last_parser->value); } parse_results[p_path] = parser; } @@ -513,9 +513,9 @@ String GDScriptWorkspace::get_file_uri(const String &p_path) const { void GDScriptWorkspace::publish_diagnostics(const String &p_path) { Dictionary params; Array errors; - const Map<String, ExtendGDScriptParser *>::Element *ele = parse_results.find(p_path); + HashMap<String, ExtendGDScriptParser *>::ConstIterator ele = parse_results.find(p_path); if (ele) { - const Vector<lsp::Diagnostic> &list = ele->get()->get_diagnostics(); + const Vector<lsp::Diagnostic> &list = ele->value->get_diagnostics(); errors.resize(list.size()); for (int i = 0; i < list.size(); ++i) { errors[i] = list[i].to_json(); @@ -682,13 +682,11 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP Vector2i offset; symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset); - const StringName *class_ptr = native_members.next(nullptr); - while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); + for (const KeyValue<StringName, ClassMembers> &E : native_members) { + const ClassMembers &members = native_members.get(E.key); if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) { r_list.push_back(*symbol); } - class_ptr = native_members.next(class_ptr); } for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) { @@ -698,23 +696,19 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP r_list.push_back(*symbol); } - const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes(); - const String *_class = inner_classes.next(nullptr); - while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); + for (const KeyValue<String, ClassMembers> &F : script->get_inner_classes()) { + const ClassMembers *inner_class = &F.value; if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) { r_list.push_back(*symbol); } - - _class = inner_classes.next(_class); } } } } const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) { - if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) { - const lsp::DocumentSymbol &symbol = E->get(); + if (HashMap<StringName, lsp::DocumentSymbol>::Iterator E = native_symbols.find(p_params.native_class)) { + const lsp::DocumentSymbol &symbol = E->value; if (p_params.symbol_name.is_empty() || p_params.symbol_name == symbol.name) { return &symbol; } @@ -790,7 +784,7 @@ GDScriptWorkspace::GDScriptWorkspace() { } GDScriptWorkspace::~GDScriptWorkspace() { - Set<String> cached_parsers; + HashSet<String> cached_parsers; for (const KeyValue<String, ExtendGDScriptParser *> &E : parse_results) { cached_parsers.insert(E.key); @@ -800,7 +794,7 @@ GDScriptWorkspace::~GDScriptWorkspace() { cached_parsers.insert(E.key); } - for (Set<String>::Element *E = cached_parsers.front(); E; E = E->next()) { - remove_cache_parser(E->get()); + for (const String &E : cached_parsers) { + remove_cache_parser(E); } } diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 92e78f8992..7bff5db81f 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -48,7 +48,7 @@ protected: static void _bind_methods(); void remove_cache_parser(const String &p_path); bool initialized = false; - Map<StringName, lsp::DocumentSymbol> native_symbols; + HashMap<StringName, lsp::DocumentSymbol> native_symbols; const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const; const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const; @@ -68,8 +68,8 @@ public: String root; String root_uri; - Map<String, ExtendGDScriptParser *> scripts; - Map<String, ExtendGDScriptParser *> parse_results; + HashMap<String, ExtendGDScriptParser *> scripts; + HashMap<String, ExtendGDScriptParser *> parse_results; HashMap<StringName, ClassMembers> native_members; public: diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index a63f9df918..d4aa207972 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -261,7 +261,7 @@ struct WorkspaceEdit { /** * Holds changes to existing resources. */ - Map<String, Vector<TextEdit>> changes; + HashMap<String, Vector<TextEdit>> changes; _FORCE_INLINE_ void add_edit(const String &uri, const TextEdit &edit) { if (changes.has(uri)) { @@ -293,8 +293,8 @@ struct WorkspaceEdit { } _FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) { - if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) { - Vector<TextEdit> edit_list = E->value(); + if (HashMap<String, Vector<TextEdit>>::Iterator E = changes.find(uri)) { + Vector<TextEdit> edit_list = E->value; for (int i = 0; i < edit_list.size(); ++i) { TextEdit edit = edit_list[i]; if (edit.range.start.character == start_character) { @@ -310,8 +310,8 @@ struct WorkspaceEdit { new_edit.range.end.line = line; new_edit.range.end.character = end_character; - if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) { - E->value().push_back(new_edit); + if (HashMap<String, Vector<TextEdit>>::Iterator E = changes.find(uri)) { + E->value.push_back(new_edit); } else { Vector<TextEdit> edit_list; edit_list.push_back(new_edit); diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 59acb1c064..b230c6ba36 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -70,7 +70,7 @@ class EditorExportGDScript : public EditorExportPlugin { GDCLASS(EditorExportGDScript, EditorExportPlugin); public: - virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features) override { + virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override { int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED; String script_key; diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index ea51990237..de5cd10e7c 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -48,11 +48,11 @@ namespace GDScriptTests { void init_autoloads() { - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); // First pass, add the constants so they exist before any script is loaded. - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (info.is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { @@ -62,8 +62,8 @@ void init_autoloads() { } // Second pass, load into global constants. - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.get(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) { + const ProjectSettings::AutoloadInfo &info = E.value; if (!info.is_singleton) { // Skip non-singletons since we don't have a scene tree here anyway. @@ -543,8 +543,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { return result; } // Test running. - const Map<StringName, GDScriptFunction *>::Element *test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name); - if (test_function_element == nullptr) { + const HashMap<StringName, GDScriptFunction *>::ConstIterator test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name); + if (!test_function_element) { enable_stdout(); result.status = GDTEST_LOAD_ERROR; result.output = ""; diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd new file mode 100644 index 0000000000..9a7c6a8250 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.gd @@ -0,0 +1,12 @@ +# https://github.com/godotengine/godot/issues/54589 +# https://github.com/godotengine/godot/issues/56265 + +extends Resource + +func test(): + print("okay") + await self.changed + await unknown(self) + +func unknown(arg): + await arg.changed diff --git a/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out new file mode 100644 index 0000000000..2dc04a363e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/await_with_signals_no_warning.out @@ -0,0 +1,2 @@ +GDTEST_OK +okay diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd new file mode 100644 index 0000000000..631e7be5ce --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd @@ -0,0 +1,14 @@ +func test(): + var instance := Parent.new() + instance.my_function({"a": 1}) + instance = Child.new() + instance.my_function({"a": 1}) + print("No failure") + +class Parent: + func my_function(_par1: Dictionary = {}) -> void: + pass + +class Child extends Parent: + func my_function(_par1: Dictionary = {}) -> void: + pass diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out new file mode 100644 index 0000000000..67f0045867 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out @@ -0,0 +1,2 @@ +GDTEST_OK +No failure diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd new file mode 100644 index 0000000000..9f86d0531c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.gd @@ -0,0 +1,2 @@ +func test(): + const arr: Array[int] = ["Hello", "World"] diff --git a/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out new file mode 100644 index 0000000000..26b6e13d4f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/typed_array_assignment.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Assigned value for constant "arr" has type Array[String] which is not compatible with defined type Array[int]. diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out index b3dc181a22..9fafcb5a64 100644 --- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out +++ b/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -Expect node path as string or identifier after "$". +Expected node path as string or identifier after "$". diff --git a/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd new file mode 100644 index 0000000000..fa0a43094e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.gd @@ -0,0 +1,3 @@ +func test(): + func standalone(): + print("can't be accessed") diff --git a/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out new file mode 100644 index 0000000000..c6830c8258 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/lambda_standalone.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Standalone lambdas cannot be accessed. Consider assigning it to a variable. diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd new file mode 100644 index 0000000000..4608c778aa --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd @@ -0,0 +1,4 @@ +func test(): + match 1: + [[[var a]]], 2: + pass diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out new file mode 100644 index 0000000000..1cdc24683b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out @@ -0,0 +1,2 @@ +GDTEST_PARSER_ERROR +Cannot use a variable bind with multiple patterns. diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out index b3dc181a22..9fafcb5a64 100644 --- a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out +++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -Expect node path as string or identifier after "$". +Expected node path as string or identifier after "$". diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out index b3dc181a22..9fafcb5a64 100644 --- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -Expect node path as string or identifier after "$". +Expected node path as string or identifier after "$". diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out index dcb4ccecb0..3062f0be70 100644 --- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out +++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.out @@ -1,2 +1,2 @@ GDTEST_PARSER_ERROR -Expect node path after "/". +Expected node path as string or identifier after "/". diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd new file mode 100644 index 0000000000..f04f4de08d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.gd @@ -0,0 +1,49 @@ +extends Node + +func test(): + var child = Node.new() + child.name = "Child" + add_child(child) + child.owner = self + + var hey = Node.new() + hey.name = "Hey" + child.add_child(hey) + hey.owner = self + hey.unique_name_in_owner = true + + var fake_hey = Node.new() + fake_hey.name = "Hey" + add_child(fake_hey) + fake_hey.owner = self + + var sub_child = Node.new() + sub_child.name = "SubChild" + hey.add_child(sub_child) + sub_child.owner = self + + var howdy = Node.new() + howdy.name = "Howdy" + sub_child.add_child(howdy) + howdy.owner = self + howdy.unique_name_in_owner = true + + print(hey == $Child/Hey) + print(howdy == $Child/Hey/SubChild/Howdy) + + print(%Hey == hey) + print($%Hey == hey) + print(%"Hey" == hey) + print($"%Hey" == hey) + print($%"Hey" == hey) + print(%Hey/%Howdy == howdy) + print($%Hey/%Howdy == howdy) + print($"%Hey/%Howdy" == howdy) + print($"%Hey"/"%Howdy" == howdy) + print(%"Hey"/"%Howdy" == howdy) + print($%"Hey"/"%Howdy" == howdy) + print($"%Hey"/%"Howdy" == howdy) + print(%"Hey"/%"Howdy" == howdy) + print($%"Hey"/%"Howdy" == howdy) + print(%"Hey/%Howdy" == howdy) + print($%"Hey/%Howdy" == howdy) diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out new file mode 100644 index 0000000000..041c4439b0 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/dollar_and_percent_get_node.out @@ -0,0 +1,19 @@ +GDTEST_OK +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd new file mode 100644 index 0000000000..f5e26ab1ab --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.gd @@ -0,0 +1,7 @@ +# https://github.com/godotengine/godot/issues/61231 + +func test(): + var my_lambda = func(): + print("hello") + if 0 == 0: + my_lambda.call() diff --git a/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out new file mode 100644 index 0000000000..58774d2d3f --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/if_after_lambda.out @@ -0,0 +1,2 @@ +GDTEST_OK +hello diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd new file mode 100644 index 0000000000..2140b6923e --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.gd @@ -0,0 +1,7 @@ +# https://github.com/godotengine/godot/issues/56751 + +func test(): + var x = "local" + var lambda = func(param = x): + print(param) + lambda.call() diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out new file mode 100644 index 0000000000..ce3241b94d --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/lambda_default_parameter_capture.out @@ -0,0 +1,2 @@ +GDTEST_OK +local diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd new file mode 100644 index 0000000000..a0ae7fb17c --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd @@ -0,0 +1,6 @@ +func test(): + match [1, 2, 3]: + [var a, var b, var c]: + print(a == 1) + print(b == 2) + print(c == 3) diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out new file mode 100644 index 0000000000..316db6d748 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out @@ -0,0 +1,4 @@ +GDTEST_OK +true +true +true diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd new file mode 100644 index 0000000000..d00d483a73 --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.gd @@ -0,0 +1,16 @@ +func test(): + var foo := "bar" + match foo: + "baz": + return + _: + pass + match foo: + "baz": + return + match foo: + "bar": + pass + _: + return + print("reached") diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out new file mode 100644 index 0000000000..47db6b631b --- /dev/null +++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return_bug_55154.out @@ -0,0 +1,2 @@ +GDTEST_OK +reached diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml index 03b4380ff4..3c28546ad7 100644 --- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -7,65 +7,52 @@ <tutorials> </tutorials> <methods> - <method name="export_post"> - <return type="int" enum="Error" /> - <argument index="0" name="document" type="GLTFDocument" /> + <method name="_export_node" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> + <argument index="1" name="gltf_node" type="GLTFNode" /> + <argument index="2" name="json" type="Dictionary" /> + <argument index="3" name="node" type="Node" /> <description> </description> </method> - <method name="export_preflight"> - <return type="int" enum="Error" /> - <argument index="0" name="document" type="GLTFDocument" /> - <argument index="1" name="node" type="Node" /> + <method name="_export_post" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> <description> </description> </method> - <method name="get_export_setting" qualifiers="const"> - <return type="Variant" /> - <argument index="0" name="key" type="StringName" /> + <method name="_export_preflight" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="root" type="Node" /> <description> </description> </method> - <method name="get_export_setting_keys" qualifiers="const"> - <return type="Array" /> + <method name="_import_node" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> + <argument index="1" name="gltf_node" type="GLTFNode" /> + <argument index="2" name="json" type="Dictionary" /> + <argument index="3" name="node" type="Node" /> <description> </description> </method> - <method name="get_import_setting" qualifiers="const"> - <return type="Variant" /> - <argument index="0" name="key" type="StringName" /> + <method name="_import_post" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> + <argument index="1" name="root" type="Node" /> <description> </description> </method> - <method name="get_import_setting_keys" qualifiers="const"> - <return type="Array" /> + <method name="_import_post_parse" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> <description> </description> </method> - <method name="import_post"> - <return type="int" enum="Error" /> - <argument index="0" name="document" type="GLTFDocument" /> - <argument index="1" name="node" type="Node" /> - <description> - </description> - </method> - <method name="import_preflight"> - <return type="int" enum="Error" /> - <argument index="0" name="document" type="GLTFDocument" /> - <description> - </description> - </method> - <method name="set_export_setting"> - <return type="void" /> - <argument index="0" name="key" type="StringName" /> - <argument index="1" name="value" type="Variant" /> - <description> - </description> - </method> - <method name="set_import_setting"> - <return type="void" /> - <argument index="0" name="key" type="StringName" /> - <argument index="1" name="value" type="Variant" /> + <method name="_import_preflight" qualifiers="virtual"> + <return type="int" /> + <argument index="0" name="state" type="GLTFState" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index a59fa900bc..44a1723563 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -192,6 +192,8 @@ </method> </methods> <members> + <member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default=""""> + </member> <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]"> </member> <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()"> diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 173d5131cf..676862ea5a 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -58,7 +58,7 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions) } Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -239,7 +239,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ } Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, - const Map<StringName, Variant> &p_options) { + const HashMap<StringName, Variant> &p_options) { if (p_path.get_extension().to_lower() != "blend") { return true; } @@ -310,7 +310,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) { Error err = OS::get_singleton()->execute(path, args, &pipe); if (err != OK) { if (r_err) { - *r_err = TTR("Can't excecute Blender binary."); + *r_err = TTR("Can't execute Blender binary."); } return false; } diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index 0925333a28..dd1c1b9889 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -66,12 +66,12 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, - const Map<StringName, Variant> &p_options) override; + const HashMap<StringName, Variant> &p_options) override; }; class LineEdit; diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index 893d2efcec..faad2d315d 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -30,7 +30,7 @@ #include "editor_scene_importer_fbx.h" -#if TOOLS_ENABLED +#ifdef TOOLS_ENABLED #include "../gltf_document.h" #include "../gltf_state.h" @@ -49,7 +49,7 @@ void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) co } Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. @@ -106,7 +106,7 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t } Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation, - const String &p_option, const Map<StringName, Variant> &p_options) { + const String &p_option, const HashMap<StringName, Variant> &p_options) { return true; } diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h index 84de7fd1cc..b0039b1c8f 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.h +++ b/modules/gltf/editor/editor_scene_importer_fbx.h @@ -45,12 +45,12 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) override; virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, - const Map<StringName, Variant> &p_options) override; + const HashMap<StringName, Variant> &p_options) override; }; #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp index 5e7811ad2b..3fadec5167 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp @@ -35,7 +35,6 @@ #include "../gltf_document.h" #include "../gltf_state.h" -#include "scene/main/node.h" #include "scene/resources/animation.h" uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const { @@ -48,7 +47,7 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c } Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { Ref<GLTFDocument> doc; doc.instantiate(); diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h index b714ada124..b17a1e4eaa 100644 --- a/modules/gltf/editor/editor_scene_importer_gltf.h +++ b/modules/gltf/editor/editor_scene_importer_gltf.h @@ -33,6 +33,9 @@ #ifdef TOOLS_ENABLED +#include "../gltf_document_extension.h" +#include "../gltf_state.h" + #include "editor/import/resource_importer_scene.h" class Animation; @@ -45,7 +48,7 @@ public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; virtual Node *import_scene(const String &p_path, uint32_t p_flags, - const Map<StringName, Variant> &p_options, int p_bake_fps, + const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h index 6bf1bf543a..f412dc2c7f 100644 --- a/modules/gltf/gltf_accessor.h +++ b/modules/gltf/gltf_accessor.h @@ -34,7 +34,6 @@ #include "core/io/resource.h" #include "gltf_document.h" -#include "gltf_document_extension.h" struct GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); diff --git a/modules/gltf/gltf_animation.cpp b/modules/gltf/gltf_animation.cpp index c857be4b2c..e598c870ab 100644 --- a/modules/gltf/gltf_animation.cpp +++ b/modules/gltf/gltf_animation.cpp @@ -45,7 +45,7 @@ void GLTFAnimation::set_loop(bool p_val) { loop = p_val; } -Map<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() { +HashMap<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() { return tracks; } diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h index ba8ae8a273..8688ddb937 100644 --- a/modules/gltf/gltf_animation.h +++ b/modules/gltf/gltf_animation.h @@ -64,11 +64,11 @@ public: public: bool get_loop() const; void set_loop(bool p_val); - Map<int, GLTFAnimation::Track> &get_tracks(); + HashMap<int, GLTFAnimation::Track> &get_tracks(); GLTFAnimation(); private: bool loop = false; - Map<int, Track> tracks; + HashMap<int, Track> tracks; }; #endif // GLTF_ANIMATION_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 082b4ce1ec..2017355717 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -128,10 +128,10 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { state->buffers.push_back(Vector<uint8_t>()); } - /* STEP 1 CONVERT MESH INSTANCES */ + /* STEP CONVERT MESH INSTANCES */ _convert_mesh_instances(state); - /* STEP 2 SERIALIZE CAMERAS */ + /* STEP SERIALIZE CAMERAS */ Error err = _serialize_cameras(state); if (err != OK) { return Error::FAILED; @@ -143,37 +143,37 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { return Error::FAILED; } - /* STEP 5 SERIALIZE MESHES (we have enough info now) */ + /* STEP SERIALIZE MESHES (we have enough info now) */ err = _serialize_meshes(state); if (err != OK) { return Error::FAILED; } - /* STEP 6 SERIALIZE TEXTURES */ + /* STEP SERIALIZE TEXTURES */ err = _serialize_materials(state); if (err != OK) { return Error::FAILED; } - /* STEP 7 SERIALIZE ANIMATIONS */ + /* STEP SERIALIZE ANIMATIONS */ err = _serialize_animations(state); if (err != OK) { return Error::FAILED; } - /* STEP 8 SERIALIZE ACCESSORS */ + /* STEP SERIALIZE ACCESSORS */ err = _encode_accessors(state); if (err != OK) { return Error::FAILED; } - /* STEP 9 SERIALIZE IMAGES */ + /* STEP SERIALIZE IMAGES */ err = _serialize_images(state, p_path); if (err != OK) { return Error::FAILED; } - /* STEP 10 SERIALIZE TEXTURES */ + /* STEP SERIALIZE TEXTURES */ err = _serialize_textures(state); if (err != OK) { return Error::FAILED; @@ -183,42 +183,49 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) { state->buffer_views.write[i]->buffer = 0; } - /* STEP 11 SERIALIZE BUFFER VIEWS */ + /* STEP SERIALIZE BUFFER VIEWS */ err = _encode_buffer_views(state); if (err != OK) { return Error::FAILED; } - /* STEP 12 SERIALIZE NODES */ + /* STEP SERIALIZE NODES */ err = _serialize_nodes(state); if (err != OK) { return Error::FAILED; } - /* STEP 13 SERIALIZE SCENE */ + /* STEP SERIALIZE SCENE */ err = _serialize_scenes(state); if (err != OK) { return Error::FAILED; } - /* STEP 14 SERIALIZE SCENE */ + /* STEP SERIALIZE SCENE */ err = _serialize_lights(state); if (err != OK) { return Error::FAILED; } - /* STEP 15 SERIALIZE EXTENSIONS */ + /* STEP SERIALIZE EXTENSIONS */ err = _serialize_extensions(state); if (err != OK) { return Error::FAILED; } - /* STEP 16 SERIALIZE VERSION */ + /* STEP SERIALIZE VERSION */ err = _serialize_version(state); if (err != OK) { return Error::FAILED; } + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->export_post(state); + ERR_FAIL_COND_V(err != OK, err); + } + return OK; } @@ -442,6 +449,15 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { } node["children"] = children; } + + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + ERR_CONTINUE(!state->scene_nodes.find(i)); + Error err = ext->export_node(state, n, state->json, state->scene_nodes[i]); + ERR_CONTINUE(err != OK); + } + nodes.push_back(node); } state->json["nodes"] = nodes; @@ -2294,7 +2310,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { attributes["COLOR_0"] = _encode_accessor_as_color(state, a, true); } } - Map<int, int> joint_i_to_bone_i; + HashMap<int, int> joint_i_to_bone_i; for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) { GLTFSkinIndex skin_i = -1; if (state->nodes[node_i]->mesh == gltf_mesh_i) { @@ -2468,9 +2484,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { mat = import_mesh->get_surface_material(surface_i); } if (mat.is_valid()) { - Map<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Element *material_cache_i = state->material_cache.find(mat); - if (material_cache_i && material_cache_i->get() != -1) { - primitive["material"] = material_cache_i->get(); + HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); + if (material_cache_i && material_cache_i->value != -1) { + primitive["material"] = material_cache_i->value; } else { GLTFMaterialIndex mat_i = state->materials.size(); state->materials.push_back(mat); @@ -5658,7 +5674,7 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent if (!current_node) { current_node = _generate_spatial(state, node_index); } - scene_parent->add_child(current_node); + scene_parent->add_child(current_node, true); if (current_node != scene_root) { current_node->set_owner(scene_root); } @@ -5904,9 +5920,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, Node *root = ap->get_parent(); ERR_FAIL_COND(root == nullptr); - Map<GLTFNodeIndex, Node *>::Element *node_element = state->scene_nodes.find(node_index); - ERR_CONTINUE_MSG(node_element == nullptr, vformat("Unable to find node %d for animation", node_index)); - node_path = root->get_path_to(node_element->get()); + HashMap<GLTFNodeIndex, Node *>::Iterator node_element = state->scene_nodes.find(node_index); + ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation", node_index)); + node_path = root->get_path_to(node_element->value); if (gltf_node->skeleton >= 0) { const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton; @@ -6116,11 +6132,11 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { if (node->mesh < 0) { continue; } - Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(mi_node_i); + HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(mi_node_i); if (!mi_element) { continue; } - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); + MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->value); if (!mi) { continue; } @@ -6250,11 +6266,11 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo if (node->skin >= 0 && node->mesh >= 0) { const GLTFSkinIndex skin_i = node->skin; - Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i); - ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i)); + HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(node_i); + ERR_CONTINUE_MSG(!mi_element, vformat("Unable to find node %d", node_i)); - ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->get()); - ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->get()->get_class_name())); + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->value); + ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->value->get_class_name())); const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton; Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i]; @@ -6436,10 +6452,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : state->scene_nodes) { if (position_scene_node_i.value == node) { GLTFNodeIndex node_index = position_scene_node_i.key; - Map<int, GLTFAnimation::Track>::Element *position_track_i = gltf_animation->get_tracks().find(node_index); + HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index); GLTFAnimation::Track track; if (position_track_i) { - track = position_track_i->get(); + track = position_track_i->value; } track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); @@ -6452,10 +6468,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : state->scene_nodes) { if (rotation_degree_scene_node_i.value == node) { GLTFNodeIndex node_index = rotation_degree_scene_node_i.key; - Map<int, GLTFAnimation::Track>::Element *rotation_degree_track_i = gltf_animation->get_tracks().find(node_index); + HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index); GLTFAnimation::Track track; if (rotation_degree_track_i) { - track = rotation_degree_track_i->get(); + track = rotation_degree_track_i->value; } track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); @@ -6468,10 +6484,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : state->scene_nodes) { if (scale_scene_node_i.value == node) { GLTFNodeIndex node_index = scale_scene_node_i.key; - Map<int, GLTFAnimation::Track>::Element *scale_track_i = gltf_animation->get_tracks().find(node_index); + HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index); GLTFAnimation::Track track; if (scale_track_i) { - track = scale_track_i->get(); + track = scale_track_i->value; } track = _convert_animation_track(state, track, animation, track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); @@ -6503,7 +6519,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } ERR_CONTINUE(mesh_index == -1); - Map<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks(); + HashMap<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks(); GLTFAnimation::Track track = gltf_animation->get_tracks().has(mesh_index) ? gltf_animation->get_tracks()[mesh_index] : GLTFAnimation::Track(); if (!tracks.has(mesh_index)) { for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) { @@ -6565,10 +6581,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, continue; } GLTFNodeIndex node_i = skeleton_gltf->godot_bone_node[bone]; - Map<int, GLTFAnimation::Track>::Element *property_track_i = gltf_animation->get_tracks().find(node_i); + HashMap<int, GLTFAnimation::Track>::Iterator property_track_i = gltf_animation->get_tracks().find(node_i); GLTFAnimation::Track track; if (property_track_i) { - track = property_track_i->get(); + track = property_track_i->value; } track = _convert_animation_track(state, track, animation, track_i, node_i); gltf_animation->get_tracks()[node_i] = track; @@ -6580,10 +6596,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) { if (scene_node_i.value == godot_node) { GLTFNodeIndex node_i = scene_node_i.key; - Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_i); + HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i); GLTFAnimation::Track track; if (node_track_i) { - track = node_track_i->get(); + track = node_track_i->value; } track = _convert_animation_track(state, track, animation, track_i, node_i); gltf_animation->get_tracks()[node_i] = track; @@ -6642,8 +6658,8 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; ERR_CONTINUE(ext.is_null()); - err = ext->import_preflight(this); - ERR_FAIL_COND_V(err != OK, FAILED); + err = ext->import_preflight(state); + ERR_FAIL_COND_V(err != OK, err); } err = _parse_gltf_state(state, p_path, p_bake_fps); ERR_FAIL_COND_V(err != OK, err); @@ -6870,12 +6886,10 @@ PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> state) { Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_path) { ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); - Error err = _serialize(state, p_path); if (err != OK) { return err; } - err = _serialize_file(state, p_path); if (err != OK) { return Error::FAILED; @@ -6886,6 +6900,7 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> state, const String &p_pa Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { ERR_FAIL_NULL_V(state, nullptr); ERR_FAIL_INDEX_V(0, state->root_nodes.size(), nullptr); + Error err = OK; GLTFNodeIndex gltf_root = state->root_nodes.write[0]; Node *gltf_root_node = state->get_scene_node(gltf_root); Node *root = gltf_root_node->get_parent(); @@ -6899,12 +6914,26 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) { _import_animation(state, ap, i, p_bake_fps); } } - + for (KeyValue<GLTFNodeIndex, Node *> E : state->scene_nodes) { + ERR_CONTINUE(!E.value); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + ERR_CONTINUE(!state->json.has("nodes")); + Array nodes = state->json["nodes"]; + ERR_CONTINUE(E.key >= nodes.size()); + ERR_CONTINUE(E.key < 0); + Dictionary node_json = nodes[E.key]; + Ref<GLTFNode> gltf_node = state->nodes[E.key]; + err = ext->import_node(state, gltf_node, node_json, E.value); + ERR_CONTINUE(err != OK); + } + } for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; ERR_CONTINUE(ext.is_null()); - Error err = ext->import_post(this, root); - ERR_FAIL_COND_V(err != OK, nullptr); + err = ext->import_post(state, root); + ERR_CONTINUE(err != OK); } ERR_FAIL_NULL_V(root, nullptr); return root; @@ -6919,13 +6948,23 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32 if (!state->buffers.size()) { state->buffers.push_back(Vector<uint8_t>()); } + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + } - /* STEP 1 CONVERT MESH INSTANCES */ - _convert_mesh_instances(state); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Error err = ext->export_preflight(p_node); + ERR_FAIL_COND_V(err != OK, FAILED); + } + _convert_scene_node(state, p_node, -1, -1); + if (!state->buffers.size()) { + state->buffers.push_back(Vector<uint8_t>()); + } - /* STEP 2 CREATE SKINS */ - Error err = _serialize_skins(state); - return err; + return OK; } Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) { @@ -6938,8 +6977,15 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa Ref<FileAccessMemory> file_access; file_access.instantiate(); file_access->open_custom(p_bytes.ptr(), p_bytes.size()); - err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps); - ERR_FAIL_COND_V(err != OK, FAILED); + state->base_path = p_base_path.get_base_dir(); + err = _parse(state, state->base_path, file_access, p_bake_fps); + ERR_FAIL_COND_V(err != OK, err); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->import_post_parse(state); + ERR_FAIL_COND_V(err != OK, err); + } return OK; } @@ -7030,6 +7076,7 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear for (int32_t root_i = 0; root_i < state->root_nodes.size(); root_i++) { _generate_scene_node(state, root, root, state->root_nodes[root_i]); } + return OK; } @@ -7049,9 +7096,16 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint if (base_path.is_empty()) { base_path = p_path.get_base_dir(); } + r_state->base_path = base_path; err = _parse(r_state, base_path, f, p_bake_fps); - ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); - return err; + ERR_FAIL_COND_V(err != OK, err); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->import_post_parse(r_state); + ERR_FAIL_COND_V(err != OK, err); + } + return OK; } Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> state) { diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 19bc507a8d..2f61210ff9 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -33,19 +33,12 @@ #include "gltf_animation.h" -#include "core/error/error_list.h" -#include "core/variant/dictionary.h" -#include "core/variant/variant.h" -#include "gltf_document_extension_convert_importer_mesh.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/material.h" -#include "scene/resources/texture.h" #include "modules/modules_enabled.gen.h" // For csg, gridmap. @@ -135,12 +128,12 @@ private: } template <class T> - static Array to_array(const Set<T> &p_inp) { + static Array to_array(const HashSet<T> &p_inp) { Array ret; - typename Set<T>::Element *elem = p_inp.front(); + typename HashSet<T>::Iterator elem = p_inp.begin(); while (elem) { - ret.push_back(elem->get()); - elem = elem->next(); + ret.push_back(*elem); + ++elem; } return ret; } @@ -154,23 +147,23 @@ private: } template <class T> - static void set_from_array(Set<T> &r_out, const Array &p_inp) { + static void set_from_array(HashSet<T> &r_out, const Array &p_inp) { r_out.clear(); for (int i = 0; i < p_inp.size(); i++) { r_out.insert(p_inp[i]); } } template <class K, class V> - static Dictionary to_dict(const Map<K, V> &p_inp) { + static Dictionary to_dict(const HashMap<K, V> &p_inp) { Dictionary ret; - for (typename Map<K, V>::Element *E = p_inp.front(); E; E = E->next()) { - ret[E->key()] = E->value(); + for (const KeyValue<K, V> &E : p_inp) { + ret[E.key] = E.value; } return ret; } template <class K, class V> - static void set_from_dict(Map<K, V> &r_out, const Dictionary &p_inp) { + static void set_from_dict(HashMap<K, V> &r_out, const Dictionary &p_inp) { r_out.clear(); Array keys = p_inp.keys(); for (int i = 0; i < keys.size(); i++) { diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp index 192a1d347c..d0bd7651e0 100644 --- a/modules/gltf/gltf_document_extension.cpp +++ b/modules/gltf/gltf_document_extension.cpp @@ -30,59 +30,79 @@ #include "gltf_document_extension.h" -#include "gltf_document.h" - void GLTFDocumentExtension::_bind_methods() { - // Import - ClassDB::bind_method(D_METHOD("get_import_setting_keys"), - &GLTFDocumentExtension::get_import_setting_keys); - ClassDB::bind_method(D_METHOD("import_preflight", "document"), - &GLTFDocumentExtension::import_preflight); - ClassDB::bind_method(D_METHOD("get_import_setting", "key"), - &GLTFDocumentExtension::get_import_setting); - ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"), - &GLTFDocumentExtension::set_import_setting); - ClassDB::bind_method(D_METHOD("import_post", "document", "node"), - &GLTFDocumentExtension::import_post); - // Export - ClassDB::bind_method(D_METHOD("get_export_setting_keys"), - &GLTFDocumentExtension::get_export_setting_keys); - ClassDB::bind_method(D_METHOD("get_export_setting", "key"), - &GLTFDocumentExtension::get_export_setting); - ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"), - &GLTFDocumentExtension::set_export_setting); - ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"), - &GLTFDocumentExtension::export_preflight); - ClassDB::bind_method(D_METHOD("export_post", "document"), - &GLTFDocumentExtension::export_post); + GDVIRTUAL_BIND(_import_preflight, "state"); + GDVIRTUAL_BIND(_import_post_parse, "state"); + GDVIRTUAL_BIND(_import_node, "state", "gltf_node", "json", "node"); + GDVIRTUAL_BIND(_import_post, "state", "root"); + GDVIRTUAL_BIND(_export_preflight, "root"); + GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node"); + GDVIRTUAL_BIND(_export_post, "state"); } -Array GLTFDocumentExtension::get_import_setting_keys() const { - return import_settings.keys(); +Error GLTFDocumentExtension::import_post(Ref<GLTFState> p_state, Node *p_root) { + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_import_post, p_state, p_root, err)) { + return Error(err); + } + return OK; } -Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const { - if (!import_settings.has(p_key)) { - return Variant(); +Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_import_preflight, p_state, err)) { + return Error(err); } - return import_settings[p_key]; + return OK; } -void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) { - import_settings[p_key] = p_var; +Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_import_post_parse, p_state, err)) { + return Error(err); + } + return OK; } -Array GLTFDocumentExtension::get_export_setting_keys() const { - return import_settings.keys(); +Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_export_post, p_state, err)) { + return Error(err); + } + return OK; +} +Error GLTFDocumentExtension::export_preflight(Node *p_root) { + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_export_preflight, p_root, err)) { + return Error(err); + } + return OK; } -Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const { - if (!import_settings.has(p_key)) { - return Variant(); +Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err)) { + return Error(err); } - return import_settings[p_key]; + return OK; } -void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) { - import_settings[p_key] = p_var; +Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) { + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); + int err = OK; + if (GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err)) { + return Error(err); + } + return OK; } diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h index f7a3531282..556f79e887 100644 --- a/modules/gltf/gltf_document_extension.h +++ b/modules/gltf/gltf_document_extension.h @@ -31,33 +31,31 @@ #ifndef GLTF_DOCUMENT_EXTENSION_H #define GLTF_DOCUMENT_EXTENSION_H -#include "core/io/resource.h" -#include "core/variant/dictionary.h" -#include "core/variant/typed_array.h" -#include "core/variant/variant.h" -class GLTFDocument; +#include "gltf_accessor.h" +#include "gltf_node.h" +#include "gltf_state.h" + class GLTFDocumentExtension : public Resource { GDCLASS(GLTFDocumentExtension, Resource); - Dictionary import_settings; - Dictionary export_settings; - protected: static void _bind_methods(); public: - virtual Array get_import_setting_keys() const; - virtual Variant get_import_setting(const StringName &p_key) const; - virtual void set_import_setting(const StringName &p_key, Variant p_var); - virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; } - virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; } - -public: - virtual Array get_export_setting_keys() const; - virtual Variant get_export_setting(const StringName &p_key) const; - virtual void set_export_setting(const StringName &p_key, Variant p_var); - virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; } - virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; } + virtual Error import_preflight(Ref<GLTFState> p_state); + virtual Error import_post_parse(Ref<GLTFState> p_state); + virtual Error export_post(Ref<GLTFState> p_state); + virtual Error import_post(Ref<GLTFState> p_state, Node *p_node); + virtual Error export_preflight(Node *p_state); + virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node); + GDVIRTUAL1R(int, _import_preflight, Ref<GLTFState>); + GDVIRTUAL1R(int, _import_post_parse, Ref<GLTFState>); + GDVIRTUAL4R(int, _import_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); + GDVIRTUAL2R(int, _import_post, Ref<GLTFState>, Node *); + GDVIRTUAL1R(int, _export_preflight, Node *); + GDVIRTUAL4R(int, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *); + GDVIRTUAL1R(int, _export_post, Ref<GLTFState>); }; #endif // GLTF_DOCUMENT_EXTENSION_H diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp index 47a3e5598f..1620900a04 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp @@ -29,41 +29,40 @@ /*************************************************************************/ #include "gltf_document_extension_convert_importer_mesh.h" + +#include "gltf_state.h" + #include "core/error/error_macros.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/resources/importer_mesh.h" -#include <cstddef> - void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() { } -Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) { - ERR_FAIL_NULL_V(p_document, ERR_INVALID_PARAMETER); - ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER); +Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFState> p_state, Node *p_root) { + ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER); + ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER); List<Node *> queue; - queue.push_back(p_node); + queue.push_back(p_root); List<Node *> delete_queue; while (!queue.is_empty()) { List<Node *>::Element *E = queue.front(); Node *node = E->get(); - { - ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node); - if (mesh_3d) { - MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D); - Ref<ImporterMesh> mesh = mesh_3d->get_mesh(); - if (mesh.is_valid()) { - Ref<ArrayMesh> array_mesh = mesh->get_mesh(); - mesh_instance_node_3d->set_name(node->get_name()); - mesh_instance_node_3d->set_transform(mesh_3d->get_transform()); - mesh_instance_node_3d->set_mesh(array_mesh); - mesh_instance_node_3d->set_skin(mesh_3d->get_skin()); - mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path()); - node->replace_by(mesh_instance_node_3d); - delete_queue.push_back(node); - } else { - memdelete(mesh_instance_node_3d); - } + ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node); + if (mesh_3d) { + MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D); + Ref<ImporterMesh> mesh = mesh_3d->get_mesh(); + if (mesh.is_valid()) { + Ref<ArrayMesh> array_mesh = mesh->get_mesh(); + mesh_instance_node_3d->set_name(node->get_name()); + mesh_instance_node_3d->set_transform(mesh_3d->get_transform()); + mesh_instance_node_3d->set_mesh(array_mesh); + mesh_instance_node_3d->set_skin(mesh_3d->get_skin()); + mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path()); + node->replace_by(mesh_instance_node_3d); + delete_queue.push_back(node); + } else { + memdelete(mesh_instance_node_3d); } } int child_count = node->get_child_count(); diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.h index 2d51143140..4c9e42a00f 100644 --- a/modules/gltf/gltf_document_extension_convert_importer_mesh.h +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h @@ -31,14 +31,10 @@ #ifndef GLTF_EXTENSION_EDITOR_H #define GLTF_EXTENSION_EDITOR_H -#include "core/io/resource.h" -#include "core/variant/dictionary.h" - -#include "gltf_document.h" #include "gltf_document_extension.h" + #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/mesh_instance_3d.h" -#include "scene/main/node.h" #include "scene/resources/importer_mesh.h" class GLTFDocumentExtension; @@ -50,6 +46,6 @@ protected: static void _bind_methods(); public: - Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override; + Error import_post(Ref<GLTFState> p_state, Node *p_root) override; }; #endif // GLTF_EXTENSION_EDITOR_H diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp index e80376f130..b813f39a27 100644 --- a/modules/gltf/gltf_skeleton.cpp +++ b/modules/gltf/gltf_skeleton.cpp @@ -46,7 +46,7 @@ void GLTFSkeleton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String> - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "godot_bone_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_godot_bone_node", "get_godot_bone_node"); // Map<int32_t, + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "godot_bone_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_godot_bone_node", "get_godot_bone_node"); // RBMap<int32_t, } Vector<GLTFNodeIndex> GLTFSkeleton::get_joints() { diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h index 7d07d528cb..92ee6e6234 100644 --- a/modules/gltf/gltf_skeleton.h +++ b/modules/gltf/gltf_skeleton.h @@ -50,9 +50,9 @@ private: Skeleton3D *godot_skeleton = nullptr; // Set of unique bone names for the skeleton - Set<String> unique_names; + HashSet<String> unique_names; - Map<int32_t, GLTFNodeIndex> godot_bone_node; + HashMap<int32_t, GLTFNodeIndex> godot_bone_node; Vector<BoneAttachment3D *> bone_attachments; @@ -78,10 +78,10 @@ public: Array get_unique_names(); void set_unique_names(Array p_unique_names); - //Map<int32_t, GLTFNodeIndex> get_godot_bone_node() { + //RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() { // return this->godot_bone_node; //} - //void set_godot_bone_node(Map<int32_t, GLTFNodeIndex> p_godot_bone_node) { + //void set_godot_bone_node(RBMap<int32_t, GLTFNodeIndex> p_godot_bone_node) { // this->godot_bone_node = p_godot_bone_node; //} Dictionary get_godot_bone_node(); diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp index 283fc34ff5..e8005aa0c1 100644 --- a/modules/gltf/gltf_skin.cpp +++ b/modules/gltf/gltf_skin.cpp @@ -59,8 +59,8 @@ void GLTFSkin::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // int - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_bone_i", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_bone_i", "get_joint_i_to_bone_i"); // Map<int, - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_name", "get_joint_i_to_name"); // Map<int, + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_bone_i", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_bone_i", "get_joint_i_to_bone_i"); // RBMap<int, + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_name", "get_joint_i_to_name"); // RBMap<int, ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "godot_skin"), "set_godot_skin", "get_godot_skin"); // Ref<Skin> } @@ -130,16 +130,16 @@ void GLTFSkin::set_joint_i_to_bone_i(Dictionary p_joint_i_to_bone_i) { Dictionary GLTFSkin::get_joint_i_to_name() { Dictionary ret; - Map<int, StringName>::Element *elem = joint_i_to_name.front(); + HashMap<int, StringName>::Iterator elem = joint_i_to_name.begin(); while (elem) { - ret[elem->key()] = String(elem->value()); - elem = elem->next(); + ret[elem->key] = String(elem->value); + ++elem; } return ret; } void GLTFSkin::set_joint_i_to_name(Dictionary p_joint_i_to_name) { - joint_i_to_name = Map<int, StringName>(); + joint_i_to_name = HashMap<int, StringName>(); Array keys = p_joint_i_to_name.keys(); for (int i = 0; i < keys.size(); i++) { joint_i_to_name[keys[i]] = p_joint_i_to_name[keys[i]]; diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h index 31cb892f19..d946324756 100644 --- a/modules/gltf/gltf_skin.h +++ b/modules/gltf/gltf_skin.h @@ -65,8 +65,8 @@ private: // A mapping from the joint indices (in the order of joints_original) to the // Godot Skeleton's bone_indices - Map<int, int> joint_i_to_bone_i; - Map<int, StringName> joint_i_to_name; + HashMap<int, int> joint_i_to_bone_i; + HashMap<int, StringName> joint_i_to_name; // The Actual Skin that will be created as a mapping between the IBM's of // this skin to the generated skeleton for the mesh instances. diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp index 6ead2f69c3..989fa476c2 100644 --- a/modules/gltf/gltf_state.cpp +++ b/modules/gltf/gltf_state.cpp @@ -57,6 +57,8 @@ void GLTFState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_materials", "materials"), &GLTFState::set_materials); ClassDB::bind_method(D_METHOD("get_scene_name"), &GLTFState::get_scene_name); ClassDB::bind_method(D_METHOD("set_scene_name", "scene_name"), &GLTFState::set_scene_name); + ClassDB::bind_method(D_METHOD("get_base_path"), &GLTFState::get_base_path); + ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &GLTFState::set_base_path); ClassDB::bind_method(D_METHOD("get_root_nodes"), &GLTFState::get_root_nodes); ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes); ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures); @@ -93,6 +95,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "meshes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_meshes", "get_meshes"); // Vector<Ref<GLTFMesh>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "materials", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_materials", "get_materials"); // Vector<Ref<Material> ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_name"), "set_scene_name", "get_scene_name"); // String + ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_path"), "set_base_path", "get_base_path"); // String ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture> @@ -102,7 +105,7 @@ void GLTFState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String> ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>> - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // Map<GLTFSkeletonIndex, + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // RBMap<GLTFSkeletonIndex, ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>> } @@ -313,3 +316,11 @@ void GLTFState::set_discard_meshes_and_materials(bool p_discard_meshes_and_mater bool GLTFState::get_discard_meshes_and_materials() { return discard_meshes_and_materials; } + +String GLTFState::get_base_path() { + return base_path; +} + +void GLTFState::set_base_path(String p_base_path) { + base_path = p_base_path; +} diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 42ca079f1c..2fdef19038 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -44,10 +44,7 @@ #include "gltf_skin.h" #include "gltf_texture.h" -#include "core/io/resource.h" -#include "core/templates/map.h" -#include "core/templates/pair.h" -#include "core/templates/vector.h" +#include "core/templates/rb_map.h" #include "scene/animation/animation_player.h" #include "scene/resources/texture.h" @@ -56,6 +53,7 @@ class GLTFState : public Resource { friend class GLTFDocument; String filename; + String base_path; Dictionary json; int major_version = 0; int minor_version = 0; @@ -72,7 +70,7 @@ class GLTFState : public Resource { Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to. Vector<AnimationPlayer *> animation_players; - Map<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; + HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; Vector<Ref<BaseMaterial3D>> materials; String scene_name; @@ -83,16 +81,16 @@ class GLTFState : public Resource { Vector<Ref<GLTFSkin>> skins; Vector<Ref<GLTFCamera>> cameras; Vector<Ref<GLTFLight>> lights; - Set<String> unique_names; - Set<String> unique_animation_names; + HashSet<String> unique_names; + HashSet<String> unique_animation_names; Vector<Ref<GLTFSkeleton>> skeletons; - Map<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node; + HashMap<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node; Vector<Ref<GLTFAnimation>> animations; - Map<GLTFNodeIndex, Node *> scene_nodes; + HashMap<GLTFNodeIndex, Node *> scene_nodes; - Map<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton; - Map<ObjectID, Map<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin; + HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton; + HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin; protected: static void _bind_methods(); @@ -137,6 +135,9 @@ public: String get_scene_name(); void set_scene_name(String p_scene_name); + String get_base_path(); + void set_base_path(String p_base_path); + Array get_root_nodes(); void set_root_nodes(Array p_root_nodes); @@ -176,7 +177,7 @@ public: AnimationPlayer *get_animation_player(int idx); - //void set_scene_nodes(Map<GLTFNodeIndex, Node *> p_scene_nodes) { + //void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) { // this->scene_nodes = p_scene_nodes; //} @@ -184,10 +185,10 @@ public: // this->animation_players = p_animation_players; //} - //Map<Ref<Material>, GLTFMaterialIndex> get_material_cache() { + //RBMap<Ref<Material>, GLTFMaterialIndex> get_material_cache() { // return this->material_cache; //} - //void set_material_cache(Map<Ref<Material>, GLTFMaterialIndex> p_material_cache) { + //void set_material_cache(RBMap<Ref<Material>, GLTFMaterialIndex> p_material_cache) { // this->material_cache = p_material_cache; //} }; diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 2f613768ee..cfff5c61de 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -930,6 +930,7 @@ void GridMapEditor::edit(GridMap *p_gridmap) { } update_palette(); + _update_cursor_instance(); set_process(true); @@ -1220,7 +1221,7 @@ GridMapEditor::GridMapEditor() { search_box = memnew(LineEdit); search_box->set_h_size_flags(SIZE_EXPAND_FILL); - search_box->set_placeholder(TTR("Filter meshes")); + search_box->set_placeholder(TTR("Filter Meshes")); hb->add_child(search_box); search_box->connect("text_changed", callable_mp(this, &GridMapEditor::_text_changed)); search_box->connect("gui_input", callable_mp(this, &GridMapEditor::_sbox_input)); diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 3c7bd5eb70..dcdb520d11 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -103,9 +103,10 @@ bool GridMap::_get(const StringName &p_name, Variant &r_ret) const { { int *w = cells.ptrw(); int i = 0; - for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next(), i++) { - encode_uint64(E->key().key, (uint8_t *)&w[i * 3]); - encode_uint32(E->get().cell, (uint8_t *)&w[i * 3 + 2]); + for (const KeyValue<IndexKey, Cell> &E : cell_map) { + encode_uint64(E.key.key, (uint8_t *)&w[i * 3]); + encode_uint32(E.value.cell, (uint8_t *)&w[i * 3 + 2]); + i++; } } @@ -480,17 +481,17 @@ bool GridMap::_octant_update(const OctantKey &p_key) { * and set said multimesh bounding box to one containing all cells which have this item */ - Map<int, List<Pair<Transform3D, IndexKey>>> multimesh_items; + HashMap<int, List<Pair<Transform3D, IndexKey>>> multimesh_items; - for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) { - ERR_CONTINUE(!cell_map.has(E->get())); - const Cell &c = cell_map[E->get()]; + for (const IndexKey &E : g.cells) { + ERR_CONTINUE(!cell_map.has(E)); + const Cell &c = cell_map[E]; if (!mesh_library.is_valid() || !mesh_library->has_item(c.item)) { continue; } - Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z); + Vector3 cellpos = Vector3(E.x, E.y, E.z); Vector3 ofs = _get_offset(); Transform3D xform; @@ -506,7 +507,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Pair<Transform3D, IndexKey> p; p.first = xform * mesh_library->get_item_mesh_transform(c.item); - p.second = E->get(); + p.second = E; multimesh_items[c.item].push_back(p); } } @@ -539,7 +540,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { nm.region = region; } - g.navmesh_ids[E->get()] = nm; + g.navmesh_ids[E] = nm; } } @@ -770,7 +771,7 @@ void GridMap::_queue_octants_dirty() { void GridMap::_recreate_octant_data() { recreating_octants = true; - Map<IndexKey, Cell> cell_copy = cell_map; + HashMap<IndexKey, Cell, IndexKey> cell_copy = cell_map; _clear_internal(); for (const KeyValue<IndexKey, Cell> &E : cell_copy) { set_cell_item(Vector3i(E.key), E.value.item, E.value.rot); @@ -969,7 +970,7 @@ Array GridMap::get_meshes() const { xform.set_origin(cellpos * cell_size + ofs); xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale)); - meshes.push_back(xform); + meshes.push_back(xform * mesh_library->get_item_mesh_transform(id)); meshes.push_back(mesh); } @@ -998,7 +999,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe } //generate - Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> surface_map; + HashMap<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>, OctantKey> surface_map; for (KeyValue<IndexKey, Cell> &E : cell_map) { IndexKey key = E.key; @@ -1028,10 +1029,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe ok.z = key.z / octant_size; if (!surface_map.has(ok)) { - surface_map[ok] = Map<Ref<Material>, Ref<SurfaceTool>>(); + surface_map[ok] = HashMap<Ref<Material>, Ref<SurfaceTool>>(); } - Map<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok]; + HashMap<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok]; for (int i = 0; i < mesh->get_surface_count(); i++) { if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { @@ -1051,7 +1052,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe } } - for (KeyValue<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) { + for (KeyValue<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) { Ref<ArrayMesh> mesh; mesh.instantiate(); for (KeyValue<Ref<Material>, Ref<SurfaceTool>> &F : E.value) { diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 5e367e149d..d0872a839b 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -56,9 +56,15 @@ class GridMap : public Node3D { }; uint64_t key = 0; + static uint32_t hash(const IndexKey &p_key) { + return hash_one_uint64(p_key.key); + } _FORCE_INLINE_ bool operator<(const IndexKey &p_key) const { return key < p_key.key; } + _FORCE_INLINE_ bool operator==(const IndexKey &p_key) const { + return key == p_key.key; + } _FORCE_INLINE_ operator Vector3i() const { return Vector3i(x, y, z); @@ -107,13 +113,13 @@ class GridMap : public Node3D { }; Vector<MultimeshInstance> multimesh_instances; - Set<IndexKey> cells; + HashSet<IndexKey> cells; RID collision_debug; RID collision_debug_instance; bool dirty = false; RID static_body; - Map<IndexKey, NavMesh> navmesh_ids; + HashMap<IndexKey, NavMesh> navmesh_ids; }; union OctantKey { @@ -126,8 +132,11 @@ class GridMap : public Node3D { uint64_t key = 0; - _FORCE_INLINE_ bool operator<(const OctantKey &p_key) const { - return key < p_key.key; + static uint32_t hash(const OctantKey &p_key) { + return hash_one_uint64(p_key.key); + } + _FORCE_INLINE_ bool operator==(const OctantKey &p_key) const { + return key == p_key.key; } //OctantKey(const IndexKey& p_k, int p_item) { indexkey=p_k.key; item=p_item; } @@ -154,8 +163,8 @@ class GridMap : public Node3D { Ref<MeshLibrary> mesh_library; - Map<OctantKey, Octant *> octant_map; - Map<IndexKey, Cell> cell_map; + HashMap<OctantKey, Octant *, OctantKey> octant_map; + HashMap<IndexKey, Cell, IndexKey> cell_map; void _recreate_octant_data(); diff --git a/modules/jsonrpc/jsonrpc.h b/modules/jsonrpc/jsonrpc.h index 3144746f6d..f57d6aef42 100644 --- a/modules/jsonrpc/jsonrpc.h +++ b/modules/jsonrpc/jsonrpc.h @@ -37,7 +37,7 @@ class JSONRPC : public Object { GDCLASS(JSONRPC, Object) - Map<String, Object *> method_scopes; + HashMap<String, Object *> method_scopes; protected: static void _bind_methods(); diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp index 1818048877..92590fbcf6 100644 --- a/modules/mbedtls/stream_peer_mbedtls.cpp +++ b/modules/mbedtls/stream_peer_mbedtls.cpp @@ -298,6 +298,10 @@ StreamPeerMbedTLS::Status StreamPeerMbedTLS::get_status() const { return status; } +Ref<StreamPeer> StreamPeerMbedTLS::get_stream() const { + return base; +} + StreamPeerSSL *StreamPeerMbedTLS::_create_func() { return memnew(StreamPeerMbedTLS); } diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h index 98b91e65ab..7660410e04 100644 --- a/modules/mbedtls/stream_peer_mbedtls.h +++ b/modules/mbedtls/stream_peer_mbedtls.h @@ -57,6 +57,7 @@ public: virtual Error accept_stream(Ref<StreamPeer> p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert, Ref<X509Certificate> p_ca_chain = Ref<X509Certificate>()); virtual Error connect_to_stream(Ref<StreamPeer> p_base, bool p_validate_certs = false, const String &p_for_hostname = String(), Ref<X509Certificate> p_valid_cert = Ref<X509Certificate>()); virtual Status get_status() const; + virtual Ref<StreamPeer> get_stream() const; virtual void disconnect_from_stream(); diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index 6cd710e792..e03940f963 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -54,7 +54,7 @@ String ResourceImporterMP3::get_resource_type() const { return "AudioStreamMP3"; } -bool ResourceImporterMP3::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const { +bool ResourceImporterMP3::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; } @@ -71,7 +71,7 @@ void ResourceImporterMP3::get_import_options(const String &p_path, List<ImportOp r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); } -Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { +Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h index 75890228b9..678a3773bb 100644 --- a/modules/minimp3/resource_importer_mp3.h +++ b/modules/minimp3/resource_importer_mp3.h @@ -48,9 +48,9 @@ public: virtual String get_preset_name(int p_idx) const override; virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override; - virtual bool get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const override; + virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; + virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; ResourceImporterMP3(); }; diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 9253f105bb..3afde1e8d3 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -40,17 +40,12 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Dictionary classes_dict; - List<StringName> names; + List<StringName> class_list; + ClassDB::get_class_list(&class_list); + // Must be alphabetically sorted for hash to compute. + class_list.sort_custom<StringName::AlphCompare>(); - const StringName *k = nullptr; - - while ((k = ClassDB::classes.next(k))) { - names.push_back(*k); - } - //must be alphabetically sorted for hash to compute - names.sort_custom<StringName::AlphCompare>(); - - for (const StringName &E : names) { + for (const StringName &E : class_list) { ClassDB::ClassInfo *t = ClassDB::classes.getptr(E); ERR_FAIL_COND(!t); if (t->api != p_api || !t->exposed) { @@ -66,10 +61,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List<StringName> snames; - k = nullptr; - - while ((k = t->method_map.next(k))) { - String name = k->operator String(); + for (const KeyValue<StringName, MethodBind *> &F : t->method_map) { + String name = F.key.operator String(); ERR_CONTINUE(name.is_empty()); @@ -77,7 +70,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { continue; // Ignore non-virtual methods that start with an underscore } - snames.push_back(*k); + snames.push_back(F.key); } snames.sort_custom<StringName::AlphCompare>(); @@ -131,10 +124,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List<StringName> snames; - k = nullptr; - - while ((k = t->constant_map.next(k))) { - snames.push_back(*k); + for (const KeyValue<StringName, int> &F : t->constant_map) { + snames.push_back(F.key); } snames.sort_custom<StringName::AlphCompare>(); @@ -158,10 +149,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List<StringName> snames; - k = nullptr; - - while ((k = t->signal_map.next(k))) { - snames.push_back(*k); + for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) { + snames.push_back(F.key); } snames.sort_custom<StringName::AlphCompare>(); @@ -193,10 +182,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { List<StringName> snames; - k = nullptr; - - while ((k = t->property_setget.next(k))) { - snames.push_back(*k); + for (const KeyValue<StringName, ClassDB::PropertySetGet> &F : t->property_setget) { + snames.push_back(F.key); } snames.sort_custom<StringName::AlphCompare>(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 5875a0fbd4..622838b308 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -686,10 +686,10 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) { #ifdef DEBUG_ENABLED MutexLock lock(unsafe_object_references_lock); ObjectID id = p_obj->get_instance_id(); - Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id); + HashMap<ObjectID, int>::Iterator elem = unsafe_object_references.find(id); ERR_FAIL_NULL(elem); - if (--elem->value() == 0) { - unsafe_object_references.erase(elem); + if (--elem->value == 0) { + unsafe_object_references.remove(elem); } #endif } @@ -875,7 +875,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Script::instances are deleted during managed object disposal, which happens on domain finalize. // Only placeholders are kept. Therefore we need to keep a copy before that happens. - for (Object *&obj : script->instances) { + for (Object *obj : script->instances) { script->pending_reload_instances.insert(obj->get_instance_id()); RefCounted *rc = Object::cast_to<RefCounted>(obj); @@ -885,7 +885,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { } #ifdef TOOLS_ENABLED - for (PlaceHolderScriptInstance *&script_instance : script->placeholders) { + for (PlaceHolderScriptInstance *script_instance : script->placeholders) { Object *obj = script_instance->get_owner(); script->pending_reload_instances.insert(obj->get_instance_id()); @@ -897,9 +897,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { #endif // Save state and remove script from instances - Map<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state; + RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state; - for (Object *&obj : script->instances) { + for (Object *obj : script->instances) { ERR_CONTINUE(!obj->get_script_instance()); CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance()); @@ -922,8 +922,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // After the state of all instances is saved, clear scripts and script instances for (Ref<CSharpScript> &script : scripts) { - while (script->instances.front()) { - Object *obj = script->instances.front()->get(); + while (script->instances.begin()) { + Object *obj = *script->instances.begin(); obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload) } @@ -1099,14 +1099,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { const StringName &name = G.first; const Array &serialized_data = G.second; - Map<StringName, CSharpScript::EventSignal>::Element *match = script->event_signals.find(name); + HashMap<StringName, CSharpScript::EventSignal>::Iterator match = script->event_signals.find(name); if (!match) { // The event or its signal attribute were removed continue; } - const CSharpScript::EventSignal &event_signal = match->value(); + const CSharpScript::EventSignal &event_signal = match->value; MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data); MonoDelegate *delegate = nullptr; @@ -1428,7 +1428,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b return true; } -Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) { +RBMap<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) { return script_bindings.insert(p_object, p_script_binding); } @@ -1437,7 +1437,7 @@ void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance MutexLock lock(csharp_lang->language_bind_mutex); - Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance); + RBMap<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance); if (match) { return (void *)match; } @@ -1467,7 +1467,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin { MutexLock lock(csharp_lang->language_bind_mutex); - Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding; + RBMap<Object *, CSharpScriptBinding>::Element *data = (RBMap<Object *, CSharpScriptBinding>::Element *)p_binding; CSharpScriptBinding &script_binding = data->value(); @@ -1488,7 +1488,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) { CRASH_COND(!p_binding); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)p_binding)->get(); RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner); @@ -1558,7 +1558,7 @@ void *CSharpLanguage::get_instance_binding(Object *p_object) { // `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that. if (binding) { - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)binding)->value(); if (!script_binding.inited) { MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); @@ -1798,8 +1798,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { List<PropertyInfo> props; - for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) { - props.push_front(E.value()); + for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) { + props.push_front(E.value); } // Call _get_property_list @@ -2301,7 +2301,7 @@ CSharpInstance::~CSharpInstance() { void *data = CSharpLanguage::get_instance_binding(owner); CRASH_COND(data == nullptr); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get(); CRASH_COND(!script_binding.inited); #ifdef DEBUG_ENABLED @@ -2315,9 +2315,9 @@ CSharpInstance::~CSharpInstance() { #ifdef DEBUG_ENABLED // CSharpInstance must not be created unless it's going to be added to the list for sure - Set<Object *>::Element *match = script->instances.find(owner); + HashSet<Object *>::Iterator match = script->instances.find(owner); CRASH_COND(!match); - script->instances.erase(match); + script->instances.remove(match); #else script->instances.erase(owner); #endif @@ -2331,7 +2331,7 @@ void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) #endif #ifdef TOOLS_ENABLED -void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) { +void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) { if (base_cache.is_valid()) { base_cache->_update_exports_values(values, propnames); } @@ -2567,12 +2567,12 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda if ((changed || p_instance_to_update) && placeholders.size()) { // Update placeholders if any - Map<StringName, Variant> values; + HashMap<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); if (changed) { - for (PlaceHolderScriptInstance *&script_instance : placeholders) { + for (PlaceHolderScriptInstance *script_instance : placeholders) { script_instance->update(propnames, values); } } else { @@ -2807,7 +2807,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage GD_MONO_ASSERT_THREAD_ATTACHED; if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) { - r_hint = PROPERTY_HINT_ENUM; + MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type()); + r_hint = GDMonoUtils::Marshal::type_has_flags_attribute(reftype) ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM; Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields(); @@ -2844,7 +2845,8 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error); ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value."); - if (val != (unsigned int)i) { + unsigned int expected_val = r_hint == PROPERTY_HINT_FLAGS ? 1 << i : i; + if (val != expected_val) { uses_default_values = false; } @@ -3144,7 +3146,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg void *data = CSharpLanguage::get_existing_instance_binding(p_owner); CRASH_COND(data == nullptr); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get(); if (script_binding.inited && !script_binding.gchandle.is_released()) { MonoObject *mono_object = script_binding.gchandle.get_target(); if (mono_object) { @@ -3401,9 +3403,9 @@ ScriptLanguage *CSharpScript::get_language() const { bool CSharpScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { #ifdef TOOLS_ENABLED - const Map<StringName, Variant>::Element *E = exported_members_defval_cache.find(p_property); + HashMap<StringName, Variant>::ConstIterator E = exported_members_defval_cache.find(p_property); if (E) { - r_value = E->get(); + r_value = E->value; return true; } @@ -3491,8 +3493,8 @@ Ref<Script> CSharpScript::get_base_script() const { void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const { List<PropertyInfo> props; - for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) { - props.push_front(E.value()); + for (const KeyValue<StringName, PropertyInfo> &E : member_info) { + props.push_front(E.value); } for (const PropertyInfo &prop : props) { @@ -3574,7 +3576,7 @@ CSharpScript::~CSharpScript() { #endif } -void CSharpScript::get_members(Set<StringName> *p_members) { +void CSharpScript::get_members(HashSet<StringName> *p_members) { #if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED) if (p_members) { for (const StringName &member_name : exported_members_names) { diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 41b54248a3..69bd8703aa 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -110,7 +110,7 @@ private: Ref<CSharpScript> base_cache; // TODO what's this for? - Set<Object *> instances; + HashSet<Object *> instances; #ifdef GD_MONO_HOT_RELOAD struct StateBackup { @@ -121,8 +121,8 @@ private: List<Pair<StringName, Array>> event_signals; }; - Set<ObjectID> pending_reload_instances; - Map<ObjectID, StateBackup> pending_reload_state; + HashSet<ObjectID> pending_reload_instances; + RBMap<ObjectID, StateBackup> pending_reload_state; StringName tied_class_name_for_reload; StringName tied_class_namespace_for_reload; #endif @@ -132,29 +132,29 @@ private: SelfList<CSharpScript> script_list = this; - Map<StringName, Vector<SignalParameter>> _signals; - Map<StringName, EventSignal> event_signals; + HashMap<StringName, Vector<SignalParameter>> _signals; + HashMap<StringName, EventSignal> event_signals; bool signals_invalidated = true; Vector<Multiplayer::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED List<PropertyInfo> exported_members_cache; // members_cache - Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache - Set<PlaceHolderScriptInstance *> placeholders; + HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache + HashSet<PlaceHolderScriptInstance *> placeholders; bool source_changed_cache = false; bool placeholder_fallback_enabled = false; bool exports_invalidated = true; - void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames); + void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames); void _update_member_info_no_exports(); void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; #endif #if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED) - Set<StringName> exported_members_names; + HashSet<StringName> exported_members_names; #endif - OrderedHashMap<StringName, PropertyInfo> member_info; + HashMap<StringName, PropertyInfo> member_info; void _clear(); @@ -218,7 +218,7 @@ public: void get_script_property_list(List<PropertyInfo> *r_list) const override; void update_exports() override; - void get_members(Set<StringName> *p_members) override; + void get_members(HashSet<StringName> *p_members) override; bool is_tool() const override { return tool; } bool is_valid() const override { return valid; } @@ -356,11 +356,11 @@ class CSharpLanguage : public ScriptLanguage { Mutex script_gchandle_release_mutex; Mutex language_bind_mutex; - Map<Object *, CSharpScriptBinding> script_bindings; + RBMap<Object *, CSharpScriptBinding> script_bindings; #ifdef DEBUG_ENABLED // List of unsafe object references - Map<ObjectID, int> unsafe_object_references; + HashMap<ObjectID, int> unsafe_object_references; Mutex unsafe_object_references_lock; #endif @@ -467,7 +467,7 @@ public: virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override; /* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions, - List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override { + List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override { return true; } String validate_path(const String &p_path) const override; @@ -518,7 +518,7 @@ public: void thread_enter() override; void thread_exit() override; - Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding); + RBMap<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding); bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object); #ifdef DEBUG_ENABLED diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs index bac7a2e6db..02e9d98647 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs @@ -63,6 +63,7 @@ namespace GodotTools.Build startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; startInfo.UseShellExecute = false; + startInfo.CreateNoWindow = true; if (UsingMonoMsBuildOnWindows) { diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index 93a1360cb6..2db549c623 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -184,7 +184,8 @@ namespace GodotTools.Utils { RedirectStandardOutput = true, RedirectStandardError = true, - UseShellExecute = false + UseShellExecute = false, + CreateNoWindow = true }; using (Process process = Process.Start(startInfo)) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 54c65c21e8..960d2fe27c 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -604,14 +604,14 @@ void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const Ty void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) { const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname); - const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname); + HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(search_cname); if (!enum_match && search_cname != p_target_cname) { enum_match = enum_types.find(p_target_cname); } if (enum_match) { - const TypeInterface &target_enum_itype = enum_match->value(); + const TypeInterface &target_enum_itype = enum_match->value; p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "."); p_xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any @@ -1078,8 +1078,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { compile_items.push_back(output_file); } - for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { - const TypeInterface &itype = E.get(); + for (const KeyValue<StringName, TypeInterface> &E : obj_types) { + const TypeInterface &itype = E.value; if (itype.api_type == ClassDB::API_EDITOR) { continue; @@ -1187,8 +1187,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { Vector<String> compile_items; - for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { - const TypeInterface &itype = E.get(); + for (const KeyValue<StringName, TypeInterface> &E : obj_types) { + const TypeInterface &itype = E.value; if (itype.api_type != ClassDB::API_EDITOR) { continue; @@ -1573,9 +1573,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte // Search it in base types too const TypeInterface *current_type = &p_itype; while (!setter && current_type->base_name != StringName()) { - OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name); + HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name); ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'."); - current_type = &base_match.get(); + current_type = &base_match->value; setter = current_type->find_method_by_name(p_iprop.setter); } @@ -1584,9 +1584,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte // Search it in base types too current_type = &p_itype; while (!getter && current_type->base_name != StringName()) { - OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name); + HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name); ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'."); - current_type = &base_match.get(); + current_type = &base_match->value; getter = current_type->find_method_by_name(p_iprop.getter); } @@ -1652,7 +1652,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte p_output.append("static "); } - p_output.append(prop_itype->cs_type); + String prop_cs_type = prop_itype->cs_type + _get_generic_type_parameters(*prop_itype, proptype_name.generic_type_parameters); + + p_output.append(prop_cs_type); p_output.append(" "); p_output.append(p_iprop.proxy_name); p_output.append("\n" INDENT2 OPEN_BLOCK); @@ -1762,6 +1764,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf "Invalid default value for parameter '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'."); } + String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters); + // Add the current arguments to the signature // If the argument has a default value which is not a constant, we will make it Nullable { @@ -1773,7 +1777,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf arguments_sig += "Nullable<"; } - arguments_sig += arg_type->cs_type; + arguments_sig += arg_cs_type; if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) { arguments_sig += "> "; @@ -1800,7 +1804,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf String arg_in = iarg.name; arg_in += "_in"; - cs_in_statements += arg_type->cs_type; + cs_in_statements += arg_cs_type; cs_in_statements += " "; cs_in_statements += arg_in; cs_in_statements += " = "; @@ -1820,7 +1824,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf cs_in_statements += " : "; } - String cs_type = arg_type->cs_type; + String cs_type = arg_cs_type; if (cs_type.ends_with("[]")) { cs_type = cs_type.substr(0, cs_type.length() - 2); } @@ -1837,7 +1841,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Escape < and > in the attribute default value String param_def_arg = def_arg.replacen("<", "<").replacen(">", ">"); - default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + param_def_arg + "</param>"); + default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is <c>" + param_def_arg + "</c>.</param>"); } else { icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name); } @@ -1903,7 +1907,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append("virtual "); } - p_output.append(return_type->cs_type + " "); + String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters); + + p_output.append(return_cs_type + " "); p_output.append(p_imethod.proxy_name + "("); p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L2); @@ -1914,7 +1920,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append("return;\n" CLOSE_BLOCK_L2); } else { p_output.append("return default("); - p_output.append(return_type->cs_type); + p_output.append(return_cs_type); p_output.append(");\n" CLOSE_BLOCK_L2); } @@ -1938,10 +1944,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf return OK; // Won't increment method bind count } - const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod); + HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod); ERR_FAIL_NULL_V(match, ERR_BUG); - const InternalCall *im_icall = match->value(); + const InternalCall *im_icall = match->value; String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS; im_call += "."; @@ -1956,7 +1962,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf } else if (return_type->cs_out.is_empty()) { p_output.append("return " + im_call + "(" + icall_params + ");\n"); } else { - p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_type->cs_type, return_type->im_type_out)); + p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_cs_type, return_type->im_type_out)); p_output.append("\n"); } @@ -2096,8 +2102,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { generated_icall_funcs.clear(); - for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) { - const TypeInterface &itype = type_elem.get(); + for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) { + const TypeInterface &itype = type_elem.value; bool is_derived_type = itype.base_name != StringName(); @@ -2322,10 +2328,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte i++; } - const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod); + HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod); ERR_FAIL_NULL_V(match, ERR_BUG); - const InternalCall *im_icall = match->value(); + const InternalCall *im_icall = match->value; String icall_method = im_icall->name; if (!generated_icall_funcs.find(im_icall)) { @@ -2468,29 +2474,29 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(const TypeReference &p_typeref) { - const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_typeref.cname); + HashMap<StringName, TypeInterface>::ConstIterator builtin_type_match = builtin_types.find(p_typeref.cname); if (builtin_type_match) { - return &builtin_type_match->get(); + return &builtin_type_match->value; } - const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname); + HashMap<StringName, TypeInterface>::ConstIterator obj_type_match = obj_types.find(p_typeref.cname); if (obj_type_match) { - return &obj_type_match.get(); + return &obj_type_match->value; } if (p_typeref.is_enum) { - const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_typeref.cname); + HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(p_typeref.cname); if (enum_match) { - return &enum_match->get(); + return &enum_match->value; } // Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead. - const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int); + HashMap<StringName, TypeInterface>::ConstIterator int_match = builtin_types.find(name_cache.type_int); ERR_FAIL_NULL_V(int_match, nullptr); - return &int_match->get(); + return &int_match->value; } return nullptr; @@ -2505,16 +2511,52 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol ERR_PRINT(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'."); - const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname); + HashMap<StringName, TypeInterface>::ConstIterator match = placeholder_types.find(p_typeref.cname); if (match) { - return &match->get(); + return &match->value; } TypeInterface placeholder; TypeInterface::create_placeholder_type(placeholder, p_typeref.cname); - return &placeholder_types.insert(placeholder.cname, placeholder)->get(); + return &placeholder_types.insert(placeholder.cname, placeholder)->value; +} + +const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters) { + if (p_generic_type_parameters.is_empty()) { + return ""; + } + + ERR_FAIL_COND_V_MSG(p_itype.type_parameter_count != p_generic_type_parameters.size(), "", + "Generic type parameter count mismatch for type '" + p_itype.name + "'." + + " Found " + itos(p_generic_type_parameters.size()) + ", but requires " + + itos(p_itype.type_parameter_count) + "."); + + int i = 0; + String params = "<"; + for (const TypeReference ¶m_type : p_generic_type_parameters) { + const TypeInterface *param_itype = _get_type_or_placeholder(param_type); + + ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "", + "Generic type parameter is a singleton: '" + param_itype->name + "'."); + + if (p_itype.api_type == ClassDB::API_CORE) { + ERR_FAIL_COND_V_MSG(param_itype->api_type == ClassDB::API_EDITOR, "", + "Generic type parameter '" + param_itype->name + "' has type from the editor API." + + " Core API cannot have dependencies on the editor API."); + } + + params += param_itype->cs_type; + if (i < p_generic_type_parameters.size() - 1) { + params += ", "; + } + + i++; + } + params += ">"; + + return params; } StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) { @@ -2708,7 +2750,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { List<PropertyInfo> property_list; ClassDB::get_property_list(type_cname, &property_list, true); - Map<StringName, StringName> accessor_methods; + HashMap<StringName, StringName> accessor_methods; for (const PropertyInfo &property : property_list) { if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY || (property.type == Variant::NIL && property.usage & PROPERTY_USAGE_ARRAY)) { @@ -2832,6 +2874,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { ERR_FAIL_COND_V_MSG(bad_reference_hint, false, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + " Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'."); + } else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) { + imethod.return_type.cname = Variant::get_type_name(return_info.type); + imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string)); } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { imethod.return_type.cname = return_info.hint_string; } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { @@ -2861,6 +2906,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { iarg.type.is_enum = true; } else if (arginfo.class_name != StringName()) { iarg.type.cname = arginfo.class_name; + } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) { + iarg.type.cname = Variant::get_type_name(arginfo.type); + iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string)); } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { iarg.type.cname = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { @@ -2903,9 +2951,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.proxy_name += "_"; } - Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname); + HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname); if (accessor) { - const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value()); + const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value); // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched. @@ -2942,12 +2990,11 @@ bool BindingsGenerator::_populate_object_type_interfaces() { // Populate signals const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map; - const StringName *k = nullptr; - while ((k = signal_map.next(k))) { + for (const KeyValue<StringName, MethodInfo> &E : signal_map) { SignalInterface isignal; - const MethodInfo &method_info = signal_map.get(*k); + const MethodInfo &method_info = E.value; isignal.name = method_info.name; isignal.cname = method_info.name; @@ -2967,6 +3014,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { iarg.type.is_enum = true; } else if (arginfo.class_name != StringName()) { iarg.type.cname = arginfo.class_name; + } else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) { + iarg.type.cname = Variant::get_type_name(arginfo.type); + iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string)); } else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { iarg.type.cname = arginfo.hint_string; } else if (arginfo.type == Variant::NIL) { @@ -3024,10 +3074,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() { ClassDB::get_integer_constant_list(type_cname, &constants, true); const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; - k = nullptr; - while ((k = enum_map.next(k))) { - StringName enum_proxy_cname = *k; + for (const KeyValue<StringName, List<StringName>> &E : enum_map) { + StringName enum_proxy_cname = E.key; String enum_proxy_name = enum_proxy_cname.operator String(); if (itype.find_property_by_proxy_name(enum_proxy_cname)) { // We have several conflicts between enums and PascalCase properties, @@ -3036,7 +3085,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { enum_proxy_cname = StringName(enum_proxy_name); } EnumInterface ienum(enum_proxy_cname); - const List<StringName> &enum_constants = enum_map.get(*k); + const List<StringName> &enum_constants = E.value; for (const StringName &constant_cname : enum_constants) { String constant_name = constant_cname.operator String(); int *value = class_info->constant_map.getptr(constant_cname); @@ -3066,7 +3115,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { TypeInterface enum_itype; enum_itype.is_enum = true; - enum_itype.name = itype.name + "." + String(*k); + enum_itype.name = itype.name + "." + String(E.key); enum_itype.cname = StringName(enum_itype.name); enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name; TypeInterface::postsetup_enum_type(enum_itype); @@ -3551,13 +3600,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.name = "Array"; itype.cname = itype.name; itype.proxy_name = itype.name; + itype.type_parameter_count = 1; itype.c_out = "\treturn memnew(Array(%1));\n"; itype.c_type = itype.name; itype.c_type_in = itype.c_type + "*"; itype.c_type_out = itype.c_type + "*"; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new " + itype.cs_type + "(%0(%1));"; + itype.cs_out = "return new %2(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -3567,13 +3617,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.name = "Dictionary"; itype.cname = itype.name; itype.proxy_name = itype.name; + itype.type_parameter_count = 2; itype.c_out = "\treturn memnew(Dictionary(%1));\n"; itype.c_type = itype.name; itype.c_type_in = itype.c_type + "*"; itype.c_type_out = itype.c_type + "*"; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new " + itype.cs_type + "(%0(%1));"; + itype.cs_out = "return new %2(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -3596,11 +3647,11 @@ void BindingsGenerator::_populate_global_constants() { int global_constants_count = CoreConstants::get_global_constant_count(); if (global_constants_count > 0) { - Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope"); + HashMap<String, DocData::ClassDoc>::Iterator match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope"); CRASH_COND_MSG(!match, "Could not find '@GlobalScope' in DocData."); - const DocData::ClassDoc &global_scope_doc = match->value(); + const DocData::ClassDoc &global_scope_doc = match->value; for (int i = 0; i < global_constants_count; i++) { String constant_name = CoreConstants::get_global_constant_name(i); @@ -3715,8 +3766,8 @@ void BindingsGenerator::_initialize() { core_custom_icalls.clear(); editor_custom_icalls.clear(); - for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { - _generate_method_icalls(E.get()); + for (const KeyValue<StringName, TypeInterface> &E : obj_types) { + _generate_method_icalls(E.value); } initialized = true; diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index dec4fae8cd..f0ba2b18e4 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -87,6 +87,8 @@ class BindingsGenerator { StringName cname; bool is_enum = false; + List<TypeReference> generic_type_parameters; + TypeReference() {} TypeReference(const StringName &p_cname) : @@ -206,6 +208,8 @@ class BindingsGenerator { String name; StringName cname; + int type_parameter_count; + /** * Identifier name of the base class. */ @@ -533,24 +537,24 @@ class BindingsGenerator { bool log_print_enabled = true; bool initialized = false; - OrderedHashMap<StringName, TypeInterface> obj_types; + HashMap<StringName, TypeInterface> obj_types; - Map<StringName, TypeInterface> placeholder_types; - Map<StringName, TypeInterface> builtin_types; - Map<StringName, TypeInterface> enum_types; + HashMap<StringName, TypeInterface> placeholder_types; + HashMap<StringName, TypeInterface> builtin_types; + HashMap<StringName, TypeInterface> enum_types; List<EnumInterface> global_enums; List<ConstantInterface> global_constants; List<InternalCall> method_icalls; - Map<const MethodInterface *, const InternalCall *> method_icalls_map; + HashMap<const MethodInterface *, const InternalCall *> method_icalls_map; List<const InternalCall *> generated_icall_funcs; List<InternalCall> core_custom_icalls; List<InternalCall> editor_custom_icalls; - Map<StringName, List<StringName>> blacklisted_methods; + HashMap<StringName, List<StringName>> blacklisted_methods; void _initialize_blacklisted_methods(); @@ -679,6 +683,8 @@ class BindingsGenerator { const TypeInterface *_get_type_or_null(const TypeReference &p_typeref); const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref); + const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters); + StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta); StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta); diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 79015686c3..a1789412f4 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -121,10 +121,10 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr case CompletionKind::NODE_PATHS: { { // Autoloads. - OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { - const ProjectSettings::AutoloadInfo &info = E.value(); + for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) { + const ProjectSettings::AutoloadInfo &info = E.value; suggestions.push_back(quoted("/root/" + String(info.name))); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs index ee4d0eed08..50ae2eb112 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs @@ -80,6 +80,11 @@ namespace Godot private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>); /// <summary> + /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type. + /// </summary> + private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false); + + /// <summary> /// Returns the generic type definition of <paramref name="type"/>. /// </summary> /// <exception cref="InvalidOperationException"> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index b10d78c593..7b9dbc87cf 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -68,7 +68,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { void *data = CSharpLanguage::get_existing_instance_binding(p_ptr); if (data) { - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get(); if (script_binding.inited) { MonoGCHandleData &gchandle = script_binding.gchandle; if (!gchandle.is_released()) { @@ -115,7 +115,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole void *data = CSharpLanguage::get_existing_instance_binding(rc); if (data) { - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get(); if (script_binding.inited) { MonoGCHandleData &gchandle = script_binding.gchandle; if (!gchandle.is_released()) { diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp index 8ed21c323f..4f7783b765 100644 --- a/modules/mono/managed_callable.cpp +++ b/modules/mono/managed_callable.cpp @@ -36,7 +36,7 @@ #ifdef GD_MONO_HOT_RELOAD SelfList<ManagedCallable>::List ManagedCallable::instances; -Map<ManagedCallable *, Array> ManagedCallable::instances_pending_reload; +RBMap<ManagedCallable *, Array> ManagedCallable::instances_pending_reload; Mutex ManagedCallable::instances_mutex; #endif diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h index d50a8a7b08..11bee6cf60 100644 --- a/modules/mono/managed_callable.h +++ b/modules/mono/managed_callable.h @@ -48,7 +48,7 @@ class ManagedCallable : public CallableCustom { #ifdef GD_MONO_HOT_RELOAD SelfList<ManagedCallable> self_instance = this; static SelfList<ManagedCallable>::List instances; - static Map<ManagedCallable *, Array> instances_pending_reload; + static RBMap<ManagedCallable *, Array> instances_pending_reload; static Mutex instances_mutex; #endif diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index e98ce8f6c1..39a8ef22b7 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -1167,9 +1167,8 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) { int32_t domain_id = mono_domain_get_id(mono_domain_get()); HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - const String *k = nullptr; - while ((k = domain_assemblies.next(k))) { - GDMonoAssembly *assembly = domain_assemblies.get(*k); + for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { + GDMonoAssembly *assembly = E.value; if (assembly->get_image() == image) { GDMonoClass *klass = assembly->get_class(p_raw_class); if (klass) { @@ -1190,9 +1189,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName & int32_t domain_id = mono_domain_get_id(mono_domain_get()); HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id]; - const String *k = nullptr; - while ((k = domain_assemblies.next(k))) { - GDMonoAssembly *assembly = domain_assemblies.get(*k); + for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { + GDMonoAssembly *assembly = E.value; klass = assembly->get_class(p_namespace, p_name); if (klass) { return klass; @@ -1205,9 +1203,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName & void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) { HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id]; - const String *k = nullptr; - while ((k = domain_assemblies.next(k))) { - memdelete(domain_assemblies.get(*k)); + for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) { + memdelete(E.value); } assemblies.erase(p_domain_id); @@ -1298,13 +1295,11 @@ GDMono::~GDMono() { // Leave the rest to 'mono_jit_cleanup' #endif - const int32_t *k = nullptr; - while ((k = assemblies.next(k))) { - HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k); + for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) { + const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value; - const String *kk = nullptr; - while ((kk = domain_assemblies.next(kk))) { - memdelete(domain_assemblies.get(*kk)); + for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) { + memdelete(F.value); } } assemblies.clear(); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 3991b14612..42c6b6305f 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -412,10 +412,10 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) { ERR_FAIL_NULL_V(image, nullptr); - Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class); + HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class); if (match) { - return match->value(); + return match->value; } StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class)); diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h index a96357b082..0a3ae6c4fe 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.h +++ b/modules/mono/mono_gd/gd_mono_assembly.h @@ -36,7 +36,7 @@ #include "core/string/ustring.h" #include "core/templates/hash_map.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "gd_mono_utils.h" class GDMonoAssembly { @@ -79,7 +79,7 @@ class GDMonoAssembly { #endif HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes; - Map<MonoClass *, GDMonoClass *> cached_raw; + HashMap<MonoClass *, GDMonoClass *> cached_raw; static Vector<String> search_dirs; diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index d8fd244067..44a8e26b8f 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -176,6 +176,7 @@ void CachedData::clear_godot_api_cache() { methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify(); methodthunk_MarshalUtils_TypeIsGenericICollection.nullify(); methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify(); + methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify(); methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify(); @@ -300,6 +301,7 @@ void update_godot_api_cache() { CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1)); CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2)); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 4000342c94..92136e1f41 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -147,6 +147,7 @@ struct CachedData { GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable; GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection; GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute; GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition; diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 3fc0f16e05..51c5aa3542 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -247,7 +247,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base if (existing_method) { memdelete(*existing_method); // Must delete old one } - methods.set(key, method); + methods.insert(key, method); break; } @@ -266,11 +266,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) { ERR_FAIL_COND_V(!methods_fetched, nullptr); - const MethodKey *k = nullptr; - - while ((k = methods.next(k))) { - if (k->name == p_name) { - return methods.get(*k); + for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) { + if (E.key.name == p_name) { + return E.value; } } @@ -307,7 +305,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_param if (raw_method) { GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method)); - methods.set(key, method); + methods.insert(key, method); return method; } @@ -342,7 +340,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName } GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method)); - methods.set(key, method); + methods.insert(key, method); return method; } @@ -362,10 +360,10 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo } GDMonoField *GDMonoClass::get_field(const StringName &p_name) { - Map<StringName, GDMonoField *>::Element *result = fields.find(p_name); + HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name); if (result) { - return result->value(); + return result->value; } if (fields_fetched) { @@ -394,10 +392,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() { while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) { StringName name = String::utf8(mono_field_get_name(raw_field)); - Map<StringName, GDMonoField *>::Element *match = fields.find(name); + HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name); if (match) { - fields_list.push_back(match->get()); + fields_list.push_back(match->value); } else { GDMonoField *field = memnew(GDMonoField(raw_field, this)); fields.insert(name, field); @@ -411,10 +409,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() { } GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) { - Map<StringName, GDMonoProperty *>::Element *result = properties.find(p_name); + HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name); if (result) { - return result->value(); + return result->value; } if (properties_fetched) { @@ -443,10 +441,10 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() { while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) { StringName name = String::utf8(mono_property_get_name(raw_property)); - Map<StringName, GDMonoProperty *>::Element *match = properties.find(name); + HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name); if (match) { - properties_list.push_back(match->get()); + properties_list.push_back(match->value); } else { GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this)); properties.insert(name, property); @@ -479,10 +477,10 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() { if (mono_class_is_delegate(raw_class)) { StringName name = String::utf8(mono_class_get_name(raw_class)); - Map<StringName, GDMonoClass *>::Element *match = delegates.find(name); + HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name); if (match) { - delegates_list.push_back(match->get()); + delegates_list.push_back(match->value); } else { GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly)); delegates.insert(name, delegate); @@ -549,9 +547,8 @@ GDMonoClass::~GDMonoClass() { Vector<GDMonoMethod *> deleted_methods; deleted_methods.resize(methods.size()); - const MethodKey *k = nullptr; - while ((k = methods.next(k))) { - GDMonoMethod *method = methods.get(*k); + for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) { + GDMonoMethod *method = E.value; if (method) { for (int i = 0; i < offset; i++) { diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index b32d561f61..6b35da30f9 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -32,7 +32,7 @@ #define GD_MONO_CLASS_H #include "core/string/ustring.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "gd_mono_field.h" #include "gd_mono_header.h" @@ -85,15 +85,15 @@ class GDMonoClass { Vector<GDMonoMethod *> method_list; bool fields_fetched; - Map<StringName, GDMonoField *> fields; + HashMap<StringName, GDMonoField *> fields; Vector<GDMonoField *> fields_list; bool properties_fetched; - Map<StringName, GDMonoProperty *> properties; + HashMap<StringName, GDMonoProperty *> properties; Vector<GDMonoProperty *> properties_list; bool delegates_fetched; - Map<StringName, GDMonoClass *> delegates; + HashMap<StringName, GDMonoClass *> delegates; Vector<GDMonoClass *> delegates_list; friend class GDMonoAssembly; diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index a884bf4da0..1983d6ebe2 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -70,7 +70,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { void *data = CSharpLanguage::get_instance_binding(unmanaged); ERR_FAIL_NULL_V(data, nullptr); - CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value(); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value(); ERR_FAIL_COND_V(!script_binding.inited, nullptr); MonoGCHandleData &gchandle = script_binding.gchandle; @@ -614,6 +614,14 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) { return (bool)res; } +bool type_has_flags_attribute(MonoReflectionType *p_reftype) { + NO_GLUE_RET(false); + MonoException *exc = nullptr; + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc); + UNHANDLED_EXCEPTION(exc); + return (bool)res; +} + void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) { MonoException *exc = nullptr; CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 4c2c2c93c2..246a1cd31e 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -61,6 +61,7 @@ bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype); bool type_is_generic_ienumerable(MonoReflectionType *p_reftype); bool type_is_generic_icollection(MonoReflectionType *p_reftype); bool type_is_generic_idictionary(MonoReflectionType *p_reftype); +bool type_has_flags_attribute(MonoReflectionType *p_reftype); void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype); diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp index 835c611709..abb59420eb 100644 --- a/modules/mono/utils/osx_utils.cpp +++ b/modules/mono/utils/osx_utils.cpp @@ -34,8 +34,8 @@ #include "core/string/print_string.h" -#include <CoreFoundation/CoreFoundation.h> -#include <CoreServices/CoreServices.h> +#import <CoreFoundation/CoreFoundation.h> +#import <CoreServices/CoreServices.h> bool osx_is_app_bundle_installed(const String &p_bundle_id) { CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8); diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index d16d41b438..cc9d05da47 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -233,6 +233,44 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 return map->get_closest_point_owner(p_point); } +Array GodotNavigationServer::map_get_regions(RID p_map) const { + Array regions_rids; + const NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_COND_V(map == nullptr, regions_rids); + for (NavRegion *region : map->get_regions()) { + regions_rids.push_back(region->get_self()); + } + return regions_rids; +} + +Array GodotNavigationServer::map_get_agents(RID p_map) const { + Array agents_rids; + const NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_COND_V(map == nullptr, agents_rids); + for (RvoAgent *agent : map->get_agents()) { + agents_rids.push_back(agent->get_self()); + } + return agents_rids; +} + +RID GodotNavigationServer::region_get_map(RID p_region) const { + NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_COND_V(region == nullptr, RID()); + if (region->get_map()) { + return region->get_map()->get_self(); + } + return RID(); +} + +RID GodotNavigationServer::agent_get_map(RID p_agent) const { + RvoAgent *agent = agent_owner.get_or_null(p_agent); + ERR_FAIL_COND_V(agent == nullptr, RID()); + if (agent->get_map()) { + return agent->get_map()->get_self(); + } + return RID(); +} + RID GodotNavigationServer::region_create() const { GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 7ad5e2d501..89e7311e51 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -105,8 +105,12 @@ public: virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override; virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override; + virtual Array map_get_regions(RID p_map) const override; + virtual Array map_get_agents(RID p_map) const override; + virtual RID region_create() const override; COMMAND_2(region_set_map, RID, p_region, RID, p_map); + virtual RID region_get_map(RID p_region) const override; COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers); virtual uint32_t region_get_layers(RID p_region) const override; COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); @@ -118,6 +122,7 @@ public: virtual RID agent_create() const override; COMMAND_2(agent_set_map, RID, p_agent, RID, p_map); + virtual RID agent_get_map(RID p_agent) const override; COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist); COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time); diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index cbc0adc574..344475fb37 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -541,7 +541,7 @@ void NavMap::sync() { } // Group all edges per key. - Map<gd::EdgeKey, Vector<gd::Edge::Connection>> connections; + HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey> connections; for (size_t poly_id(0); poly_id < polygons.size(); poly_id++) { gd::Polygon &poly(polygons[poly_id]); @@ -549,7 +549,7 @@ void NavMap::sync() { int next_point = (p + 1) % poly.points.size(); gd::EdgeKey ek(poly.points[p].key, poly.points[next_point].key); - Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *connection = connections.find(ek); + HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey>::Iterator connection = connections.find(ek); if (!connection) { connections[ek] = Vector<gd::Edge::Connection>(); } diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 5232e42bed..f58a78d4ca 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RVO_SPACE_H -#define RVO_SPACE_H +#ifndef NAV_MAP_H +#define NAV_MAP_H #include "nav_rid.h" #include "core/math/math_defs.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "core/templates/thread_work_pool.h" #include "nav_utils.h" @@ -141,4 +141,4 @@ private: void clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys, Vector<Vector3> &path, const gd::NavigationPoly *from_poly, const Vector3 &p_to_point, const gd::NavigationPoly *p_to_poly) const; }; -#endif // RVO_SPACE_H +#endif // NAV_MAP_H diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h index 5b6c695ca4..a9f4e0e2fc 100644 --- a/modules/navigation/nav_utils.h +++ b/modules/navigation/nav_utils.h @@ -32,8 +32,9 @@ #define NAV_UTILS_H #include "core/math/vector3.h" +#include "core/templates/hash_map.h" +#include "core/templates/hashfuncs.h" #include "core/templates/vector.h" - #include <vector> class NavRegion; @@ -49,15 +50,18 @@ union PointKey { }; uint64_t key = 0; - bool operator<(const PointKey &p_key) const { return key < p_key.key; } }; struct EdgeKey { PointKey a; PointKey b; - bool operator<(const EdgeKey &p_key) const { - return (a.key == p_key.a.key) ? (b.key < p_key.b.key) : (a.key < p_key.a.key); + static uint32_t hash(const EdgeKey &p_val) { + return hash_one_uint64(p_val.a.key) ^ hash_one_uint64(p_val.b.key); + } + + bool operator==(const EdgeKey &p_key) const { + return (a.key == p_key.a.key) && (b.key == p_key.b.key); } EdgeKey(const PointKey &p_a = PointKey(), const PointKey &p_b = PointKey()) : diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 2d6c78f704..1bc7cd7cdc 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -172,14 +172,16 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans if (Object::cast_to<MultiMeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MultiMeshInstance3D *multimesh_instance = Object::cast_to<MultiMeshInstance3D>(p_node); Ref<MultiMesh> multimesh = multimesh_instance->get_multimesh(); - Ref<Mesh> mesh = multimesh->get_mesh(); - if (mesh.is_valid()) { - int n = multimesh->get_visible_instance_count(); - if (n == -1) { - n = multimesh->get_instance_count(); - } - for (int i = 0; i < n; i++) { - _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices); + if (multimesh.is_valid()) { + Ref<Mesh> mesh = multimesh->get_mesh(); + if (mesh.is_valid()) { + int n = multimesh->get_visible_instance_count(); + if (n == -1) { + n = multimesh->get_instance_count(); + } + for (int i = 0; i < n; i++) { + _add_mesh(mesh, p_navmesh_transform * multimesh_instance->get_global_transform() * multimesh->get_instance_transform(i), p_vertices, p_indices); + } } } } @@ -445,7 +447,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size()); cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size()); cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly(); - cfg.detailSampleDist = p_nav_mesh->get_detail_sample_distance() < 0.9f ? 0 : p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(); + cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f); cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error(); cfg.bmin[0] = bmin[0]; @@ -462,6 +464,14 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( #endif rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height); + // ~30000000 seems to be around sweetspot where Editor baking breaks + if ((cfg.width * cfg.height) > 30000000) { + WARN_PRINT("NavigationMesh baking process will likely fail." + "\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings." + "\nIf baking does not fail, the resulting NavigationMesh will create serious pathfinding performance issues." + "\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry."); + } + #ifdef TOOLS_ENABLED if (ep) { ep->step(TTR("Creating heightfield..."), 3); diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp index a8d38dee62..b21e3247d7 100644 --- a/modules/noise/fastnoise_lite.cpp +++ b/modules/noise/fastnoise_lite.cpp @@ -30,6 +30,24 @@ #include "fastnoise_lite.h" +_FastNoiseLite::FractalType FastNoiseLite::_convert_domain_warp_fractal_type_enum(DomainWarpFractalType p_domain_warp_fractal_type) { + _FastNoiseLite::FractalType type; + switch (p_domain_warp_fractal_type) { + case DOMAIN_WARP_FRACTAL_NONE: + type = _FastNoiseLite::FractalType_None; + break; + case DOMAIN_WARP_FRACTAL_PROGRESSIVE: + type = _FastNoiseLite::FractalType_DomainWarpProgressive; + break; + case DOMAIN_WARP_FRACTAL_INDEPENDENT: + type = _FastNoiseLite::FractalType_DomainWarpIndependent; + break; + default: + type = _FastNoiseLite::FractalType_None; + } + return type; +} + FastNoiseLite::FastNoiseLite() { _noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type); _noise.SetSeed(seed); @@ -50,7 +68,7 @@ FastNoiseLite::FastNoiseLite() { _domain_warp_noise.SetSeed(seed); _domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude); _domain_warp_noise.SetFrequency(domain_warp_frequency); - _domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None); + _domain_warp_noise.SetFractalType(_convert_domain_warp_fractal_type_enum(domain_warp_fractal_type)); _domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves); _domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity); _domain_warp_noise.SetFractalGain(domain_warp_fractal_gain); @@ -241,23 +259,7 @@ real_t FastNoiseLite::get_domain_warp_frequency() const { void FastNoiseLite::set_domain_warp_fractal_type(DomainWarpFractalType p_domain_warp_fractal_type) { domain_warp_fractal_type = p_domain_warp_fractal_type; - // This needs manual conversion because Godots Inspector property API does not support discontiguous enum indices. - _FastNoiseLite::FractalType type; - switch (p_domain_warp_fractal_type) { - case DOMAIN_WARP_FRACTAL_NONE: - type = _FastNoiseLite::FractalType_None; - break; - case DOMAIN_WARP_FRACTAL_PROGRESSIVE: - type = _FastNoiseLite::FractalType_DomainWarpProgressive; - break; - case DOMAIN_WARP_FRACTAL_INDEPENDENT: - type = _FastNoiseLite::FractalType_DomainWarpIndependent; - break; - default: - type = _FastNoiseLite::FractalType_None; - } - - _domain_warp_noise.SetFractalType(type); + _domain_warp_noise.SetFractalType(_convert_domain_warp_fractal_type_enum(p_domain_warp_fractal_type)); emit_changed(); } @@ -298,6 +300,12 @@ real_t FastNoiseLite::get_domain_warp_fractal_gain() const { // Noise interface functions. real_t FastNoiseLite::get_noise_1d(real_t p_x) const { + p_x += offset.x; + if (domain_warp_enabled) { + // Needed since DomainWarp expects a reference. + real_t y_dummy = 0; + _domain_warp_noise.DomainWarp(p_x, y_dummy); + } return get_noise_2d(p_x, 0.0); } @@ -306,10 +314,12 @@ real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const { } real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const { + p_x += offset.x; + p_y += offset.y; if (domain_warp_enabled) { _domain_warp_noise.DomainWarp(p_x, p_y); } - return _noise.GetNoise(p_x + offset.x, p_y + offset.y); + return _noise.GetNoise(p_x, p_y); } real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const { @@ -317,10 +327,13 @@ real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const { } real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const { + p_x += offset.x; + p_y += offset.y; + p_z += offset.z; if (domain_warp_enabled) { _domain_warp_noise.DomainWarp(p_x, p_y, p_z); } - return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z); + return _noise.GetNoise(p_x, p_y, p_z); } void FastNoiseLite::_changed() { diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h index 0a4251868b..fe8cd7ce6e 100644 --- a/modules/noise/fastnoise_lite.h +++ b/modules/noise/fastnoise_lite.h @@ -127,6 +127,9 @@ private: real_t domain_warp_fractal_lacunarity = 6; real_t domain_warp_fractal_gain = 0.5; + // This needs manual conversion because Godots Inspector property API does not support discontiguous enum indices. + _FastNoiseLite::FractalType _convert_domain_warp_fractal_type_enum(DomainWarpFractalType p_domain_warp_fractal_type); + public: FastNoiseLite(); ~FastNoiseLite(); diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp index e2a4f67f16..41c6465f43 100644 --- a/modules/openxr/editor/openxr_action_editor.cpp +++ b/modules/openxr/editor/openxr_action_editor.cpp @@ -63,8 +63,7 @@ void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_te } void OpenXRActionEditor::_on_item_selected(int p_idx) { - ERR_FAIL_COND(p_idx < 0); - ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX); + ERR_FAIL_INDEX(p_idx, OpenXRAction::OPENXR_ACTION_MAX); action->set_action_type(OpenXRAction::ActionType(p_idx)); } diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp index 6e9a2e1b61..87b7f50224 100644 --- a/modules/openxr/editor/openxr_action_map_editor.cpp +++ b/modules/openxr/editor/openxr_action_map_editor.cpp @@ -344,6 +344,7 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() { tabs = memnew(TabContainer); tabs->set_h_size_flags(SIZE_EXPAND_FILL); tabs->set_v_size_flags(SIZE_EXPAND_FILL); + tabs->set_theme_type_variation("TabContainerOdd"); tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed)); tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed)); add_child(tabs); diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index f3064041b8..0f7c0ba0bc 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -33,7 +33,7 @@ #include "core/error/error_macros.h" #include "core/math/camera_matrix.h" -#include "core/templates/map.h" +#include "core/templates/hash_map.h" #include "core/templates/rid.h" #include "thirdparty/openxr/src/common/xr_linear.h" @@ -49,10 +49,10 @@ protected: // Store extension we require. // If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available // If bool pointer is set, value will be set to true or false depending on whether extension is available - Map<const char *, bool *> request_extensions; + HashMap<String, bool *> request_extensions; public: - virtual Map<const char *, bool *> get_request_extensions() { + virtual HashMap<String, bool *> get_request_extensions() { return request_extensions; } diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index 1eb7635a82..2ddf3b8a7d 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -33,6 +33,7 @@ #include "../extensions/openxr_vulkan_extension.h" #include "../openxr_api.h" #include "../openxr_util.h" +#include "servers/rendering/renderer_rd/effects/copy_effects.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h" #include "servers/rendering/rendering_server_globals.h" @@ -450,11 +451,9 @@ bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target ERR_FAIL_COND_V(fb.is_null(), false); // Our vulkan extension can only be used in conjunction with our vulkan renderer. - // We need access to the effects object in order to have access to our copy logic. - // Breaking all the rules but there is no nice way to do this. - EffectsRD *effects = RendererStorageRD::base_singleton->get_effects(); - ERR_FAIL_NULL_V(effects, false); - effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview); + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_V(copy_effects, false); + copy_effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview); return true; } diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 2e9be48f01..f42af0492f 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -170,9 +170,9 @@ bool OpenXRAPI::load_supported_extensions() { return true; } -bool OpenXRAPI::is_extension_supported(const char *p_extension) const { +bool OpenXRAPI::is_extension_supported(const String &p_extension) const { for (uint32_t i = 0; i < num_supported_extensions; i++) { - if (strcmp(supported_extensions[i].extensionName, p_extension) == 0) { + if (supported_extensions[i].extensionName == p_extension) { #ifdef DEBUG print_line("OpenXR: requested extension", p_extension, "is supported"); #endif @@ -204,9 +204,9 @@ bool OpenXRAPI::create_instance() { // Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable. // Append the extensions requested by the registered extension wrappers. - Map<const char *, bool *> requested_extensions; + HashMap<String, bool *> requested_extensions; for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { - Map<const char *, bool *> wrapper_request_extensions = wrapper->get_request_extensions(); + const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_request_extensions(); // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end()); for (auto &requested_extension : wrapper_request_extensions) { @@ -224,6 +224,7 @@ bool OpenXRAPI::create_instance() { // Check which extensions are supported enabled_extensions.clear(); + for (auto &requested_extension : requested_extensions) { if (!is_extension_supported(requested_extension.key)) { if (requested_extension.value == nullptr) { @@ -238,13 +239,18 @@ bool OpenXRAPI::create_instance() { *requested_extension.value = true; // and record that we want to enable it - enabled_extensions.push_back(requested_extension.key); + enabled_extensions.push_back(requested_extension.key.ascii()); } else { // record that we want to enable this - enabled_extensions.push_back(requested_extension.key); + enabled_extensions.push_back(requested_extension.key.ascii()); } } + Vector<const char *> extension_ptrs; + for (int i = 0; i < enabled_extensions.size(); i++) { + extension_ptrs.push_back(enabled_extensions[i].get_data()); + } + // Get our project name String project_name = GLOBAL_GET("application/config/name"); @@ -264,8 +270,8 @@ bool OpenXRAPI::create_instance() { application_info, // applicationInfo 0, // enabledApiLayerCount, need to find out if we need support for this? nullptr, // enabledApiLayerNames - uint32_t(enabled_extensions.size()), // enabledExtensionCount - enabled_extensions.ptr() // enabledExtensionNames + uint32_t(extension_ptrs.size()), // enabledExtensionCount + extension_ptrs.ptr() // enabledExtensionNames }; copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE); @@ -1001,7 +1007,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { ERR_FAIL_V(false); #endif } else if (p_rendering_driver == "opengl3") { -#ifdef OPENGL3_ENABLED +#ifdef GLES3_ENABLED // graphics_extension = memnew(OpenXROpenGLExtension(this)); // register_extension_wrapper(graphics_extension); ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time."); diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 702f6b9b1d..bd71f0e1c2 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -37,7 +37,7 @@ #include "core/math/vector2.h" #include "core/os/memory.h" #include "core/string/ustring.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "core/templates/rid_owner.h" #include "core/templates/vector.h" #include "servers/xr/xr_pose.h" @@ -73,7 +73,7 @@ private: uint32_t num_supported_extensions = 0; XrExtensionProperties *supported_extensions = nullptr; Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; - Vector<const char *> enabled_extensions; + Vector<CharString> enabled_extensions; bool ext_hp_mixed_reality_available = false; bool ext_samsung_odyssey_available = false; @@ -132,7 +132,7 @@ private: bool load_layer_properties(); bool load_supported_extensions(); - bool is_extension_supported(const char *p_extension) const; + bool is_extension_supported(const String &p_extension) const; // instance bool create_instance(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 41ce8c019e..ab06583932 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -113,7 +113,7 @@ void OpenXRInterface::_load_action_map() { // process our action map if (action_map.is_valid()) { - Map<Ref<OpenXRAction>, Action *> xr_actions; + HashMap<Ref<OpenXRAction>, Action *> xr_actions; Array action_sets = action_map->get_action_sets(); for (int i = 0; i < action_sets.size(); i++) { diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp index ecc256bff9..9b35b5616e 100644 --- a/modules/raycast/lightmap_raycaster.cpp +++ b/modules/raycast/lightmap_raycaster.cpp @@ -152,17 +152,17 @@ void LightmapRaycasterEmbree::commit() { rtcCommitScene(embree_scene); } -void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) { - for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) { - rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get())); +void LightmapRaycasterEmbree::set_mesh_filter(const HashSet<int> &p_mesh_ids) { + for (const int &E : p_mesh_ids) { + rtcDisableGeometry(rtcGetGeometry(embree_scene, E)); } rtcCommitScene(embree_scene); filter_meshes = p_mesh_ids; } void LightmapRaycasterEmbree::clear_mesh_filter() { - for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) { - rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get())); + for (const int &E : filter_meshes) { + rtcEnableGeometry(rtcGetGeometry(embree_scene, E)); } rtcCommitScene(embree_scene); filter_meshes.clear(); diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h index c420e617e5..4266b46ea8 100644 --- a/modules/raycast/lightmap_raycaster.h +++ b/modules/raycast/lightmap_raycaster.h @@ -52,8 +52,8 @@ private: static void filter_function(const struct RTCFilterFunctionNArguments *p_args); - Map<unsigned int, AlphaTextureData> alpha_textures; - Set<int> filter_meshes; + HashMap<unsigned int, AlphaTextureData> alpha_textures; + HashSet<int> filter_meshes; public: virtual bool intersect(Ray &p_ray) override; @@ -64,7 +64,7 @@ public: virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override; virtual void commit() override; - virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override; + virtual void set_mesh_filter(const HashSet<int> &p_mesh_ids) override; virtual void clear_mesh_filter() override; static LightmapRaycaster *create_embree_raycaster(); diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 1550f0ef8b..89e75f774e 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -223,9 +223,9 @@ void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3 occluder->vertices = p_vertices; occluder->indices = p_indices; - for (Set<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) { - RID scenario_rid = E->get().scenario; - RID instance_rid = E->get().instance; + for (const InstanceID &E : occluder->users) { + RID scenario_rid = E.scenario; + RID instance_rid = E.instance; ERR_CONTINUE(!scenarios.has(scenario_rid)); Scenario &scenario = scenarios[scenario_rid]; ERR_CONTINUE(!scenario.instances.has(instance_rid)); @@ -454,10 +454,9 @@ bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) { next_scene = rtcNewScene(raycast_singleton->ebr_device); rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality)); - const RID *inst_rid = nullptr; - while ((inst_rid = instances.next(inst_rid))) { - OccluderInstance *occ_inst = instances.getptr(*inst_rid); - Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder); + for (const KeyValue<RID, OccluderInstance> &E : instances) { + const OccluderInstance *occ_inst = &E.value; + const Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder); if (!occ || !occ_inst->enabled) { continue; @@ -573,9 +572,8 @@ void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQu build_quality = p_quality; - const RID *scenario_rid = nullptr; - while ((scenario_rid = scenarios.next(scenario_rid))) { - scenarios[*scenario_rid].dirty = true; + for (KeyValue<RID, Scenario> &K : scenarios) { + K.value.dirty = true; } } @@ -596,9 +594,8 @@ RaycastOcclusionCull::RaycastOcclusionCull() { } RaycastOcclusionCull::~RaycastOcclusionCull() { - const RID *scenario_rid = nullptr; - while ((scenario_rid = scenarios.next(scenario_rid))) { - Scenario &scenario = scenarios[*scenario_rid]; + for (KeyValue<RID, Scenario> &K : scenarios) { + Scenario &scenario = K.value; if (scenario.commit_thread) { scenario.commit_thread->wait_to_finish(); memdelete(scenario.commit_thread); diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index 8453c5341d..4474031991 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -86,11 +86,13 @@ private: RID scenario; RID instance; - bool operator<(const InstanceID &rhs) const { - if (instance == rhs.instance) { - return rhs.scenario < scenario; - } - return instance < rhs.instance; + static uint32_t hash(const InstanceID &p_ins) { + uint32_t h = hash_djb2_one_64(p_ins.scenario.get_id()); + return hash_djb2_one_64(p_ins.instance.get_id(), h); + } + bool operator==(const InstanceID &rhs) const { + return instance == rhs.instance && rhs.scenario == scenario; + ; } InstanceID() {} @@ -101,7 +103,7 @@ private: struct Occluder { PackedVector3Array vertices; PackedInt32Array indices; - Set<InstanceID> users; + HashSet<InstanceID, InstanceID> users; }; struct OccluderInstance { @@ -136,7 +138,7 @@ private: int current_scene_idx = 0; HashMap<RID, OccluderInstance> instances; - Set<RID> dirty_instances; // To avoid duplicates + HashSet<RID> dirty_instances; // To avoid duplicates LocalVector<RID> dirty_instances_array; // To iterate and split into threads LocalVector<RID> removed_instances; diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster.cpp index 9df6d5ff43..7659eea27f 100644 --- a/modules/raycast/static_raycaster.cpp +++ b/modules/raycast/static_raycaster.cpp @@ -94,17 +94,17 @@ void StaticRaycasterEmbree::commit() { rtcCommitScene(embree_scene); } -void StaticRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) { - for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) { - rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get())); +void StaticRaycasterEmbree::set_mesh_filter(const HashSet<int> &p_mesh_ids) { + for (const int &E : p_mesh_ids) { + rtcDisableGeometry(rtcGetGeometry(embree_scene, E)); } rtcCommitScene(embree_scene); filter_meshes = p_mesh_ids; } void StaticRaycasterEmbree::clear_mesh_filter() { - for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) { - rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get())); + for (const int &E : filter_meshes) { + rtcEnableGeometry(rtcGetGeometry(embree_scene, E)); } rtcCommitScene(embree_scene); filter_meshes.clear(); diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster.h index cce19ba60d..e2909f9b56 100644 --- a/modules/raycast/static_raycaster.h +++ b/modules/raycast/static_raycaster.h @@ -41,7 +41,7 @@ private: static RTCDevice embree_device; RTCScene embree_scene; - Set<int> filter_meshes; + HashSet<int> filter_meshes; public: virtual bool intersect(Ray &p_ray) override; @@ -50,7 +50,7 @@ public: virtual void add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) override; virtual void commit() override; - virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override; + virtual void set_mesh_filter(const HashSet<int> &p_mesh_ids) override; virtual void clear_mesh_filter() override; static StaticRaycaster *create_embree_raycaster(); diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index ee1137b71f..bbe92139e0 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -52,9 +52,9 @@ int RegExMatch::_find(const Variant &p_name) const { return i; } else if (p_name.get_type() == Variant::STRING) { - const Map<String, int>::Element *found = names.find((String)p_name); + HashMap<String, int>::ConstIterator found = names.find((String)p_name); if (found) { - return found->value(); + return found->value; } } @@ -75,8 +75,8 @@ int RegExMatch::get_group_count() const { Dictionary RegExMatch::get_names() const { Dictionary result; - for (const Map<String, int>::Element *i = names.front(); i != nullptr; i = i->next()) { - result[i->key()] = i->value(); + for (const KeyValue<String, int> &E : names) { + result[E.key] = E.value; } return result; diff --git a/modules/regex/regex.h b/modules/regex/regex.h index e7221f4070..1455188670 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -33,7 +33,7 @@ #include "core/object/ref_counted.h" #include "core/string/ustring.h" -#include "core/templates/map.h" +#include "core/templates/rb_map.h" #include "core/templates/vector.h" #include "core/variant/array.h" #include "core/variant/dictionary.h" @@ -48,7 +48,7 @@ class RegExMatch : public RefCounted { String subject; Vector<Range> data; - Map<String, int> names; + HashMap<String, int> names; friend class RegEx; diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 7fe2e589b1..dcb1f1d744 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -94,7 +94,7 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin ERR_FAIL_MSG("ImageLoaderSVG can't create image."); } - res = sw_canvas->push(move(picture)); + res = sw_canvas->push(std::move(picture)); if (res != tvg::Result::Success) { memfree(buffer); ERR_FAIL_MSG("ImageLoaderSVG can't create image."); diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 525d4d3efb..a46f17311a 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -442,7 +442,7 @@ if env["builtin_icu"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt70l.dat" + icu_data_name = "icudt71l.dat" if env_icu["tools"]: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 1c38398c88..0e36ef6805 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -116,6 +116,7 @@ if env["freetype_enabled"]: "src/psnames/psnames.c", "src/raster/raster.c", "src/sdf/sdf.c", + "src/svg/svg.c", "src/smooth/smooth.c", "src/truetype/truetype.c", "src/type1/type1.c", @@ -164,7 +165,14 @@ if env["freetype_enabled"]: env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) - env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)]) + env_freetype.Append( + CPPDEFINES=[ + "FT2_BUILD_LIBRARY", + "FT_CONFIG_OPTION_USE_PNG", + ("PNG_ARM_NEON_OPT", 0), + "FT_CONFIG_OPTION_SYSTEM_ZLIB", + ] + ) if env["target"] == "debug": env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) @@ -564,7 +572,7 @@ thirdparty_icu_sources = [ ] thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] -icu_data_name = "icudt70l.dat" +icu_data_name = "icudt71l.dat" if env["static_icu_data"]: env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index ba249aff7a..598ccd1238 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1691,6 +1691,8 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_ } RID TextServerAdvanced::create_font() { + _THREAD_SAFE_METHOD_ + FontDataAdvanced *fd = memnew(FontDataAdvanced); return font_owner.make_rid(fd); @@ -2172,6 +2174,11 @@ void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, d Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); +#ifdef MODULE_FREETYPE_ENABLED + if (fd->cache[size]->face) { + return; // Do not override scale for dynamic fonts, it's calculated automatically. + } +#endif fd->cache[size]->scale = p_scale; } @@ -2366,9 +2373,8 @@ Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vecto Array ret; const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - const int32_t *E = nullptr; - while ((E = gl.next(E))) { - ret.push_back(*E); + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + ret.push_back(E.key); } return ret; } @@ -2684,13 +2690,22 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); ERR_FAIL_COND_V(error, Dictionary()); - double h = fd->cache[size]->ascent; + if (fd->embolden != 0.f) { + FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64). + FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength); + } + + if (fd->transform != Transform2D()) { + FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). + FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat); + } + double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; if (fd->msdf) { scale = scale * (double)p_size / (double)fd->msdf_source_size; } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { - points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); + points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); @@ -2765,7 +2780,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map; + const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map; if (kern.has(p_glyph_pair)) { if (fd->msdf) { @@ -2823,7 +2838,7 @@ bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) co if (fd->cache.is_empty()) { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false); } - FontDataForSizeAdvanced *at_size = fd->cache.front()->get(); + FontDataForSizeAdvanced *at_size = fd->cache.begin()->value; #ifdef MODULE_FREETYPE_ENABLED if (at_size && at_size->face) { @@ -2841,7 +2856,7 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const if (fd->cache.is_empty()) { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String()); } - FontDataForSizeAdvanced *at_size = fd->cache.front()->get(); + FontDataForSizeAdvanced *at_size = fd->cache.begin()->value; String chars; #ifdef MODULE_FREETYPE_ENABLED @@ -2859,9 +2874,8 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const #endif if (at_size) { const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; - const int32_t *E = nullptr; - while ((E = gl.next(E))) { - chars = chars + String::chr(*E); + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + chars = chars + String::chr(E.key); } } return chars; @@ -3347,6 +3361,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced); sd->hb_buffer = hb_buffer_create(); sd->direction = p_direction; @@ -3736,6 +3751,8 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const { } RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -4572,7 +4589,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape Glyph *sd_glyphs = sd->glyphs.ptrw(); int sd_size = sd->glyphs.size(); - if (sd->jstops.size() > 0) { + if (!sd->jstops.is_empty()) { for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; @@ -5572,7 +5589,7 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri // Convert to UTF-16. Char16String utf16 = p_string.utf16(); - Set<int> breaks; + HashSet<int> breaks; UErrorCode err = U_ZERO_ERROR; UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err); if (U_FAILURE(err)) { @@ -5623,8 +5640,10 @@ TextServerAdvanced::TextServerAdvanced() { TextServerAdvanced::~TextServerAdvanced() { _bmp_free_font_funcs(); +#ifdef MODULE_FREETYPE_ENABLED if (ft_library != nullptr) { FT_Done_FreeType(ft_library); } +#endif u_cleanup(); } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 1b4293aa72..fe1d4bdcbf 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -67,7 +67,6 @@ #include <godot_cpp/classes/ref.hpp> #include <godot_cpp/templates/hash_map.hpp> -#include <godot_cpp/templates/map.hpp> #include <godot_cpp/templates/rid_owner.hpp> #include <godot_cpp/templates/set.hpp> #include <godot_cpp/templates/thread_work_pool.hpp> @@ -78,6 +77,7 @@ using namespace godot; #else // Headers for building as built-in module. +#include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" #include "core/templates/thread_work_pool.h" #include "scene/resources/texture.h" @@ -126,15 +126,15 @@ class TextServerAdvanced : public TextServerExtension { _THREAD_SAFE_CLASS_ struct NumSystemData { - Set<StringName> lang; + HashSet<StringName> lang; String digits; String percent_sign; String exp; }; Vector<NumSystemData> num_systems; - Map<StringName, int32_t> feature_sets; - Map<int32_t, StringName> feature_sets_inv; + HashMap<StringName, int32_t> feature_sets; + HashMap<int32_t, StringName> feature_sets_inv; void _insert_num_systems_lang(); void _insert_feature_sets(); @@ -191,8 +191,7 @@ class TextServerAdvanced : public TextServerExtension { Vector<FontTexture> textures; HashMap<int32_t, FontGlyph> glyph_map; - Map<Vector2i, Vector2> kerning_map; - + HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map; hb_font_t *hb_handle = nullptr; #ifdef MODULE_FREETYPE_ENABLED @@ -233,17 +232,17 @@ class TextServerAdvanced : public TextServerExtension { String font_name; String style_name; - Map<Vector2i, FontDataForSizeAdvanced *> cache; + HashMap<Vector2i, FontDataForSizeAdvanced *, VariantHasher, VariantComparator> cache; bool face_init = false; - Set<uint32_t> supported_scripts; + HashSet<uint32_t> supported_scripts; Dictionary supported_features; Dictionary supported_varaitions; Dictionary feature_overrides; // Language/script support override. - Map<String, bool> language_support_overrides; - Map<String, bool> script_support_overrides; + HashMap<String, bool> language_support_overrides; + HashMap<String, bool> script_support_overrides; PackedByteArray data; const uint8_t *data_ptr; @@ -334,7 +333,7 @@ class TextServerAdvanced : public TextServerExtension { InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; Rect2 rect; }; - Map<Variant, EmbeddedObject> objects; + HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects; /* Shaped data */ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 1753bc8b86..6c9e10db18 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -111,6 +111,7 @@ if env["freetype_enabled"]: "src/psnames/psnames.c", "src/raster/raster.c", "src/sdf/sdf.c", + "src/svg/svg.c", "src/smooth/smooth.c", "src/truetype/truetype.c", "src/type1/type1.c", @@ -159,7 +160,14 @@ if env["freetype_enabled"]: env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir]) env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"]) - env_freetype.Append(CPPDEFINES=["FT2_BUILD_LIBRARY", "FT_CONFIG_OPTION_USE_PNG", ("PNG_ARM_NEON_OPT", 0)]) + env_freetype.Append( + CPPDEFINES=[ + "FT2_BUILD_LIBRARY", + "FT_CONFIG_OPTION_USE_PNG", + ("PNG_ARM_NEON_OPT", 0), + "FT_CONFIG_OPTION_SYSTEM_ZLIB", + ] + ) if env["target"] == "debug": env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 8ae56aa64d..498b58175e 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -853,6 +853,8 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontDataFallback *p_fo } RID TextServerFallback::create_font() { + _THREAD_SAFE_METHOD_ + FontDataFallback *fd = memnew(FontDataFallback); return font_owner.make_rid(fd); @@ -1334,6 +1336,11 @@ void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, d Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); +#ifdef MODULE_FREETYPE_ENABLED + if (fd->cache[size]->face) { + return; // Do not override scale for dynamic fonts, it's calculated automatically. + } +#endif fd->cache[size]->scale = p_scale; } @@ -1528,9 +1535,8 @@ Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vecto Array ret; const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; - const int32_t *E = nullptr; - while ((E = gl.next(E))) { - ret.push_back(*E); + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + ret.push_back(E.key); } return ret; } @@ -1832,13 +1838,22 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); ERR_FAIL_COND_V(error, Dictionary()); - double h = fd->cache[size]->ascent; + if (fd->embolden != 0.f) { + FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64). + FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength); + } + + if (fd->transform != Transform2D()) { + FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536). + FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat); + } + double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; if (fd->msdf) { scale = scale * (double)p_size / (double)fd->msdf_source_size; } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { - points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); + points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); @@ -1913,7 +1928,7 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2()); - const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map; + const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map; if (kern.has(p_glyph_pair)) { if (fd->msdf) { @@ -1953,7 +1968,7 @@ bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) co if (fd->cache.is_empty()) { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false); } - FontDataForSizeFallback *at_size = fd->cache.front()->get(); + FontDataForSizeFallback *at_size = fd->cache.begin()->value; #ifdef MODULE_FREETYPE_ENABLED if (at_size && at_size->face) { @@ -1971,7 +1986,7 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const if (fd->cache.is_empty()) { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String()); } - FontDataForSizeFallback *at_size = fd->cache.front()->get(); + FontDataForSizeFallback *at_size = fd->cache.begin()->value; String chars; #ifdef MODULE_FREETYPE_ENABLED @@ -1989,9 +2004,8 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const #endif if (at_size) { const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map; - const int32_t *E = nullptr; - while ((E = gl.next(E))) { - chars = chars + String::chr(*E); + for (const KeyValue<int32_t, FontGlyph> &E : gl) { + chars = chars + String::chr(E.key); } } return chars; @@ -2417,6 +2431,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) { RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ + ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback); sd->direction = p_direction; sd->orientation = p_orientation; @@ -2795,6 +2810,8 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const { } RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index c837029623..0d2fc2628d 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -67,7 +67,6 @@ #include <godot_cpp/classes/ref.hpp> #include <godot_cpp/templates/hash_map.hpp> -#include <godot_cpp/templates/map.hpp> #include <godot_cpp/templates/rid_owner.hpp> #include <godot_cpp/templates/set.hpp> #include <godot_cpp/templates/thread_work_pool.hpp> @@ -80,6 +79,7 @@ using namespace godot; #include "servers/text/text_server_extension.h" +#include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" #include "core/templates/thread_work_pool.h" #include "scene/resources/texture.h" @@ -106,8 +106,8 @@ class TextServerFallback : public TextServerExtension { GDCLASS(TextServerFallback, TextServerExtension); _THREAD_SAFE_CLASS_ - Map<StringName, int32_t> feature_sets; - Map<int32_t, StringName> feature_sets_inv; + HashMap<StringName, int32_t> feature_sets; + HashMap<int32_t, StringName> feature_sets_inv; void _insert_feature_sets(); _FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag); @@ -159,7 +159,7 @@ class TextServerFallback : public TextServerExtension { Vector<FontTexture> textures; HashMap<int32_t, FontGlyph> glyph_map; - Map<Vector2i, Vector2> kerning_map; + HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map; #ifdef MODULE_FREETYPE_ENABLED FT_Face face = nullptr; @@ -196,15 +196,15 @@ class TextServerFallback : public TextServerExtension { String font_name; String style_name; - Map<Vector2i, FontDataForSizeFallback *> cache; + HashMap<Vector2i, FontDataForSizeFallback *, VariantHasher, VariantComparator> cache; bool face_init = false; Dictionary supported_varaitions; Dictionary feature_overrides; // Language/script support override. - Map<String, bool> language_support_overrides; - Map<String, bool> script_support_overrides; + HashMap<String, bool> language_support_overrides; + HashMap<String, bool> script_support_overrides; PackedByteArray data; const uint8_t *data_ptr; @@ -294,7 +294,7 @@ class TextServerFallback : public TextServerExtension { InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER; Rect2 rect; }; - Map<Variant, EmbeddedObject> objects; + HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects; /* Shaped data */ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 3e6680d8d8..4741c7f887 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -647,6 +647,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons")) }; + // Visual script specific theme for MSDF font. + Ref<Theme> vstheme; + vstheme.instantiate(); + Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts"); + vstheme->set_font("font", "Label", label_font); + vstheme->set_font("font", "LineEdit", label_font); + vstheme->set_font("font", "Button", label_font); + Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons")); List<int> node_ids; script->get_node_list(&node_ids); @@ -881,7 +889,49 @@ void VisualScriptEditor::_update_graph(int p_only_id) { EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr); } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) { - button->set_text(pi.hint_string.get_slice(",", value)); + bool found = false; + const Vector<String> options = pi.hint_string.split(","); + int64_t current_val = 0; + for (const String &option : options) { + Vector<String> text_split = option.split(":"); + if (text_split.size() != 1) { + current_val = text_split[1].to_int(); + } + if (value.operator int() == current_val) { + button->set_text(text_split[0]); + found = true; + break; + } + current_val += 1; + } + if (!found) { + button->set_text(value); + } + } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_FLAGS) { + Vector<String> value_texts; + const Vector<String> options = pi.hint_string.split(","); + uint32_t v = value; + for (const String &option : options) { + uint32_t current_val; + Vector<String> text_split = option.split(":"); + if (text_split.size() != -1) { + current_val = text_split[1].to_int(); + } else { + current_val = 1 << i; + } + if ((v & current_val) == current_val) { + value_texts.push_back(text_split[0]); + } + } + if (value_texts.size() != 0) { + String value_text = value_texts[0]; + for (const String &text : value_texts) { + value_text += " | " + text; + } + button->set_text(value_text); + } else { + button->set_text(value); + } } else { button->set_text(value); } @@ -960,9 +1010,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { slot_idx++; } - graph->add_child(gnode); - + gnode->set_theme(vstheme); if (gnode->is_comment()) { graph->move_child(gnode, 0); } @@ -973,6 +1022,9 @@ void VisualScriptEditor::_update_graph(int p_only_id) { float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); + // Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything. graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE); updating_graph = false; @@ -1433,7 +1485,11 @@ void VisualScriptEditor::_deselect_input_names() { } } -void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) { +void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button) { + if (p_mouse_button != MouseButton::LEFT) { + return; + } + TreeItem *ti = Object::cast_to<TreeItem>(p_item); TreeItem *root = members->get_root(); @@ -1603,12 +1659,12 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { List<VisualScript::DataConnection> data_connections; script->get_data_connection_list(&data_connections); - HashMap<int, Set<int>> conn_map; + HashMap<int, RBSet<int>> conn_map; for (const VisualScript::DataConnection &E : data_connections) { if (E.from_node == p_id && E.from_port == p_port) { // Push into the connections map. if (!conn_map.has(E.to_node)) { - conn_map.set(E.to_node, Set<int>()); + conn_map.insert(E.to_node, RBSet<int>()); } conn_map[E.to_node].insert(E.to_port); } @@ -1617,11 +1673,9 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port); undo_redo->add_do_method(this, "_update_graph", p_id); - List<int> keys; - conn_map.get_key_list(&keys); - for (const int &E : keys) { - for (const Set<int>::Element *F = conn_map[E].front(); F; F = F->next()) { - undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F->get()); + for (const KeyValue<int, RBSet<int>> &E : conn_map) { + for (const int &F : E.value) { + undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F); } } @@ -1762,14 +1816,14 @@ void VisualScriptEditor::_on_nodes_paste() { return; } - Map<int, int> remap; + HashMap<int, int> remap; undo_redo->create_action(TTR("Paste VisualScript Nodes")); int idc = script->get_available_id() + 1; - Set<int> to_select; + RBSet<int> to_select; - Set<Vector2> existing_positions; + RBSet<Vector2> existing_positions; { List<int> nodes; @@ -1808,14 +1862,14 @@ void VisualScriptEditor::_on_nodes_paste() { undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); } - for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); - undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); + for (const VisualScript::SequenceConnection &E : clipboard->sequence_connections) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E.from_node], E.from_output, remap[E.to_node]); } - for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); - undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port); + for (const VisualScript::DataConnection &E : clipboard->data_connections) { + undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); + undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); } undo_redo->add_do_method(this, "_update_graph"); @@ -1883,7 +1937,7 @@ void VisualScriptEditor::_on_nodes_delete() { } void VisualScriptEditor::_on_nodes_duplicate() { - Set<int> to_duplicate; + RBSet<int> to_duplicate; for (int i = 0; i < graph->get_child_count(); i++) { GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); @@ -1902,20 +1956,20 @@ void VisualScriptEditor::_on_nodes_duplicate() { undo_redo->create_action(TTR("Duplicate VisualScript Nodes")); int idc = script->get_available_id() + 1; - Set<int> to_select; + RBSet<int> to_select; HashMap<int, int> remap; - for (Set<int>::Element *F = to_duplicate.front(); F; F = F->next()) { + for (const int &F : to_duplicate) { // Duplicate from the specific function but place it into the default func as it would lack the connections. - Ref<VisualScriptNode> node = script->get_node(F->get()); + Ref<VisualScriptNode> node = script->get_node(F); Ref<VisualScriptNode> dupe = node->duplicate(true); int new_id = idc++; - remap.set(F->get(), new_id); + remap.insert(F, new_id); to_select.insert(new_id); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20)); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F) + Vector2(20, 20)); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); } @@ -1961,15 +2015,6 @@ void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) { } new_connect_node_select->select_from_visual_script(script, false); // do not reset text - - // Ensure that the dialog fits inside the graph. - Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size(); - pos.x = pos.x > bounds.x ? bounds.x : pos.x; - pos.y = pos.y > bounds.y ? bounds.y : pos.y; - - if (pos != Vector2()) { - new_connect_node_select->set_position(pos); - } } void VisualScriptEditor::input(const Ref<InputEvent> &p_event) { @@ -3177,7 +3222,7 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro } } -VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) { +VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &visited_nodes) { VisualScriptNode::TypeGuess tg; tg.type = Variant::NIL; @@ -3228,7 +3273,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac } void VisualScriptEditor::_port_action_menu(int p_option) { - Set<int> vn; + RBSet<int> vn; switch (p_option) { case CREATE_CALL_SET_GET: { @@ -3340,7 +3385,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri #endif Vector2 pos = _get_pos_in_graph(port_action_pos); - Set<int> vn; + RBSet<int> vn; bool port_node_exists = true; if (drop_position != Vector2()) { @@ -4096,8 +4141,8 @@ void VisualScriptEditor::_menu_option(int p_what) { } break; case EDIT_CREATE_FUNCTION: { // Create Function. - Map<int, Ref<VisualScriptNode>> nodes; - Set<int> selections; + HashMap<int, Ref<VisualScriptNode>> nodes; + RBSet<int> selections; for (int i = 0; i < graph->get_child_count(); i++) { GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); if (gn) { @@ -4120,18 +4165,18 @@ void VisualScriptEditor::_menu_option(int p_what) { return; // nothing to be done if there are no valid nodes selected } - Set<VisualScript::SequenceConnection> seqmove; - Set<VisualScript::DataConnection> datamove; + RBSet<VisualScript::SequenceConnection> seqmove; + RBSet<VisualScript::DataConnection> datamove; - Set<VisualScript::SequenceConnection> seqext; - Set<VisualScript::DataConnection> dataext; + RBSet<VisualScript::SequenceConnection> seqext; + RBSet<VisualScript::DataConnection> dataext; int start_node = -1; - Set<int> end_nodes; + RBSet<int> end_nodes; if (nodes.size() == 1) { - Ref<VisualScriptNode> nd = script->get_node(nodes.front()->key()); + Ref<VisualScriptNode> nd = script->get_node(nodes.begin()->key); if (nd.is_valid() && nd->has_input_sequence_port()) { - start_node = nodes.front()->key(); + start_node = nodes.begin()->key; } else { EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port.")); return; @@ -4169,8 +4214,8 @@ void VisualScriptEditor::_menu_option(int p_what) { } } else { // Pick the node with input sequence. - Set<int> nodes_from; - Set<int> nodes_to; + RBSet<int> nodes_from; + RBSet<int> nodes_to; for (const VisualScript::SequenceConnection &E : seqs) { if (nodes.has(E.from_node) && nodes.has(E.to_node)) { seqmove.insert(E); @@ -4196,9 +4241,9 @@ void VisualScriptEditor::_menu_option(int p_what) { // If we still don't have a start node then, // run through the nodes and select the first tree node, // i.e. node without any input sequence but output sequence. - for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) { - if (!nodes_to.has(E->get())) { - start_node = E->get(); + for (const int &E : nodes_from) { + if (!nodes_to.has(E)) { + start_node = E; } } } @@ -4267,13 +4312,13 @@ void VisualScriptEditor::_menu_option(int p_what) { // Move the nodes. // Handles reconnection of sequence connections on undo, start here in case of issues. - for (Set<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E->get().from_node, E->get().from_output, E->get().to_node); - undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node); + for (const VisualScript::SequenceConnection &E : seqext) { + undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E.from_node, E.from_output, E.to_node); + undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); } - for (Set<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) { - undo_redo->add_do_method(script.ptr(), "data_disconnect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); - undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + for (const VisualScript::DataConnection &E : dataext) { + undo_redo->add_do_method(script.ptr(), "data_disconnect", E.from_node, E.from_port, E.to_node, E.to_port); + undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); } // I don't really think we need support for non sequenced functions at this moment. @@ -4281,24 +4326,24 @@ void VisualScriptEditor::_menu_option(int p_what) { // Could fail with the new changes, start here when searching for bugs in create function shortcut. int m = 1; - for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) { + for (const int &G : end_nodes) { Ref<VisualScriptReturn> ret_node; ret_node.instantiate(); int ret_id = fn_id + (m++); selections.insert(ret_id); - Vector2 posi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100)); + Vector2 posi = _get_available_pos(false, script->get_node_position(G) + Vector2(80, -100)); undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi); undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id); - undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id); + undo_redo->add_do_method(script.ptr(), "sequence_connect", G, 0, ret_id); // Add data outputs from each of the end_nodes. - Ref<VisualScriptNode> vsn = script->get_node(G->get()); + Ref<VisualScriptNode> vsn = script->get_node(G); if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) { ret_node->set_enable_return_value(true); // Use the zeroth data port cause that's the likely one that is planned to be used. ret_node->set_return_type(vsn->get_output_value_port_info(0).type); - undo_redo->add_do_method(script.ptr(), "data_connect", G->get(), 0, ret_id, 0); + undo_redo->add_do_method(script.ptr(), "data_connect", G, 0, ret_id, 0); } } @@ -4333,7 +4378,7 @@ void VisualScriptEditor::_menu_option(int p_what) { // This is likely going to be very slow and I am not sure if I should keep it, // but I hope that it will not be a problem considering that we won't be creating functions so frequently, // and cyclic connections would be a problem but hopefully we won't let them get to this point. -void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes) { +void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes) { for (const VisualScript::SequenceConnection &E : p_seqs) { int from = E.from_node; int to = E.to_node; @@ -4347,7 +4392,11 @@ void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::Sequence } } -void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { +void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos, MouseButton p_button) { + if (p_button != MouseButton::RIGHT) { + return; + } + TreeItem *ti = members->get_selected(); ERR_FAIL_COND(!ti); @@ -4548,11 +4597,11 @@ VisualScriptEditor::VisualScriptEditor() { members_section->add_margin_child(TTR("Members:"), members, true); members->set_custom_minimum_size(Size2(0, 50 * EDSCALE)); members->set_hide_root(true); - members->connect("button_pressed", callable_mp(this, &VisualScriptEditor::_member_button)); + members->connect("button_clicked", callable_mp(this, &VisualScriptEditor::_member_button)); members->connect("item_edited", callable_mp(this, &VisualScriptEditor::_member_edited)); members->connect("cell_selected", callable_mp(this, &VisualScriptEditor::_member_selected), varray(), CONNECT_DEFERRED); members->connect("gui_input", callable_mp(this, &VisualScriptEditor::_members_gui_input)); - members->connect("item_rmb_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected)); + members->connect("item_mouse_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected)); members->set_allow_rmb_select(true); members->set_allow_reselect(true); members->set_hide_folding(true); @@ -4577,6 +4626,7 @@ VisualScriptEditor::VisualScriptEditor() { add_child(graph); graph->set_v_size_flags(Control::SIZE_EXPAND_FILL); graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + graph->set_show_zoom_label(true); graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected)); graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move)); graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move)); @@ -4588,6 +4638,8 @@ VisualScriptEditor::VisualScriptEditor() { graph->set_drag_forwarding(this); float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"); graph->set_minimap_opacity(graph_minimap_opacity); + float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"); + graph->set_connection_lines_curvature(graph_lines_curvature); graph->hide(); graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed)); @@ -4839,7 +4891,7 @@ Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String & } VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr; -Map<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes; +HashMap<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes; VisualScriptCustomNodes::VisualScriptCustomNodes() { singleton = this; diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index e63539ac5b..fd59d22cbe 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -142,9 +142,9 @@ class VisualScriptEditor : public ScriptEditorBase { Vector<Pair<Variant::Type, String>> args; }; - Map<StringName, Color> node_colors; + HashMap<StringName, Color> node_colors; HashMap<StringName, Ref<StyleBox>> node_styles; - Map<StringName, Variant::Type> base_type_map; + HashMap<StringName, Variant::Type> base_type_map; void _update_graph_connections(); void _update_graph(int p_only_id = -1); @@ -159,11 +159,11 @@ class VisualScriptEditor : public ScriptEditorBase { String _validate_name(const String &p_name) const; struct Clipboard { - Map<int, Ref<VisualScriptNode>> nodes; - Map<int, Vector2> nodes_positions; + HashMap<int, Ref<VisualScriptNode>> nodes; + HashMap<int, Vector2> nodes_positions; - Set<VisualScript::SequenceConnection> sequence_connections; - Set<VisualScript::DataConnection> data_connections; + RBSet<VisualScript::SequenceConnection> sequence_connections; + RBSet<VisualScript::DataConnection> data_connections; }; static Clipboard *clipboard; @@ -213,7 +213,7 @@ class VisualScriptEditor : public ScriptEditorBase { void _end_node_move(); void _move_node(int p_id, const Vector2 &p_to); - void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes); + void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes); void _node_moved(Vector2 p_from, Vector2 p_to, int p_id); void _remove_node(int p_id); @@ -226,7 +226,7 @@ class VisualScriptEditor : public ScriptEditorBase { void _update_available_nodes(); - void _member_button(Object *p_item, int p_column, int p_button); + void _member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button); void _expression_text_changed(const String &p_text, int p_id); void _add_input_port(int p_id); @@ -287,9 +287,9 @@ class VisualScriptEditor : public ScriptEditorBase { void _draw_color_over_button(Object *obj, Color p_color); void _button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud); - VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &p_visited_nodes); + VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &p_visited_nodes); - void _member_rmb_selected(const Vector2 &p_pos); + void _member_rmb_selected(const Vector2 &p_pos, MouseButton p_button); void _member_option(int p_option); void _toggle_scripts_pressed(); @@ -359,7 +359,7 @@ protected: static void _bind_methods(); static VisualScriptCustomNodes *singleton; - static Map<String, Ref<RefCounted>> custom_nodes; + static HashMap<String, Ref<RefCounted>> custom_nodes; static Ref<VisualScriptNode> create_node_custom(const String &p_name); public: diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp index c8549ddb53..ae30655301 100644 --- a/modules/visual_script/editor/visual_script_property_selector.cpp +++ b/modules/visual_script/editor/visual_script_property_selector.cpp @@ -182,7 +182,7 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_base_script, bool p_virtuals_only, const bool p_connecting, bool clear_text) { set_title(TTR("Select from base type")); base_type = p_base; - base_script = p_base_script.lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + base_script = p_base_script.trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name type = Variant::NIL; connecting = p_connecting; @@ -217,7 +217,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip ERR_FAIL_COND(p_script.is_null()); base_type = p_script->get_instance_base_type(); - base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name type = Variant::NIL; script = p_script->get_instance_id(); connecting = p_connecting; @@ -312,7 +312,7 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons if (p_script == nullptr) { base_script = ""; } else { - base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name } type = Variant::NIL; @@ -346,7 +346,7 @@ void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> & if (p_script == nullptr) { base_script = ""; } else { - base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name + base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name } type = Variant::NIL; connecting = false; @@ -521,8 +521,17 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() { results_tree->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected)); vbox->add_child(results_tree); + ScrollContainer *scroller = memnew(ScrollContainer); + scroller->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + scroller->set_v_size_flags(Control::SIZE_EXPAND_FILL); + scroller->set_custom_minimum_size(Size2(600, 400) * EDSCALE); + vbox->add_child(scroller); + help_bit = memnew(EditorHelpBit); - vbox->add_child(help_bit); + help_bit->set_h_size_flags(Control::SIZE_EXPAND_FILL); + help_bit->set_v_size_flags(Control::SIZE_EXPAND_FILL); + scroller->add_child(help_bit); + help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested)); get_ok_button()->set_text(TTR("Open")); get_ok_button()->set_disabled(true); @@ -726,7 +735,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes_init() { combined_docs.insert(class_doc.name, class_doc); } } - iterator_doc = combined_docs.front(); + iterator_doc = combined_docs.begin(); return true; } @@ -787,7 +796,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() { } bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() { - DocData::ClassDoc &class_doc = iterator_doc->value(); + DocData::ClassDoc &class_doc = iterator_doc->value; if ( (!_is_class_disabled_by_feature_profile(class_doc.name) && !_is_class_disabled_by_scope(class_doc.name)) || _match_visual_script(class_doc)) { @@ -909,13 +918,13 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() { } } - iterator_doc = iterator_doc->next(); + ++iterator_doc; return !iterator_doc; } bool VisualScriptPropertySelector::SearchRunner::_phase_class_items_init() { results_tree->clear(); - iterator_match = matches.front(); + iterator_match = matches.begin(); root_item = results_tree->create_item(); class_items.clear(); @@ -928,7 +937,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() { return true; } - ClassMatch &match = iterator_match->value(); + ClassMatch &match = iterator_match->value; if (search_flags & SEARCH_SHOW_HIERARCHY) { if (match.required()) { @@ -940,12 +949,12 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() { } } - iterator_match = iterator_match->next(); + ++iterator_match; return !iterator_match; } bool VisualScriptPropertySelector::SearchRunner::_phase_member_items_init() { - iterator_match = matches.front(); + iterator_match = matches.begin(); return true; } @@ -955,7 +964,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() { return true; } - ClassMatch &match = iterator_match->value(); + ClassMatch &match = iterator_match->value; TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item; bool constructor_created = false; @@ -986,7 +995,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() { _create_theme_property_item(parent, match.doc, match.theme_properties[i]); } - iterator_match = iterator_match->next(); + ++iterator_match; return !iterator_match; } diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h index 90a6265ab7..91d81bba47 100644 --- a/modules/visual_script/editor/visual_script_property_selector.h +++ b/modules/visual_script/editor/visual_script_property_selector.h @@ -179,15 +179,15 @@ class VisualScriptPropertySelector::SearchRunner : public RefCounted { Ref<Texture2D> empty_icon; Color disabled_color; - Map<String, DocData::ClassDoc>::Element *iterator_doc = nullptr; - Map<String, ClassMatch> matches; - Map<String, ClassMatch>::Element *iterator_match = nullptr; + HashMap<String, DocData::ClassDoc>::Iterator iterator_doc; + HashMap<String, ClassMatch> matches; + HashMap<String, ClassMatch>::Iterator iterator_match; TreeItem *root_item = nullptr; - Map<String, TreeItem *> class_items; + HashMap<String, TreeItem *> class_items; TreeItem *matched_item = nullptr; float match_highest_score = 0; - Map<String, DocData::ClassDoc> combined_docs; + HashMap<String, DocData::ClassDoc> combined_docs; List<String> vs_nodes; bool _is_class_disabled_by_feature_profile(const StringName &p_class); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 7028fead9a..24bb22960e 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -209,8 +209,9 @@ Vector2 VisualScript::get_scroll() const { } void VisualScript::get_function_list(List<StringName> *r_functions) const { - functions.get_key_list(r_functions); - // r_functions->sort_custom<StringName::AlphCompare>(); // Don't force sorting. + for (const KeyValue<StringName, Function> &E : functions) { + r_functions->push_back(E.key); + } } int VisualScript::get_function_node_id(const StringName &p_name) const { @@ -229,12 +230,12 @@ void VisualScript::_node_ports_changed(int p_id) { { List<SequenceConnection> to_remove; - for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) { - if (E->get().from_node == p_id && E->get().from_output >= vsn->get_output_sequence_port_count()) { - to_remove.push_back(E->get()); + for (const SequenceConnection &E : sequence_connections) { + if (E.from_node == p_id && E.from_output >= vsn->get_output_sequence_port_count()) { + to_remove.push_back(E); } - if (E->get().to_node == p_id && !vsn->has_input_sequence_port()) { - to_remove.push_back(E->get()); + if (E.to_node == p_id && !vsn->has_input_sequence_port()) { + to_remove.push_back(E); } } @@ -247,12 +248,12 @@ void VisualScript::_node_ports_changed(int p_id) { { List<DataConnection> to_remove; - for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (E->get().from_node == p_id && E->get().from_port >= vsn->get_output_value_port_count()) { - to_remove.push_back(E->get()); + for (const DataConnection &E : data_connections) { + if (E.from_node == p_id && E.from_port >= vsn->get_output_value_port_count()) { + to_remove.push_back(E); } - if (E->get().to_node == p_id && E->get().to_port >= vsn->get_input_value_port_count()) { - to_remove.push_back(E->get()); + if (E.to_node == p_id && E.to_port >= vsn->get_input_value_port_count()) { + to_remove.push_back(E); } } @@ -291,9 +292,9 @@ void VisualScript::remove_node(int p_id) { { List<SequenceConnection> to_remove; - for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) { - if (E->get().from_node == p_id || E->get().to_node == p_id) { - to_remove.push_back(E->get()); + for (const SequenceConnection &E : sequence_connections) { + if (E.from_node == p_id || E.to_node == p_id) { + to_remove.push_back(E); } } @@ -306,9 +307,9 @@ void VisualScript::remove_node(int p_id) { { List<DataConnection> to_remove; - for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (E->get().from_node == p_id || E->get().to_node == p_id) { - to_remove.push_back(E->get()); + for (const DataConnection &E : data_connections) { + if (E.from_node == p_id || E.to_node == p_id) { + to_remove.push_back(E); } } @@ -346,7 +347,9 @@ Point2 VisualScript::get_node_position(int p_id) const { } void VisualScript::get_node_list(List<int> *r_nodes) const { - nodes.get_key_list(r_nodes); + for (const KeyValue<int, NodeData> &E : nodes) { + r_nodes->push_back(E.key); + } } void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) { @@ -381,8 +384,8 @@ bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, i } void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const { - for (const Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) { - r_connection->push_back(E->get()); + for (const SequenceConnection &E : sequence_connections) { + r_connection->push_back(E); } } @@ -423,8 +426,8 @@ bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_t } bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const { - for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (E->get().to_node == p_node && E->get().to_port == p_port) { + for (const DataConnection &E : data_connections) { + if (E.to_node == p_node && E.to_port == p_port) { return true; } } @@ -432,10 +435,10 @@ bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const { } bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const { - for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (E->get().to_node == p_node && E->get().to_port == p_port) { - *r_node = E->get().from_node; - *r_port = E->get().from_port; + for (const DataConnection &E : data_connections) { + if (E.to_node == p_node && E.to_port == p_port) { + *r_node = E.from_node; + *r_port = E.from_port; return true; } } @@ -443,8 +446,8 @@ bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port } void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const { - for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - r_connection->push_back(E->get()); + for (const DataConnection &E : data_connections) { + r_connection->push_back(E); } } @@ -563,8 +566,9 @@ Dictionary VisualScript::_get_variable_info(const StringName &p_name) const { } void VisualScript::get_variable_list(List<StringName> *r_variables) const { - variables.get_key_list(r_variables); - // r_variables->sort_custom<StringName::AlphCompare>(); // Don't force it. + for (const KeyValue<StringName, Variable> &E : variables) { + r_variables->push_back(E.key); + } } void VisualScript::set_instance_base_type(const StringName &p_type) { @@ -713,12 +717,11 @@ int VisualScript::get_available_id() const { // This is infinitely increasing, // so one might want to implement a better solution, // if the there is a case for huge number of nodes to be added to visual script. - List<int> nds; - nodes.get_key_list(&nds); + int max = -1; - for (const int &E : nds) { - if (E > max) { - max = E; + for (const KeyValue<int, NodeData> &E : nodes) { + if (E.key > max) { + max = E.key; } } return (max + 1); @@ -748,24 +751,21 @@ void VisualScript::_update_placeholders() { return; // No bother if no placeholders. } List<PropertyInfo> pinfo; - Map<StringName, Variant> values; - - List<StringName> keys; - variables.get_key_list(&keys); + HashMap<StringName, Variant> values; - for (const StringName &E : keys) { - if (!variables[E]._export) { + for (const KeyValue<StringName, Variable> &E : variables) { + if (!variables[E.key]._export) { continue; } - PropertyInfo p = variables[E].info; - p.name = String(E); + PropertyInfo p = variables[E.key].info; + p.name = String(E.key); pinfo.push_back(p); - values[p.name] = variables[E].default_value; + values[p.name] = variables[E.key].default_value; } - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(pinfo, values); + for (PlaceHolderScriptInstance *E : placeholders) { + E->update(pinfo, values); } } @@ -779,20 +779,17 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) { placeholders.insert(sins); List<PropertyInfo> pinfo; - Map<StringName, Variant> values; + HashMap<StringName, Variant> values; - List<StringName> keys; - variables.get_key_list(&keys); - - for (const StringName &E : keys) { - if (!variables[E]._export) { + for (const KeyValue<StringName, Variable> &E : variables) { + if (!variables[E.key]._export) { continue; } - PropertyInfo p = variables[E].info; - p.name = String(E); + PropertyInfo p = variables[E.key].info; + p.name = String(E.key); pinfo.push_back(p); - values[p.name] = variables[E].default_value; + values[p.name] = variables[E.key].default_value; } sins->update(pinfo, values); @@ -872,14 +869,11 @@ bool VisualScript::get_property_default_value(const StringName &p_property, Vari } void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const { - List<StringName> funcs; - functions.get_key_list(&funcs); - - for (const StringName &E : funcs) { + for (const KeyValue<StringName, Function> &E : functions) { MethodInfo mi; - mi.name = E; - if (functions[E].func_id >= 0) { - Ref<VisualScriptFunction> func = nodes[functions[E].func_id].node; + mi.name = E.key; + if (functions[E.key].func_id >= 0) { + Ref<VisualScriptFunction> func = nodes[functions[E.key].func_id].node; if (func.is_valid()) { for (int i = 0; i < func->get_argument_count(); i++) { PropertyInfo arg; @@ -945,10 +939,8 @@ int VisualScript::get_member_line(const StringName &p_member) const { #ifdef TOOLS_ENABLED bool VisualScript::are_subnodes_edited() const { - List<int> keys; - nodes.get_key_list(&keys); - for (const int &F : keys) { - if (nodes[F].node->is_edited()) { + for (const KeyValue<int, NodeData> &F : nodes) { + if (F.value.node->is_edited()) { return true; } } @@ -1017,15 +1009,13 @@ void VisualScript::_set_data(const Dictionary &p_data) { // Takes all the rpc methods. rpc_functions.clear(); - List<StringName> fns; - functions.get_key_list(&fns); - for (const StringName &E : fns) { - if (functions[E].func_id >= 0 && nodes.has(functions[E].func_id)) { - Ref<VisualScriptFunction> vsf = nodes[functions[E].func_id].node; + for (const KeyValue<StringName, Function> &E : functions) { + if (E.value.func_id >= 0 && nodes.has(E.value.func_id)) { + Ref<VisualScriptFunction> vsf = nodes[E.value.func_id].node; if (vsf.is_valid()) { if (vsf->get_rpc_mode() != Multiplayer::RPC_MODE_DISABLED) { Multiplayer::RPCConfig nd; - nd.name = E; + nd.name = E.key; nd.rpc_mode = vsf->get_rpc_mode(); nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; // TODO if (rpc_functions.find(nd) == -1) { @@ -1045,13 +1035,11 @@ Dictionary VisualScript::_get_data() const { d["base_type"] = base_type; Array vars; - List<StringName> var_names; - variables.get_key_list(&var_names); - for (const StringName &E : var_names) { - Dictionary var = _get_variable_info(E); - var["name"] = E; // Make sure it's the right one. - var["default_value"] = variables[E].default_value; - var["export"] = variables[E]._export; + for (const KeyValue<StringName, Variable> &E : variables) { + Dictionary var = _get_variable_info(E.key); + var["name"] = E.key; // Make sure it's the right one. + var["default_value"] = E.value.default_value; + var["export"] = E.value._export; vars.push_back(var); } d["variables"] = vars; @@ -1073,40 +1061,36 @@ Dictionary VisualScript::_get_data() const { d["signals"] = sigs; Array funcs; - List<StringName> func_names; - functions.get_key_list(&func_names); - for (const StringName &E : func_names) { + for (const KeyValue<StringName, Function> &E : functions) { Dictionary func; - func["name"] = E; - func["function_id"] = functions[E].func_id; + func["name"] = E.key; + func["function_id"] = E.value.func_id; funcs.push_back(func); } d["functions"] = funcs; Array nds; - List<int> node_ids; - nodes.get_key_list(&node_ids); - for (const int &F : node_ids) { - nds.push_back(F); - nds.push_back(nodes[F].pos); - nds.push_back(nodes[F].node); + for (const KeyValue<int, NodeData> &F : nodes) { + nds.push_back(F.key); + nds.push_back(F.value.pos); + nds.push_back(F.value.node); } d["nodes"] = nds; Array seqconns; - for (const Set<SequenceConnection>::Element *F = sequence_connections.front(); F; F = F->next()) { - seqconns.push_back(F->get().from_node); - seqconns.push_back(F->get().from_output); - seqconns.push_back(F->get().to_node); + for (const SequenceConnection &F : sequence_connections) { + seqconns.push_back(F.from_node); + seqconns.push_back(F.from_output); + seqconns.push_back(F.to_node); } d["sequence_connections"] = seqconns; Array dataconns; - for (const Set<DataConnection>::Element *F = data_connections.front(); F; F = F->next()) { - dataconns.push_back(F->get().from_node); - dataconns.push_back(F->get().from_port); - dataconns.push_back(F->get().to_node); - dataconns.push_back(F->get().to_port); + for (const DataConnection &F : data_connections) { + dataconns.push_back(F.from_node); + dataconns.push_back(F.from_port); + dataconns.push_back(F.to_node); + dataconns.push_back(F.to_port); } d["data_connections"] = dataconns; @@ -1184,10 +1168,10 @@ bool VisualScript::inherits_script(const Ref<Script> &p_script) const { return this == p_script.ptr(); // There is no inheritance in visual scripts, so this is enough. } -Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) { +RBSet<int> VisualScript::get_output_sequence_ports_connected(int from_node) { List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>); get_sequence_connection_list(sc); - Set<int> connected; + RBSet<int> connected; for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) { if (E->get().from_node == from_node) { connected.insert(E->get().from_output); @@ -1199,45 +1183,41 @@ Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) { VisualScript::~VisualScript() { // Remove all nodes and stuff that hold data refs. - List<int> nds; - nodes.get_key_list(&nds); - for (const int &E : nds) { - remove_node(E); + for (const KeyValue<int, NodeData> &E : nodes) { + remove_node(E.key); } } //////////////////////////////////////////// bool VisualScriptInstance::set(const StringName &p_name, const Variant &p_value) { - Map<StringName, Variant>::Element *E = variables.find(p_name); + HashMap<StringName, Variant>::Iterator E = variables.find(p_name); if (!E) { return false; } - E->get() = p_value; + E->value = p_value; return true; } bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const { - const Map<StringName, Variant>::Element *E = variables.find(p_name); + HashMap<StringName, Variant>::ConstIterator E = variables.find(p_name); if (!E) { return false; } - r_ret = E->get(); + r_ret = E->value; return true; } void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - List<StringName> vars; - script->variables.get_key_list(&vars); - for (const StringName &E : vars) { - if (!script->variables[E]._export) { + for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) { + if (!E.value._export) { continue; } - PropertyInfo p = script->variables[E].info; - p.name = String(E); + PropertyInfo p = E.value.info; + p.name = String(E.key); p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_properties->push_back(p); } @@ -1259,13 +1239,11 @@ Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name, } void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const { - List<StringName> fns; - script->functions.get_key_list(&fns); - for (const StringName &E : fns) { + for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) { MethodInfo mi; - mi.name = E; - if (script->functions[E].func_id >= 0 && script->nodes.has(script->functions[E].func_id)) { - Ref<VisualScriptFunction> vsf = script->nodes[script->functions[E].func_id].node; + mi.name = E.key; + if (E.value.func_id >= 0 && script->nodes.has(E.value.func_id)) { + Ref<VisualScriptFunction> vsf = script->nodes[E.value.func_id].node; if (vsf.is_valid()) { for (int i = 0; i < vsf->get_argument_count(); i++) { PropertyInfo arg; @@ -1337,9 +1315,9 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int } Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error) { - Map<StringName, Function>::Element *F = functions.find(p_method); + HashMap<StringName, Function>::Iterator F = functions.find(p_method); ERR_FAIL_COND_V(!F, Variant()); - Function *f = &F->get(); + Function *f = &F->value; // This call goes separate, so it can be yielded and suspended. Variant *variant_stack = (Variant *)p_stack; @@ -1711,7 +1689,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { r_error.error = Callable::CallError::CALL_OK; //ok by default - Map<StringName, Function>::Element *F = functions.find(p_method); + HashMap<StringName, Function>::Iterator F = functions.find(p_method); if (!F) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; return Variant(); @@ -1719,7 +1697,7 @@ Variant VisualScriptInstance::callp(const StringName &p_method, const Variant ** VSDEBUG("CALLING: " + String(p_method)); - Function *f = &F->get(); + Function *f = &F->value; int total_stack_size = 0; @@ -1753,14 +1731,14 @@ Variant VisualScriptInstance::callp(const StringName &p_method, const Variant ** memset(pass_stack, 0, f->pass_stack_size * sizeof(int)); - Map<int, VisualScriptNodeInstance *>::Element *E = instances.find(f->node); + HashMap<int, VisualScriptNodeInstance *>::Iterator E = instances.find(f->node); if (!E) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "No VisualScriptFunction node in function."); } - VisualScriptNodeInstance *node = E->get(); + VisualScriptNodeInstance *node = E->value; if (flow_stack) { flow_stack[0] = node->get_id(); @@ -1845,19 +1823,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o // Setup variables. { - List<StringName> keys; - script->variables.get_key_list(&keys); - for (const StringName &E : keys) { - variables[E] = script->variables[E].default_value; + for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) { + variables[E.key] = E.value.default_value; } } // Setup functions from sequence trees. { - List<StringName> keys; - script->functions.get_key_list(&keys); - for (const StringName &E : keys) { - const VisualScript::Function vsfn = p_script->functions[E]; + for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) { + const VisualScript::Function &vsfn = E.value; Function function; function.node = vsfn.func_id; function.max_stack = 0; @@ -1865,10 +1839,10 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o function.pass_stack_size = 0; function.node_count = 0; - Map<StringName, int> local_var_indices; + HashMap<StringName, int> local_var_indices; if (function.node < 0) { - VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E)); + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E.key)); ERR_CONTINUE(function.node < 0); } @@ -1876,7 +1850,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id); if (func_node.is_null()) { - VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E)); + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E.key)); } ERR_CONTINUE(!func_node.is_valid()); @@ -1887,42 +1861,41 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o max_input_args = MAX(max_input_args, function.argument_count); } // Function nodes graphs. - Set<VisualScript::SequenceConnection> seqconns; - Set<VisualScript::DataConnection> dataconns; - Set<int> node_ids; + RBSet<VisualScript::SequenceConnection> seqconns; + RBSet<VisualScript::DataConnection> dataconns; + RBSet<int> node_ids; node_ids.insert(function.node); { List<int> nd_queue; nd_queue.push_back(function.node); while (!nd_queue.is_empty()) { - for (const Set<VisualScript::SequenceConnection>::Element *F = script->sequence_connections.front(); F; F = F->next()) { - if (nd_queue.front()->get() == F->get().from_node && !node_ids.has(F->get().to_node)) { - nd_queue.push_back(F->get().to_node); - node_ids.insert(F->get().to_node); + for (const VisualScript::SequenceConnection &F : script->sequence_connections) { + if (nd_queue.front()->get() == F.from_node && !node_ids.has(F.to_node)) { + nd_queue.push_back(F.to_node); + node_ids.insert(F.to_node); } - if (nd_queue.front()->get() == F->get().from_node && !seqconns.has(F->get())) { - seqconns.insert(F->get()); + if (nd_queue.front()->get() == F.from_node && !seqconns.has(F)) { + seqconns.insert(F); } } nd_queue.pop_front(); } HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port) - for (const Set<VisualScript::DataConnection>::Element *F = script->data_connections.front(); F; F = F->next()) { - dc_lut[F->get().to_node][F->get().to_port] = Pair<int, int>(F->get().from_node, F->get().from_port); + for (const VisualScript::DataConnection &F : script->data_connections) { + dc_lut[F.to_node][F.to_port] = Pair<int, int>(F.from_node, F.from_port); } - for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) { - nd_queue.push_back(F->get()); + for (const int &F : node_ids) { + nd_queue.push_back(F); } List<int> dc_keys; while (!nd_queue.is_empty()) { int ky = nd_queue.front()->get(); - dc_lut[ky].get_key_list(&dc_keys); - for (const int &F : dc_keys) { + for (const KeyValue<int, Pair<int, int>> &F : dc_lut[ky]) { VisualScript::DataConnection dc; - dc.from_node = dc_lut[ky][F].first; - dc.from_port = dc_lut[ky][F].second; + dc.from_node = F.value.first; + dc.from_port = F.value.second; dc.to_node = ky; - dc.to_port = F; + dc.to_port = F.key; dataconns.insert(dc); nd_queue.push_back(dc.from_node); node_ids.insert(dc.from_node); @@ -1934,15 +1907,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o //Multiple passes are required to set up this complex thing.. //First create the nodes. - for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) { - Ref<VisualScriptNode> node = script->nodes[F->get()].node; + for (const int &F : node_ids) { + Ref<VisualScriptNode> node = script->nodes[F].node; VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance. ERR_FAIL_COND(!instance); instance->base = node.ptr(); - instance->id = F->get(); + instance->id = F; instance->input_port_count = node->get_input_value_port_count(); instance->input_ports = nullptr; instance->output_port_count = node->get_output_value_port_count(); @@ -2002,14 +1975,14 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o max_input_args = MAX(max_input_args, instance->input_port_count); max_output_args = MAX(max_output_args, instance->output_port_count); - instances[F->get()] = instance; + instances[F] = instance; } function.trash_pos = function.max_stack++; // create pos for trash // Second pass, do data connections. - for (const Set<VisualScript::DataConnection>::Element *F = dataconns.front(); F; F = F->next()) { - VisualScript::DataConnection dc = F->get(); + for (const VisualScript::DataConnection &F : dataconns) { + VisualScript::DataConnection dc = F; ERR_CONTINUE(!instances.has(dc.from_node)); VisualScriptNodeInstance *from = instances[dc.from_node]; ERR_CONTINUE(!instances.has(dc.to_node)); @@ -2035,8 +2008,8 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o } // Third pass, do sequence connections. - for (const Set<VisualScript::SequenceConnection>::Element *F = seqconns.front(); F; F = F->next()) { - VisualScript::SequenceConnection sc = F->get(); + for (const VisualScript::SequenceConnection &F : seqconns) { + VisualScript::SequenceConnection sc = F; ERR_CONTINUE(!instances.has(sc.from_node)); VisualScriptNodeInstance *from = instances[sc.from_node]; ERR_CONTINUE(!instances.has(sc.to_node)); @@ -2049,11 +2022,11 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o //fourth pass: // 1) unassigned input ports to default values // 2) connect unassigned output ports to trash - for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) { - ERR_CONTINUE(!instances.has(F->get())); + for (const int &F : node_ids) { + ERR_CONTINUE(!instances.has(F)); - Ref<VisualScriptNode> node = script->nodes[F->get()].node; - VisualScriptNodeInstance *instance = instances[F->get()]; + Ref<VisualScriptNode> node = script->nodes[F].node; + VisualScriptNodeInstance *instance = instances[F]; // Connect to default values. for (int i = 0; i < instance->input_port_count; i++) { @@ -2072,7 +2045,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o } } - functions[E] = function; + functions[E.key] = function; } } } @@ -2250,7 +2223,7 @@ Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const return script; } -bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const { return false; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 6b27af15f6..0f3b8de3fc 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -36,6 +36,7 @@ #include "core/doc_data.h" #include "core/object/script_language.h" #include "core/os/thread.h" +#include "core/templates/rb_set.h" class VisualScriptInstance; class VisualScriptNodeInstance; @@ -214,8 +215,8 @@ private: HashMap<int, NodeData> nodes; // Can be a sparse map. - Set<SequenceConnection> sequence_connections; - Set<DataConnection> data_connections; + RBSet<SequenceConnection> sequence_connections; + RBSet<DataConnection> data_connections; Vector2 scroll; @@ -233,15 +234,15 @@ private: HashMap<StringName, Function> functions; HashMap<StringName, Variable> variables; - Map<StringName, Vector<Argument>> custom_signals; + HashMap<StringName, Vector<Argument>> custom_signals; Vector<Multiplayer::RPCConfig> rpc_functions; - Map<Object *, VisualScriptInstance *> instances; + HashMap<Object *, VisualScriptInstance *> instances; bool is_tool_script; #ifdef TOOLS_ENABLED - Set<PlaceHolderScriptInstance *> placeholders; + RBSet<PlaceHolderScriptInstance *> placeholders; // void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override; void _update_placeholders(); @@ -283,7 +284,7 @@ public: void sequence_disconnect(int p_from_node, int p_from_output, int p_to_node); bool has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const; void get_sequence_connection_list(List<SequenceConnection> *r_connection) const; - Set<int> get_output_sequence_ports_connected(int from_node); + RBSet<int> get_output_sequence_ports_connected(int from_node); void data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port); void data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port); @@ -317,7 +318,7 @@ public: void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx); void remove_custom_signal(const StringName &p_name); void rename_custom_signal(const StringName &p_name, const StringName &p_new_name); - Set<int> get_output_sequence_ports_connected(const String &edited_func, int from_node); + RBSet<int> get_output_sequence_ports_connected(const String &edited_func, int from_node); void get_custom_signal_list(List<StringName> *r_custom_signals) const; @@ -376,8 +377,8 @@ class VisualScriptInstance : public ScriptInstance { Object *owner = nullptr; Ref<VisualScript> script; - Map<StringName, Variant> variables; // Using variable path, not script. - Map<int, VisualScriptNodeInstance *> instances; + HashMap<StringName, Variant> variables; // Using variable path, not script. + HashMap<int, VisualScriptNodeInstance *> instances; struct Function { int node = 0; @@ -389,7 +390,7 @@ class VisualScriptInstance : public ScriptInstance { int argument_count = 0; }; - Map<StringName, Function> functions; + HashMap<StringName, Function> functions; Vector<Variant> default_values; int max_input_args = 0; @@ -415,22 +416,22 @@ public: String to_string(bool *r_valid); bool set_variable(const StringName &p_variable, const Variant &p_value) { - Map<StringName, Variant>::Element *E = variables.find(p_variable); + HashMap<StringName, Variant>::Iterator E = variables.find(p_variable); if (!E) { return false; } - E->get() = p_value; + E->value = p_value; return true; } bool get_variable(const StringName &p_variable, Variant *r_variable) const { - const Map<StringName, Variant>::Element *E = variables.find(p_variable); + HashMap<StringName, Variant>::ConstIterator E = variables.find(p_variable); if (!E) { return false; } - *r_variable = E->get(); + *r_variable = E->value; return true; } @@ -480,7 +481,7 @@ public: typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String &p_type); class VisualScriptLanguage : public ScriptLanguage { - Map<String, VisualScriptNodeRegisterFunc> register_funcs; + HashMap<String, VisualScriptNodeRegisterFunc> register_funcs; struct CallLevel { Variant *stack = nullptr; @@ -570,7 +571,7 @@ public: virtual void get_string_delimiters(List<String> *p_delimiters) const override; virtual bool is_using_templates() override; virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override; - virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override; virtual Script *create_script() const override; virtual bool has_named_classes() const override; virtual bool supports_builtin_mode() const override; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index dbbe74f3d5..ac33526ddc 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -3416,7 +3416,7 @@ VisualScriptConstructor::VisualScriptConstructor() { type = Variant::NIL; } -static Map<String, Pair<Variant::Type, MethodInfo>> constructor_map; +static HashMap<String, Pair<Variant::Type, MethodInfo>> constructor_map; static Ref<VisualScriptNode> create_constructor_node(const String &p_name) { ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>()); diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 5ff5b2339c..b645a48c88 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -350,7 +350,6 @@ void AudioStreamOGGVorbis::maybe_update_info() { vorbis_info_init(&info); vorbis_comment_init(&comment); - int packet_count = 0; Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instance_playback(); for (int i = 0; i < 3; i++) { @@ -369,8 +368,6 @@ void AudioStreamOGGVorbis::maybe_update_info() { err = vorbis_synthesis_headerin(&info, &comment, packet); ERR_FAIL_COND_MSG(err != 0, "Error parsing header packet " + itos(i) + ": " + itos(err)); - - packet_count++; } packet_sequence->set_sampling_rate(info.rate); diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index 03e145216a..7ee6446313 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -57,7 +57,7 @@ String ResourceImporterOGGVorbis::get_resource_type() const { return "AudioStreamOGGVorbis"; } -bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const { +bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; } @@ -74,7 +74,7 @@ void ResourceImporterOGGVorbis::get_import_options(const String &p_path, List<Im r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); } -Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { +Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 07291803a1..3b4a68a1fd 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -52,9 +52,9 @@ public: virtual int get_preset_count() const override; virtual String get_preset_name(int p_idx) const override; virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override; - virtual bool get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const override; + virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; - virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; + virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; ResourceImporterOGGVorbis(); }; diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h index eac8f85a84..75e29283ec 100644 --- a/modules/webrtc/webrtc_data_channel.h +++ b/modules/webrtc/webrtc_data_channel.h @@ -33,7 +33,7 @@ #include "core/io/packet_peer.h" -#define WRTC_IN_BUF "network/limits/webrtc/max_channel_in_buffer_kb" +#define WRTC_IN_BUF PNAME("network/limits/webrtc/max_channel_in_buffer_kb") class WebRTCDataChannel : public PacketPeer { GDCLASS(WebRTCDataChannel, PacketPeer); diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 0bc42b104c..6f68b84ad3 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -140,41 +140,41 @@ void WebRTCMultiplayerPeer::poll() { } void WebRTCMultiplayerPeer::_find_next_peer() { - Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer); + HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(next_packet_peer); if (E) { - E = E->next(); + ++E; } // After last. while (E) { - if (!E->get()->connected) { - E = E->next(); + if (!E->value->connected) { + ++E; continue; } - for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + for (const Ref<WebRTCDataChannel> &F : E->value->channels) { if (F->get_available_packet_count()) { - next_packet_peer = E->key(); + next_packet_peer = E->key; return; } } - E = E->next(); + ++E; } - E = peer_map.front(); + E = peer_map.begin(); // Before last while (E) { - if (!E->get()->connected) { - E = E->next(); + if (!E->value->connected) { + ++E; continue; } - for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + for (const Ref<WebRTCDataChannel> &F : E->value->channels) { if (F->get_available_packet_count()) { - next_packet_peer = E->key(); + next_packet_peer = E->key; return; } } - if (E->key() == (int)next_packet_peer) { + if (E->key == (int)next_packet_peer) { break; } - E = E->next(); + ++E; } // No packet found next_packet_peer = 0; @@ -354,12 +354,12 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si } if (target_peer > 0) { - Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(target_peer); + HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(target_peer); ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + "."); - ERR_FAIL_COND_V_MSG(E->value()->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); - ERR_FAIL_COND_V(E->value()->channels[ch].is_null(), ERR_BUG); - return E->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); + ERR_FAIL_COND_V_MSG(E->value->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value->channels.size())); + ERR_FAIL_COND_V(E->value->channels[ch].is_null(), ERR_BUG); + return E->value->channels[ch]->put_packet(p_buffer, p_buffer_size); } else { int exclude = -target_peer; diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 6675c67867..97550a3e9d 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -69,7 +69,7 @@ private: int next_packet_peer = 0; bool server_compat = false; - Map<int, Ref<ConnectedPeer>> peer_map; + HashMap<int, Ref<ConnectedPeer>> peer_map; List<Dictionary> channels_config; void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict); diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 43d9d59f38..db529a669d 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -62,7 +62,7 @@ protected: }; List<Packet> _incoming_packets; - Map<int, Ref<WebSocketPeer>> _peer_map; + HashMap<int, Ref<WebSocketPeer>> _peer_map; Packet _current_packet; bool _is_multiplayer = false; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 894ba7766f..478dbb9d47 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -113,7 +113,7 @@ bool WSLClient::_verify_headers(String &r_protocol) { ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'."); ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'."); - Map<String, String> headers; + HashMap<String, String> headers; for (int i = 1; i < len; i++) { Vector<String> header = psa[i].split(":", false, 1); ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i] + "."); diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index b58b2e4724..517b9643f8 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -46,7 +46,7 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St ERR_FAIL_COND_V_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", false, "Invalid method or HTTP version."); r_resource_name = req[1]; - Map<String, String> headers; + HashMap<String, String> headers; for (int i = 1; i < len; i++) { Vector<String> header = psa[i].split(":", false, 1); ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i]); |