diff options
Diffstat (limited to 'modules')
165 files changed, 4461 insertions, 3717 deletions
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 1fd656c9b4..399b102284 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -52,7 +52,7 @@ bool GodotFilterCallback::needBroadphaseCollision(btBroadphaseProxy *proxy0, btB } bool GodotClosestRayResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); @@ -85,7 +85,7 @@ bool GodotAllConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) con return false; } - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); if (m_exclude->has(gObj->get_self())) { @@ -117,7 +117,7 @@ btScalar GodotAllConvexResultCallback::addSingleResult(btCollisionWorld::LocalCo } bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); if (gObj == m_self_object) { @@ -143,7 +143,7 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox } bool GodotClosestConvexResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); @@ -180,7 +180,7 @@ bool GodotAllContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) co return false; } - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); @@ -235,7 +235,7 @@ bool GodotContactPairContactResultCallback::needsCollision(btBroadphaseProxy *pr return false; } - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); @@ -277,7 +277,7 @@ btScalar GodotContactPairContactResultCallback::addSingleResult(btManifoldPoint } bool GodotRestInfoContactResultCallback::needsCollision(btBroadphaseProxy *proxy0) const { - if (m_collisionFilterGroup & proxy0->m_collisionFilterMask) { + if (proxy0->m_collisionFilterGroup & m_collisionFilterMask) { btCollisionObject *btObj = static_cast<btCollisionObject *>(proxy0->m_clientObject); CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(btObj->getUserPointer()); diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 8c286a8629..583900e6bc 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -1133,7 +1133,7 @@ public: virtual bool process(const btBroadphaseProxy *proxy) { btCollisionObject *co = static_cast<btCollisionObject *>(proxy->m_clientObject); if (co->getInternalType() <= btCollisionObject::CO_RIGID_BODY) { - if (self_collision_object != proxy->m_clientObject && (collision_layer & proxy->m_collisionFilterMask)) { + if (self_collision_object != proxy->m_clientObject && (proxy->collision_layer & m_collisionFilterMask)) { if (co->getCollisionShape()->isCompound()) { const btCompoundShape *cs = static_cast<btCompoundShape *>(co->getCollisionShape()); diff --git a/modules/camera/camera_osx.h b/modules/camera/camera_osx.h index 964b7c1edc..84274f0bf6 100644 --- a/modules/camera/camera_osx.h +++ b/modules/camera/camera_osx.h @@ -32,7 +32,7 @@ #define CAMERAOSX_H ///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!! -// If you fix something here, make sure you fix it there as wel! +// If you fix something here, make sure you fix it there as well! #include "servers/camera_server.h" diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 6bc56add20..4875eb578a 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -29,7 +29,7 @@ /*************************************************************************/ ///@TODO this is a near duplicate of CameraIOS, we should find a way to combine those to minimize code duplication!!!! -// If you fix something here, make sure you fix it there as wel! +// If you fix something here, make sure you fix it there as well! #include "camera_osx.h" #include "servers/camera/camera_feed.h" diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 57206ae18b..cb82b65307 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -530,8 +530,8 @@ void CSGBrushOperation::MeshMerge::_add_distance(List<real_t> &r_intersectionsA, List<real_t> &intersections = p_from_B ? r_intersectionsB : r_intersectionsA; // Check if distance exists. - for (const List<real_t>::Element *E = intersections.front(); E; E = E->next()) { - if (Math::is_equal_approx(**E, p_distance)) { + for (const real_t E : intersections) { + if (Math::is_equal_approx(E, p_distance)) { return; } } diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 37a7d96de5..42f8b9f163 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "csg_gizmos.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/camera_3d.h" /////////// @@ -48,7 +50,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { create_handle_material("handles"); } -String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { +String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -60,17 +62,17 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, } if (Object::cast_to<CSGCylinder3D>(cs)) { - return p_idx == 0 ? "Radius" : "Height"; + return p_id == 0 ? "Radius" : "Height"; } if (Object::cast_to<CSGTorus3D>(cs)) { - return p_idx == 0 ? "InnerRadius" : "OuterRadius"; + return p_id == 0 ? "InnerRadius" : "OuterRadius"; } return ""; } -Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { +Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -85,18 +87,18 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int if (Object::cast_to<CSGCylinder3D>(cs)) { CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); - return p_idx == 0 ? s->get_radius() : s->get_height(); + return p_id == 0 ? s->get_radius() : s->get_height(); } if (Object::cast_to<CSGTorus3D>(cs)) { CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs); - return p_idx == 0 ? s->get_inner_radius() : s->get_outer_radius(); + return p_id == 0 ? s->get_inner_radius() : s->get_outer_radius(); } return Variant(); } -void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { +void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Transform3D gt = cs->get_global_transform(); @@ -129,10 +131,16 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca CSGBox3D *s = Object::cast_to<CSGBox3D>(cs); Vector3 axis; - axis[p_idx] = 1.0; + axis[p_id] = 1.0; Vector3 ra, rb; Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; + float d = ra[p_id]; + + if (Math::is_nan(d)) { + // The handle is perpendicular to the camera. + return; + } + if (Node3DEditor::get_singleton()->is_snap_enabled()) { d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); } @@ -142,7 +150,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca } Vector3 h = s->get_size(); - h[p_idx] = d * 2; + h[p_id] = d * 2; s->set_size(h); } @@ -150,7 +158,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); Vector3 axis; - axis[p_idx == 0 ? 0 : 1] = 1.0; + axis[p_id == 0 ? 0 : 1] = 1.0; Vector3 ra, rb; Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); float d = axis.dot(ra); @@ -162,9 +170,9 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca d = 0.001; } - if (p_idx == 0) { + if (p_id == 0) { s->set_radius(d); - } else if (p_idx == 1) { + } else if (p_id == 1) { s->set_height(d * 2.0); } } @@ -185,15 +193,15 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca d = 0.001; } - if (p_idx == 0) { + if (p_id == 0) { s->set_inner_radius(d); - } else if (p_idx == 1) { + } else if (p_id == 1) { s->set_outer_radius(d); } } } -void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { +void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { @@ -227,7 +235,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, if (Object::cast_to<CSGCylinder3D>(cs)) { CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); if (p_cancel) { - if (p_idx == 0) { + if (p_id == 0) { s->set_radius(p_restore); } else { s->set_height(p_restore); @@ -236,7 +244,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, } UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); - if (p_idx == 0) { + if (p_id == 0) { ur->create_action(TTR("Change Cylinder Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); ur->add_undo_method(s, "set_radius", p_restore); @@ -252,7 +260,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, if (Object::cast_to<CSGTorus3D>(cs)) { CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs); if (p_cancel) { - if (p_idx == 0) { + if (p_id == 0) { s->set_inner_radius(p_restore); } else { s->set_outer_radius(p_restore); @@ -261,7 +269,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, } UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); - if (p_idx == 0) { + if (p_id == 0) { ur->create_action(TTR("Change Torus Inner Radius")); ur->add_do_method(s, "set_inner_radius", s->get_inner_radius()); ur->add_undo_method(s, "set_inner_radius", p_restore); @@ -356,7 +364,7 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { break; } - p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), solid_material); + p_gizmo->add_mesh(mesh, solid_material); } if (Object::cast_to<CSGSphere3D>(cs)) { diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 8f7da35de3..847313c0b4 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -33,22 +33,22 @@ #include "csg_shape.h" #include "editor/editor_plugin.h" -#include "editor/node_3d_editor_gizmos.h" +#include "editor/plugins/node_3d_editor_gizmos.h" class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin); public: - bool has_gizmo(Node3D *p_spatial) override; - String get_gizmo_name() const override; - int get_priority() const override; - bool is_selectable_when_hidden() const override; - void redraw(EditorNode3DGizmo *p_gizmo) override; - - String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override; - Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const override; - void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override; - void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) override; + virtual bool has_gizmo(Node3D *p_spatial) override; + virtual String get_gizmo_name() const override; + virtual int get_priority() const override; + virtual bool is_selectable_when_hidden() const override; + virtual void redraw(EditorNode3DGizmo *p_gizmo) override; + + virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; + virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; + virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; + virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const override; CSGShape3DGizmoPlugin(); }; diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 729dc2f8fc..b47fa35f1a 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -548,7 +548,7 @@ void CSGShape3D::_notification(int p_what) { void CSGShape3D::set_operation(Operation p_operation) { operation = p_operation; _make_dirty(); - update_gizmo(); + update_gizmos(); } CSGShape3D::Operation CSGShape3D::get_operation() const { @@ -845,7 +845,7 @@ CSGBrush *CSGMesh3D::_build_brush() { void CSGMesh3D::_mesh_changed() { _make_dirty(); - update_gizmo(); + update_gizmos(); } void CSGMesh3D::set_material(const Ref<Material> &p_material) { @@ -923,36 +923,40 @@ CSGBrush *CSGSphere3D::_build_brush() { Ref<Material> *materialsw = materials.ptrw(); bool *invertw = invert.ptrw(); - const double lat_step = 1.0 / rings; - const double lon_step = 1.0 / radial_segments; + // We want to follow an order that's convenient for UVs. + // For latitude step we start at the top and move down like in an image. + const double latitude_step = -Math_PI / rings; + const double longitude_step = Math_TAU / radial_segments; int face = 0; - for (int i = 1; i <= rings; i++) { - double lat0 = Math_PI * (0.5 - (i - 1) * lat_step); - double c0 = Math::cos(lat0); - double s0 = Math::sin(lat0); - double v0 = double(i - 1) / rings; - - double lat1 = Math_PI * (0.5 - i * lat_step); - double c1 = Math::cos(lat1); - double s1 = Math::sin(lat1); - double v1 = double(i) / rings; - - for (int j = 1; j <= radial_segments; j++) { - double lng0 = Math_TAU * (0.5 - (j - 1) * lon_step); - double x0 = Math::cos(lng0); - double y0 = Math::sin(lng0); - double u0 = double(j - 1) / radial_segments; - - double lng1 = Math_TAU * (0.5 - j * lon_step); - double x1 = Math::cos(lng1); - double y1 = Math::sin(lng1); - double u1 = double(j) / radial_segments; + for (int i = 0; i < rings; i++) { + double latitude0 = latitude_step * i + Math_TAU / 4; + double cos0 = Math::cos(latitude0); + double sin0 = Math::sin(latitude0); + double v0 = double(i) / rings; + + double latitude1 = latitude_step * (i + 1) + Math_TAU / 4; + double cos1 = Math::cos(latitude1); + double sin1 = Math::sin(latitude1); + double v1 = double(i + 1) / rings; + + for (int j = 0; j < radial_segments; j++) { + double longitude0 = longitude_step * j; + // We give sin to X and cos to Z on purpose. + // This allows UVs to be CCW on +X so it maps to images well. + double x0 = Math::sin(longitude0); + double z0 = Math::cos(longitude0); + double u0 = double(j) / radial_segments; + + double longitude1 = longitude_step * (j + 1); + double x1 = Math::sin(longitude1); + double z1 = Math::cos(longitude1); + double u1 = double(j + 1) / radial_segments; Vector3 v[4] = { - Vector3(x0 * c0, s0, y0 * c0) * radius, - Vector3(x1 * c0, s0, y1 * c0) * radius, - Vector3(x1 * c1, s1, y1 * c1) * radius, - Vector3(x0 * c1, s1, y0 * c1) * radius, + Vector3(x0 * cos0, sin0, z0 * cos0) * radius, + Vector3(x1 * cos0, sin0, z1 * cos0) * radius, + Vector3(x1 * cos1, sin1, z1 * cos1) * radius, + Vector3(x0 * cos1, sin1, z0 * cos1) * radius, }; Vector2 u[4] = { @@ -962,8 +966,8 @@ CSGBrush *CSGSphere3D::_build_brush() { Vector2(u0, v1), }; - if (i < rings) { - //face 1 + // Draw the first face, but skip this at the north pole (i == 0). + if (i > 0) { facesw[face * 3 + 0] = v[0]; facesw[face * 3 + 1] = v[1]; facesw[face * 3 + 2] = v[2]; @@ -979,8 +983,8 @@ CSGBrush *CSGSphere3D::_build_brush() { face++; } - if (i > 1) { - //face 2 + // Draw the second face, but skip this at the south pole (i == rings - 1). + if (i < rings - 1) { facesw[face * 3 + 0] = v[2]; facesw[face * 3 + 1] = v[3]; facesw[face * 3 + 2] = v[0]; @@ -1034,7 +1038,7 @@ void CSGSphere3D::set_radius(const float p_radius) { ERR_FAIL_COND(p_radius <= 0); radius = p_radius; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGSphere3D::get_radius() const { @@ -1044,7 +1048,7 @@ float CSGSphere3D::get_radius() const { void CSGSphere3D::set_radial_segments(const int p_radial_segments) { radial_segments = p_radial_segments > 4 ? p_radial_segments : 4; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGSphere3D::get_radial_segments() const { @@ -1054,7 +1058,7 @@ int CSGSphere3D::get_radial_segments() const { void CSGSphere3D::set_rings(const int p_rings) { rings = p_rings > 1 ? p_rings : 1; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGSphere3D::get_rings() const { @@ -1203,7 +1207,7 @@ void CSGBox3D::_bind_methods() { void CSGBox3D::set_size(const Vector3 &p_size) { size = p_size; _make_dirty(); - update_gizmo(); + update_gizmos(); } Vector3 CSGBox3D::get_size() const { @@ -1213,7 +1217,7 @@ Vector3 CSGBox3D::get_size() const { void CSGBox3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); - update_gizmo(); + update_gizmos(); } Ref<Material> CSGBox3D::get_material() const { @@ -1384,7 +1388,7 @@ void CSGCylinder3D::_bind_methods() { void CSGCylinder3D::set_radius(const float p_radius) { radius = p_radius; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGCylinder3D::get_radius() const { @@ -1394,7 +1398,7 @@ float CSGCylinder3D::get_radius() const { void CSGCylinder3D::set_height(const float p_height) { height = p_height; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGCylinder3D::get_height() const { @@ -1405,7 +1409,7 @@ void CSGCylinder3D::set_sides(const int p_sides) { ERR_FAIL_COND(p_sides < 3); sides = p_sides; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGCylinder3D::get_sides() const { @@ -1415,7 +1419,7 @@ int CSGCylinder3D::get_sides() const { void CSGCylinder3D::set_cone(const bool p_cone) { cone = p_cone; _make_dirty(); - update_gizmo(); + update_gizmos(); } bool CSGCylinder3D::is_cone() const { @@ -1603,7 +1607,7 @@ void CSGTorus3D::_bind_methods() { void CSGTorus3D::set_inner_radius(const float p_inner_radius) { inner_radius = p_inner_radius; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGTorus3D::get_inner_radius() const { @@ -1613,7 +1617,7 @@ float CSGTorus3D::get_inner_radius() const { void CSGTorus3D::set_outer_radius(const float p_outer_radius) { outer_radius = p_outer_radius; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGTorus3D::get_outer_radius() const { @@ -1624,7 +1628,7 @@ void CSGTorus3D::set_sides(const int p_sides) { ERR_FAIL_COND(p_sides < 3); sides = p_sides; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGTorus3D::get_sides() const { @@ -1635,7 +1639,7 @@ void CSGTorus3D::set_ring_sides(const int p_ring_sides) { ERR_FAIL_COND(p_ring_sides < 3); ring_sides = p_ring_sides; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGTorus3D::get_ring_sides() const { @@ -2172,7 +2176,7 @@ void CSGPolygon3D::_validate_property(PropertyInfo &property) const { void CSGPolygon3D::_path_changed() { _make_dirty(); - update_gizmo(); + update_gizmos(); } void CSGPolygon3D::_path_exited() { @@ -2248,7 +2252,7 @@ void CSGPolygon3D::_bind_methods() { void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) { polygon = p_polygon; _make_dirty(); - update_gizmo(); + update_gizmos(); } Vector<Vector2> CSGPolygon3D::get_polygon() const { @@ -2258,7 +2262,7 @@ Vector<Vector2> CSGPolygon3D::get_polygon() const { void CSGPolygon3D::set_mode(Mode p_mode) { mode = p_mode; _make_dirty(); - update_gizmo(); + update_gizmos(); notify_property_list_changed(); } @@ -2270,7 +2274,7 @@ void CSGPolygon3D::set_depth(const float p_depth) { ERR_FAIL_COND(p_depth < 0.001); depth = p_depth; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGPolygon3D::get_depth() const { @@ -2290,7 +2294,7 @@ void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) { ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360); spin_degrees = p_spin_degrees; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGPolygon3D::get_spin_degrees() const { @@ -2301,7 +2305,7 @@ void CSGPolygon3D::set_spin_sides(const int p_spin_sides) { ERR_FAIL_COND(p_spin_sides < 3); spin_sides = p_spin_sides; _make_dirty(); - update_gizmo(); + update_gizmos(); } int CSGPolygon3D::get_spin_sides() const { @@ -2311,7 +2315,7 @@ int CSGPolygon3D::get_spin_sides() const { void CSGPolygon3D::set_path_node(const NodePath &p_path) { path_node = p_path; _make_dirty(); - update_gizmo(); + update_gizmos(); } NodePath CSGPolygon3D::get_path_node() const { @@ -2322,7 +2326,7 @@ void CSGPolygon3D::set_path_interval(float p_interval) { ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001."); path_interval = p_interval; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGPolygon3D::get_path_interval() const { @@ -2332,7 +2336,7 @@ float CSGPolygon3D::get_path_interval() const { void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) { path_rotation = p_rotation; _make_dirty(); - update_gizmo(); + update_gizmos(); } CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const { @@ -2342,7 +2346,7 @@ CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const { void CSGPolygon3D::set_path_local(bool p_enable) { path_local = p_enable; _make_dirty(); - update_gizmo(); + update_gizmos(); } bool CSGPolygon3D::is_path_local() const { @@ -2352,7 +2356,7 @@ bool CSGPolygon3D::is_path_local() const { void CSGPolygon3D::set_path_joined(bool p_enable) { path_joined = p_enable; _make_dirty(); - update_gizmo(); + update_gizmos(); } bool CSGPolygon3D::is_path_joined() const { diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index 01ec46e707..f42ce8c379 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -10,55 +10,43 @@ </tutorials> <methods> <method name="get_collision_layer_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="bit" type="int" /> <description> Returns an individual bit on the collision mask. </description> </method> <method name="get_collision_mask_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="bit" type="int" /> <description> Returns an individual bit on the collision mask. </description> </method> <method name="get_meshes" qualifiers="const"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an [Array] with two elements, the first is the [Transform3D] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape. </description> </method> <method name="is_root_shape" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this is a root shape and is thus the object that is rendered. </description> </method> <method name="set_collision_layer_bit"> - <return type="void"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="bit" type="int" /> + <argument index="1" name="value" type="bool" /> <description> Sets individual bits on the layer mask. Use this if you only need to change one layer's value. </description> </method> <method name="set_collision_mask_bit"> - <return type="void"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="bit" type="int" /> + <argument index="1" name="value" type="bool" /> <description> Sets individual bits on the collision mask. Use this if you only need to change one layer's value. </description> diff --git a/modules/enet/config.py b/modules/enet/config.py index 3662b2d94e..9102c74579 100644 --- a/modules/enet/config.py +++ b/modules/enet/config.py @@ -9,6 +9,8 @@ def configure(env): def get_doc_classes(): return [ "ENetMultiplayerPeer", + "ENetConnection", + "ENetPacketPeer", ] diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml new file mode 100644 index 0000000000..c2a85ffdf8 --- /dev/null +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ENetConnection" inherits="RefCounted" version="4.0"> + <brief_description> + A wrapper class for an [url=http://enet.bespin.org/group__host.html]ENetHost[/url]. + </brief_description> + <description> + ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol). + </description> + <tutorials> + <link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link> + </tutorials> + <methods> + <method name="bandwidth_limit"> + <return type="void" /> + <argument index="0" name="in_bandwidth" type="int" default="0" /> + <argument index="1" name="out_bandwidth" type="int" default="0" /> + <description> + Adjusts the bandwidth limits of a host. + </description> + </method> + <method name="broadcast"> + <return type="void" /> + <argument index="0" name="channel" type="int" /> + <argument index="1" name="packet" type="PackedByteArray" /> + <argument index="2" name="flags" type="int" /> + <description> + Queues a [code]packet[/code] to be sent to all peers associated with the host over the specified [code]channel[/code]. See [ENetPacketPeer] [code]FLAG_*[/code] constants for available packet flags. + </description> + </method> + <method name="channel_limit"> + <return type="void" /> + <argument index="0" name="limit" type="int" /> + <description> + Limits the maximum allowed channels of future incoming connections. + </description> + </method> + <method name="compress"> + <return type="void" /> + <argument index="0" name="mode" type="int" enum="ENetConnection.CompressionMode" /> + <description> + Sets the compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. + [b]Note:[/b] Most games' network design involve sending many small packets frequently (smaller than 4 KB each). If in doubt, it is recommended to keep the default compression algorithm as it works best on these small packets. + </description> + </method> + <method name="connect_to_host"> + <return type="ENetPacketPeer" /> + <argument index="0" name="address" type="String" /> + <argument index="1" name="port" type="int" /> + <argument index="2" name="channels" type="int" default="0" /> + <argument index="3" name="data" type="int" default="0" /> + <description> + Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocting the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer. + Note: You must call either [method create_host] or [method create_host_bound] before calling this method. + </description> + </method> + <method name="create_host"> + <return type="int" enum="Error" /> + <argument index="0" name="max_peers" type="int" default="32" /> + <argument index="1" name="max_channels" type="int" default="0" /> + <argument index="2" name="in_bandwidth" type="int" default="0" /> + <argument index="3" name="out_bandwidth" type="int" default="0" /> + <description> + Create an ENetHost that will allow up to [code]max_peers[/code] connected peers, each allocating up to [code]max_channels[/code] channels, optionally limiting bandwith to [code]in_bandwidth[/code] and [code]out_bandwidth[/code]. + </description> + </method> + <method name="create_host_bound"> + <return type="int" enum="Error" /> + <argument index="0" name="bind_address" type="String" /> + <argument index="1" name="bind_port" type="int" /> + <argument index="2" name="max_peers" type="int" default="32" /> + <argument index="3" name="max_channels" type="int" default="0" /> + <argument index="4" name="in_bandwidth" type="int" default="0" /> + <argument index="5" name="out_bandwidth" type="int" default="0" /> + <description> + Create an ENetHost like [method create_host] which is also bound to the given [code]bind_address[/code] and [code]bind_port[/code]. + </description> + </method> + <method name="destroy"> + <return type="void" /> + <description> + Destroys the host and all resources associated with it. + </description> + </method> + <method name="dtls_client_setup"> + <return type="int" enum="Error" /> + <argument index="0" name="certificate" type="X509Certificate" /> + <argument index="1" name="hostname" type="String" /> + <argument index="2" name="verify" type="bool" default="true" /> + <description> + Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet clients. Call this before [method connect_to_host] to have ENet connect using DTLS with [code]certificate[/code] and [code]hostname[/code] verification. Verification can be optionally turned off via the [code]verify[/code] parameter. + </description> + </method> + <method name="dtls_server_setup"> + <return type="int" enum="Error" /> + <argument index="0" name="key" type="CryptoKey" /> + <argument index="1" name="certificate" type="X509Certificate" /> + <description> + Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet servers. Call this right after [method create_host_bound] to have ENet expect peers to connect using DTLS. + </description> + </method> + <method name="flush"> + <return type="void" /> + <description> + Sends any queued packets on the host specified to its designated peers. + </description> + </method> + <method name="get_local_port" qualifiers="const"> + <return type="int" /> + <description> + Returns the local port to which this peer is bound. + </description> + </method> + <method name="get_max_channels" qualifiers="const"> + <return type="int" /> + <description> + Returns the maximum number of channels allowed for connected peers. + </description> + </method> + <method name="get_peers"> + <return type="Array" /> + <description> + Returns the list of peers associated with this host. + Note: This list might include some peers that are not fully connected or are still being disconnected. + </description> + </method> + <method name="pop_statistic"> + <return type="float" /> + <argument index="0" name="statistic" type="int" enum="ENetConnection.HostStatistic" /> + <description> + Returns and resets host statistics. See [enum HostStatistic] for more info. + </description> + </method> + <method name="refuse_new_connections"> + <return type="void" /> + <argument index="0" name="refuse" type="bool" /> + <description> + Configures the DTLS server to automatically drop new connections. + Note: This method is only relevant after calling [method dtls_server_setup]. + </description> + </method> + <method name="service"> + <return type="Array" /> + <argument index="0" name="timeout" type="int" default="0" /> + <description> + Waits for events on the host specified and shuttles packets between the host and its peers. The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer]. + Call this function regularly to handle connections, disconnections, and to receive new packets. + </description> + </method> + </methods> + <constants> + <constant name="COMPRESS_NONE" value="0" enum="CompressionMode"> + No compression. This uses the most bandwidth, but has the upside of requiring the fewest CPU resources. This option may also be used to make network debugging using tools like Wireshark easier. + </constant> + <constant name="COMPRESS_RANGE_CODER" value="1" enum="CompressionMode"> + ENet's built-in range encoding. Works well on small packets, but is not the most efficient algorithm on packets larger than 4 KB. + </constant> + <constant name="COMPRESS_FASTLZ" value="2" enum="CompressionMode"> + [url=http://fastlz.org/]FastLZ[/url] compression. This option uses less CPU resources compared to [constant COMPRESS_ZLIB], at the expense of using more bandwidth. + </constant> + <constant name="COMPRESS_ZLIB" value="3" enum="CompressionMode"> + [url=https://www.zlib.net/]Zlib[/url] compression. This option uses less bandwidth compared to [constant COMPRESS_FASTLZ], at the expense of using more CPU resources. + </constant> + <constant name="COMPRESS_ZSTD" value="4" enum="CompressionMode"> + [url=https://facebook.github.io/zstd/]Zstandard[/url] compression. Note that this algorithm is not very efficient on packets smaller than 4 KB. Therefore, it's recommended to use other compression algorithms in most cases. + </constant> + <constant name="EVENT_ERROR" value="-1" enum="EventType"> + An error occurred during [method service]. You will likely need to [method destroy] the host and recreate it. + </constant> + <constant name="EVENT_NONE" value="0" enum="EventType"> + No event occurred within the specified time limit. + </constant> + <constant name="EVENT_CONNECT" value="1" enum="EventType"> + A connection request initiated by enet_host_connect has completed. The array will contain the peer which successfully connected. + </constant> + <constant name="EVENT_DISCONNECT" value="2" enum="EventType"> + A peer has disconnected. This event is generated on a successful completion of a disconnect initiated by [method ENetPacketPeer.peer_disconnect], if a peer has timed out, or if a connection request intialized by [method connect_to_host] has timed out. The array will contain the peer which disconnected. The data field contains user supplied data describing the disconnection, or 0, if none is available. + </constant> + <constant name="EVENT_RECEIVE" value="3" enum="EventType"> + A packet has been received from a peer. The array will contain the peer which sent the packet, the channel number upon which the packet was received, and the received packet. + </constant> + <constant name="HOST_TOTAL_SENT_DATA" value="0" enum="HostStatistic"> + Total data sent. + </constant> + <constant name="HOST_TOTAL_SENT_PACKETS" value="1" enum="HostStatistic"> + Total UDP packets sent. + </constant> + <constant name="HOST_TOTAL_RECEIVED_DATA" value="2" enum="HostStatistic"> + Total data received. + </constant> + <constant name="HOST_TOTAL_RECEIVED_PACKETS" value="3" enum="HostStatistic"> + Total UDP packets received. + </constant> + </constants> +</class> diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index 30dec5987b..3a37b396a4 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -1,11 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> - PacketPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library. + A MultiplayerPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library. </brief_description> <description> - A PacketPeer implementation that should be passed to [member MultiplayerAPI.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. - ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol). + A MultiplayerPeer implementation that should be passed to [member MultiplayerAPI.network_peer] after being initialized as either a client, server, or mesh. Events can then be handled by connecting to [MultiplayerAPI] signals. See [ENetConnection] for more information on the ENet library wrapper. [b]Note:[/b] ENet only uses UDP, not TCP. When forwarding the server port to make your server accessible on the public Internet, you only need to forward the server port in UDP. You can use the [UPNP] class to try to forward the server port automatically when starting the server. </description> <tutorials> @@ -13,183 +12,77 @@ <link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link> </tutorials> <methods> - <method name="close_connection"> - <return type="void"> - </return> - <argument index="0" name="wait_usec" type="int" default="100"> - </argument> + <method name="add_mesh_peer"> + <return type="int" enum="Error" /> + <argument index="0" name="peer_id" type="int" /> + <argument index="1" name="host" type="ENetConnection" /> <description> - Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server. + Add a new remote peer with the given [code]peer_id[/code] connected to the given [code]host[/code]. + Note: The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state. </description> </method> - <method name="create_client"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="address" type="String"> - </argument> - <argument index="1" name="port" type="int"> - </argument> - <argument index="2" name="in_bandwidth" type="int" default="0"> - </argument> - <argument index="3" name="out_bandwidth" type="int" default="0"> - </argument> - <argument index="4" name="local_port" type="int" default="0"> - </argument> - <description> - Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. - </description> - </method> - <method name="create_server"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="max_clients" type="int" default="32"> - </argument> - <argument index="2" name="in_bandwidth" type="int" default="0"> - </argument> - <argument index="3" name="out_bandwidth" type="int" default="0"> - </argument> - <description> - Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. - </description> - </method> - <method name="disconnect_peer"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="now" type="bool" default="false"> - </argument> - <description> - Disconnect the given peer. If "now" is set to [code]true[/code], the connection will be closed immediately without flushing queued messages. - </description> - </method> - <method name="get_last_packet_channel" qualifiers="const"> - <return type="int"> - </return> + <method name="close_connection"> + <return type="void" /> + <argument index="0" name="wait_usec" type="int" default="100" /> <description> - Returns the channel of the last packet fetched via [method PacketPeer.get_packet]. + Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server. </description> </method> - <method name="get_local_port" qualifiers="const"> - <return type="int"> - </return> + <method name="create_client"> + <return type="int" enum="Error" /> + <argument index="0" name="address" type="String" /> + <argument index="1" name="port" type="int" /> + <argument index="2" name="channel_count" type="int" default="0" /> + <argument index="3" name="in_bandwidth" type="int" default="0" /> + <argument index="4" name="out_bandwidth" type="int" default="0" /> + <argument index="5" name="local_port" type="int" default="0" /> <description> - Returns the local port to which this peer is bound. + Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. </description> </method> - <method name="get_packet_channel" qualifiers="const"> - <return type="int"> - </return> + <method name="create_mesh"> + <return type="int" enum="Error" /> + <argument index="0" name="unique_id" type="int" /> <description> - Returns the channel of the next packet that will be retrieved via [method PacketPeer.get_packet]. + Initialize this [MultiplayerPeer] in mesh mode. The provided [code]unique_id[/code] will be used as the local peer network unique ID once assigned as the [member MultiplayerAPI.network_peer]. In the mesh configuration you will need to set up each new peer manually using [ENetConnection] before calling [method add_mesh_peer]. While this technique is more advanced, it allows for better control over the connection process (e.g. when dealing with NAT punch-through) and for better distribution of the network load (which would otherwise be more taxing on the server). </description> </method> - <method name="get_peer_address" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <method name="create_server"> + <return type="int" enum="Error" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="max_clients" type="int" default="32" /> + <argument index="2" name="max_channels" type="int" default="0" /> + <argument index="3" name="in_bandwidth" type="int" default="0" /> + <argument index="4" name="out_bandwidth" type="int" default="0" /> <description> - Returns the IP address of the given peer. + Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. </description> </method> - <method name="get_peer_port" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <method name="get_peer" qualifiers="const"> + <return type="ENetPacketPeer" /> + <argument index="0" name="id" type="int" /> <description> - Returns the remote port of the given peer. + Return the [ENetPacketPeer] associated to the given [code]id[/code]. </description> </method> <method name="set_bind_ip"> - <return type="void"> - </return> - <argument index="0" name="ip" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="ip" type="String" /> <description> The IP used when creating a server. This is set to the wildcard [code]"*"[/code] by default, which binds to all available interfaces. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]"192.168.1.1"[/code]. </description> </method> - <method name="set_dtls_certificate"> - <return type="void"> - </return> - <argument index="0" name="certificate" type="X509Certificate"> - </argument> - <description> - Configure the [X509Certificate] to use when [member use_dtls] is [code]true[/code]. For servers, you must also setup the [CryptoKey] via [method set_dtls_key]. - </description> - </method> - <method name="set_dtls_key"> - <return type="void"> - </return> - <argument index="0" name="key" type="CryptoKey"> - </argument> - <description> - Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate]. - </description> - </method> - <method name="set_peer_timeout"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="timeout_limit" type="int"> - </argument> - <argument index="2" name="timeout_min" type="int"> - </argument> - <argument index="3" name="timeout_max" type="int"> - </argument> - <description> - Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds. - The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped. - </description> - </method> </methods> <members> - <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false"> - Enforce ordered packets when using [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. - </member> - <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3"> - The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per-channel basis. This is done to combat latency and reduces ordering restrictions on packets. The delivery status of a packet in one channel won't stall the delivery of other packets in another channel. - </member> - <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="ENetMultiplayerPeer.CompressionMode" default="1"> - The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. - [b]Note:[/b] Most games' network design involve sending many small packets frequently (smaller than 4 KB each). If in doubt, it is recommended to keep the default compression algorithm as it works best on these small packets. - </member> - <member name="dtls_verify" type="bool" setter="set_dtls_verify_enabled" getter="is_dtls_verify_enabled" default="true"> - Enable or disable certificate verification when [member use_dtls] [code]true[/code]. + <member name="host" type="ENetConnection" setter="" getter="get_host"> + The underlying [ENetConnection] created after [method create_client] and [method create_server]. </member> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true"> Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server. </member> - <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1"> - Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels: one for reliable packets, and one for unreliable packets. The channel [code]0[/code] is reserved and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. See [member channel_count] for more information about ENet channels. - </member> <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> - <member name="use_dtls" type="bool" setter="set_dtls_enabled" getter="is_dtls_enabled" default="false"> - When enabled, the client or server created by this peer, will use [PacketPeerDTLS] instead of raw UDP sockets for communicating with the remote peer. This will make the communication encrypted with DTLS at the cost of higher resource usage and potentially larger packet size. - Note: When creating a DTLS server, make sure you setup the key/certificate pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS clients, have a look at the [member dtls_verify] option, and configure the certificate accordingly via [method set_dtls_certificate]. - </member> </members> <constants> - <constant name="COMPRESS_NONE" value="0" enum="CompressionMode"> - No compression. This uses the most bandwidth, but has the upside of requiring the fewest CPU resources. This option may also be used to make network debugging using tools like Wireshark easier. - </constant> - <constant name="COMPRESS_RANGE_CODER" value="1" enum="CompressionMode"> - ENet's built-in range encoding. Works well on small packets, but is not the most efficient algorithm on packets larger than 4 KB. - </constant> - <constant name="COMPRESS_FASTLZ" value="2" enum="CompressionMode"> - [url=http://fastlz.org/]FastLZ[/url] compression. This option uses less CPU resources compared to [constant COMPRESS_ZLIB], at the expense of using more bandwidth. - </constant> - <constant name="COMPRESS_ZLIB" value="3" enum="CompressionMode"> - [url=https://www.zlib.net/]Zlib[/url] compression. This option uses less bandwidth compared to [constant COMPRESS_FASTLZ], at the expense of using more CPU resources. - </constant> - <constant name="COMPRESS_ZSTD" value="4" enum="CompressionMode"> - [url=https://facebook.github.io/zstd/]Zstandard[/url] compression. Note that this algorithm is not very efficient on packets smaller than 4 KB. Therefore, it's recommended to use other compression algorithms in most cases. - </constant> </constants> </class> diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml new file mode 100644 index 0000000000..8f0693fb01 --- /dev/null +++ b/modules/enet/doc_classes/ENetPacketPeer.xml @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ENetPacketPeer" inherits="PacketPeer" version="4.0"> + <brief_description> + A wrapper class for an [url=http://enet.bespin.org/group__peer.html]ENetPeer[/url]. + </brief_description> + <description> + A PacketPeer implementation representing a peer of an [ENetConnection]. + This class cannot be instantiated directly but can be retrieved during [method ENetConnection.service] or via [method ENetConnection.get_peers]. + </description> + <tutorials> + <link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link> + </tutorials> + <methods> + <method name="get_channels" qualifiers="const"> + <return type="int" /> + <description> + Returns the number of channels allocated for communication with peer. + </description> + </method> + <method name="get_state" qualifiers="const"> + <return type="int" enum="ENetPacketPeer.PeerState" /> + <description> + Returns the current peer state. See [enum PeerState]. + </description> + </method> + <method name="get_statistic"> + <return type="float" /> + <argument index="0" name="statistic" type="int" enum="ENetPacketPeer.PeerStatistic" /> + <description> + Returns the requested [code]statistic[/code] for this peer. See [enum PeerStatistic]. + </description> + </method> + <method name="is_active" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the peer is currently active (i.e. the associated [ENetConnection] is still valid). + </description> + </method> + <method name="peer_disconnect"> + <return type="void" /> + <argument index="0" name="data" type="int" default="0" /> + <description> + Request a disconnection from a peer. An [constant ENetConnection.EVENT_DISCONNECT] will be generated during [method ENetConnection.service] once the disconnection is complete. + </description> + </method> + <method name="peer_disconnect_later"> + <return type="void" /> + <argument index="0" name="data" type="int" default="0" /> + <description> + Request a disconnection from a peer, but only after all queued outgoing packets are sent. An [constant ENetConnection.EVENT_DISCONNECT] will be generated during [method ENetConnection.service] once the disconnection is complete. + </description> + </method> + <method name="peer_disconnect_now"> + <return type="void" /> + <argument index="0" name="data" type="int" default="0" /> + <description> + Force an immediate disconnection from a peer. No [constant ENetConnection.EVENT_DISCONNECT] will be generated. The foreign peer is not guaranteed to receive the disconnect notification, and is reset immediately upon return from this function. + </description> + </method> + <method name="ping"> + <return type="void" /> + <description> + Sends a ping request to a peer. ENet automatically pings all connected peers at regular intervals, however, this function may be called to ensure more frequent ping requests. + </description> + </method> + <method name="ping_interval"> + <return type="void" /> + <argument index="0" name="ping_interval" type="int" /> + <description> + Sets the [code]ping_interval[/code] in milliseconds at which pings will be sent to a peer. Pings are used both to monitor the liveness of the connection and also to dynamically adjust the throttle during periods of low traffic so that the throttle has reasonable responsiveness during traffic spikes. + </description> + </method> + <method name="reset"> + <return type="void" /> + <description> + Forcefully disconnects a peer. The foreign host represented by the peer is not notified of the disconnection and will timeout on its connection to the local host. + </description> + </method> + <method name="send"> + <return type="int" enum="Error" /> + <argument index="0" name="channel" type="int" /> + <argument index="1" name="packet" type="PackedByteArray" /> + <argument index="2" name="flags" type="int" /> + <description> + Queues a [code]packet[/code] to be sent over the specified [code]channel[/code]. See [code]FLAG_*[/code] constants for available packet flags. + </description> + </method> + <method name="set_timeout"> + <return type="void" /> + <argument index="0" name="timeout" type="int" /> + <argument index="1" name="timeout_min" type="int" /> + <argument index="2" name="timeout_max" type="int" /> + <description> + Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds. + The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped. + </description> + </method> + <method name="throttle_configure"> + <return type="void" /> + <argument index="0" name="interval" type="int" /> + <argument index="1" name="acceleration" type="int" /> + <argument index="2" name="deceleration" type="int" /> + <description> + Configures throttle parameter for a peer. + Unreliable packets are dropped by ENet in response to the varying conditions of the Internet connection to the peer. The throttle represents a probability that an unreliable packet should not be dropped and thus sent by ENet to the peer. By measuring fluctuations in round trip times of reliable packets over the specified [code]interval[/code], ENet will either increase the probably by the amount specified in the [code]acceleration[/code] parameter, or decrease it by the amount specified in the [code]deceleration[/code] parameter (both are ratios to [constant PACKET_THROTTLE_SCALE]). + When the throttle has a value of [constant PACKET_THROTTLE_SCALE], no unreliable packets are dropped by ENet, and so 100% of all unreliable packets will be sent. + When the throttle has a value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable packets will be sent. + Intermediate values for the throttle represent intermediate probabilities between 0% and 100% of unreliable packets being sent. The bandwidth limits of the local and foreign hosts are taken into account to determine a sensible limit for the throttle probability above which it should not raise even in the best of conditions. + </description> + </method> + </methods> + <constants> + <constant name="STATE_DISCONNECTED" value="0" enum="PeerState"> + </constant> + <constant name="STATE_CONNECTING" value="1" enum="PeerState"> + </constant> + <constant name="STATE_ACKNOWLEDGING_CONNECT" value="2" enum="PeerState"> + </constant> + <constant name="STATE_CONNECTION_PENDING" value="3" enum="PeerState"> + </constant> + <constant name="STATE_CONNECTION_SUCCEEDED" value="4" enum="PeerState"> + </constant> + <constant name="STATE_CONNECTED" value="5" enum="PeerState"> + </constant> + <constant name="STATE_DISCONNECT_LATER" value="6" enum="PeerState"> + </constant> + <constant name="STATE_DISCONNECTING" value="7" enum="PeerState"> + </constant> + <constant name="STATE_ACKNOWLEDGING_DISCONNECT" value="8" enum="PeerState"> + </constant> + <constant name="STATE_ZOMBIE" value="9" enum="PeerState"> + </constant> + <constant name="PEER_PACKET_LOSS" value="0" enum="PeerStatistic"> + Mean packet loss of reliable packets as a ratio with respect to the [constant PACKET_LOSS_SCALE]. + </constant> + <constant name="PEER_PACKET_LOSS_VARIANCE" value="1" enum="PeerStatistic"> + Packet loss variance. + </constant> + <constant name="PEER_PACKET_LOSS_EPOCH" value="2" enum="PeerStatistic"> + </constant> + <constant name="PEER_ROUND_TRIP_TIME" value="3" enum="PeerStatistic"> + Mean packet round trip time for reliable packets. + </constant> + <constant name="PEER_ROUND_TRIP_TIME_VARIANCE" value="4" enum="PeerStatistic"> + Variance of the mean round trip time. + </constant> + <constant name="PEER_LAST_ROUND_TRIP_TIME" value="5" enum="PeerStatistic"> + Last recorded round trip time for a reliable packet. + </constant> + <constant name="PEER_LAST_ROUND_TRIP_TIME_VARIANCE" value="6" enum="PeerStatistic"> + Variance of the last trip time recorded. + </constant> + <constant name="PEER_PACKET_THROTTLE" value="7" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_LIMIT" value="8" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_COUNTER" value="9" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_EPOCH" value="10" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_ACCELERATION" value="11" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_DECELERATION" value="12" enum="PeerStatistic"> + </constant> + <constant name="PEER_PACKET_THROTTLE_INTERVAL" value="13" enum="PeerStatistic"> + </constant> + <constant name="PACKET_LOSS_SCALE" value="65536"> + The reference scale for packet loss. See [method get_statistic] and [constant PEER_PACKET_LOSS]. + </constant> + <constant name="PACKET_THROTTLE_SCALE" value="32"> + The reference value for throttle configuration. See [method throttle_configure]. + </constant> + <constant name="FLAG_RELIABLE" value="1"> + Mark the packet to be sent as reliable. + </constant> + <constant name="FLAG_UNSEQUENCED" value="2"> + Mark the packet to be sent unsequenced (unreliable). + </constant> + <constant name="FLAG_UNRELIABLE_FRAGMENT" value="8"> + Mark the packet to be sent unreliable even if the packet is too big and needs fragmentation (increasing the chance of it being dropped). + </constant> + </constants> +</class> diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp new file mode 100644 index 0000000000..e833264d6a --- /dev/null +++ b/modules/enet/enet_connection.cpp @@ -0,0 +1,470 @@ +/*************************************************************************/ +/* enet_connection.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "enet_connection.h" + +#include "enet_packet_peer.h" + +#include "core/io/compression.h" +#include "core/io/ip.h" + +void ENetConnection::broadcast(enet_uint8 p_channel, ENetPacket *p_packet) { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_MSG(p_channel >= host->channelLimit, vformat("Unable to send packet on channel %d, max channels: %d", p_channel, (int)host->channelLimit)); + enet_host_broadcast(host, p_channel, p_packet); +} + +Error ENetConnection::create_host_bound(const IPAddress &p_bind_address, int p_port, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) { + ERR_FAIL_COND_V_MSG(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER, "Invalid bind IP."); + ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); + + ENetAddress address; + memset(&address, 0, sizeof(address)); + address.port = p_port; +#ifdef GODOT_ENET + if (p_bind_address.is_wildcard()) { + address.wildcard = 1; + } else { + enet_address_set_ip(&address, p_bind_address.get_ipv6(), 16); + } +#else + if (p_bind_address.is_wildcard()) { + address.host = 0; + } else { + ERR_FAIL_COND_V(!p_bind_address.is_ipv4(), ERR_INVALID_PARAMETER); + address.host = *(uint32_t *)p_bind_address.get_ipv4(); + } +#endif + return _create(&address, p_max_peers, p_max_channels, p_in_bandwidth, p_out_bandwidth); +} + +Error ENetConnection::create_host(int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) { + return _create(nullptr, p_max_peers, p_max_channels, p_in_bandwidth, p_out_bandwidth); +} + +void ENetConnection::destroy() { + ERR_FAIL_COND_MSG(!host, "Host already destroyed"); + for (List<Ref<ENetPacketPeer>>::Element *E = peers.front(); E; E = E->next()) { + E->get()->_on_disconnect(); + } + peers.clear(); + enet_host_destroy(host); + host = nullptr; +} + +Ref<ENetPacketPeer> ENetConnection::connect_to_host(const String &p_address, int p_port, int p_channels, int p_data) { + Ref<ENetPacketPeer> out; + ERR_FAIL_COND_V_MSG(!host, out, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_V_MSG(peers.size(), out, "The ENetConnection is already connected to a peer."); + ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, out, "The remote port number must be between 1 and 65535 (inclusive)."); + + IPAddress ip; + if (p_address.is_valid_ip_address()) { + ip = p_address; + } else { +#ifdef GODOT_ENET + ip = IP::get_singleton()->resolve_hostname(p_address); +#else + ip = IP::get_singleton()->resolve_hostname(p_address, IP::TYPE_IPV4); +#endif + ERR_FAIL_COND_V_MSG(!ip.is_valid(), out, "Couldn't resolve the server IP address or domain name."); + } + + ENetAddress address; +#ifdef GODOT_ENET + enet_address_set_ip(&address, ip.get_ipv6(), 16); +#else + ERR_FAIL_COND_V_MSG(!ip.is_ipv4(), out, "Connecting to an IPv6 server isn't supported when using vanilla ENet. Recompile Godot with the bundled ENet library."); + address.host = *(uint32_t *)ip.get_ipv4(); +#endif + address.port = p_port; + + // Initiate connection, allocating enough channels + ENetPeer *peer = enet_host_connect(host, &address, p_channels > 0 ? p_channels : ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT, p_data); + + if (peer == nullptr) { + return nullptr; + } + out = Ref<ENetPacketPeer>(memnew(ENetPacketPeer(peer))); + peers.push_back(out); + return out; +} + +ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) { + ERR_FAIL_COND_V_MSG(!host, EVENT_ERROR, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_V(r_event.peer.is_valid(), EVENT_ERROR); + + // Drop peers that have already been disconnected. + // NOTE: Forcibly disconnected peers (i.e. peers disconnected via + // enet_peer_disconnect*) do not trigger DISCONNECTED events. + List<Ref<ENetPacketPeer>>::Element *E = peers.front(); + while (E) { + if (!E->get()->is_active()) { + peers.erase(E->get()); + } + E = E->next(); + } + + ENetEvent event; + int ret = enet_host_service(host, &event, p_timeout); + + if (ret < 0) { + return EVENT_ERROR; + } else if (ret == 0) { + return EVENT_NONE; + } + switch (event.type) { + case ENET_EVENT_TYPE_CONNECT: { + if (event.peer->data == nullptr) { + Ref<ENetPacketPeer> pp = memnew(ENetPacketPeer(event.peer)); + peers.push_back(pp); + } + r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); + r_event.data = event.data; + return EVENT_CONNECT; + } break; + case ENET_EVENT_TYPE_DISCONNECT: { + // A peer disconnected. + if (event.peer->data != nullptr) { + Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); + pp->_on_disconnect(); + peers.erase(pp); + r_event.peer = pp; + r_event.data = event.data; + return EVENT_DISCONNECT; + } + return EVENT_ERROR; + } break; + case ENET_EVENT_TYPE_RECEIVE: { + // Packet reveived. + if (event.peer->data != nullptr) { + Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); + r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); + r_event.channel_id = event.channelID; + r_event.packet = event.packet; + return EVENT_RECEIVE; + } + return EVENT_ERROR; + } break; + case ENET_EVENT_TYPE_NONE: + return EVENT_NONE; + default: + return EVENT_NONE; + } +} + +void ENetConnection::flush() { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + enet_host_flush(host); +} + +void ENetConnection::bandwidth_limit(int p_in_bandwidth, int p_out_bandwidth) { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + enet_host_bandwidth_limit(host, p_in_bandwidth, p_out_bandwidth); +} + +void ENetConnection::channel_limit(int p_max_channels) { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + enet_host_channel_limit(host, p_max_channels); +} + +void ENetConnection::bandwidth_throttle() { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + enet_host_bandwidth_throttle(host); +} + +void ENetConnection::compress(CompressionMode p_mode) { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + Compressor::setup(host, p_mode); +} + +double ENetConnection::pop_statistic(HostStatistic p_stat) { + ERR_FAIL_COND_V_MSG(!host, 0, "The ENetConnection instance isn't currently active."); + uint32_t *ptr = nullptr; + switch (p_stat) { + case HOST_TOTAL_SENT_DATA: + ptr = &(host->totalSentData); + break; + case HOST_TOTAL_SENT_PACKETS: + ptr = &(host->totalSentPackets); + break; + case HOST_TOTAL_RECEIVED_DATA: + ptr = &(host->totalReceivedData); + break; + case HOST_TOTAL_RECEIVED_PACKETS: + ptr = &(host->totalReceivedPackets); + break; + } + ERR_FAIL_COND_V_MSG(ptr == nullptr, 0, "Invalid statistic: " + itos(p_stat)); + uint32_t ret = *ptr; + *ptr = 0; + return ret; +} + +int ENetConnection::get_max_channels() const { + ERR_FAIL_COND_V_MSG(!host, 0, "The ENetConnection instance isn't currently active."); + return host->channelLimit; +} + +int ENetConnection::get_local_port() const { + ERR_FAIL_COND_V_MSG(!host, 0, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_V_MSG(!(host->socket), 0, "The ENetConnection instance isn't currently bound"); + ENetAddress address; + ERR_FAIL_COND_V_MSG(enet_socket_get_address(host->socket, &address), 0, "Unable to get socket address"); + return address.port; +} + +void ENetConnection::get_peers(List<Ref<ENetPacketPeer>> &r_peers) { + for (const Ref<ENetPacketPeer> &I : peers) { + r_peers.push_back(I); + } +} + +Array ENetConnection::_get_peers() { + ERR_FAIL_COND_V_MSG(!host, Array(), "The ENetConnection instance isn't currently active."); + Array out; + for (const Ref<ENetPacketPeer> &I : peers) { + out.push_back(I); + } + return out; +} + +Error ENetConnection::dtls_server_setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) { +#ifdef GODOT_ENET + ERR_FAIL_COND_V_MSG(!host, ERR_UNCONFIGURED, "The ENetConnection instance isn't currently active."); + return enet_host_dtls_server_setup(host, p_key.ptr(), p_cert.ptr()) ? FAILED : OK; +#else + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "ENet DTLS support not available in this build."); +#endif +} + +void ENetConnection::refuse_new_connections(bool p_refuse) { +#ifdef GODOT_ENET + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + enet_host_refuse_new_connections(host, p_refuse); +#else + ERR_FAIL_MSG("ENet DTLS support not available in this build."); +#endif +} + +Error ENetConnection::dtls_client_setup(Ref<X509Certificate> p_cert, const String &p_hostname, bool p_verify) { +#ifdef GODOT_ENET + ERR_FAIL_COND_V_MSG(!host, ERR_UNCONFIGURED, "The ENetConnection instance isn't currently active."); + return enet_host_dtls_client_setup(host, p_cert.ptr(), p_verify, p_hostname.utf8().get_data()) ? FAILED : OK; +#else + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "ENet DTLS support not available in this build."); +#endif +} + +Error ENetConnection::_create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) { + ERR_FAIL_COND_V_MSG(host != nullptr, ERR_ALREADY_IN_USE, "The ENetConnection instance is already active."); + ERR_FAIL_COND_V_MSG(p_max_peers < 1 || p_max_peers > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_max_channels < 0 || p_max_channels > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT, ERR_INVALID_PARAMETER, "Invalid channel count. Must be between 0 and 255 (0 means maximum, i.e. 255)"); + ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); + ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); + + host = enet_host_create(p_address /* the address to bind the server host to */, + p_max_peers /* allow up to p_max_peers connections */, + p_max_channels /* allow up to p_max_channel to be used */, + p_in_bandwidth /* limit incoming bandwidth if > 0 */, + p_out_bandwidth /* limit outgoing bandwidth if > 0 */); + + ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create an ENet host."); + return OK; +} + +Array ENetConnection::_service(int p_timeout) { + Array out; + Event event; + Ref<ENetPacketPeer> peer; + EventType ret = service(p_timeout, event); + out.push_back(ret); + out.push_back(event.peer); + out.push_back(event.data); + out.push_back(event.channel_id); + if (event.packet && event.peer.is_valid()) { + event.peer->_queue_packet(event.packet); + } + return out; +} + +void ENetConnection::_broadcast(int p_channel, PackedByteArray p_packet, int p_flags) { + ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_MSG(p_channel < 0 || p_channel > (int)host->channelLimit, "Invalid channel"); + ERR_FAIL_COND_MSG(p_flags & ~ENetPacketPeer::FLAG_ALLOWED, "Invalid flags"); + ENetPacket *pkt = enet_packet_create(p_packet.ptr(), p_packet.size(), p_flags); + broadcast(p_channel, pkt); +} + +void ENetConnection::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_host_bound", "bind_address", "bind_port", "max_peers", "max_channels", "in_bandwidth", "out_bandwidth"), &ENetConnection::create_host_bound, DEFVAL(32), DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_host", "max_peers", "max_channels", "in_bandwidth", "out_bandwidth"), &ENetConnection::create_host, DEFVAL(32), DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("destroy"), &ENetConnection::destroy); + ClassDB::bind_method(D_METHOD("connect_to_host", "address", "port", "channels", "data"), &ENetConnection::connect_to_host, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("service", "timeout"), &ENetConnection::_service, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("flush"), &ENetConnection::flush); + ClassDB::bind_method(D_METHOD("bandwidth_limit", "in_bandwidth", "out_bandwidth"), &ENetConnection::bandwidth_limit, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("channel_limit", "limit"), &ENetConnection::channel_limit); + ClassDB::bind_method(D_METHOD("broadcast", "channel", "packet", "flags"), &ENetConnection::_broadcast); + ClassDB::bind_method(D_METHOD("compress", "mode"), &ENetConnection::compress); + ClassDB::bind_method(D_METHOD("dtls_server_setup", "key", "certificate"), &ENetConnection::dtls_server_setup); + ClassDB::bind_method(D_METHOD("dtls_client_setup", "certificate", "hostname", "verify"), &ENetConnection::dtls_client_setup, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("refuse_new_connections", "refuse"), &ENetConnection::refuse_new_connections); + ClassDB::bind_method(D_METHOD("pop_statistic", "statistic"), &ENetConnection::pop_statistic); + ClassDB::bind_method(D_METHOD("get_max_channels"), &ENetConnection::get_max_channels); + ClassDB::bind_method(D_METHOD("get_local_port"), &ENetConnection::get_local_port); + ClassDB::bind_method(D_METHOD("get_peers"), &ENetConnection::_get_peers); + + BIND_ENUM_CONSTANT(COMPRESS_NONE); + BIND_ENUM_CONSTANT(COMPRESS_RANGE_CODER); + BIND_ENUM_CONSTANT(COMPRESS_FASTLZ); + BIND_ENUM_CONSTANT(COMPRESS_ZLIB); + BIND_ENUM_CONSTANT(COMPRESS_ZSTD); + + BIND_ENUM_CONSTANT(EVENT_ERROR); + BIND_ENUM_CONSTANT(EVENT_NONE); + BIND_ENUM_CONSTANT(EVENT_CONNECT); + BIND_ENUM_CONSTANT(EVENT_DISCONNECT); + BIND_ENUM_CONSTANT(EVENT_RECEIVE); + + BIND_ENUM_CONSTANT(HOST_TOTAL_SENT_DATA); + BIND_ENUM_CONSTANT(HOST_TOTAL_SENT_PACKETS); + BIND_ENUM_CONSTANT(HOST_TOTAL_RECEIVED_DATA); + BIND_ENUM_CONSTANT(HOST_TOTAL_RECEIVED_PACKETS); +} + +ENetConnection::~ENetConnection() { + if (host) { + destroy(); + } +} + +size_t ENetConnection::Compressor::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + Compressor *compressor = (Compressor *)(context); + + if (size_t(compressor->src_mem.size()) < inLimit) { + compressor->src_mem.resize(inLimit); + } + + int total = inLimit; + int ofs = 0; + while (total) { + for (size_t i = 0; i < inBufferCount; i++) { + int to_copy = MIN(total, int(inBuffers[i].dataLength)); + memcpy(&compressor->src_mem.write[ofs], inBuffers[i].data, to_copy); + ofs += to_copy; + total -= to_copy; + } + } + + Compression::Mode mode; + + switch (compressor->mode) { + case COMPRESS_FASTLZ: { + mode = Compression::MODE_FASTLZ; + } break; + case COMPRESS_ZLIB: { + mode = Compression::MODE_DEFLATE; + } break; + case COMPRESS_ZSTD: { + mode = Compression::MODE_ZSTD; + } break; + default: { + ERR_FAIL_V_MSG(0, vformat("Invalid ENet compression mode: %d", compressor->mode)); + } + } + + int req_size = Compression::get_max_compressed_buffer_size(ofs, mode); + if (compressor->dst_mem.size() < req_size) { + compressor->dst_mem.resize(req_size); + } + int ret = Compression::compress(compressor->dst_mem.ptrw(), compressor->src_mem.ptr(), ofs, mode); + + if (ret < 0) { + return 0; + } + + if (ret > int(outLimit)) { + return 0; // Do not bother + } + + memcpy(outData, compressor->dst_mem.ptr(), ret); + + return ret; +} + +size_t ENetConnection::Compressor::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + Compressor *compressor = (Compressor *)(context); + int ret = -1; + switch (compressor->mode) { + case COMPRESS_FASTLZ: { + ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_FASTLZ); + } break; + case COMPRESS_ZLIB: { + ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_DEFLATE); + } break; + case COMPRESS_ZSTD: { + ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_ZSTD); + } break; + default: { + } + } + if (ret < 0) { + return 0; + } else { + return ret; + } +} + +void ENetConnection::Compressor::setup(ENetHost *p_host, CompressionMode p_mode) { + ERR_FAIL_COND(!p_host); + switch (p_mode) { + case COMPRESS_NONE: { + enet_host_compress(p_host, nullptr); + } break; + case COMPRESS_RANGE_CODER: { + enet_host_compress_with_range_coder(p_host); + } break; + case COMPRESS_FASTLZ: + case COMPRESS_ZLIB: + case COMPRESS_ZSTD: { + Compressor *compressor = memnew(Compressor(p_mode)); + enet_host_compress(p_host, &(compressor->enet_compressor)); + } break; + } +} + +ENetConnection::Compressor::Compressor(CompressionMode p_mode) { + mode = p_mode; + enet_compressor.context = this; + enet_compressor.compress = enet_compress; + enet_compressor.decompress = enet_decompress; + enet_compressor.destroy = enet_compressor_destroy; +} diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h new file mode 100644 index 0000000000..0f7744953e --- /dev/null +++ b/modules/enet/enet_connection.h @@ -0,0 +1,138 @@ +/*************************************************************************/ +/* enet_connection.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef ENET_CONNECTION_H +#define ENET_CONNECTION_H + +#include "core/object/ref_counted.h" + +#include "core/crypto/crypto.h" +#include "enet_packet_peer.h" + +#include <enet/enet.h> + +class ENetConnection : public RefCounted { + GDCLASS(ENetConnection, RefCounted); + +public: + enum CompressionMode { + COMPRESS_NONE = 0, + COMPRESS_RANGE_CODER, + COMPRESS_FASTLZ, + COMPRESS_ZLIB, + COMPRESS_ZSTD, + }; + + enum HostStatistic { + HOST_TOTAL_SENT_DATA, + HOST_TOTAL_SENT_PACKETS, + HOST_TOTAL_RECEIVED_DATA, + HOST_TOTAL_RECEIVED_PACKETS, + }; + + enum EventType { + EVENT_ERROR = -1, + EVENT_NONE = 0, + EVENT_CONNECT, + EVENT_DISCONNECT, + EVENT_RECEIVE, + }; + + struct Event { + Ref<ENetPacketPeer> peer; + enet_uint8 channel_id = 0; + enet_uint32 data = 0; + ENetPacket *packet = nullptr; + }; + +protected: + static void _bind_methods(); + +private: + ENetHost *host = nullptr; + List<Ref<ENetPacketPeer>> peers; + + Error _create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth); + Array _service(int p_timeout = 0); + void _broadcast(int p_channel, PackedByteArray p_packet, int p_flags); + Array _get_peers(); + + class Compressor { + private: + CompressionMode mode = COMPRESS_NONE; + Vector<uint8_t> src_mem; + Vector<uint8_t> dst_mem; + ENetCompressor enet_compressor; + + Compressor(CompressionMode mode); + + static size_t enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit); + static size_t enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit); + static void enet_compressor_destroy(void *context) { + memdelete((Compressor *)context); + } + + public: + static void setup(ENetHost *p_host, CompressionMode p_mode); + }; + +public: + void broadcast(enet_uint8 p_channel, ENetPacket *p_packet); + Error create_host_bound(const IPAddress &p_bind_address = IPAddress("*"), int p_port = 0, int p_max_peers = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0); + Error create_host(int p_max_peers = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0); + void destroy(); + Ref<ENetPacketPeer> connect_to_host(const String &p_address, int p_port, int p_channels, int p_data = 0); + EventType service(int p_timeout, Event &r_event); + void flush(); + void bandwidth_limit(int p_in_bandwidth = 0, int p_out_bandwidth = 0); + void channel_limit(int p_max_channels); + void bandwidth_throttle(); + void compress(CompressionMode p_mode); + double pop_statistic(HostStatistic p_stat); + int get_max_channels() const; + + // Extras + void get_peers(List<Ref<ENetPacketPeer>> &r_peers); + int get_local_port() const; + + // Godot additions + Error dtls_server_setup(Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert); + Error dtls_client_setup(Ref<X509Certificate> p_cert, const String &p_hostname, bool p_verify = true); + void refuse_new_connections(bool p_refuse); + + ENetConnection() {} + ~ENetConnection(); +}; + +VARIANT_ENUM_CAST(ENetConnection::CompressionMode); +VARIANT_ENUM_CAST(ENetConnection::EventType); +VARIANT_ENUM_CAST(ENetConnection::HostStatistic); + +#endif // ENET_CONNECTION_H diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index b4ca93f4d9..aa0e09bcde 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -33,6 +33,14 @@ #include "core/io/marshalls.h" #include "core/os/os.h" +void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { + transfer_channel = p_channel; +} + +int ENetMultiplayerPeer::get_transfer_channel() const { + return transfer_channel; +} + void ENetMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } @@ -46,458 +54,375 @@ void ENetMultiplayerPeer::set_target_peer(int p_peer) { } int ENetMultiplayerPeer::get_packet_peer() const { - ERR_FAIL_COND_V_MSG(!active, 1, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_V_MSG(!_is_active(), 1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); return incoming_packets.front()->get().from; } -int ENetMultiplayerPeer::get_packet_channel() const { - ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); - ERR_FAIL_COND_V(incoming_packets.size() == 0, -1); - - return incoming_packets.front()->get().channel; -} - -int ENetMultiplayerPeer::get_last_packet_channel() const { - ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); - ERR_FAIL_COND_V(!current_packet.packet, -1); +Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) { + ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + Ref<ENetConnection> host; + host.instantiate(); + Error err = host->create_host_bound(bind_ip, p_port, p_max_clients, 0, p_max_channels > 0 ? p_max_channels + SYSCH_MAX : 0, p_out_bandwidth); + if (err != OK) { + return err; + } - return current_packet.channel; + active_mode = MODE_SERVER; + refuse_connections = false; + unique_id = 1; + connection_status = CONNECTION_CONNECTED; + hosts[0] = host; + return OK; } -Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { - ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive)."); - ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); - ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); - ERR_FAIL_COND_V(dtls_enabled && (dtls_key.is_null() || dtls_cert.is_null()), ERR_INVALID_PARAMETER); - - ENetAddress address; - memset(&address, 0, sizeof(address)); - -#ifdef GODOT_ENET - if (bind_ip.is_wildcard()) { - address.wildcard = 1; +Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_channel_count, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { + ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + Ref<ENetConnection> host; + host.instantiate(); + Error err; + if (p_local_port) { + err = host->create_host_bound(bind_ip, p_local_port, 1, 0, p_in_bandwidth, p_out_bandwidth); } else { - enet_address_set_ip(&address, bind_ip.get_ipv6(), 16); + err = host->create_host(1, 0, p_in_bandwidth, p_out_bandwidth); } -#else - if (bind_ip.is_wildcard()) { - address.host = 0; - } else { - ERR_FAIL_COND_V(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER); - address.host = *(uint32_t *)bind_ip.get_ipv4(); + if (err != OK) { + return err; } -#endif - address.port = p_port; - host = enet_host_create(&address /* the address to bind the server host to */, - p_max_clients /* allow up to 32 clients and/or outgoing connections */, - channel_count /* allow up to channel_count to be used */, - p_in_bandwidth /* limit incoming bandwidth if > 0 */, - p_out_bandwidth /* limit outgoing bandwidth if > 0 */); + unique_id = generate_unique_id(); - ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create an ENet multiplayer server."); -#ifdef GODOT_ENET - if (dtls_enabled) { - enet_host_dtls_server_setup(host, dtls_key.ptr(), dtls_cert.ptr()); + Ref<ENetPacketPeer> peer = host->connect_to_host(p_address, p_port, p_channel_count > 0 ? p_channel_count + SYSCH_MAX : 0, unique_id); + if (peer.is_null()) { + host->destroy(); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server."); } - enet_host_refuse_new_connections(host, refuse_connections); -#endif - _setup_compressor(); - active = true; - server = true; + // Need to wait for CONNECT event. + connection_status = CONNECTION_CONNECTING; + active_mode = MODE_CLIENT; refuse_connections = false; - unique_id = 1; + peers[1] = peer; + hosts[0] = host; + + return OK; +} + +Error ENetMultiplayerPeer::create_mesh(int p_id) { + ERR_FAIL_COND_V_MSG(p_id <= 0, ERR_INVALID_PARAMETER, "The unique ID must be greater then 0"); + ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); + active_mode = MODE_MESH; + refuse_connections = false; + unique_id = p_id; connection_status = CONNECTION_CONNECTED; return OK; } -Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { - ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); - ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); - ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit)."); - ENetAddress c_client; +Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) { + ERR_FAIL_COND_V(p_host.is_null(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(active_mode != MODE_MESH, ERR_UNCONFIGURED, "The multiplayer instance is not configured as a mesh. Call 'create_mesh' first."); + List<Ref<ENetPacketPeer>> host_peers; + p_host->get_peers(host_peers); + ERR_FAIL_COND_V_MSG(host_peers.size() != 1 || host_peers[0]->get_state() != ENetPacketPeer::STATE_CONNECTED, ERR_INVALID_PARAMETER, "The provided host must have excatly one peer in the connected state."); + hosts[p_id] = p_host; + peers[p_id] = host_peers[0]; + emit_signal(SNAME("peer_connected"), p_id); + return OK; +} -#ifdef GODOT_ENET - if (bind_ip.is_wildcard()) { - c_client.wildcard = 1; - } else { - enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16); - } -#else - if (bind_ip.is_wildcard()) { - c_client.host = 0; - } else { - ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6."); - c_client.host = *(uint32_t *)bind_ip.get_ipv4(); +bool ENetMultiplayerPeer::_poll_server() { + for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (!(E.value->is_active())) { + emit_signal(SNAME("peer_disconnected"), E.value->get_meta(SNAME("_net_id"))); + peers.erase(E.key); + } } -#endif - - c_client.port = p_local_port; - - host = enet_host_create(&c_client /* create a client host */, - 1 /* only allow 1 outgoing connection */, - channel_count /* allow up to channel_count to be used */, - p_in_bandwidth /* limit incoming bandwidth if > 0 */, - p_out_bandwidth /* limit outgoing bandwidth if > 0 */); - - ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host."); -#ifdef GODOT_ENET - if (dtls_enabled) { - enet_host_dtls_client_setup(host, dtls_cert.ptr(), dtls_verify, p_address.utf8().get_data()); + ENetConnection::Event event; + ENetConnection::EventType ret = hosts[0]->service(0, event); + if (ret == ENetConnection::EVENT_ERROR) { + return true; } - enet_host_refuse_new_connections(host, refuse_connections); -#endif + switch (ret) { + case ENetConnection::EVENT_CONNECT: { + if (refuse_connections) { + event.peer->reset(); + return false; + } + // Client joined with invalid ID, probably trying to exploit us. + if (event.data < 2 || peers.has((int)event.data)) { + event.peer->reset(); + return false; + } + int id = event.data; + event.peer->set_meta(SNAME("_net_id"), id); + peers[id] = event.peer; - _setup_compressor(); + emit_signal(SNAME("peer_connected"), id); + if (server_relay) { + _notify_peers(id, true); + } + return false; + } + case ENetConnection::EVENT_DISCONNECT: { + int id = event.peer->get_meta(SNAME("_net_id")); + if (!peers.has(id)) { + // Never fully connected. + return false; + } - IPAddress ip; - if (p_address.is_valid_ip_address()) { - ip = p_address; - } else { -#ifdef GODOT_ENET - ip = IP::get_singleton()->resolve_hostname(p_address); -#else - ip = IP::get_singleton()->resolve_hostname(p_address, IP::TYPE_IPV4); -#endif + emit_signal(SNAME("peer_disconnected"), id); + peers.erase(id); + if (!server_relay) { + _notify_peers(id, false); + } + return false; + } + case ENetConnection::EVENT_RECEIVE: { + if (event.channel_id == SYSCH_CONFIG) { + _destroy_unused(event.packet); + ERR_FAIL_V_MSG(false, "Only server can send config messages"); + } else { + if (event.packet->dataLength < 8) { + _destroy_unused(event.packet); + ERR_FAIL_V_MSG(false, "Invalid packet size"); + } - ERR_FAIL_COND_V_MSG(!ip.is_valid(), ERR_CANT_RESOLVE, "Couldn't resolve the server IP address or domain name."); - } + uint32_t source = decode_uint32(&event.packet->data[0]); + int target = decode_uint32(&event.packet->data[4]); - ENetAddress address; -#ifdef GODOT_ENET - enet_address_set_ip(&address, ip.get_ipv6(), 16); -#else - ERR_FAIL_COND_V_MSG(!ip.is_ipv4(), ERR_INVALID_PARAMETER, "Connecting to an IPv6 server isn't supported when using vanilla ENet. Recompile Godot with the bundled ENet library."); - address.host = *(uint32_t *)ip.get_ipv4(); -#endif - address.port = p_port; + uint32_t id = event.peer->get_meta(SNAME("_net_id")); + // Someone is cheating and trying to fake the source! + if (source != id) { + _destroy_unused(event.packet); + ERR_FAIL_V_MSG(false, "Someone is cheating and trying to fake the source!"); + } - unique_id = _gen_unique_id(); + Packet packet; + packet.packet = event.packet; + packet.channel = event.channel_id; + packet.from = id; - // Initiate connection, allocating enough channels - ENetPeer *peer = enet_host_connect(host, &address, channel_count, unique_id); + // Even if relaying is disabled, these targets are valid as incoming packets. + if (target == 1 || target == 0 || target < -1) { + packet.packet->referenceCount++; + incoming_packets.push_back(packet); + } - if (peer == nullptr) { - enet_host_destroy(host); - ERR_FAIL_COND_V_MSG(!peer, ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server."); + if (server_relay && target != 1) { + packet.packet->referenceCount++; + _relay(source, target, event.channel_id, event.packet); + packet.packet->referenceCount--; + _destroy_unused(event.packet); + } + // Destroy packet later + } + return false; + } + default: + return true; } - - // Technically safe to ignore the peer or anything else. - - connection_status = CONNECTION_CONNECTING; - active = true; - server = false; - refuse_connections = false; - - return OK; } -void ENetMultiplayerPeer::poll() { - ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); - - _pop_current_packet(); - - ENetEvent event; - /* Keep servicing until there are no available events left in queue. */ - while (true) { - if (!host || !active) { // Might have been disconnected while emitting a notification - return; +bool ENetMultiplayerPeer::_poll_client() { + if (peers.has(1) && !peers[1]->is_active()) { + if (connection_status == CONNECTION_CONNECTED) { + // Client just disconnected from server. + emit_signal(SNAME("server_disconnected")); + } else { + emit_signal(SNAME("connection_failed")); } - - int ret = enet_host_service(host, &event, 0); - - if (ret < 0) { - // Error, do something? - break; - } else if (ret == 0) { - break; + close_connection(); + return true; + } + ENetConnection::Event event; + ENetConnection::EventType ret = hosts[0]->service(0, event); + if (ret == ENetConnection::EVENT_ERROR) { + return true; + } + switch (ret) { + case ENetConnection::EVENT_CONNECT: { + emit_signal(SNAME("peer_connected"), 1); + connection_status = CONNECTION_CONNECTED; + emit_signal(SNAME("connection_succeeded")); + return false; + } + case ENetConnection::EVENT_DISCONNECT: { + if (connection_status == CONNECTION_CONNECTED) { + // Client just disconnected from server. + emit_signal(SNAME("server_disconnected")); + } else { + emit_signal(SNAME("connection_failed")); + } + close_connection(); + return true; } + case ENetConnection::EVENT_RECEIVE: { + if (event.channel_id == SYSCH_CONFIG) { + // Config message + if (event.packet->dataLength != 8) { + _destroy_unused(event.packet); + ERR_FAIL_V(false); + } - switch (event.type) { - case ENET_EVENT_TYPE_CONNECT: { - // Store any relevant client information here. + int msg = decode_uint32(&event.packet->data[0]); + int id = decode_uint32(&event.packet->data[4]); - if (server && refuse_connections) { - enet_peer_reset(event.peer); - break; - } + switch (msg) { + case SYSMSG_ADD_PEER: { + peers[id] = Ref<ENetPacketPeer>(); + emit_signal(SNAME("peer_connected"), id); - // A client joined with an invalid ID (negative values, 0, and 1 are reserved). - // Probably trying to exploit us. - if (server && ((int)event.data < 2 || peer_map.has((int)event.data))) { - enet_peer_reset(event.peer); - ERR_CONTINUE(true); + } break; + case SYSMSG_REMOVE_PEER: { + peers.erase(id); + emit_signal(SNAME("peer_disconnected"), id); + } break; + } + _destroy_unused(event.packet); + } else { + if (event.packet->dataLength < 8) { + _destroy_unused(event.packet); + ERR_FAIL_V_MSG(false, "Invalid packet size"); } - int *new_id = memnew(int); - *new_id = event.data; + uint32_t source = decode_uint32(&event.packet->data[0]); + Packet packet; + packet.packet = event.packet; + packet.from = source; + packet.channel = event.channel_id; - if (*new_id == 0) { // Data zero is sent by server (ENet won't let you configure this). Server is always 1. - *new_id = 1; - } + packet.packet->referenceCount++; + incoming_packets.push_back(packet); + // Destroy packet later + } + return false; + } + default: + return true; + } +} - event.peer->data = new_id; - - peer_map[*new_id] = event.peer; - - connection_status = CONNECTION_CONNECTED; // If connecting, this means it connected to something! - - emit_signal(SNAME("peer_connected"), *new_id); - - if (server) { - // Do not notify other peers when server_relay is disabled. - if (!server_relay) { - break; - } - - // Someone connected, notify all the peers available - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (E->key() == *new_id) { - continue; - } - // Send existing peers to new peer - ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); - encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); - encode_uint32(E->key(), &packet->data[4]); - enet_peer_send(event.peer, SYSCH_CONFIG, packet); - // Send the new peer to existing peers - packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); - encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); - encode_uint32(*new_id, &packet->data[4]); - enet_peer_send(E->get(), SYSCH_CONFIG, packet); - } - } else { - emit_signal(SNAME("connection_succeeded")); +bool ENetMultiplayerPeer::_poll_mesh() { + for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (!(E.value->is_active())) { + emit_signal(SNAME("peer_disconnected"), E.key); + peers.erase(E.key); + if (hosts.has(E.key)) { + hosts.erase(E.key); + } + } + } + bool should_stop = true; + for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { + ENetConnection::Event event; + ENetConnection::EventType ret = E.value->service(0, event); + if (ret == ENetConnection::EVENT_ERROR) { + if (peers.has(E.key)) { + emit_signal(SNAME("peer_disconnected"), E.key); + peers.erase(E.key); + } + hosts.erase(E.key); + continue; + } + switch (ret) { + case ENetConnection::EVENT_CONNECT: + should_stop = false; + event.peer->reset(); + break; + case ENetConnection::EVENT_DISCONNECT: + should_stop = false; + if (peers.has(E.key)) { + emit_signal(SNAME("peer_disconnected"), E.key); + peers.erase(E.key); } + hosts.erase(E.key); + break; + case ENetConnection::EVENT_RECEIVE: { + should_stop = false; + if (event.packet->dataLength < 8) { + _destroy_unused(event.packet); + ERR_CONTINUE_MSG(true, "Invalid packet size"); + } + + Packet packet; + packet.packet = event.packet; + packet.from = E.key; + packet.channel = event.channel_id; + packet.packet->referenceCount++; + incoming_packets.push_back(packet); } break; - case ENET_EVENT_TYPE_DISCONNECT: { - // Reset the peer's client information. + default: + break; // Nothing to do + } + } + return should_stop; +} - int *id = (int *)event.peer->data; +void ENetMultiplayerPeer::poll() { + ERR_FAIL_COND_MSG(!_is_active(), "The multiplayer instance isn't currently active."); - if (!id) { - if (!server) { - emit_signal(SNAME("connection_failed")); - } - // Never fully connected. - break; - } + _pop_current_packet(); - if (!server) { - // Client just disconnected from server. - emit_signal(SNAME("server_disconnected")); - close_connection(); + while (true) { + switch (active_mode) { + case MODE_CLIENT: + if (_poll_client()) { return; - } else if (server_relay) { - // Server just received a client disconnect and is in relay mode, notify everyone else. - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (E->key() == *id) { - continue; - } - - ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); - encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); - encode_uint32(*id, &packet->data[4]); - enet_peer_send(E->get(), SYSCH_CONFIG, packet); - } } - - emit_signal(SNAME("peer_disconnected"), *id); - peer_map.erase(*id); - memdelete(id); - } break; - case ENET_EVENT_TYPE_RECEIVE: { - if (event.channelID == SYSCH_CONFIG) { - // Some config message - ERR_CONTINUE(event.packet->dataLength < 8); - - // Only server can send config messages - ERR_CONTINUE(server); - - int msg = decode_uint32(&event.packet->data[0]); - int id = decode_uint32(&event.packet->data[4]); - - switch (msg) { - case SYSMSG_ADD_PEER: { - peer_map[id] = nullptr; - emit_signal(SNAME("peer_connected"), id); - - } break; - case SYSMSG_REMOVE_PEER: { - peer_map.erase(id); - emit_signal(SNAME("peer_disconnected"), id); - } break; - } - - enet_packet_destroy(event.packet); - } else if (event.channelID < channel_count) { - Packet packet; - packet.packet = event.packet; - - uint32_t *id = (uint32_t *)event.peer->data; - - ERR_CONTINUE(event.packet->dataLength < 8); - - uint32_t source = decode_uint32(&event.packet->data[0]); - int target = decode_uint32(&event.packet->data[4]); - - packet.from = source; - packet.channel = event.channelID; - - if (server) { - // Someone is cheating and trying to fake the source! - ERR_CONTINUE(source != *id); - - packet.from = *id; - - if (target == 1) { - // To myself and only myself - incoming_packets.push_back(packet); - } else if (!server_relay) { - // When relaying is disabled, other destinations will only be processed by the server. - if (target == 0 || target < -1) { - incoming_packets.push_back(packet); - } - continue; - } else if (target == 0) { - // Re-send to everyone but sender :| - - incoming_packets.push_back(packet); - // And make copies for sending - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (uint32_t(E->key()) == source) { // Do not resend to self - continue; - } - - ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags); - - enet_peer_send(E->get(), event.channelID, packet2); - } - - } else if (target < 0) { - // To all but one - - // And make copies for sending - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (uint32_t(E->key()) == source || E->key() == -target) { // Do not resend to self, also do not send to excluded - continue; - } - - ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags); - - enet_peer_send(E->get(), event.channelID, packet2); - } - - if (-target != 1) { - // Server is not excluded - incoming_packets.push_back(packet); - } else { - // Server is excluded, erase packet - enet_packet_destroy(packet.packet); - } - - } else { - // To someone else, specifically - ERR_CONTINUE(!peer_map.has(target)); - enet_peer_send(peer_map[target], event.channelID, packet.packet); - } - } else { - incoming_packets.push_back(packet); - } - - // Destroy packet later - } else { - ERR_CONTINUE(true); + break; + case MODE_SERVER: + if (_poll_server()) { + return; } - - } break; - case ENET_EVENT_TYPE_NONE: { - // Do nothing - } break; + break; + case MODE_MESH: + if (_poll_mesh()) { + return; + } + break; + default: + return; } } } bool ENetMultiplayerPeer::is_server() const { - ERR_FAIL_COND_V_MSG(!active, false, "The multiplayer instance isn't currently active."); - - return server; + return active_mode == MODE_SERVER; } void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) { - ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_MSG(!_is_active(), "The multiplayer instance isn't currently active."); _pop_current_packet(); bool peers_disconnected = false; - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (E->get()) { - enet_peer_disconnect_now(E->get(), unique_id); - int *id = (int *)(E->get()->data); - memdelete(id); + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.value.is_valid() && E.value->get_state() == ENetPacketPeer::STATE_CONNECTED) { + E.value->peer_disconnect_now(unique_id); peers_disconnected = true; } } if (peers_disconnected) { - enet_host_flush(host); + for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { + E.value->flush(); + } if (wait_usec > 0) { OS::get_singleton()->delay_usec(wait_usec); // Wait for disconnection packets to send } } - enet_host_destroy(host); - active = false; + active_mode = MODE_NONE; incoming_packets.clear(); - peer_map.clear(); - unique_id = 1; // Server is 1 + peers.clear(); + hosts.clear(); + unique_id = 0; connection_status = CONNECTION_DISCONNECTED; } -void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool now) { - ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); - ERR_FAIL_COND_MSG(!is_server(), "Can't disconnect a peer when not acting as a server."); - ERR_FAIL_COND_MSG(!peer_map.has(p_peer), vformat("Peer ID %d not found in the list of peers.", p_peer)); - - if (now) { - int *id = (int *)peer_map[p_peer]->data; - enet_peer_disconnect_now(peer_map[p_peer], 0); - - // enet_peer_disconnect_now doesn't generate ENET_EVENT_TYPE_DISCONNECT, - // notify everyone else, send disconnect signal & remove from peer_map like in poll() - if (server_relay) { - for (Map<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) { - if (E->key() == p_peer) { - continue; - } - - ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); - encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); - encode_uint32(p_peer, &packet->data[4]); - enet_peer_send(E->get(), SYSCH_CONFIG, packet); - } - } - - if (id) { - memdelete(id); - } - - emit_signal(SNAME("peer_disconnected"), p_peer); - peer_map.erase(p_peer); - } else { - enet_peer_disconnect_later(peer_map[p_peer], 0); - } -} - int ENetMultiplayerPeer::get_available_packet_count() const { return incoming_packets.size(); } @@ -517,40 +442,30 @@ Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_si } Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V_MSG(!active, ERR_UNCONFIGURED, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_V_MSG(!_is_active(), ERR_UNCONFIGURED, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client."); + ERR_FAIL_COND_V_MSG(target_peer != 0 && !peers.has(ABS(target_peer)), ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer)); + ERR_FAIL_COND_V(active_mode == MODE_CLIENT && !peers.has(1), ERR_BUG); int packet_flags = 0; int channel = SYSCH_RELIABLE; - - switch (transfer_mode) { - case TRANSFER_MODE_UNRELIABLE: { - if (always_ordered) { - packet_flags = 0; - } else { + if (transfer_channel > 0) { + channel = SYSCH_MAX + transfer_channel - 1; + } else { + switch (transfer_mode) { + case TRANSFER_MODE_UNRELIABLE: { packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; - } - channel = SYSCH_UNRELIABLE; - } break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: { - packet_flags = 0; - channel = SYSCH_UNRELIABLE; - } break; - case TRANSFER_MODE_RELIABLE: { - packet_flags = ENET_PACKET_FLAG_RELIABLE; - channel = SYSCH_RELIABLE; - } break; - } - - if (transfer_channel > SYSCH_CONFIG) { - channel = transfer_channel; - } - - Map<int, ENetPeer *>::Element *E = nullptr; - - if (target_peer != 0) { - E = peer_map.find(ABS(target_peer)); - ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer)); + channel = SYSCH_UNRELIABLE; + } break; + case TRANSFER_MODE_UNRELIABLE_ORDERED: { + packet_flags = 0; + channel = SYSCH_UNRELIABLE; + } break; + case TRANSFER_MODE_RELIABLE: { + packet_flags = ENET_PACKET_FLAG_RELIABLE; + channel = SYSCH_RELIABLE; + } break; + } } ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags); @@ -558,36 +473,50 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size encode_uint32(target_peer, &packet->data[4]); // Dest ID memcpy(&packet->data[8], p_buffer, p_buffer_size); - if (server) { + if (is_server()) { if (target_peer == 0) { - enet_host_broadcast(host, channel, packet); - } else if (target_peer < 0) { - // Send to all but one - // and make copies for sending + hosts[0]->broadcast(channel, packet); + } else if (target_peer < 0) { + // Send to all but one and make copies for sending. int exclude = -target_peer; - - for (Map<int, ENetPeer *>::Element *F = peer_map.front(); F; F = F->next()) { - if (F->key() == exclude) { // Exclude packet + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == exclude) { continue; } + E.value->send(channel, packet); + } + _destroy_unused(packet); + } else { + peers[target_peer]->send(channel, packet); + } + ERR_FAIL_COND_V(!hosts.has(0), ERR_BUG); + hosts[0]->flush(); - ENetPacket *packet2 = enet_packet_create(packet->data, packet->dataLength, packet_flags); + } else if (active_mode == MODE_CLIENT) { + peers[1]->send(channel, packet); // Send to server for broadcast. + ERR_FAIL_COND_V(!hosts.has(0), ERR_BUG); + hosts[0]->flush(); - enet_peer_send(F->get(), channel, packet2); + } else { + if (target_peer <= 0) { + int exclude = ABS(target_peer); + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == exclude) { + continue; + } + E.value->send(channel, packet); + ERR_CONTINUE(!hosts.has(E.key)); + hosts[E.key]->flush(); } - - enet_packet_destroy(packet); // Original packet no longer needed + _destroy_unused(packet); } else { - enet_peer_send(E->get(), channel, packet); + peers[target_peer]->send(channel, packet); + ERR_FAIL_COND_V(!hosts.has(target_peer), ERR_BUG); + hosts[target_peer]->flush(); } - } else { - ERR_FAIL_COND_V(!peer_map.has(1), ERR_BUG); - enet_peer_send(peer_map[1], channel, packet); // Send to server for broadcast } - enet_host_flush(host); - return OK; } @@ -597,7 +526,8 @@ int ENetMultiplayerPeer::get_max_packet_size() const { void ENetMultiplayerPeer::_pop_current_packet() { if (current_packet.packet) { - enet_packet_destroy(current_packet.packet); + current_packet.packet->referenceCount--; + _destroy_unused(current_packet.packet); current_packet.packet = nullptr; current_packet.from = 0; current_packet.channel = -1; @@ -608,37 +538,18 @@ MultiplayerPeer::ConnectionStatus ENetMultiplayerPeer::get_connection_status() c return connection_status; } -uint32_t ENetMultiplayerPeer::_gen_unique_id() const { - uint32_t hash = 0; - - while (hash == 0 || hash == 1) { - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_ticks_usec()); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_unix_time(), hash); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_user_data_dir().hash64(), hash); - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)this), hash); // Rely on ASLR heap - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)&hash), hash); // Rely on ASLR stack - - hash = hash & 0x7FFFFFFF; // Make it compatible with unsigned, since negative ID is used for exclusion - } - - return hash; -} - int ENetMultiplayerPeer::get_unique_id() const { - ERR_FAIL_COND_V_MSG(!active, 0, "The multiplayer instance isn't currently active."); + ERR_FAIL_COND_V_MSG(!_is_active(), 0, "The multiplayer instance isn't currently active."); return unique_id; } void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; #ifdef GODOT_ENET - if (active) { - enet_host_refuse_new_connections(host, p_enable); + if (_is_active()) { + for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { + E.value->refuse_new_connections(p_enable); + } } #endif } @@ -647,244 +558,122 @@ bool ENetMultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } -void ENetMultiplayerPeer::set_compression_mode(CompressionMode p_mode) { - compression_mode = p_mode; -} +void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) { + ERR_FAIL_COND_MSG(_is_active(), "Server relaying can't be toggled while the multiplayer instance is active."); -ENetMultiplayerPeer::CompressionMode ENetMultiplayerPeer::get_compression_mode() const { - return compression_mode; + server_relay = p_enabled; } -size_t ENetMultiplayerPeer::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); - - if (size_t(enet->src_compressor_mem.size()) < inLimit) { - enet->src_compressor_mem.resize(inLimit); - } +bool ENetMultiplayerPeer::is_server_relay_enabled() const { + return server_relay; +} - int total = inLimit; - int ofs = 0; - while (total) { - for (size_t i = 0; i < inBufferCount; i++) { - int to_copy = MIN(total, int(inBuffers[i].dataLength)); - memcpy(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy); - ofs += to_copy; - total -= to_copy; - } - } +Ref<ENetConnection> ENetMultiplayerPeer::get_host() const { + ERR_FAIL_COND_V(!_is_active(), nullptr); + ERR_FAIL_COND_V(active_mode == MODE_MESH, nullptr); + return hosts[0]; +} - Compression::Mode mode; - - switch (enet->compression_mode) { - case COMPRESS_FASTLZ: { - mode = Compression::MODE_FASTLZ; - } break; - case COMPRESS_ZLIB: { - mode = Compression::MODE_DEFLATE; - } break; - case COMPRESS_ZSTD: { - mode = Compression::MODE_ZSTD; - } break; - default: { - ERR_FAIL_V_MSG(0, vformat("Invalid ENet compression mode: %d", enet->compression_mode)); - } - } +Ref<ENetPacketPeer> ENetMultiplayerPeer::get_peer(int p_id) const { + ERR_FAIL_COND_V(!_is_active(), nullptr); + ERR_FAIL_COND_V(!peers.has(p_id), nullptr); + ERR_FAIL_COND_V(active_mode == MODE_CLIENT && p_id != 1, nullptr); + return peers[p_id]; +} - int req_size = Compression::get_max_compressed_buffer_size(ofs, mode); - if (enet->dst_compressor_mem.size() < req_size) { - enet->dst_compressor_mem.resize(req_size); +void ENetMultiplayerPeer::_destroy_unused(ENetPacket *p_packet) { + if (p_packet->referenceCount == 0) { + enet_packet_destroy(p_packet); } - int ret = Compression::compress(enet->dst_compressor_mem.ptrw(), enet->src_compressor_mem.ptr(), ofs, mode); +} - if (ret < 0) { - return 0; - } +void ENetMultiplayerPeer::_relay(int p_from, int p_to, enet_uint8 p_channel, ENetPacket *p_packet) { + if (p_to == 0) { + // Re-send to everyone but sender :| + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == p_from) { + continue; + } - if (ret > int(outLimit)) { - return 0; // Do not bother - } + E.value->send(p_channel, p_packet); + } + } else if (p_to < 0) { + // Re-send to everyone but excluded and sender. + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == p_from || E.key == -p_to) { // Do not resend to self, also do not send to excluded + continue; + } - memcpy(outData, enet->dst_compressor_mem.ptr(), ret); - - return ret; -} - -size_t ENetMultiplayerPeer::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); - int ret = -1; - switch (enet->compression_mode) { - case COMPRESS_FASTLZ: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_FASTLZ); - } break; - case COMPRESS_ZLIB: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_DEFLATE); - } break; - case COMPRESS_ZSTD: { - ret = Compression::decompress(outData, outLimit, inData, inLimit, Compression::MODE_ZSTD); - } break; - default: { + E.value->send(p_channel, p_packet); } - } - if (ret < 0) { - return 0; } else { - return ret; + // To someone else, specifically + ERR_FAIL_COND(!peers.has(p_to)); + ENetPacket *packet = enet_packet_create(p_packet->data, p_packet->dataLength, p_packet->flags); + peers[p_to]->send(p_channel, packet); } } -void ENetMultiplayerPeer::_setup_compressor() { - switch (compression_mode) { - case COMPRESS_NONE: { - enet_host_compress(host, nullptr); - } break; - case COMPRESS_RANGE_CODER: { - enet_host_compress_with_range_coder(host); - } break; - case COMPRESS_FASTLZ: - case COMPRESS_ZLIB: - case COMPRESS_ZSTD: { - enet_host_compress(host, &enet_compressor); - } break; +void ENetMultiplayerPeer::_notify_peers(int p_id, bool p_connected) { + if (p_connected) { + ERR_FAIL_COND(!peers.has(p_id)); + // Someone connected, notify all the peers available. + Ref<ENetPacketPeer> peer = peers[p_id]; + ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); + encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]); + encode_uint32(p_id, &packet->data[4]); + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == p_id) { + continue; + } + // Send new peer to existing peer. + E.value->send(SYSCH_CONFIG, packet); + // Send existing peer to new peer. + // This packet will be automatically destroyed by ENet after send. + ENetPacket *packet2 = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); + encode_uint32(SYSMSG_ADD_PEER, &packet2->data[0]); + encode_uint32(E.key, &packet2->data[4]); + peer->send(SYSCH_CONFIG, packet2); + } + _destroy_unused(packet); + } else { + // Server just received a client disconnect and is in relay mode, notify everyone else. + ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE); + encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]); + encode_uint32(p_id, &packet->data[4]); + for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.key == p_id) { + continue; + } + E.value->send(SYSCH_CONFIG, packet); + } + _destroy_unused(packet); } } -void ENetMultiplayerPeer::enet_compressor_destroy(void *context) { - // Nothing to do -} - -IPAddress ENetMultiplayerPeer::get_peer_address(int p_peer_id) const { - ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IPAddress(), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); - ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IPAddress(), "Can't get the address of peers other than the server (ID -1) when acting as a client."); - ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IPAddress(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); - - IPAddress out; -#ifdef GODOT_ENET - out.set_ipv6((uint8_t *)&(peer_map[p_peer_id]->address.host)); -#else - out.set_ipv4((uint8_t *)&(peer_map[p_peer_id]->address.host)); -#endif - - return out; -} - -int ENetMultiplayerPeer::get_peer_port(int p_peer_id) const { - ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id)); - ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client."); - ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); -#ifdef GODOT_ENET - return peer_map[p_peer_id]->address.port; -#else - return peer_map[p_peer_id]->address.port; -#endif -} - -int ENetMultiplayerPeer::get_local_port() const { - ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active."); - return host->address.port; -} - -void ENetMultiplayerPeer::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) { - ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); - ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client."); - ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); - ERR_FAIL_COND_MSG(p_timeout_limit > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout"); - enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max); -} - -void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { - ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel)); - ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG)); - transfer_channel = p_channel; -} - -int ENetMultiplayerPeer::get_transfer_channel() const { - return transfer_channel; -} - -void ENetMultiplayerPeer::set_channel_count(int p_channel) { - ERR_FAIL_COND_MSG(active, "The channel count can't be set while the multiplayer instance is active."); - ERR_FAIL_COND_MSG(p_channel < SYSCH_MAX, vformat("The channel count must be greater than or equal to %d to account for reserved channels (got %d).", SYSCH_MAX, p_channel)); - channel_count = p_channel; -} - -int ENetMultiplayerPeer::get_channel_count() const { - return channel_count; -} - -void ENetMultiplayerPeer::set_always_ordered(bool p_ordered) { - always_ordered = p_ordered; -} - -bool ENetMultiplayerPeer::is_always_ordered() const { - return always_ordered; -} - -void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) { - ERR_FAIL_COND_MSG(active, "Server relaying can't be toggled while the multiplayer instance is active."); - - server_relay = p_enabled; -} - -bool ENetMultiplayerPeer::is_server_relay_enabled() const { - return server_relay; -} - void ENetMultiplayerPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "max_channels", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_client", "address", "port", "channel_count", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_mesh", "unique_id"), &ENetMultiplayerPeer::create_mesh); + ClassDB::bind_method(D_METHOD("add_mesh_peer", "peer_id", "host"), &ENetMultiplayerPeer::add_mesh_peer); ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &ENetMultiplayerPeer::close_connection, DEFVAL(100)); - ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &ENetMultiplayerPeer::disconnect_peer, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &ENetMultiplayerPeer::set_compression_mode); - ClassDB::bind_method(D_METHOD("get_compression_mode"), &ENetMultiplayerPeer::get_compression_mode); ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip); - ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &ENetMultiplayerPeer::is_dtls_enabled); - ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &ENetMultiplayerPeer::set_dtls_key); - ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &ENetMultiplayerPeer::set_dtls_certificate); - ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &ENetMultiplayerPeer::is_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &ENetMultiplayerPeer::get_peer_address); - ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &ENetMultiplayerPeer::get_peer_port); - ClassDB::bind_method(D_METHOD("get_local_port"), &ENetMultiplayerPeer::get_local_port); - ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &ENetMultiplayerPeer::set_peer_timeout); - - ClassDB::bind_method(D_METHOD("get_packet_channel"), &ENetMultiplayerPeer::get_packet_channel); - ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &ENetMultiplayerPeer::get_last_packet_channel); - ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &ENetMultiplayerPeer::set_transfer_channel); - ClassDB::bind_method(D_METHOD("get_transfer_channel"), &ENetMultiplayerPeer::get_transfer_channel); - ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &ENetMultiplayerPeer::set_channel_count); - ClassDB::bind_method(D_METHOD("get_channel_count"), &ENetMultiplayerPeer::get_channel_count); - ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &ENetMultiplayerPeer::set_always_ordered); - ClassDB::bind_method(D_METHOD("is_always_ordered"), &ENetMultiplayerPeer::is_always_ordered); + ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &ENetMultiplayerPeer::set_server_relay_enabled); ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &ENetMultiplayerPeer::is_server_relay_enabled); + ClassDB::bind_method(D_METHOD("get_host"), &ENetMultiplayerPeer::get_host); + ClassDB::bind_method(D_METHOD("get_peer", "id"), &ENetMultiplayerPeer::get_peer); - ADD_PROPERTY(PropertyInfo(Variant::INT, "compression_mode", PROPERTY_HINT_ENUM, "None,Range Coder,FastLZ,ZLib,ZStd"), "set_compression_mode", "get_compression_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel"), "set_transfer_channel", "get_transfer_channel"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "channel_count"), "set_channel_count", "get_channel_count"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "always_ordered"), "set_always_ordered", "is_always_ordered"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dtls_verify"), "set_dtls_verify_enabled", "is_dtls_verify_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_dtls"), "set_dtls_enabled", "is_dtls_enabled"); - - BIND_ENUM_CONSTANT(COMPRESS_NONE); - BIND_ENUM_CONSTANT(COMPRESS_RANGE_CODER); - BIND_ENUM_CONSTANT(COMPRESS_FASTLZ); - BIND_ENUM_CONSTANT(COMPRESS_ZLIB); - BIND_ENUM_CONSTANT(COMPRESS_ZSTD); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "host", PROPERTY_HINT_RESOURCE_TYPE, "ENetConnection", PROPERTY_USAGE_NONE), "", "get_host"); } ENetMultiplayerPeer::ENetMultiplayerPeer() { - enet_compressor.context = this; - enet_compressor.compress = enet_compress; - enet_compressor.decompress = enet_decompress; - enet_compressor.destroy = enet_compressor_destroy; - bind_ip = IPAddress("*"); } ENetMultiplayerPeer::~ENetMultiplayerPeer() { - if (active) { + if (_is_active()) { close_connection(); } } @@ -896,31 +685,3 @@ void ENetMultiplayerPeer::set_bind_ip(const IPAddress &p_ip) { bind_ip = p_ip; } - -void ENetMultiplayerPeer::set_dtls_enabled(bool p_enabled) { - ERR_FAIL_COND(active); - dtls_enabled = p_enabled; -} - -bool ENetMultiplayerPeer::is_dtls_enabled() const { - return dtls_enabled; -} - -void ENetMultiplayerPeer::set_dtls_verify_enabled(bool p_enabled) { - ERR_FAIL_COND(active); - dtls_verify = p_enabled; -} - -bool ENetMultiplayerPeer::is_dtls_verify_enabled() const { - return dtls_verify; -} - -void ENetMultiplayerPeer::set_dtls_key(Ref<CryptoKey> p_key) { - ERR_FAIL_COND(active); - dtls_key = p_key; -} - -void ENetMultiplayerPeer::set_dtls_certificate(Ref<X509Certificate> p_cert) { - ERR_FAIL_COND(active); - dtls_cert = p_cert; -} diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index 63f2ec5870..78e280db7c 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -32,23 +32,14 @@ #define NETWORKED_MULTIPLAYER_ENET_H #include "core/crypto/crypto.h" -#include "core/io/compression.h" #include "core/io/multiplayer_peer.h" +#include "enet_connection.h" #include <enet/enet.h> class ENetMultiplayerPeer : public MultiplayerPeer { GDCLASS(ENetMultiplayerPeer, MultiplayerPeer); -public: - enum CompressionMode { - COMPRESS_NONE, - COMPRESS_RANGE_CODER, - COMPRESS_FASTLZ, - COMPRESS_ZLIB, - COMPRESS_ZSTD - }; - private: enum { SYSMSG_ADD_PEER, @@ -56,33 +47,34 @@ private: }; enum { - SYSCH_CONFIG, - SYSCH_RELIABLE, - SYSCH_UNRELIABLE, - SYSCH_MAX + SYSCH_CONFIG = 0, + SYSCH_RELIABLE = 1, + SYSCH_UNRELIABLE = 2, + SYSCH_MAX = 3 + }; + + enum Mode { + MODE_NONE, + MODE_SERVER, + MODE_CLIENT, + MODE_MESH, }; - bool active = false; - bool server = false; + Mode active_mode = MODE_NONE; uint32_t unique_id = 0; int target_peer = 0; + int transfer_channel = 0; TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; - int transfer_channel = -1; - int channel_count = SYSCH_MAX; - bool always_ordered = false; - - ENetEvent event; - ENetPeer *peer = nullptr; - ENetHost *host = nullptr; bool refuse_connections = false; bool server_relay = true; ConnectionStatus connection_status = CONNECTION_DISCONNECTED; - Map<int, ENetPeer *> peer_map; + Map<int, Ref<ENetConnection>> hosts; + Map<int, Ref<ENetPacketPeer>> peers; struct Packet { ENetPacket *packet = nullptr; @@ -90,48 +82,38 @@ private: int channel = 0; }; - CompressionMode compression_mode = COMPRESS_RANGE_CODER; - List<Packet> incoming_packets; Packet current_packet; - uint32_t _gen_unique_id() const; void _pop_current_packet(); - - Vector<uint8_t> src_compressor_mem; - Vector<uint8_t> dst_compressor_mem; - - ENetCompressor enet_compressor; - static size_t enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit); - static size_t enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit); - static void enet_compressor_destroy(void *context); - void _setup_compressor(); + bool _poll_server(); + bool _poll_client(); + bool _poll_mesh(); + void _relay(int p_from, int p_to, enet_uint8 p_channel, ENetPacket *p_packet); + void _notify_peers(int p_id, bool p_connected); + void _destroy_unused(ENetPacket *p_packet); + _FORCE_INLINE_ bool _is_active() const { return active_mode != MODE_NONE; } IPAddress bind_ip; - bool dtls_enabled = false; - Ref<CryptoKey> dtls_key; - Ref<X509Certificate> dtls_cert; - bool dtls_verify = true; - protected: static void _bind_methods(); public: + virtual void set_transfer_channel(int p_channel) override; + virtual int get_transfer_channel() const override; + virtual void set_transfer_mode(TransferMode p_mode) override; virtual TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer) override; virtual int get_packet_peer() const override; - virtual IPAddress get_peer_address(int p_peer_id) const; - virtual int get_peer_port(int p_peer_id) const; - virtual int get_local_port() const; - void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max); - - Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0); - Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0); + Error create_server(int p_port, int p_max_clients = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0); + Error create_client(const String &p_address, int p_port, int p_channel_count = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0); + Error create_mesh(int p_id); + Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host); void close_connection(uint32_t wait_usec = 100); @@ -154,32 +136,15 @@ public: virtual int get_unique_id() const override; - void set_compression_mode(CompressionMode p_mode); - CompressionMode get_compression_mode() const; - - int get_packet_channel() const; - int get_last_packet_channel() const; - void set_transfer_channel(int p_channel); - int get_transfer_channel() const; - void set_channel_count(int p_channel); - int get_channel_count() const; - void set_always_ordered(bool p_ordered); - bool is_always_ordered() const; + void set_bind_ip(const IPAddress &p_ip); void set_server_relay_enabled(bool p_enabled); bool is_server_relay_enabled() const; + Ref<ENetConnection> get_host() const; + Ref<ENetPacketPeer> get_peer(int p_id) const; + ENetMultiplayerPeer(); ~ENetMultiplayerPeer(); - - void set_bind_ip(const IPAddress &p_ip); - void set_dtls_enabled(bool p_enabled); - bool is_dtls_enabled() const; - void set_dtls_verify_enabled(bool p_enabled); - bool is_dtls_verify_enabled() const; - void set_dtls_key(Ref<CryptoKey> p_key); - void set_dtls_certificate(Ref<X509Certificate> p_cert); }; -VARIANT_ENUM_CAST(ENetMultiplayerPeer::CompressionMode); - #endif // NETWORKED_MULTIPLAYER_ENET_H diff --git a/modules/enet/enet_packet_peer.cpp b/modules/enet/enet_packet_peer.cpp new file mode 100644 index 0000000000..d7d2ec9ebe --- /dev/null +++ b/modules/enet/enet_packet_peer.cpp @@ -0,0 +1,263 @@ +/*************************************************************************/ +/* enet_packet_peer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "enet_packet_peer.h" + +void ENetPacketPeer::peer_disconnect(int p_data) { + ERR_FAIL_COND(!peer); + enet_peer_disconnect(peer, p_data); +} + +void ENetPacketPeer::peer_disconnect_later(int p_data) { + ERR_FAIL_COND(!peer); + enet_peer_disconnect_later(peer, p_data); +} + +void ENetPacketPeer::peer_disconnect_now(int p_data) { + ERR_FAIL_COND(!peer); + enet_peer_disconnect_now(peer, p_data); + _on_disconnect(); +} + +void ENetPacketPeer::ping() { + ERR_FAIL_COND(!peer); + enet_peer_ping(peer); +} + +void ENetPacketPeer::ping_interval(int p_interval) { + ERR_FAIL_COND(!peer); + enet_peer_ping_interval(peer, p_interval); +} + +int ENetPacketPeer::send(uint8_t p_channel, ENetPacket *p_packet) { + ERR_FAIL_COND_V(peer == nullptr, -1); + ERR_FAIL_COND_V(p_packet == nullptr, -1); + ERR_FAIL_COND_V_MSG(p_channel >= peer->channelCount, -1, vformat("Unable to send packet on channel %d, max channels: %d", p_channel, (int)peer->channelCount)); + return enet_peer_send(peer, p_channel, p_packet); +} + +void ENetPacketPeer::reset() { + ERR_FAIL_COND_MSG(peer == nullptr, "Peer not connected"); + enet_peer_reset(peer); + _on_disconnect(); +} + +void ENetPacketPeer::throttle_configure(int p_interval, int p_acceleration, int p_deceleration) { + ERR_FAIL_COND_MSG(peer == nullptr, "Peer not connected"); + enet_peer_throttle_configure(peer, p_interval, p_acceleration, p_deceleration); +} + +void ENetPacketPeer::set_timeout(int p_timeout, int p_timeout_min, int p_timeout_max) { + ERR_FAIL_COND_MSG(peer == nullptr, "Peer not connected"); + ERR_FAIL_COND_MSG(p_timeout > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout"); + enet_peer_timeout(peer, p_timeout, p_timeout_min, p_timeout_max); +} + +int ENetPacketPeer::get_max_packet_size() const { + return 1 << 24; +} + +int ENetPacketPeer::get_available_packet_count() const { + return packet_queue.size(); +} + +Error ENetPacketPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { + ERR_FAIL_COND_V(!peer, ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!packet_queue.size(), ERR_UNAVAILABLE); + if (last_packet) { + enet_packet_destroy(last_packet); + last_packet = nullptr; + } + last_packet = packet_queue.front()->get(); + packet_queue.pop_front(); + *r_buffer = (const uint8_t *)(last_packet->data); + r_buffer_size = last_packet->dataLength; + return OK; +} + +Error ENetPacketPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(!peer, ERR_UNCONFIGURED); + ENetPacket *packet = enet_packet_create(p_buffer, p_buffer_size, ENET_PACKET_FLAG_RELIABLE); + return send(0, packet) < 0 ? FAILED : OK; +} + +IPAddress ENetPacketPeer::get_remote_address() const { + ERR_FAIL_COND_V(!peer, IPAddress()); + IPAddress out; +#ifdef GODOT_ENET + out.set_ipv6((uint8_t *)&(peer->address.host)); +#else + out.set_ipv4((uint8_t *)&(peer->address.host)); +#endif + return out; +} + +int ENetPacketPeer::get_remote_port() const { + ERR_FAIL_COND_V(!peer, 0); + return peer->address.port; +} + +bool ENetPacketPeer::is_active() const { + return peer != nullptr; +} + +double ENetPacketPeer::get_statistic(PeerStatistic p_stat) { + ERR_FAIL_COND_V(!peer, 0); + switch (p_stat) { + case PEER_PACKET_LOSS: + return peer->packetLoss; + case PEER_PACKET_LOSS_VARIANCE: + return peer->packetLossVariance; + case PEER_PACKET_LOSS_EPOCH: + return peer->packetLossEpoch; + case PEER_ROUND_TRIP_TIME: + return peer->roundTripTime; + case PEER_ROUND_TRIP_TIME_VARIANCE: + return peer->roundTripTimeVariance; + case PEER_LAST_ROUND_TRIP_TIME: + return peer->lastRoundTripTime; + case PEER_LAST_ROUND_TRIP_TIME_VARIANCE: + return peer->lastRoundTripTimeVariance; + case PEER_PACKET_THROTTLE: + return peer->packetThrottle; + case PEER_PACKET_THROTTLE_LIMIT: + return peer->packetThrottleLimit; + case PEER_PACKET_THROTTLE_COUNTER: + return peer->packetThrottleCounter; + case PEER_PACKET_THROTTLE_EPOCH: + return peer->packetThrottleEpoch; + case PEER_PACKET_THROTTLE_ACCELERATION: + return peer->packetThrottleAcceleration; + case PEER_PACKET_THROTTLE_DECELERATION: + return peer->packetThrottleDeceleration; + case PEER_PACKET_THROTTLE_INTERVAL: + return peer->packetThrottleInterval; + } + ERR_FAIL_V(0); +} + +ENetPacketPeer::PeerState ENetPacketPeer::get_state() const { + if (!is_active()) { + return STATE_DISCONNECTED; + } + return (PeerState)peer->state; +} + +int ENetPacketPeer::get_channels() const { + ERR_FAIL_COND_V_MSG(!peer, 0, "The ENetConnection instance isn't currently active."); + return peer->channelCount; +} + +void ENetPacketPeer::_on_disconnect() { + if (peer) { + peer->data = nullptr; + } + peer = nullptr; +} + +void ENetPacketPeer::_queue_packet(ENetPacket *p_packet) { + ERR_FAIL_COND(!peer); + packet_queue.push_back(p_packet); +} + +Error ENetPacketPeer::_send(int p_channel, PackedByteArray p_packet, int p_flags) { + ERR_FAIL_COND_V_MSG(peer == nullptr, ERR_UNCONFIGURED, "Peer not connected"); + ERR_FAIL_COND_V_MSG(p_channel < 0 || p_channel > (int)peer->channelCount, ERR_INVALID_PARAMETER, "Invalid channel"); + ERR_FAIL_COND_V_MSG(p_flags & ~FLAG_ALLOWED, ERR_INVALID_PARAMETER, "Invalid flags"); + ENetPacket *packet = enet_packet_create(p_packet.ptr(), p_packet.size(), p_flags); + return send(p_channel, packet) == 0 ? OK : FAILED; +} + +void ENetPacketPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("peer_disconnect", "data"), &ENetPacketPeer::peer_disconnect, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("peer_disconnect_later", "data"), &ENetPacketPeer::peer_disconnect_later, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("peer_disconnect_now", "data"), &ENetPacketPeer::peer_disconnect_now, DEFVAL(0)); + + ClassDB::bind_method(D_METHOD("ping"), &ENetPacketPeer::ping); + ClassDB::bind_method(D_METHOD("ping_interval", "ping_interval"), &ENetPacketPeer::ping_interval); + ClassDB::bind_method(D_METHOD("reset"), &ENetPacketPeer::reset); + ClassDB::bind_method(D_METHOD("send", "channel", "packet", "flags"), &ENetPacketPeer::_send); + ClassDB::bind_method(D_METHOD("throttle_configure", "interval", "acceleration", "deceleration"), &ENetPacketPeer::throttle_configure); + ClassDB::bind_method(D_METHOD("set_timeout", "timeout", "timeout_min", "timeout_max"), &ENetPacketPeer::set_timeout); + ClassDB::bind_method(D_METHOD("get_statistic", "statistic"), &ENetPacketPeer::get_statistic); + ClassDB::bind_method(D_METHOD("get_state"), &ENetPacketPeer::get_state); + ClassDB::bind_method(D_METHOD("get_channels"), &ENetPacketPeer::get_channels); + ClassDB::bind_method(D_METHOD("is_active"), &ENetPacketPeer::is_active); + + BIND_ENUM_CONSTANT(STATE_DISCONNECTED); + BIND_ENUM_CONSTANT(STATE_CONNECTING); + BIND_ENUM_CONSTANT(STATE_ACKNOWLEDGING_CONNECT); + BIND_ENUM_CONSTANT(STATE_CONNECTION_PENDING); + BIND_ENUM_CONSTANT(STATE_CONNECTION_SUCCEEDED); + BIND_ENUM_CONSTANT(STATE_CONNECTED); + BIND_ENUM_CONSTANT(STATE_DISCONNECT_LATER); + BIND_ENUM_CONSTANT(STATE_DISCONNECTING); + BIND_ENUM_CONSTANT(STATE_ACKNOWLEDGING_DISCONNECT); + BIND_ENUM_CONSTANT(STATE_ZOMBIE); + + BIND_ENUM_CONSTANT(PEER_PACKET_LOSS); + BIND_ENUM_CONSTANT(PEER_PACKET_LOSS_VARIANCE); + BIND_ENUM_CONSTANT(PEER_PACKET_LOSS_EPOCH); + BIND_ENUM_CONSTANT(PEER_ROUND_TRIP_TIME); + BIND_ENUM_CONSTANT(PEER_ROUND_TRIP_TIME_VARIANCE); + BIND_ENUM_CONSTANT(PEER_LAST_ROUND_TRIP_TIME); + BIND_ENUM_CONSTANT(PEER_LAST_ROUND_TRIP_TIME_VARIANCE); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_LIMIT); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_COUNTER); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_EPOCH); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_ACCELERATION); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_DECELERATION); + BIND_ENUM_CONSTANT(PEER_PACKET_THROTTLE_INTERVAL); + + BIND_CONSTANT(PACKET_LOSS_SCALE); + BIND_CONSTANT(PACKET_THROTTLE_SCALE); + + BIND_CONSTANT(FLAG_RELIABLE); + BIND_CONSTANT(FLAG_UNSEQUENCED); + BIND_CONSTANT(FLAG_UNRELIABLE_FRAGMENT); +} + +ENetPacketPeer::ENetPacketPeer(ENetPeer *p_peer) { + peer = p_peer; + peer->data = this; +} + +ENetPacketPeer::~ENetPacketPeer() { + _on_disconnect(); + if (last_packet) { + enet_packet_destroy(last_packet); + last_packet = nullptr; + } + for (List<ENetPacket *>::Element *E = packet_queue.front(); E; E = E->next()) { + enet_packet_destroy(E->get()); + } + packet_queue.clear(); +} diff --git a/modules/enet/enet_packet_peer.h b/modules/enet/enet_packet_peer.h new file mode 100644 index 0000000000..9af004de2f --- /dev/null +++ b/modules/enet/enet_packet_peer.h @@ -0,0 +1,131 @@ +/*************************************************************************/ +/* enet_packet_peer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef ENET_PACKET_PEER_H +#define ENET_PACKET_PEER_H + +#include "core/io/packet_peer.h" + +#include <enet/enet.h> + +class ENetPacketPeer : public PacketPeer { + GDCLASS(ENetPacketPeer, PacketPeer); + +private: + ENetPeer *peer = nullptr; + List<ENetPacket *> packet_queue; + ENetPacket *last_packet = nullptr; + + static void _bind_methods(); + Error _send(int p_channel, PackedByteArray p_packet, int p_flags); + +protected: + friend class ENetConnection; + // Internally used by ENetConnection during service, destroy, etc. + void _on_disconnect(); + void _queue_packet(ENetPacket *p_packet); + +public: + enum { + PACKET_THROTTLE_SCALE = ENET_PEER_PACKET_THROTTLE_SCALE, + PACKET_LOSS_SCALE = ENET_PEER_PACKET_LOSS_SCALE, + }; + + enum { + FLAG_RELIABLE = ENET_PACKET_FLAG_RELIABLE, + FLAG_UNSEQUENCED = ENET_PACKET_FLAG_UNSEQUENCED, + FLAG_UNRELIABLE_FRAGMENT = ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, + FLAG_ALLOWED = ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, + }; + + enum PeerState { + STATE_DISCONNECTED = ENET_PEER_STATE_DISCONNECTED, + STATE_CONNECTING = ENET_PEER_STATE_CONNECTING, + STATE_ACKNOWLEDGING_CONNECT = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT, + STATE_CONNECTION_PENDING = ENET_PEER_STATE_CONNECTION_PENDING, + STATE_CONNECTION_SUCCEEDED = ENET_PEER_STATE_CONNECTION_SUCCEEDED, + STATE_CONNECTED = ENET_PEER_STATE_CONNECTED, + STATE_DISCONNECT_LATER = ENET_PEER_STATE_DISCONNECT_LATER, + STATE_DISCONNECTING = ENET_PEER_STATE_DISCONNECTING, + STATE_ACKNOWLEDGING_DISCONNECT = ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT, + STATE_ZOMBIE = ENET_PEER_STATE_ZOMBIE, + }; + + enum PeerStatistic { + PEER_PACKET_LOSS, + PEER_PACKET_LOSS_VARIANCE, + PEER_PACKET_LOSS_EPOCH, + PEER_ROUND_TRIP_TIME, + PEER_ROUND_TRIP_TIME_VARIANCE, + PEER_LAST_ROUND_TRIP_TIME, + PEER_LAST_ROUND_TRIP_TIME_VARIANCE, + PEER_PACKET_THROTTLE, + PEER_PACKET_THROTTLE_LIMIT, + PEER_PACKET_THROTTLE_COUNTER, + PEER_PACKET_THROTTLE_EPOCH, + PEER_PACKET_THROTTLE_ACCELERATION, + PEER_PACKET_THROTTLE_DECELERATION, + PEER_PACKET_THROTTLE_INTERVAL, + }; + + int get_max_packet_size() const override; + int get_available_packet_count() const override; + Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet + Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + + void peer_disconnect(int p_data = 0); + void peer_disconnect_later(int p_data = 0); + void peer_disconnect_now(int p_data = 0); + + void ping(); + void ping_interval(int p_interval); + void reset(); + int send(uint8_t p_channel, ENetPacket *p_packet); + void throttle_configure(int interval, int acceleration, int deceleration); + void set_timeout(int p_timeout, int p_timeout_min, int p_timeout_max); + double get_statistic(PeerStatistic p_stat); + PeerState get_state() const; + int get_channels() const; + + // Extras + IPAddress get_remote_address() const; + int get_remote_port() const; + + // Used by ENetMultiplayer (TODO use meta? If only they where StringNames) + bool is_active() const; + + ENetPacketPeer(ENetPeer *p_peer); + ~ENetPacketPeer(); +}; + +VARIANT_ENUM_CAST(ENetPacketPeer::PeerState); +VARIANT_ENUM_CAST(ENetPacketPeer::PeerStatistic); + +#endif // ENET_PACKET_PEER_H diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 38870316e4..7570f5b643 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -30,7 +30,9 @@ #include "register_types.h" #include "core/error/error_macros.h" +#include "enet_connection.h" #include "enet_multiplayer_peer.h" +#include "enet_packet_peer.h" static bool enet_ok = false; @@ -42,6 +44,8 @@ void register_enet_types() { } GDREGISTER_CLASS(ENetMultiplayerPeer); + GDREGISTER_VIRTUAL_CLASS(ENetPacketPeer); + GDREGISTER_CLASS(ENetConnection); } void unregister_enet_types() { diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h index 5c16383974..08d38147d5 100644 --- a/modules/fbx/fbx_parser/ByteSwapper.h +++ b/modules/fbx/fbx_parser/ByteSwapper.h @@ -70,7 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Helper class tp perform various byte oder swappings +/** @file Helper class tp perform various byte order swappings (e.g. little to big endian) */ #ifndef BYTE_SWAPPER_H #define BYTE_SWAPPER_H diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp index 89c69d2ee8..92c62e68b5 100644 --- a/modules/fbx/fbx_parser/FBXDocument.cpp +++ b/modules/fbx/fbx_parser/FBXDocument.cpp @@ -198,7 +198,7 @@ ObjectPtr LazyObject::LoadObject() { object.reset(new ModelLimbNode(id, element, doc, name)); } else if (strcmp(classtag.c_str(), "IKEffector") && strcmp(classtag.c_str(), "FKEffector")) { - // FK and IK effectors are not supporte + // FK and IK effectors are not supported. object.reset(new Model(id, element, doc, name)); } } else if (!strncmp(obtype, "Material", length)) { diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml index 4f1530598c..e4c5d34a2c 100644 --- a/modules/gdnative/doc_classes/GDNative.xml +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -8,26 +8,20 @@ </tutorials> <methods> <method name="call_native"> - <return type="Variant"> - </return> - <argument index="0" name="calling_type" type="StringName"> - </argument> - <argument index="1" name="procedure_name" type="StringName"> - </argument> - <argument index="2" name="arguments" type="Array"> - </argument> + <return type="Variant" /> + <argument index="0" name="calling_type" type="StringName" /> + <argument index="1" name="procedure_name" type="StringName" /> + <argument index="2" name="arguments" type="Array" /> <description> </description> </method> <method name="initialize"> - <return type="bool"> - </return> + <return type="bool" /> <description> </description> </method> <method name="terminate"> - <return type="bool"> - </return> + <return type="bool" /> <description> </description> </method> diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml index 05cda05f9f..f84d4e60f3 100644 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -12,15 +12,13 @@ </tutorials> <methods> <method name="get_current_dependencies" qualifiers="const"> - <return type="PackedStringArray"> - </return> + <return type="PackedStringArray" /> <description> Returns paths to all dependency libraries for the current platform and architecture. </description> </method> <method name="get_current_library_path" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the path to the dynamic library file for the current platform and architecture. </description> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index f2e9cac6dc..397d12a3a9 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -8,42 +8,34 @@ </tutorials> <methods> <method name="get_class_documentation" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the documentation string that was previously set with [code]godot_nativescript_set_class_documentation[/code]. </description> </method> <method name="get_method_documentation" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="method" type="StringName"> - </argument> + <return type="String" /> + <argument index="0" name="method" type="StringName" /> <description> Returns the documentation string that was previously set with [code]godot_nativescript_set_method_documentation[/code]. </description> </method> <method name="get_property_documentation" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="path" type="StringName"> - </argument> + <return type="String" /> + <argument index="0" name="path" type="StringName" /> <description> Returns the documentation string that was previously set with [code]godot_nativescript_set_property_documentation[/code]. </description> </method> <method name="get_signal_documentation" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="signal_name" type="StringName"> - </argument> + <return type="String" /> + <argument index="0" name="signal_name" type="StringName" /> <description> Returns the documentation string that was previously set with [code]godot_nativescript_set_signal_documentation[/code]. </description> </method> <method name="new" qualifiers="vararg"> - <return type="Variant"> - </return> + <return type="Variant" /> <description> Constructs a new object of the base type with a script of this type already attached. [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml index 9616101090..8e28187482 100644 --- a/modules/gdnative/doc_classes/PluginScript.xml +++ b/modules/gdnative/doc_classes/PluginScript.xml @@ -8,8 +8,7 @@ </tutorials> <methods> <method name="new" qualifiers="vararg"> - <return type="Variant"> - </return> + <return type="Variant" /> <description> Returns a new instance of the script. </description> diff --git a/modules/gdnative/doc_classes/VideoStreamGDNative.xml b/modules/gdnative/doc_classes/VideoStreamGDNative.xml index 153988bad8..8b1a3210df 100644 --- a/modules/gdnative/doc_classes/VideoStreamGDNative.xml +++ b/modules/gdnative/doc_classes/VideoStreamGDNative.xml @@ -11,17 +11,14 @@ </tutorials> <methods> <method name="get_file"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the video file handled by this [VideoStreamGDNative]. </description> </method> <method name="set_file"> - <return type="void"> - </return> - <argument index="0" name="file" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="file" type="String" /> <description> Sets the video file that this [VideoStreamGDNative] resource handles. The supported extensions depend on the GDNative plugins used to expose video formats. </description> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 1ff591a87f..9445fac1c6 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -129,9 +129,7 @@ void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { config_file->get_section_keys("entry", &entry_key_list); } - for (List<String>::Element *E = entry_key_list.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : entry_key_list) { PropertyInfo prop; prop.type = Variant::STRING; @@ -147,9 +145,7 @@ void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const { config_file->get_section_keys("dependencies", &dependency_key_list); } - for (List<String>::Element *E = dependency_key_list.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : dependency_key_list) { PropertyInfo prop; prop.type = Variant::STRING; @@ -175,9 +171,7 @@ void GDNativeLibrary::set_config_file(Ref<ConfigFile> p_config_file) { p_config_file->get_section_keys("entry", &entry_keys); } - for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : entry_keys) { Vector<String> tags = key.split("."); bool skip = false; @@ -207,9 +201,7 @@ void GDNativeLibrary::set_config_file(Ref<ConfigFile> p_config_file) { p_config_file->get_section_keys("dependencies", &dependency_keys); } - for (List<String>::Element *E = dependency_keys.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : dependency_keys) { Vector<String> tags = key.split("."); bool skip = false; diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp index cfb57137bb..1d75ea206c 100644 --- a/modules/gdnative/gdnative/variant.cpp +++ b/modules/gdnative/gdnative/variant.cpp @@ -915,8 +915,8 @@ void GDAPI godot_variant_get_builtin_method_list(godot_variant_type p_type, godo List<StringName> list; Variant::get_builtin_method_list((Variant::Type)p_type, &list); int i = 0; - for (const List<StringName>::Element *E = list.front(); E; E = E->next()) { - memnew_placement_custom(&r_list[i], StringName, StringName(E->get())); + for (const StringName &E : list) { + memnew_placement_custom(&r_list[i], StringName, StringName(E)); } } @@ -970,8 +970,8 @@ void GDAPI godot_variant_get_member_list(godot_variant_type p_type, godot_string List<StringName> members; Variant::get_member_list((Variant::Type)p_type, &members); int i = 0; - for (const List<StringName>::Element *E = members.front(); E; E = E->next()) { - memnew_placement_custom(&r_list[i++], StringName, StringName(E->get())); + for (const StringName &E : members) { + memnew_placement_custom(&r_list[i++], StringName, StringName(E)); } } @@ -1075,8 +1075,8 @@ void GDAPI godot_variant_get_constants_list(godot_variant_type p_type, godot_str List<StringName> constants; int i = 0; Variant::get_constants_for_type((Variant::Type)p_type, &constants); - for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) { - memnew_placement_custom(&r_list[i++], StringName, StringName(E->get())); + for (const StringName &E : constants) { + memnew_placement_custom(&r_list[i++], StringName, StringName(E)); } } @@ -1227,8 +1227,8 @@ void GDAPI godot_variant_get_utility_function_list(godot_string_name *r_function godot_string_name *func = r_functions; Variant::get_utility_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - memnew_placement_custom(func++, StringName, StringName(E->get())); + for (const StringName &E : functions) { + memnew_placement_custom(func++, StringName, StringName(E)); } } diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index 94e7739ef9..3fb7b9e1cc 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -91,6 +91,8 @@ typedef struct { godot_int (*get_max_packet_size)(const void *); /* This is MultiplayerPeer */ + void (*set_transfer_channel)(void *, godot_int); + godot_int (*get_transfer_channel)(void *); void (*set_transfer_mode)(void *, godot_int); godot_int (*get_transfer_mode)(const void *); // 0 = broadcast, 1 = server, <0 = all but abs(value) diff --git a/modules/gdnative/include/net/godot_webrtc.h b/modules/gdnative/include/net/godot_webrtc.h index 62b7e3c2c5..52006e56ec 100644 --- a/modules/gdnative/include/net/godot_webrtc.h +++ b/modules/gdnative/include/net/godot_webrtc.h @@ -37,8 +37,8 @@ extern "C" { #endif -#define GODOT_NET_WEBRTC_API_MAJOR 3 -#define GODOT_NET_WEBRTC_API_MINOR 2 +#define GODOT_NET_WEBRTC_API_MAJOR 4 +#define GODOT_NET_WEBRTC_API_MINOR 0 /* Library Interface (used to set default GDNative WebRTC implementation */ typedef struct { diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index 477bc9f74d..df0f29277e 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -425,11 +425,11 @@ List<ClassAPI> generate_c_api_classes() { List<EnumAPI> enums; List<StringName> enum_names; ClassDB::get_enum_list(class_name, &enum_names, true); - for (List<StringName>::Element *E = enum_names.front(); E; E = E->next()) { + for (const StringName &E : enum_names) { List<StringName> value_names; EnumAPI enum_api; - enum_api.name = E->get(); - ClassDB::get_enum_constants(class_name, E->get(), &value_names, true); + enum_api.name = E; + ClassDB::get_enum_constants(class_name, E, &value_names, true); for (List<StringName>::Element *val_e = value_names.front(); val_e; val_e = val_e->next()) { int int_val = ClassDB::get_integer_constant(class_name, val_e->get(), nullptr); enum_api.values.push_back(Pair<int, String>(int_val, val_e->get())); @@ -459,8 +459,8 @@ List<ClassAPI> generate_c_builtin_api_types() { List<StringName> utility_functions; Variant::get_utility_function_list(&utility_functions); - for (const List<StringName>::Element *E = utility_functions.front(); E; E = E->next()) { - const StringName &function_name = E->get(); + for (const StringName &E : utility_functions) { + const StringName &function_name = E; MethodAPI function_api; function_api.method_name = function_name; @@ -521,8 +521,8 @@ List<ClassAPI> generate_c_builtin_api_types() { List<StringName> methods; Variant::get_builtin_method_list(type, &methods); - for (const List<StringName>::Element *E = methods.front(); E; E = E->next()) { - const StringName &method_name = E->get(); + for (const StringName &E : methods) { + const StringName &method_name = E; MethodAPI method_api; @@ -578,8 +578,8 @@ List<ClassAPI> generate_c_builtin_api_types() { List<StringName> constants; Variant::get_constants_for_type(type, &constants); - for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) { - const StringName &constant_name = E->get(); + for (const StringName &E : constants) { + const StringName &constant_name = E; ConstantAPI constant_api; constant_api.constant_name = constant_name; @@ -593,8 +593,8 @@ List<ClassAPI> generate_c_builtin_api_types() { List<StringName> members; Variant::get_member_list(type, &members); - for (const List<StringName>::Element *E = members.front(); E; E = E->next()) { - const StringName &member_name = E->get(); + for (const StringName &E : members) { + const StringName &member_name = E; PropertyAPI member_api; member_api.name = member_name; diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index d7943827c2..f3a0e9603f 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -98,10 +98,10 @@ void NativeScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) List<PropertyInfo> info; get_script_property_list(&info); Map<StringName, Variant> values; - for (List<PropertyInfo>::Element *E = info.front(); E; E = E->next()) { + for (const PropertyInfo &E : info) { Variant value; - get_property_default_value(E->get().name, value); - values[E->get().name] = value; + get_property_default_value(E.name, value); + values[E.name] = value; } p_placeholder->update(info, values); diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 8ceba0f339..9908ed4533 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -62,6 +62,16 @@ int MultiplayerPeerGDNative::get_available_packet_count() const { } /* MultiplayerPeer */ +void MultiplayerPeerGDNative::set_transfer_channel(int p_channel) { + ERR_FAIL_COND(interface == nullptr); + return interface->set_transfer_channel(interface->data, p_channel); +} + +int MultiplayerPeerGDNative::get_transfer_channel() const { + ERR_FAIL_COND_V(interface == nullptr, 0); + return interface->get_transfer_channel(interface->data); +} + void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { ERR_FAIL_COND(interface == nullptr); interface->set_transfer_mode(interface->data, (godot_int)p_mode); @@ -113,6 +123,7 @@ MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status } void MultiplayerPeerGDNative::_bind_methods() { + ADD_PROPERTY_DEFAULT("transfer_channel", 0); ADD_PROPERTY_DEFAULT("transfer_mode", TRANSFER_MODE_UNRELIABLE); ADD_PROPERTY_DEFAULT("refuse_new_connections", true); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h index 7c10ab77f7..ab084faae6 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -56,6 +56,8 @@ public: virtual int get_available_packet_count() const override; /* Specific to MultiplayerPeer */ + virtual void set_transfer_channel(int p_channel) override; + virtual int get_transfer_channel() const override; virtual void set_transfer_mode(TransferMode p_mode) override; virtual TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer_id) override; diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 8e5ae29ed9..a41c4f7b19 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -79,9 +79,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty List<String> entry_keys; config->get_section_keys("entry", &entry_keys); - for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : entry_keys) { Vector<String> tags = key.split("."); bool skip = false; @@ -112,9 +110,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty List<String> dependency_keys; config->get_section_keys("dependencies", &dependency_keys); - for (List<String>::Element *E = dependency_keys.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : dependency_keys) { Vector<String> tags = key.split("."); bool skip = false; @@ -149,9 +145,7 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty List<String> entry_keys; config->get_section_keys("entry", &entry_keys); - for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) { - String key = E->get(); - + for (const String &key : entry_keys) { Vector<String> tags = key.split("."); bool skip = false; diff --git a/modules/gdnative/tests/test_variant.h b/modules/gdnative/tests/test_variant.h index 2850036604..c506882283 100644 --- a/modules/gdnative/tests/test_variant.h +++ b/modules/gdnative/tests/test_variant.h @@ -191,8 +191,8 @@ TEST_CASE("[GDNative Variant] Get utility function list") { godot_string_name *cur = c_list; - for (const List<StringName>::Element *E = cpp_list.front(); E; E = E->next()) { - const StringName &cpp_name = E->get(); + for (const StringName &E : cpp_list) { + const StringName &cpp_name = E; StringName *c_name = (StringName *)cur++; CHECK(*c_name == cpp_name); diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 839aa6b3c6..51b3452a3a 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -11,16 +11,11 @@ </tutorials> <methods> <method name="Color8"> - <return type="Color"> - </return> - <argument index="0" name="r8" type="int"> - </argument> - <argument index="1" name="g8" type="int"> - </argument> - <argument index="2" name="b8" type="int"> - </argument> - <argument index="3" name="a8" type="int" default="255"> - </argument> + <return type="Color" /> + <argument index="0" name="r8" type="int" /> + <argument index="1" name="g8" type="int" /> + <argument index="2" name="b8" type="int" /> + <argument index="3" name="a8" type="int" default="255" /> <description> Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255. [code]r8[/code] red channel @@ -33,12 +28,9 @@ </description> </method> <method name="assert"> - <return type="void"> - </return> - <argument index="0" name="condition" type="bool"> - </argument> - <argument index="1" name="message" type="String" default=""""> - </argument> + <return type="void" /> + <argument index="0" name="condition" type="bool" /> + <argument index="1" name="message" type="String" default="""" /> <description> Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users. [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode. @@ -54,10 +46,8 @@ </description> </method> <method name="char"> - <return type="String"> - </return> - <argument index="0" name="char" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="char" type="int" /> <description> Returns a character as a String of the given Unicode code point (which is compatible with ASCII code). [codeblock] @@ -68,12 +58,9 @@ </description> </method> <method name="convert"> - <return type="Variant"> - </return> - <argument index="0" name="what" type="Variant"> - </argument> - <argument index="1" name="type" type="int"> - </argument> + <return type="Variant" /> + <argument index="0" name="what" type="Variant" /> + <argument index="1" name="type" type="int" /> <description> Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values. [codeblock] @@ -87,17 +74,14 @@ </description> </method> <method name="dict2inst"> - <return type="Object"> - </return> - <argument index="0" name="dictionary" type="Dictionary"> - </argument> + <return type="Object" /> + <argument index="0" name="dictionary" type="Dictionary" /> <description> Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing. </description> </method> <method name="get_stack"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of dictionaries representing the current call stack. [codeblock] @@ -117,10 +101,8 @@ </description> </method> <method name="inst2dict"> - <return type="Dictionary"> - </return> - <argument index="0" name="instance" type="Object"> - </argument> + <return type="Dictionary" /> + <argument index="0" name="instance" type="Object" /> <description> Returns the passed instance converted to a dictionary (useful for serializing). [codeblock] @@ -138,10 +120,8 @@ </description> </method> <method name="len"> - <return type="int"> - </return> - <argument index="0" name="var" type="Variant"> - </argument> + <return type="int" /> + <argument index="0" name="var" type="Variant" /> <description> Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc. [b]Note:[/b] Generates a fatal error if Variant can not provide a length. @@ -152,10 +132,8 @@ </description> </method> <method name="load"> - <return type="Resource"> - </return> - <argument index="0" name="path" type="String"> - </argument> + <return type="Resource" /> + <argument index="0" name="path" type="String" /> <description> Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload]. [b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. @@ -168,10 +146,8 @@ </description> </method> <method name="preload"> - <return type="Resource"> - </return> - <argument index="0" name="path" type="String"> - </argument> + <return type="Resource" /> + <argument index="0" name="path" type="String" /> <description> Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load]. [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. @@ -182,15 +158,13 @@ </description> </method> <method name="print_debug" qualifiers="vararg"> - <return type="void"> - </return> + <return type="void" /> <description> Like [method @GlobalScope.print], but prints only when used in debug mode. </description> </method> <method name="print_stack"> - <return type="void"> - </return> + <return type="void" /> <description> Prints a stack track at code location, only works when running with debugger turned on. Output in the console would look something like this: @@ -200,8 +174,7 @@ </description> </method> <method name="range" qualifiers="vararg"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial, final-1, increment). [codeblock] @@ -218,8 +191,7 @@ </description> </method> <method name="str" qualifiers="vararg"> - <return type="String"> - </return> + <return type="String" /> <description> Converts one or more arguments to string in the best way possible. [codeblock] @@ -231,26 +203,26 @@ </description> </method> <method name="type_exists"> - <return type="bool"> - </return> - <argument index="0" name="type" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="type" type="StringName" /> <description> </description> </method> </methods> <constants> <constant name="PI" value="3.14159265358979"> - Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code]. + Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code], or 180 degrees in rotations. </constant> <constant name="TAU" value="6.28318530717959"> - The circle constant, the circumference of the unit circle in radians. + The circle constant, the circumference of the unit circle in radians. This is equivalent to [code]PI * 2[/code], or 360 degrees in rotations. </constant> <constant name="INF" value="inf"> - Positive infinity. For negative infinity, use -INF. + Positive floating-point infinity. This is the result of floating-point division when the divisor is [code]0.0[/code]. For negative infinity, use [code]-INF[/code]. Dividing by [code]-0.0[/code] will result in negative infinity if the numerator is positive, so dividing by [code]0.0[/code] is not the same as dividing by [code]-0.0[/code] (despite [code]0.0 == -0.0[/code] returning [code]true[/code]). + [b]Note:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead. </constant> <constant name="NAN" value="nan"> - "Not a Number", an invalid value. [code]NaN[/code] has special properties, including that it is not equal to itself. It is output by some invalid operations, such as dividing zero by zero. + "Not a Number", an invalid floating-point value. [constant NAN] has special properties, including that it is not equal to itself ([code]NAN == NAN[/code] returns [code]false[/code]). It is output by some invalid operations, such as dividing floating-point [code]0.0[/code] by [code]0.0[/code]. + [b]Note:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead. </constant> </constants> </class> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 631a102130..72738f027a 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -12,15 +12,13 @@ </tutorials> <methods> <method name="get_as_byte_code" qualifiers="const"> - <return type="PackedByteArray"> - </return> + <return type="PackedByteArray" /> <description> Returns byte code for the script source code. </description> </method> <method name="new" qualifiers="vararg"> - <return type="Variant"> - </return> + <return type="Variant" /> <description> Returns a new instance of the script. For example: diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 9a4c22f49f..ed8b0a4690 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -458,8 +458,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color types_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); List<StringName> types; ClassDB::get_class_list(&types); - for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - String n = E->get(); + for (const StringName &E : types) { + String n = E; if (n.begins_with("_")) { n = n.substr(1, n.length()); } @@ -470,8 +470,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color usertype_color = EDITOR_GET("text_editor/highlighting/user_type_color"); List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); - for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { - keywords[String(E->get())] = usertype_color; + for (const StringName &E : global_classes) { + keywords[String(E)] = usertype_color; } /* Autoloads. */ @@ -489,8 +489,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); List<String> core_types; gdscript->get_core_type_words(&core_types); - for (List<String>::Element *E = core_types.front(); E; E = E->next()) { - keywords[E->get()] = basetype_color; + for (const String &E : core_types) { + keywords[E] = basetype_color; } /* Reserved words. */ @@ -498,11 +498,11 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color control_flow_keyword_color = EDITOR_GET("text_editor/highlighting/control_flow_keyword_color"); List<String> keyword_list; gdscript->get_reserved_words(&keyword_list); - for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { - if (gdscript->is_control_flow_keyword(E->get())) { - keywords[E->get()] = control_flow_keyword_color; + for (const String &E : keyword_list) { + if (gdscript->is_control_flow_keyword(E)) { + keywords[E] = control_flow_keyword_color; } else { - keywords[E->get()] = keyword_color; + keywords[E] = keyword_color; } } @@ -510,8 +510,7 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); List<String> comments; gdscript->get_comment_delimiters(&comments); - for (List<String>::Element *E = comments.front(); E; E = E->next()) { - String comment = E->get(); + for (const String &comment : comments) { String beg = comment.get_slice(" ", 0); String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); add_color_region(beg, end, comment_color, end == ""); @@ -521,8 +520,7 @@ void GDScriptSyntaxHighlighter::_update_cache() { const Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); List<String> strings; gdscript->get_string_delimiters(&strings); - for (List<String>::Element *E = strings.front(); E; E = E->next()) { - String string = E->get(); + for (const String &string : strings) { String beg = string.get_slice(" ", 0); String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); add_color_region(beg, end, string_color, end == ""); @@ -536,9 +534,9 @@ void GDScriptSyntaxHighlighter::_update_cache() { if (instance_base != StringName()) { List<PropertyInfo> plist; ClassDB::get_property_list(instance_base, &plist); - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - String name = E->get().name; - if (E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_SUBGROUP) { + for (const PropertyInfo &E : plist) { + String name = E.name; + if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) { continue; } if (name.find("/") != -1) { @@ -549,8 +547,8 @@ void GDScriptSyntaxHighlighter::_update_cache() { List<String> clist; ClassDB::get_integer_constant_list(instance_base, &clist); - for (List<String>::Element *E = clist.front(); E; E = E->next()) { - member_keywords[E->get()] = member_variable_color; + for (const String &E : clist) { + member_keywords[E] = member_variable_color; } } } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index f7113674ec..8957b00a1b 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -291,8 +291,8 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl sptr = sptr->_base; } - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - r_list->push_back(E->get()); + for (const PropertyInfo &E : props) { + r_list->push_back(E); } } @@ -401,8 +401,8 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro values[E->key()] = E->get(); } - for (List<PropertyInfo>::Element *E = members_cache.front(); E; E = E->next()) { - propnames.push_back(E->get()); + for (const PropertyInfo &E : members_cache) { + propnames.push_back(E); } } @@ -861,8 +861,7 @@ Error GDScript::reload(bool p_keep_state) { } } #ifdef DEBUG_ENABLED - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { - const GDScriptWarning &warning = E->get(); + for (const GDScriptWarning &warning : parser.get_warnings()) { if (EngineDebugger::is_active()) { Vector<ScriptLanguage::StackInfo> si; EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si); @@ -1445,8 +1444,8 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const sptr = sptr->_base; } - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - p_properties->push_back(E->get()); + for (const PropertyInfo &E : props) { + p_properties->push_back(E); } } @@ -1644,26 +1643,25 @@ void GDScriptLanguage::init() { List<StringName> class_list; ClassDB::get_class_list(&class_list); - for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { - StringName n = E->get(); + for (const StringName &n : class_list) { String s = String(n); if (s.begins_with("_")) { - n = s.substr(1, s.length()); + s = s.substr(1, s.length()); } - if (globals.has(n)) { + if (globals.has(s)) { continue; } - Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(E->get())); - _add_global(n, nc); + Ref<GDScriptNativeClass> nc = memnew(GDScriptNativeClass(n)); + _add_global(s, nc); } //populate singletons List<Engine::Singleton> singletons; Engine::get_singleton()->get_singletons(&singletons); - for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - _add_global(E->get().name, E->get().ptr); + for (const Engine::Singleton &E : singletons) { + _add_global(E.name, E.ptr); } #ifdef TESTS_ENABLED @@ -1806,10 +1804,10 @@ void GDScriptLanguage::reload_all_scripts() { scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - print_verbose("GDScript: Reloading: " + E->get()->get_path()); - E->get()->load_source_code(E->get()->get_path()); - E->get()->reload(true); + for (Ref<GDScript> &script : scripts) { + print_verbose("GDScript: Reloading: " + script->get_path()); + script->load_source_code(script->get_path()); + script->reload(true); } #endif } @@ -1838,21 +1836,21 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order - for (List<Ref<GDScript>>::Element *E = scripts.front(); E; E = E->next()) { - bool reload = E->get() == p_script || to_reload.has(E->get()->get_base()); + for (Ref<GDScript> &script : scripts) { + bool reload = script == p_script || to_reload.has(script->get_base()); if (!reload) { continue; } - to_reload.insert(E->get(), Map<ObjectID, List<Pair<StringName, Variant>>>()); + to_reload.insert(script, Map<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[E->get()]; + Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script]; - while (E->get()->instances.front()) { - Object *obj = E->get()->instances.front()->get(); + while (script->instances.front()) { + Object *obj = script->instances.front()->get(); //save instance info List<Pair<StringName, Variant>> state; if (obj->get_script_instance()) { @@ -1865,8 +1863,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so //same thing for placeholders #ifdef TOOLS_ENABLED - while (E->get()->placeholders.size()) { - Object *obj = E->get()->placeholders.front()->get()->get_owner(); + while (script->placeholders.size()) { + Object *obj = script->placeholders.front()->get()->get_owner(); //save instance info if (obj->get_script_instance()) { @@ -1876,13 +1874,13 @@ 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 - E->get()->placeholders.erase(E->get()->placeholders.front()->get()); + script->placeholders.erase(script->placeholders.front()->get()); } } #endif - for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get()->pending_reload_state.front(); F; F = F->next()) { + for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = script->pending_reload_state.front(); F; F = F->next()) { map[F->key()] = F->get(); //pending to reload, use this one instead } } @@ -2025,8 +2023,8 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - p_words->push_back(String(E->get())); + for (const StringName &E : functions) { + p_words->push_back(String(E)); } } @@ -2296,8 +2294,8 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S return; } - for (const List<String>::Element *E = parser.get_dependencies().front(); E; E = E->next()) { - p_dependencies->push_back(E->get()); + for (const String &E : parser.get_dependencies()) { + p_dependencies->push_back(E); } } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index e7fb33a6a7..ab37e54cf1 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -115,8 +115,8 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class); ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values); - for (const List<StringName>::Element *E = enum_values.front(); E != nullptr; E = E->next()) { - type.enum_values[E->get()] = ClassDB::get_integer_constant(real_native_name, E->get()); + for (const StringName &E : enum_values) { + type.enum_values[E] = ClassDB::get_integer_constant(real_native_name, E); } return type; @@ -573,8 +573,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.variable->set_datatype(datatype); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.variable->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.variable); + for (GDScriptParser::AnnotationNode *&E : member.variable->annotations) { + E->apply(parser, member.variable); } } break; case GDScriptParser::ClassNode::Member::CONSTANT: { @@ -622,8 +622,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.constant->set_datatype(datatype); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.constant->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.constant); + for (GDScriptParser::AnnotationNode *&E : member.constant->annotations) { + E->apply(parser, member.constant); } } break; case GDScriptParser::ClassNode::Member::SIGNAL: { @@ -641,8 +641,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.signal->set_datatype(signal_type); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.signal->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.signal); + for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { + E->apply(parser, member.signal); } } break; case GDScriptParser::ClassNode::Member::ENUM: { @@ -688,8 +688,8 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas member.m_enum->set_datatype(enum_type); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.m_enum->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.m_enum); + for (GDScriptParser::AnnotationNode *&E : member.m_enum->annotations) { + E->apply(parser, member.m_enum); } } break; case GDScriptParser::ClassNode::Member::FUNCTION: @@ -761,8 +761,8 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { resolve_function_body(member.function); // Apply annotations. - for (List<GDScriptParser::AnnotationNode *>::Element *E = member.function->annotations.front(); E; E = E->next()) { - E->get()->apply(parser, member.function); + for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { + E->apply(parser, member.function); } } @@ -1927,9 +1927,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa Variant::get_constructor_list(builtin_type, &constructors); bool match = false; - for (const List<MethodInfo>::Element *E = constructors.front(); E != nullptr; E = E->next()) { - const MethodInfo &info = E->get(); - + for (const MethodInfo &info : constructors) { if (p_call->arguments.size() < info.arguments.size() - info.default_arguments.size()) { continue; } @@ -2326,8 +2324,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod Variant::construct(base.builtin_type, dummy, nullptr, 0, temp); List<PropertyInfo> properties; dummy.get_property_list(&properties); - for (const List<PropertyInfo>::Element *E = properties.front(); E != nullptr; E = E->next()) { - const PropertyInfo &prop = E->get(); + for (const PropertyInfo &prop : properties) { if (prop.name == name) { p_identifier->set_datatype(type_from_property(prop)); return; @@ -3125,8 +3122,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va GDScriptParser::ClassNode *found = ref->get_parser()->head; // It should be okay to assume this exists, since we have a complete script already. - for (const List<StringName>::Element *E = class_chain.front(); E; E = E->next()) { - found = found->get_member(E->get()).m_class; + for (const StringName &E : class_chain) { + found = found->get_member(E).m_class; } result.class_type = found; @@ -3222,9 +3219,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD List<MethodInfo> methods; dummy.get_method_list(&methods); - for (const List<MethodInfo>::Element *E = methods.front(); E != nullptr; E = E->next()) { - if (E->get().name == p_function) { - return function_signature_from_info(E->get(), r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); + for (const MethodInfo &E : methods) { + if (E.name == p_function) { + return function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg); } } @@ -3321,8 +3318,8 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD r_default_arg_count = p_info.default_arguments.size(); r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0; - for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E != nullptr; E = E->next()) { - r_par_types.push_back(type_from_property(E->get())); + for (const PropertyInfo &E : p_info.arguments) { + r_par_types.push_back(type_from_property(E)); } return true; } @@ -3330,8 +3327,8 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD bool GDScriptAnalyzer::validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call) { List<GDScriptParser::DataType> arg_types; - for (const List<PropertyInfo>::Element *E = p_method.arguments.front(); E != nullptr; E = E->next()) { - arg_types.push_back(type_from_property(E->get())); + for (const PropertyInfo &E : p_method.arguments) { + arg_types.push_back(type_from_property(E)); } return validate_call_arg(arg_types, p_method.default_arguments.size(), (p_method.flags & METHOD_FLAG_VARARG) != 0, p_call); @@ -3658,11 +3655,11 @@ Error GDScriptAnalyzer::resolve_program() { List<String> parser_keys; depended_parsers.get_key_list(&parser_keys); - for (const List<String>::Element *E = parser_keys.front(); E != nullptr; E = E->next()) { - if (depended_parsers[E->get()].is_null()) { + for (const String &E : parser_keys) { + if (depended_parsers[E].is_null()) { return ERR_PARSE_ERROR; } - depended_parsers[E->get()]->raise_status(GDScriptParserRef::FULLY_SOLVED); + depended_parsers[E]->raise_status(GDScriptParserRef::FULLY_SOLVED); } return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR; } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 9ff5a342ec..5958326315 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -1459,8 +1459,8 @@ void GDScriptByteCodeGenerator::write_endfor() { } // Patch break statements. - for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : current_breaks_to_patch.back()->get()) { + patch_jump(E); } current_breaks_to_patch.pop_back(); @@ -1494,8 +1494,8 @@ void GDScriptByteCodeGenerator::write_endwhile() { while_jmp_addrs.pop_back(); // Patch break statements. - for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : current_breaks_to_patch.back()->get()) { + patch_jump(E); } current_breaks_to_patch.pop_back(); } @@ -1506,8 +1506,8 @@ void GDScriptByteCodeGenerator::start_match() { void GDScriptByteCodeGenerator::start_match_branch() { // Patch continue statements. - for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : match_continues_to_patch.back()->get()) { + patch_jump(E); } match_continues_to_patch.pop_back(); // Start a new list for next branch. @@ -1516,8 +1516,8 @@ void GDScriptByteCodeGenerator::start_match_branch() { void GDScriptByteCodeGenerator::end_match() { // Patch continue statements. - for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) { - patch_jump(E->get()); + for (const int &E : match_continues_to_patch.back()->get()) { + patch_jump(E); } match_continues_to_patch.pop_back(); } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index fbe791a109..7c9d08b782 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -981,8 +981,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code assigned = prev_base; // Set back the values into their bases. - for (List<ChainInfo>::Element *E = set_chain.front(); E; E = E->next()) { - const ChainInfo &info = E->get(); + for (const ChainInfo &info : set_chain) { if (!info.is_named) { gen->write_set(info.base, info.key, assigned); if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 79023df284..2e570d5a5b 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -141,8 +141,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li } #ifdef DEBUG_ENABLED if (r_warnings) { - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { - const GDScriptWarning &warn = E->get(); + for (const GDScriptWarning &E : parser.get_warnings()) { + const GDScriptWarning &warn = E; ScriptLanguage::Warning w; w.start_line = warn.start_line; w.end_line = warn.end_line; @@ -157,8 +157,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li #endif if (err) { if (r_errors) { - for (const List<GDScriptParser::ParserError>::Element *E = parser.get_errors().front(); E; E = E->next()) { - const GDScriptParser::ParserError &pe = E->get(); + for (const GDScriptParser::ParserError &E : parser.get_errors()) { + const GDScriptParser::ParserError &pe = E; ScriptLanguage::ScriptError e; e.line = pe.line; e.column = pe.column; @@ -319,9 +319,9 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p List<Pair<StringName, int>> locals; f->debug_get_stack_member_state(*_call_stack[l].line, &locals); - for (List<Pair<StringName, int>>::Element *E = locals.front(); E; E = E->next()) { - p_locals->push_back(E->get().first); - p_values->push_back(_call_stack[l].stack[E->get().second]); + for (const Pair<StringName, int> &E : locals) { + p_locals->push_back(E.first); + p_values->push_back(_call_stack[l].stack[E.second]); } } @@ -421,8 +421,8 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E->get())); + for (const StringName &E : functions) { + p_functions->push_back(GDScriptUtilityFunctions::get_function_info(E)); } // Not really "functions", but show in documentation. @@ -548,7 +548,7 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool int def_args = p_info.arguments.size() - p_info.default_arguments.size(); int i = 0; - for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E; E = E->next()) { + for (const PropertyInfo &E : p_info.arguments) { if (i > 0) { arghint += ", "; } @@ -556,7 +556,7 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool if (i == p_arg_idx) { arghint += String::chr(0xFFFF); } - arghint += E->get().name + ": " + _get_visual_datatype(E->get(), true); + arghint += E.name + ": " + _get_visual_datatype(E, true); if (i - def_args >= 0) { arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string(); @@ -662,11 +662,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a r_result.insert(node.display, node); List<StringName> node_types; ClassDB::get_inheriters_from_class("Node", &node_types); - for (const List<StringName>::Element *E = node_types.front(); E != nullptr; E = E->next()) { - if (!ClassDB::is_class_exposed(E->get())) { + for (const StringName &E : node_types) { + if (!ClassDB::is_class_exposed(E)) { continue; } - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } } @@ -675,9 +675,9 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptCodeCompletionOption> &r_result) { List<StringName> native_types; ClassDB::get_class_list(&native_types); - for (const List<StringName>::Element *E = native_types.front(); E != nullptr; E = E->next()) { - if (ClassDB::is_class_exposed(E->get()) && !Engine::get_singleton()->has_singleton(E->get())) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + for (const StringName &E : native_types) { + if (ClassDB::is_class_exposed(E) && !Engine::get_singleton()->has_singleton(E)) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } } @@ -687,8 +687,8 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio // Native enums from base class List<StringName> enums; ClassDB::get_enum_list(p_context.current_class->base_type.native_type, &enums); - for (const List<StringName>::Element *E = enums.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_ENUM); + for (const StringName &E : enums) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_ENUM); r_result.insert(option.display, option); } } @@ -725,8 +725,8 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio // Global scripts List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); - for (const List<StringName>::Element *E = global_classes.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CLASS); + for (const StringName &E : global_classes) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS); r_result.insert(option.display, option); } @@ -865,8 +865,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (!_static) { List<PropertyInfo> members; scr->get_script_property_list(&members); - for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + for (const PropertyInfo &E : members) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -879,20 +879,20 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> signals; scr->get_script_signal_list(&signals); - for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_SIGNAL); + for (const MethodInfo &E : signals) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_SIGNAL); r_result.insert(option.display, option); } } List<MethodInfo> methods; scr->get_script_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("@")) { + for (const MethodInfo &E : methods) { + if (E.name.begins_with("@")) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -920,22 +920,22 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base if (!p_only_functions) { List<String> constants; ClassDB::get_integer_constant_list(type, &constants); - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + for (const String &E : constants) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); r_result.insert(option.display, option); } if (!_static || Engine::get_singleton()->has_singleton(type)) { List<PropertyInfo> pinfo; ClassDB::get_property_list(type, &pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { + for (const PropertyInfo &E : pinfo) { + if (E.usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { continue; } - if (E->get().name.find("/") != -1) { + if (E.name.find("/") != -1) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -945,12 +945,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> methods; bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize(); ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("_")) { + for (const MethodInfo &E : methods) { + if (E.name.begins_with("_")) { continue; } - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -977,9 +977,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base tmp.get_property_list(&members); } - for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - if (String(E->get().name).find("/") == -1) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_MEMBER); + for (const PropertyInfo &E : members) { + if (String(E.name).find("/") == -1) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_MEMBER); r_result.insert(option.display, option); } } @@ -987,9 +987,9 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base List<MethodInfo> methods; tmp.get_method_list(&methods); - for (const List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name, ScriptCodeCompletionOption::KIND_FUNCTION); - if (E->get().arguments.size()) { + for (const MethodInfo &E : methods) { + ScriptCodeCompletionOption option(E.name, ScriptCodeCompletionOption::KIND_FUNCTION); + if (E.arguments.size()) { option.insert_text += "("; } else { option.insert_text += "()"; @@ -1019,9 +1019,9 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool List<StringName> functions; GDScriptUtilityFunctions::get_function_list(&functions); - for (const List<StringName>::Element *E = functions.front(); E; E = E->next()) { - MethodInfo function = GDScriptUtilityFunctions::get_function_info(E->get()); - ScriptCodeCompletionOption option(String(E->get()), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const StringName &E : functions) { + MethodInfo function = GDScriptUtilityFunctions::get_function_info(E); + ScriptCodeCompletionOption option(String(E), ScriptCodeCompletionOption::KIND_FUNCTION); if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) { option.insert_text += "("; } else { @@ -1768,9 +1768,9 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type); MethodInfo info; if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) { - for (const List<PropertyInfo>::Element *E = info.arguments.front(); E; E = E->next()) { - if (E->get().name == p_identifier) { - r_type = _type_from_property(E->get()); + for (const PropertyInfo &E : info.arguments) { + if (E.name == p_identifier) { + r_type = _type_from_property(E); return true; } } @@ -1932,8 +1932,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext & if (!is_static) { List<PropertyInfo> members; scr->get_script_property_list(&members); - for (const List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { - const PropertyInfo &prop = E->get(); + for (const PropertyInfo &prop : members) { if (prop.name == p_identifier) { r_type = _type_from_property(prop); return true; @@ -2096,8 +2095,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex if (scr.is_valid()) { List<MethodInfo> methods; scr->get_script_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : methods) { if (mi.name == p_method) { r_type = _type_from_property(mi.return_val); return true; @@ -2137,8 +2135,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex List<MethodInfo> methods; tmp.get_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : methods) { if (mi.name == p_method) { r_type = _type_from_property(mi.return_val); return true; @@ -2183,8 +2180,8 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co List<StringName> enum_constants; ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); - for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { - String candidate = class_name + "." + E->get(); + for (const StringName &E : enum_constants) { + String candidate = class_name + "." + E; ScriptCodeCompletionOption option(candidate, ScriptCodeCompletionOption::KIND_ENUM); r_result.insert(option.display, option); } @@ -2228,8 +2225,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (obj) { List<String> options; obj->get_argument_options(p_method, p_argidx, &options); - for (List<String>::Element *F = options.front(); F; F = F->next()) { - ScriptCodeCompletionOption option(F->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const String &F : options) { + ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION); r_result.insert(option.display, option); } } @@ -2250,8 +2247,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; + for (const PropertyInfo &E : props) { + String s = E.name; if (!s.begins_with("autoload/")) { continue; } @@ -2266,8 +2263,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c // Get input actions List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; + for (const PropertyInfo &E : props) { + String s = E.name; if (!s.begins_with("input/")) { continue; } @@ -2291,9 +2288,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<MethodInfo> methods; base.get_method_list(&methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name == p_method) { - r_arghint = _make_arguments_hint(E->get(), p_argidx); + for (const MethodInfo &E : methods) { + if (E.name == p_method) { + r_arghint = _make_arguments_hint(E, p_argidx); return; } } @@ -2340,14 +2337,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors); int i = 0; - for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) { - if (p_argidx >= E->get().arguments.size()) { + for (const MethodInfo &E : constructors) { + if (p_argidx >= E.arguments.size()) { continue; } if (i > 0) { r_arghint += "\n"; } - r_arghint += _make_arguments_hint(E->get(), p_argidx); + r_arghint += _make_arguments_hint(E, p_argidx); i++; } return; @@ -2406,9 +2403,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c case GDScriptParser::COMPLETION_ANNOTATION: { List<MethodInfo> annotations; parser.get_annotation_list(&annotations); - for (const List<MethodInfo>::Element *E = annotations.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get().name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); - if (E->get().arguments.size() > 0) { + for (const MethodInfo &E : annotations) { + ScriptCodeCompletionOption option(E.name.substr(1), ScriptCodeCompletionOption::KIND_PLAIN_TEXT); + if (E.arguments.size() > 0) { option.insert_text += "("; } options.insert(option.display, option); @@ -2426,10 +2423,10 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { List<StringName> constants; Variant::get_constants_for_type(completion_context.builtin_type, &constants); - for (const List<StringName>::Element *E = constants.front(); E != nullptr; E = E->next()) { - ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_CONSTANT); + for (const StringName &E : constants) { + ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CONSTANT); bool valid = false; - Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E->get(), &valid); + Variant default_value = Variant::get_constant_value(completion_context.builtin_type, E, &valid); if (valid) { option.default_value = default_value; } @@ -2606,8 +2603,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<MethodInfo> virtual_methods; ClassDB::get_virtual_methods(class_name, &virtual_methods); - for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - MethodInfo &mi = E->get(); + for (const MethodInfo &mi : virtual_methods) { String method_hint = mi.name; if (method_hint.find(":") != -1) { method_hint = method_hint.get_slice(":", 0); @@ -2656,8 +2652,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<String> opts; p_owner->get_argument_options("get_node", 0, &opts); - for (List<String>::Element *E = opts.front(); E; E = E->next()) { - String opt = E->get().strip_edges(); + for (const String &E : opts) { + String opt = E.strip_edges(); if (opt.is_quoted()) { r_forced = true; String idopt = opt.unquote(); @@ -2799,6 +2795,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co if (base_type.class_type->has_member(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; r_result.location = base_type.class_type->get_member(p_symbol).get_line(); + r_result.class_path = base_type.script_path; return OK; } base_type = base_type.class_type->base_type; @@ -2841,8 +2838,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co List<MethodInfo> virtual_methods; ClassDB::get_virtual_methods(class_name, &virtual_methods, true); - for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - if (E->get().name == p_symbol) { + for (const MethodInfo &E : virtual_methods) { + if (E.name == p_symbol) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; @@ -2860,8 +2857,8 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co List<String> constants; ClassDB::get_integer_constant_list(class_name, &constants, true); - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - if (E->get() == p_symbol) { + for (const String &E : constants) { + if (E == p_symbol) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; r_result.class_name = base_type.native_type; r_result.class_member = p_symbol; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index f300d5a2c9..876c508689 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -94,8 +94,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; - for (const List<StackDebug>::Element *E = stack_debug.front(); E; E = E->next()) { - const StackDebug &sd = E->get(); + for (const StackDebug &sd : stack_debug) { if (sd.line > p_line) { break; } @@ -131,10 +130,10 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String stackpositions.sort(); - for (List<_GDFKCS>::Element *E = stackpositions.front(); E; E = E->next()) { + for (_GDFKCS &E : stackpositions) { Pair<StringName, int> p; - p.first = E->get().id; - p.second = E->get().pos; + p.first = E.id; + p.second = E.pos; r_stackvars->push_back(p); } } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index e103d86b15..466ddb4b10 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -136,8 +136,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 List<StringName>::Element *E = keys.front(); E != nullptr; E = E->next()) { - r_annotations->push_back(valid_annotations[E->get()].info); + for (const StringName &E : keys) { + r_annotations->push_back(valid_annotations[E].info); } } @@ -248,7 +248,7 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_ warning.rightmost_column = p_source->rightmost_column; List<GDScriptWarning>::Element *before = nullptr; - for (List<GDScriptWarning>::Element *E = warnings.front(); E != nullptr; E = E->next()) { + for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { if (E->get().start_line > warning.start_line) { break; } @@ -1332,8 +1332,7 @@ GDScriptParser::AnnotationNode *GDScriptParser::parse_annotation(uint32_t p_vali } void GDScriptParser::clear_unused_annotations() { - for (const List<AnnotationNode *>::Element *E = annotation_stack.front(); E != nullptr; E = E->next()) { - AnnotationNode *annotation = E->get(); + for (const AnnotationNode *annotation : annotation_stack) { push_error(vformat(R"(Annotation "%s" does not precedes a valid target, so it will have no effect.)", annotation->name), annotation); } @@ -1796,8 +1795,8 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() { List<StringName> binds; branch->patterns[0]->binds.get_key_list(&binds); - for (List<StringName>::Element *E = binds.front(); E != nullptr; E = E->next()) { - SuiteNode::Local local(branch->patterns[0]->binds[E->get()], current_function); + for (const StringName &E : binds) { + SuiteNode::Local local(branch->patterns[0]->binds[E], current_function); suite->add_local(local); } } @@ -3618,7 +3617,7 @@ void GDScriptParser::TreePrinter::push_text(const String &p_text) { printed += p_text; } -void GDScriptParser::TreePrinter::print_annotation(AnnotationNode *p_annotation) { +void GDScriptParser::TreePrinter::print_annotation(const AnnotationNode *p_annotation) { push_text(p_annotation->name); push_text(" ("); for (int i = 0; i < p_annotation->arguments.size(); i++) { @@ -3993,8 +3992,8 @@ void GDScriptParser::TreePrinter::print_for(ForNode *p_for) { } void GDScriptParser::TreePrinter::print_function(FunctionNode *p_function, const String &p_context) { - for (const List<AnnotationNode *>::Element *E = p_function->annotations.front(); E != nullptr; E = E->next()) { - print_annotation(E->get()); + for (const AnnotationNode *E : p_function->annotations) { + print_annotation(E); } push_text(p_context); push_text(" "); @@ -4333,8 +4332,8 @@ void GDScriptParser::TreePrinter::print_unary_op(UnaryOpNode *p_unary_op) { } void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { - for (const List<AnnotationNode *>::Element *E = p_variable->annotations.front(); E != nullptr; E = E->next()) { - print_annotation(E->get()); + for (const AnnotationNode *E : p_variable->annotations) { + print_annotation(E); } push_text("Variable "); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 043d87c705..6a227a55e5 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1431,7 +1431,7 @@ public: void push_line(const String &p_line = String()); void push_text(const String &p_text); - void print_annotation(AnnotationNode *p_annotation); + void print_annotation(const AnnotationNode *p_annotation); void print_array(ArrayNode *p_array); void print_assert(AssertNode *p_assert); void print_assignment(AssignmentNode *p_assignment); diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 64c629662c..62531473c3 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -706,8 +706,8 @@ bool GDScriptUtilityFunctions::function_exists(const StringName &p_function) { } void GDScriptUtilityFunctions::get_function_list(List<StringName> *r_functions) { - for (const List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) { - r_functions->push_back(E->get()); + for (const StringName &E : utility_function_name_table) { + r_functions->push_back(E); } } diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index e9a7bf3830..d106b3b541 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -39,8 +39,7 @@ void ExtendGDScriptParser::update_diagnostics() { diagnostics.clear(); const List<ParserError> &errors = get_errors(); - for (const List<ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const ParserError &error = E->get(); + for (const ParserError &error : errors) { lsp::Diagnostic diagnostic; diagnostic.severity = lsp::DiagnosticSeverity::Error; diagnostic.message = error.message; @@ -61,8 +60,7 @@ void ExtendGDScriptParser::update_diagnostics() { } const List<GDScriptWarning> &warnings = get_warnings(); - for (const List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { - const GDScriptWarning &warning = E->get(); + for (const GDScriptWarning &warning : warnings) { lsp::Diagnostic diagnostic; diagnostic.severity = lsp::DiagnosticSeverity::Warning; diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message(); @@ -152,9 +150,9 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } r_symbol.kind = lsp::SymbolKind::Class; r_symbol.deprecated = false; - r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->start_line); - r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_class->start_column); - r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line); + r_symbol.range.start.line = p_class->start_line; + r_symbol.range.start.character = p_class->start_column; + r_symbol.range.end.line = lines.size(); r_symbol.selectionRange.start.line = r_symbol.range.start.line; r_symbol.detail = "class " + r_symbol.name; bool is_root_class = &r_symbol == &class_symbol; @@ -167,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p case ClassNode::Member::VARIABLE: { lsp::DocumentSymbol symbol; symbol.name = m.variable->identifier->name; - symbol.kind = lsp::SymbolKind::Variable; + symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property; symbol.deprecated = false; symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line); symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column); @@ -319,7 +317,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN const String uri = get_uri(); r_symbol.name = p_func->identifier->name; - r_symbol.kind = lsp::SymbolKind::Function; + r_symbol.kind = p_func->is_static ? lsp::SymbolKind::Function : lsp::SymbolKind::Method; r_symbol.detail = "func " + String(p_func->identifier->name) + "("; r_symbol.deprecated = false; r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line); @@ -467,8 +465,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { } String doc; - for (List<String>::Element *E = doc_lines.front(); E; E = E->next()) { - doc += E->get() + "\n"; + for (const String &E : doc_lines) { + doc += E + "\n"; } return doc; } diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 0d1f98778e..b6c48468f5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -128,13 +128,13 @@ Error GDScriptLanguageProtocol::on_client_connected() { peer->connection = tcp_peer; clients.set(next_client_id, peer); next_client_id++; - EditorNode::get_log()->add_message("Connection Taken", EditorLog::MSG_TYPE_EDITOR); + EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR); return OK; } void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) { clients.erase(p_client_id); - EditorNode::get_log()->add_message("Disconnected", EditorLog::MSG_TYPE_EDITOR); + EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR); } String GDScriptLanguageProtocol::process_message(const String &p_text) { diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 55aff618aa..c0013ac23a 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -42,10 +42,12 @@ void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose); ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange); + ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave); ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol); ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol); ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion); ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve); + ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename); ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange); ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens); ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink); @@ -79,6 +81,20 @@ void GDScriptTextDocument::didChange(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::didSave(const Variant &p_param) { + lsp::TextDocumentItem doc = load_document_item(p_param); + Dictionary dict = p_param; + String text = dict["text"]; + + sync_script_content(doc.uri, text); + + /*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); + + Ref<GDScript> script = ResourceLoader::load(path); + script->load_source_code(path); + script->reload(true);*/ +} + lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) { lsp::TextDocumentItem doc; Dictionary params = p_param; @@ -157,8 +173,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { int i = 0; arr.resize(options.size()); - for (const List<ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { - const ScriptCodeCompletionOption &option = E->get(); + for (const ScriptCodeCompletionOption &option : options) { lsp::CompletionItem item; item.label = option.display; item.data = request_data; @@ -216,6 +231,14 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) { return arr; } +Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) { + lsp::TextDocumentPositionParams params; + params.load(p_params); + String new_name = p_params["newName"]; + + return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name); +} + Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { lsp::CompletionItem item; item.load(p_params); @@ -294,8 +317,8 @@ Array GDScriptTextDocument::documentLink(const Dictionary &p_params) { List<lsp::DocumentLink> links; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links); - for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { - ret.push_back(E->get().to_json()); + for (const lsp::DocumentLink &E : links) { + ret.push_back(E.to_json()); } return ret; } @@ -322,8 +345,8 @@ Variant GDScriptTextDocument::hover(const Dictionary &p_params) { Array contents; List<const lsp::DocumentSymbol *> list; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(params, list); - for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { + for (const lsp::DocumentSymbol *&E : list) { + if (const lsp::DocumentSymbol *s = E) { contents.push_back(s->render().value); } } @@ -406,7 +429,11 @@ GDScriptTextDocument::~GDScriptTextDocument() { void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) { String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); + EditorFileSystem::get_singleton()->update_file(path); + Ref<GDScript> script = ResourceLoader::load(path); + script->load_source_code(path); + script->reload(true); } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { @@ -430,8 +457,8 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams & } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { List<const lsp::DocumentSymbol *> list; GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list); - for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { + for (const lsp::DocumentSymbol *&E : list) { + if (const lsp::DocumentSymbol *s = E) { if (!s->uri.is_empty()) { lsp::Location location; location.uri = s->uri; diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index e2987f779c..9021c84a3f 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -45,6 +45,7 @@ protected: void didOpen(const Variant &p_param); void didClose(const Variant &p_param); void didChange(const Variant &p_param); + void didSave(const Variant &p_param); void sync_script_content(const String &p_path, const String &p_content); void show_native_symbol_in_editor(const String &p_symbol_id); @@ -61,6 +62,7 @@ public: Array documentSymbol(const Dictionary &p_params); Array completion(const Dictionary &p_params); Dictionary resolve(const Dictionary &p_params); + Dictionary rename(const Dictionary &p_params); Array foldingRange(const Dictionary &p_params); Array codeLens(const Dictionary &p_params); Array documentLink(const Dictionary &p_params); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 1915c92cbf..148aeec47a 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -116,11 +116,40 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_ return nullptr; } +const lsp::DocumentSymbol *GDScriptWorkspace::get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier) { + for (int i = 0; i < p_parent->children.size(); ++i) { + const lsp::DocumentSymbol *parameter_symbol = &p_parent->children[i]; + if (!parameter_symbol->detail.is_empty() && parameter_symbol->name == symbol_identifier) { + return parameter_symbol; + } + } + + return nullptr; +} + +const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier) { + const lsp::DocumentSymbol *class_symbol = &p_parser->get_symbols(); + + for (int i = 0; i < class_symbol->children.size(); ++i) { + if (class_symbol->children[i].kind == lsp::SymbolKind::Function || class_symbol->children[i].kind == lsp::SymbolKind::Class) { + const lsp::DocumentSymbol *function_symbol = &class_symbol->children[i]; + + for (int l = 0; l < function_symbol->children.size(); ++l) { + const lsp::DocumentSymbol *local = &function_symbol->children[l]; + if (!local->detail.is_empty() && local->name == p_symbol_identifier) { + return local; + } + } + } + } + + return nullptr; +} + void GDScriptWorkspace::reload_all_workspace_scripts() { List<String> paths; list_script_files("res://", paths); - for (List<String>::Element *E = paths.front(); E; E = E->next()) { - const String &path = E->get(); + for (const String &path : paths) { Error err; String content = FileAccess::get_file_as_string(path, &err); ERR_CONTINUE(err != OK); @@ -232,18 +261,13 @@ Error GDScriptWorkspace::initialize() { class_symbol.children.push_back(symbol); } - Vector<DocData::PropertyDoc> properties; - properties.append_array(class_data.properties); - const int theme_prop_start_idx = properties.size(); - properties.append_array(class_data.theme_properties); - for (int i = 0; i < class_data.properties.size(); i++) { const DocData::PropertyDoc &data = class_data.properties[i]; lsp::DocumentSymbol symbol; symbol.name = data.name; symbol.native_class = class_name; symbol.kind = lsp::SymbolKind::Property; - symbol.detail = String(i >= theme_prop_start_idx ? "<Theme> var" : "var") + " " + class_name + "." + data.name; + symbol.detail = "var " + class_name + "." + data.name; if (data.enumeration.length()) { symbol.detail += ": " + data.enumeration; } else { @@ -253,6 +277,17 @@ Error GDScriptWorkspace::initialize() { class_symbol.children.push_back(symbol); } + for (int i = 0; i < class_data.theme_properties.size(); i++) { + const DocData::ThemeItemDoc &data = class_data.theme_properties[i]; + lsp::DocumentSymbol symbol; + symbol.name = data.name; + symbol.native_class = class_name; + symbol.kind = lsp::SymbolKind::Property; + symbol.detail = "<Theme> var " + class_name + "." + data.name + ": " + data.type; + symbol.documentation = data.description; + class_symbol.children.push_back(symbol); + } + Vector<DocData::MethodDoc> methods_signals; methods_signals.append_array(class_data.methods); const int signal_start_idx = methods_signals.size(); @@ -351,6 +386,50 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont return err; } +Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) { + Error err; + String path = get_file_path(p_doc_pos.textDocument.uri); + + lsp::WorkspaceEdit edit; + + List<String> paths; + list_script_files("res://", paths); + + const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos); + if (reference_symbol) { + String identifier = reference_symbol->name; + + for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) { + PackedStringArray content = FileAccess::get_file_as_string(PE->get(), &err).split("\n"); + for (int i = 0; i < content.size(); ++i) { + String line = content[i]; + + int character = line.find(identifier); + while (character > -1) { + lsp::TextDocumentPositionParams params; + + lsp::TextDocumentIdentifier text_doc; + text_doc.uri = get_file_uri(PE->get()); + + params.textDocument = text_doc; + params.position.line = i; + params.position.character = character; + + const lsp::DocumentSymbol *other_symbol = resolve_symbol(params); + + if (other_symbol == reference_symbol) { + edit.add_change(text_doc.uri, i, character, character + identifier.length(), new_name); + } + + character = line.find(identifier, character + 1); + } + } + } + } + + return edit.to_json(); +} + Error GDScriptWorkspace::parse_local_script(const String &p_path) { Error err; String content = FileAccess::get_file_as_string(p_path, &err); @@ -479,10 +558,16 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu String target_script_path = path; if (!ret.script.is_null()) { target_script_path = ret.script->get_path(); + } else if (!ret.class_path.is_empty()) { + target_script_path = ret.class_path; } if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) { symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location)); + + if (symbol && symbol->kind == lsp::SymbolKind::Function && symbol->name != symbol_identifier) { + symbol = get_parameter_symbol(symbol, symbol_identifier); + } } } else { @@ -494,6 +579,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } } else { symbol = parser->get_member_symbol(symbol_identifier); + + if (!symbol) { + symbol = get_local_symbol(parser, symbol_identifier); + } } } } @@ -559,8 +648,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::N void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) { if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) { const List<lsp::DocumentLink> &links = parser->get_document_links(); - for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { - r_list.push_back(E->get()); + for (const lsp::DocumentLink &E : links) { + r_list.push_back(E); } } } @@ -587,8 +676,7 @@ Error GDScriptWorkspace::resolve_signature(const lsp::TextDocumentPositionParams GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(text_pos, symbols); } - for (List<const lsp::DocumentSymbol *>::Element *E = symbols.front(); E; E = E->next()) { - const lsp::DocumentSymbol *symbol = E->get(); + for (const lsp::DocumentSymbol *const &symbol : symbols) { if (symbol->kind == lsp::SymbolKind::Method || symbol->kind == lsp::SymbolKind::Function) { lsp::SignatureInformation signature_info; signature_info.label = symbol->detail; diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 8b166a873c..9496677449 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -52,6 +52,8 @@ protected: 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; + const lsp::DocumentSymbol *get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier); + const lsp::DocumentSymbol *get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier); void reload_all_workspace_scripts(); @@ -90,6 +92,7 @@ public: Dictionary generate_script_api(const String &p_path); Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature); void did_delete_files(const Dictionary &p_params); + Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name); GDScriptWorkspace(); ~GDScriptWorkspace(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index a7dcfdb22d..9ac6c6bd4e 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -255,6 +255,62 @@ struct TextEdit { }; /** + * The edits to be applied. + */ +struct WorkspaceEdit { + /** + * Holds changes to existing resources. + */ + Map<String, Vector<TextEdit>> changes; + + _FORCE_INLINE_ Dictionary to_json() const { + Dictionary dict; + + Dictionary out_changes; + for (Map<String, Vector<TextEdit>>::Element *E = changes.front(); E; E = E->next()) { + Array edits; + for (int i = 0; i < E->get().size(); ++i) { + Dictionary text_edit; + text_edit["range"] = E->get()[i].range.to_json(); + text_edit["newText"] = E->get()[i].newText; + edits.push_back(text_edit); + } + out_changes[E->key()] = edits; + } + dict["changes"] = out_changes; + + return dict; + } + + _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(); + for (int i = 0; i < edit_list.size(); ++i) { + TextEdit edit = edit_list[i]; + if (edit.range.start.character == start_character) { + return; + } + } + } + + TextEdit new_edit; + new_edit.newText = new_text; + new_edit.range.start.line = line; + new_edit.range.start.character = start_character; + 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); + } else { + Vector<TextEdit> edit_list; + edit_list.push_back(new_edit); + changes.insert(uri, edit_list); + } + } +}; + +/** * Represents a reference to a command. * Provides a title which will be used to represent a command in the UI. * Commands are identified by a string identifier. @@ -486,7 +542,7 @@ struct TextDocumentSyncOptions { * If present save notifications are sent to the server. If omitted the notification should not be * sent. */ - bool save = false; + SaveOptions save; Dictionary to_json() { Dictionary dict; @@ -494,7 +550,7 @@ struct TextDocumentSyncOptions { dict["willSave"] = willSave; dict["openClose"] = openClose; dict["change"] = change; - dict["save"] = save; + dict["save"] = save.to_json(); return dict; } }; @@ -1018,32 +1074,32 @@ struct CompletionList { * A symbol kind. */ namespace SymbolKind { -static const int File = 0; -static const int Module = 1; -static const int Namespace = 2; -static const int Package = 3; -static const int Class = 4; -static const int Method = 5; -static const int Property = 6; -static const int Field = 7; -static const int Constructor = 8; -static const int Enum = 9; -static const int Interface = 10; -static const int Function = 11; -static const int Variable = 12; -static const int Constant = 13; -static const int String = 14; -static const int Number = 15; -static const int Boolean = 16; -static const int Array = 17; -static const int Object = 18; -static const int Key = 19; -static const int Null = 20; -static const int EnumMember = 21; -static const int Struct = 22; -static const int Event = 23; -static const int Operator = 24; -static const int TypeParameter = 25; +static const int File = 1; +static const int Module = 2; +static const int Namespace = 3; +static const int Package = 4; +static const int Class = 5; +static const int Method = 6; +static const int Property = 7; +static const int Field = 8; +static const int Constructor = 9; +static const int Enum = 10; +static const int Interface = 11; +static const int Function = 12; +static const int Variable = 13; +static const int Constant = 14; +static const int String = 15; +static const int Number = 16; +static const int Boolean = 17; +static const int Array = 18; +static const int Object = 19; +static const int Key = 20; +static const int Null = 21; +static const int EnumMember = 22; +static const int Struct = 23; +static const int Event = 24; +static const int Operator = 25; +static const int TypeParameter = 26; }; // namespace SymbolKind /** diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index b7faebb4ef..03a48bf071 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -295,7 +295,7 @@ void GDScriptTestRunner::handle_cmdline() { String test_cmd = "--gdscript-test"; String gen_cmd = "--gdscript-generate-tests"; - for (List<String>::Element *E = cmdline_args.front(); E != nullptr; E = E->next()) { + for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { String &cmd = E->get(); if (cmd == test_cmd || cmd == gen_cmd) { if (E->next() == nullptr) { @@ -440,8 +440,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { result.output = get_text_for_status(result.status) + "\n"; const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { - result.output += E->get().message + "\n"; // TODO: line, column? + for (const GDScriptParser::ParserError &E : errors) { + result.output += E.message + "\n"; // TODO: line, column? break; // Only the first error since the following might be cascading. } if (!p_is_generating) { @@ -459,8 +459,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { result.output = get_text_for_status(result.status) + "\n"; const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E; E = E->next()) { - result.output += E->get().message + "\n"; // TODO: line, column? + for (const GDScriptParser::ParserError &E : errors) { + result.output += E.message + "\n"; // TODO: line, column? break; // Only the first error since the following might be cascading. } if (!p_is_generating) { @@ -470,8 +470,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { } StringBuilder warning_string; - for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E != nullptr; E = E->next()) { - const GDScriptWarning warning = E->get(); + for (const GDScriptWarning &E : parser.get_warnings()) { + const GDScriptWarning warning = E; warning_string.append(">> WARNING"); warning_string.append("\n>> Line: "); warning_string.append(itos(warning.start_line)); diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 7aa5895981..52e9d92223 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -113,8 +113,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } } @@ -124,8 +123,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } } @@ -143,8 +141,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con if (err != OK) { print_line("Error in parser:"); const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } return; @@ -156,8 +153,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con if (err != OK) { print_line("Error in analyzer:"); const List<GDScriptParser::ParserError> &errors = parser.get_errors(); - for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { - const GDScriptParser::ParserError &error = E->get(); + for (const GDScriptParser::ParserError &error : errors) { print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); } return; diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 730c6b89f7..dd545ff431 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -193,7 +193,7 @@ void preregister_glslang_types() { // initialize in case it's not initialized. This is done once per thread // and it's safe to call multiple times glslang::InitializeProcess(); - RenderingDevice::shader_set_compile_function(_compile_shader_glsl); + RenderingDevice::shader_set_compile_to_spirv_function(_compile_shader_glsl); RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl); } diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index 40563c9ac6..6e83cec252 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -8,50 +8,40 @@ </tutorials> <methods> <method name="get_bone_attachment"> - <return type="BoneAttachment3D"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="BoneAttachment3D" /> + <argument index="0" name="idx" type="int" /> <description> </description> </method> <method name="get_bone_attachment_count"> - <return type="int"> - </return> + <return type="int" /> <description> </description> </method> <method name="get_godot_bone_node"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> </description> </method> <method name="get_godot_skeleton"> - <return type="Skeleton3D"> - </return> + <return type="Skeleton3D" /> <description> </description> </method> <method name="get_unique_names"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="set_godot_bone_node"> - <return type="void"> - </return> - <argument index="0" name="godot_bone_node" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="godot_bone_node" type="Dictionary" /> <description> </description> </method> <method name="set_unique_names"> - <return type="void"> - </return> - <argument index="0" name="unique_names" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="unique_names" type="Array" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index e20e127e52..107ca960cd 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -8,44 +8,35 @@ </tutorials> <methods> <method name="get_inverse_binds"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_joint_i_to_bone_i"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> </description> </method> <method name="get_joint_i_to_name"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> </description> </method> <method name="set_inverse_binds"> - <return type="void"> - </return> - <argument index="0" name="inverse_binds" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="inverse_binds" type="Array" /> <description> </description> </method> <method name="set_joint_i_to_bone_i"> - <return type="void"> - </return> - <argument index="0" name="joint_i_to_bone_i" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="joint_i_to_bone_i" type="Dictionary" /> <description> </description> </method> <method name="set_joint_i_to_name"> - <return type="void"> - </return> - <argument index="0" name="joint_i_to_name" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="joint_i_to_name" type="Dictionary" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index a7b5b7b43e..ae976fc04c 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -8,236 +8,185 @@ </tutorials> <methods> <method name="get_accessors"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_animation_player"> - <return type="AnimationPlayer"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="AnimationPlayer" /> + <argument index="0" name="idx" type="int" /> <description> </description> </method> <method name="get_animation_players_count"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="idx" type="int" /> <description> </description> </method> <method name="get_animations"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_buffer_views"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_cameras"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_images"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_lights"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_materials"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_meshes"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_nodes"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_scene_node"> - <return type="Node"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="Node" /> + <argument index="0" name="idx" type="int" /> <description> </description> </method> <method name="get_skeleton_to_node"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> </description> </method> <method name="get_skeletons"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_skins"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_textures"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_unique_animation_names"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="get_unique_names"> - <return type="Array"> - </return> + <return type="Array" /> <description> </description> </method> <method name="set_accessors"> - <return type="void"> - </return> - <argument index="0" name="accessors" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="accessors" type="Array" /> <description> </description> </method> <method name="set_animations"> - <return type="void"> - </return> - <argument index="0" name="animations" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="animations" type="Array" /> <description> </description> </method> <method name="set_buffer_views"> - <return type="void"> - </return> - <argument index="0" name="buffer_views" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="buffer_views" type="Array" /> <description> </description> </method> <method name="set_cameras"> - <return type="void"> - </return> - <argument index="0" name="cameras" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="cameras" type="Array" /> <description> </description> </method> <method name="set_images"> - <return type="void"> - </return> - <argument index="0" name="images" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="images" type="Array" /> <description> </description> </method> <method name="set_lights"> - <return type="void"> - </return> - <argument index="0" name="lights" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="lights" type="Array" /> <description> </description> </method> <method name="set_materials"> - <return type="void"> - </return> - <argument index="0" name="materials" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="materials" type="Array" /> <description> </description> </method> <method name="set_meshes"> - <return type="void"> - </return> - <argument index="0" name="meshes" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="meshes" type="Array" /> <description> </description> </method> <method name="set_nodes"> - <return type="void"> - </return> - <argument index="0" name="nodes" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="nodes" type="Array" /> <description> </description> </method> <method name="set_skeleton_to_node"> - <return type="void"> - </return> - <argument index="0" name="skeleton_to_node" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="skeleton_to_node" type="Dictionary" /> <description> </description> </method> <method name="set_skeletons"> - <return type="void"> - </return> - <argument index="0" name="skeletons" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="skeletons" type="Array" /> <description> </description> </method> <method name="set_skins"> - <return type="void"> - </return> - <argument index="0" name="skins" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="skins" type="Array" /> <description> </description> </method> <method name="set_textures"> - <return type="void"> - </return> - <argument index="0" name="textures" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="textures" type="Array" /> <description> </description> </method> <method name="set_unique_animation_names"> - <return type="void"> - </return> - <argument index="0" name="unique_animation_names" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="unique_animation_names" type="Array" /> <description> </description> </method> <method name="set_unique_names"> - <return type="void"> - </return> - <argument index="0" name="unique_names" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="unique_names" type="Array" /> <description> </description> </method> diff --git a/modules/gltf/doc_classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml index a22111e9b7..d0136c6402 100644 --- a/modules/gltf/doc_classes/PackedSceneGLTF.xml +++ b/modules/gltf/doc_classes/PackedSceneGLTF.xml @@ -8,44 +8,29 @@ </tutorials> <methods> <method name="export_gltf"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="node" type="Node"> - </argument> - <argument index="1" name="path" type="String"> - </argument> - <argument index="2" name="flags" type="int" default="0"> - </argument> - <argument index="3" name="bake_fps" type="float" default="1000.0"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="node" type="Node" /> + <argument index="1" name="path" type="String" /> + <argument index="2" name="flags" type="int" default="0" /> + <argument index="3" name="bake_fps" type="float" default="1000.0" /> <description> </description> </method> <method name="import_gltf_scene"> - <return type="Node"> - </return> - <argument index="0" name="path" type="String"> - </argument> - <argument index="1" name="flags" type="int" default="0"> - </argument> - <argument index="2" name="bake_fps" type="float" default="1000.0"> - </argument> - <argument index="3" name="state" type="GLTFState" default="null"> - </argument> + <return type="Node" /> + <argument index="0" name="path" type="String" /> + <argument index="1" name="flags" type="int" default="0" /> + <argument index="2" name="bake_fps" type="float" default="1000.0" /> + <argument index="3" name="state" type="GLTFState" default="null" /> <description> </description> </method> <method name="pack_gltf"> - <return type="void"> - </return> - <argument index="0" name="path" type="String"> - </argument> - <argument index="1" name="flags" type="int" default="0"> - </argument> - <argument index="2" name="bake_fps" type="float" default="1000.0"> - </argument> - <argument index="3" name="state" type="GLTFState" default="null"> - </argument> + <return type="void" /> + <argument index="0" name="path" type="String" /> + <argument index="1" name="flags" type="int" default="0" /> + <argument index="2" name="bake_fps" type="float" default="1000.0" /> + <argument index="3" name="state" type="GLTFState" default="null" /> <description> </description> </method> diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 09bae884b9..be44f66423 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -2796,7 +2796,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { mat = mat3d; } - import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat->get_name()); + import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat.is_valid() ? mat->get_name() : String()); } Vector<float> blend_weights; @@ -3002,24 +3002,31 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat Ref<Image> img; + // First we honor the mime types if they were defined. if (mimetype == "image/png") { // Load buffer as PNG. ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE); img = Image::_png_mem_loader_func(data_ptr, data_size); } else if (mimetype == "image/jpeg") { // Loader buffer as JPEG. ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE); img = Image::_jpg_mem_loader_func(data_ptr, data_size); - } else { - // We can land here if we got an URI with base64-encoded data with application/* MIME type, - // and the optional mimeType property was not defined to tell us how to handle this data (or was invalid). - // So let's try PNG first, then JPEG. + } + + // If we didn't pass the above tests, we attempt loading as PNG and then + // JPEG directly. + // This covers URIs with base64-encoded data with application/* type but + // no optional mimeType property, or bufferViews with a bogus mimeType + // (e.g. `image/jpeg` but the data is actually PNG). + // That's not *exactly* what the spec mandates but this lets us be + // lenient with bogus glb files which do exist in production. + if (img.is_null()) { // Try PNG first. ERR_FAIL_COND_V(Image::_png_mem_loader_func == nullptr, ERR_UNAVAILABLE); img = Image::_png_mem_loader_func(data_ptr, data_size); - if (img.is_null()) { - ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE); - img = Image::_jpg_mem_loader_func(data_ptr, data_size); - } } - + if (img.is_null()) { // And then JPEG. + ERR_FAIL_COND_V(Image::_jpg_mem_loader_func == nullptr, ERR_UNAVAILABLE); + img = Image::_jpg_mem_loader_func(data_ptr, data_size); + } + // Now we've done our best, fix your scenes. if (img.is_null()) { ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype)); state->images.push_back(Ref<Texture2D>()); @@ -5531,7 +5538,10 @@ struct EditorSceneImporterGLTFInterpolate<Quaternion> { template <class T> T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { ERR_FAIL_COND_V(!p_values.size(), T()); - ERR_FAIL_COND_V(p_times.size() != p_values.size(), p_values[0]); + if (p_times.size() != p_values.size()) { + ERR_PRINT_ONCE("The interpolated values are not corresponding to its times."); + return p_values[0]; + } //could use binary search, worth it? int idx = -1; for (int i = 0; i < p_times.size(); i++) { diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index a2c8e8eabf..8ea7384658 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -17,119 +17,93 @@ </tutorials> <methods> <method name="clear"> - <return type="void"> - </return> + <return type="void" /> <description> Clear all cells. </description> </method> <method name="clear_baked_meshes"> - <return type="void"> - </return> + <return type="void" /> <description> </description> </method> <method name="get_bake_mesh_instance"> - <return type="RID"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="RID" /> + <argument index="0" name="idx" type="int" /> <description> </description> </method> <method name="get_bake_meshes"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap. </description> </method> <method name="get_cell_item" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="position" type="Vector3i"> - </argument> + <return type="int" /> + <argument index="0" name="position" type="Vector3i" /> <description> The [MeshLibrary] item index located at the given grid coordinates. If the cell is empty, [constant INVALID_CELL_ITEM] will be returned. </description> </method> <method name="get_cell_item_orientation" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="position" type="Vector3i"> - </argument> + <return type="int" /> + <argument index="0" name="position" type="Vector3i" /> <description> The orientation of the cell at the given grid coordinates. [code]-1[/code] is returned if the cell is empty. </description> </method> <method name="get_collision_layer_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="bit" type="int" /> <description> Returns an individual bit on the [member collision_layer]. </description> </method> <method name="get_collision_mask_bit" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="bit" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="bit" type="int" /> <description> Returns an individual bit on the [member collision_mask]. </description> </method> <method name="get_meshes"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. </description> </method> <method name="get_used_cells" qualifiers="const"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of [Vector3] with the non-empty cell coordinates in the grid map. </description> </method> <method name="make_baked_meshes"> - <return type="void"> - </return> - <argument index="0" name="gen_lightmap_uv" type="bool" default="false"> - </argument> - <argument index="1" name="lightmap_uv_texel_size" type="float" default="0.1"> - </argument> + <return type="void" /> + <argument index="0" name="gen_lightmap_uv" type="bool" default="false" /> + <argument index="1" name="lightmap_uv_texel_size" type="float" default="0.1" /> <description> </description> </method> <method name="map_to_world" qualifiers="const"> - <return type="Vector3"> - </return> - <argument index="0" name="map_position" type="Vector3i"> - </argument> + <return type="Vector3" /> + <argument index="0" name="map_position" type="Vector3i" /> <description> Returns the position of a grid cell in the GridMap's local coordinate space. </description> </method> <method name="resource_changed"> - <return type="void"> - </return> - <argument index="0" name="resource" type="Resource"> - </argument> + <return type="void" /> + <argument index="0" name="resource" type="Resource" /> <description> </description> </method> <method name="set_cell_item"> - <return type="void"> - </return> - <argument index="0" name="position" type="Vector3i"> - </argument> - <argument index="1" name="item" type="int"> - </argument> - <argument index="2" name="orientation" type="int" default="0"> - </argument> + <return type="void" /> + <argument index="0" name="position" type="Vector3i" /> + <argument index="1" name="item" type="int" /> + <argument index="2" name="orientation" type="int" default="0" /> <description> Sets the mesh index for the cell referenced by its grid coordinates. A negative item index such as [constant INVALID_CELL_ITEM] will clear the cell. @@ -137,46 +111,33 @@ </description> </method> <method name="set_clip"> - <return type="void"> - </return> - <argument index="0" name="enabled" type="bool"> - </argument> - <argument index="1" name="clipabove" type="bool" default="true"> - </argument> - <argument index="2" name="floor" type="int" default="0"> - </argument> - <argument index="3" name="axis" type="int" enum="Vector3.Axis" default="0"> - </argument> + <return type="void" /> + <argument index="0" name="enabled" type="bool" /> + <argument index="1" name="clipabove" type="bool" default="true" /> + <argument index="2" name="floor" type="int" default="0" /> + <argument index="3" name="axis" type="int" enum="Vector3.Axis" default="0" /> <description> </description> </method> <method name="set_collision_layer_bit"> - <return type="void"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="bit" type="int" /> + <argument index="1" name="value" type="bool" /> <description> Sets an individual bit on the [member collision_layer]. </description> </method> <method name="set_collision_mask_bit"> - <return type="void"> - </return> - <argument index="0" name="bit" type="int"> - </argument> - <argument index="1" name="value" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="bit" type="int" /> + <argument index="1" name="value" type="bool" /> <description> Sets an individual bit on the [member collision_mask]. </description> </method> <method name="world_to_map" qualifiers="const"> - <return type="Vector3i"> - </return> - <argument index="0" name="world_position" type="Vector3"> - </argument> + <return type="Vector3i" /> + <argument index="0" name="world_position" type="Vector3" /> <description> Returns the coordinates of the grid cell containing the given point. [code]pos[/code] should be in the GridMap's local coordinate space. @@ -223,8 +184,7 @@ </members> <signals> <signal name="cell_size_changed"> - <argument index="0" name="cell_size" type="Vector3"> - </argument> + <argument index="0" name="cell_size" type="Vector3" /> <description> Emitted when [member cell_size] changes. </description> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 0cd41133f1..fea513c820 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -519,14 +519,14 @@ bool GridMap::_octant_update(const OctantKey &p_key) { RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid()); int idx = 0; - for (List<Pair<Transform3D, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) { - RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first); + for (const Pair<Transform3D, IndexKey> &F : E->get()) { + RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F.first); #ifdef TOOLS_ENABLED Octant::MultimeshInstance::Item it; it.index = idx; - it.transform = F->get().first; - it.key = F->get().second; + it.transform = F.first; + it.key = F.second; mmi.items.push_back(it); #endif diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 046f8c0adb..f101c43e89 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -497,8 +497,8 @@ void GridMapEditor::_fill_selection() { } void GridMapEditor::_clear_clipboard_data() { - for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) { - RenderingServer::get_singleton()->free(E->get().instance); + for (const ClipboardItem &E : clipboard_items) { + RenderingServer::get_singleton()->free(E.instance); } clipboard_items.clear(); @@ -552,9 +552,7 @@ void GridMapEditor::_update_paste_indicator() { RenderingServer::get_singleton()->instance_set_transform(paste_instance, node->get_global_transform() * xf); - for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) { - ClipboardItem &item = E->get(); - + for (const ClipboardItem &item : clipboard_items) { xf = Transform3D(); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); xf.basis = rot * xf.basis; @@ -578,9 +576,7 @@ void GridMapEditor::_do_paste() { Vector3 ofs = paste_indicator.current - paste_indicator.click; undo_redo->create_action(TTR("GridMap Paste Selection")); - for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) { - ClipboardItem &item = E->get(); - + for (const ClipboardItem &item : clipboard_items) { Vector3 position = rot.xform(item.grid_offset) + paste_indicator.begin + ofs; Basis orm; @@ -663,8 +659,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) { if (set_items.size()) { undo_redo->create_action(TTR("GridMap Paint")); - for (List<SetItem>::Element *E = set_items.front(); E; E = E->next()) { - const SetItem &si = E->get(); + for (const SetItem &si : set_items) { undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation); } for (List<SetItem>::Element *E = set_items.back(); E; E = E->prev()) { @@ -680,7 +675,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In } if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) { - undo_redo->create_action("GridMap Selection"); + undo_redo->create_action(TTR("GridMap Selection")); undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end); undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end); undo_redo->commit_action(); @@ -869,8 +864,8 @@ void GridMapEditor::update_palette() { int item = 0; - for (List<_CGMEItemSort>::Element *E = il.front(); E; E = E->next()) { - int id = E->get().id; + for (_CGMEItemSort &E : il) { + int id = E.id; String name = mesh_library->get_item_name(id); Ref<Texture2D> preview = mesh_library->get_item_preview(id); diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index b75cf6502e..fe941e25e7 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -794,7 +794,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); - RID rasterize_shader = rd->shader_create_from_bytecode(raster_shader->get_bytecode()); + RID rasterize_shader = rd->shader_create_from_spirv(raster_shader->get_spirv_stages()); ERR_FAIL_COND_V(rasterize_shader.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //this is a bug check, though, should not happen @@ -945,27 +945,27 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // Unoccluder - RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude")); + RID compute_shader_unocclude = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("unocclude")); ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude); // Direct light - RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary")); + RID compute_shader_primary = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("primary")); ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary); // Indirect light - RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary")); + RID compute_shader_secondary = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("secondary")); ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary); // Dilate - RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate")); + RID compute_shader_dilate = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("dilate")); ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate); // Light probes - RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes")); + RID compute_shader_light_probes = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("light_probes")); ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes); @@ -1506,11 +1506,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d } ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); - RID blendseams_line_raster_shader = rd->shader_create_from_bytecode(blendseams_shader->get_bytecode("lines")); + RID blendseams_line_raster_shader = rd->shader_create_from_spirv(blendseams_shader->get_spirv_stages("lines")); ERR_FAIL_COND_V(blendseams_line_raster_shader.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); - RID blendseams_triangle_raster_shader = rd->shader_create_from_bytecode(blendseams_shader->get_bytecode("triangles")); + RID blendseams_triangle_raster_shader = rd->shader_create_from_spirv(blendseams_shader->get_spirv_stages("triangles")); ERR_FAIL_COND_V(blendseams_triangle_raster_shader.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); diff --git a/modules/mono/.editorconfig b/modules/mono/.editorconfig new file mode 100644 index 0000000000..c9dcd7724e --- /dev/null +++ b/modules/mono/.editorconfig @@ -0,0 +1,14 @@ +[*.sln] +indent_style = tab + +[*.{csproj,props,targets,nuspec,resx}] +indent_style = space +indent_size = 2 + +[*.cs] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 120 +csharp_indent_case_contents_when_block = false diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 25193a1352..0da06131af 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -50,8 +50,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { //must be alphabetically sorted for hash to compute names.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - ClassDB::ClassInfo *t = ClassDB::classes.getptr(E->get()); + for (const StringName &E : names) { + ClassDB::ClassInfo *t = ClassDB::classes.getptr(E); ERR_FAIL_COND(!t); if (t->api != p_api || !t->exposed) { continue; @@ -84,11 +84,11 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array methods; - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + for (const StringName &F : snames) { Dictionary method_dict; methods.push_back(method_dict); - MethodBind *mb = t->method_map[F->get()]; + MethodBind *mb = t->method_map[F]; method_dict["name"] = mb->get_name(); method_dict["argument_count"] = mb->get_argument_count(); method_dict["return_type"] = mb->get_argument_type(-1); @@ -141,12 +141,12 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array constants; - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + for (const StringName &F : snames) { Dictionary constant_dict; constants.push_back(constant_dict); - constant_dict["name"] = F->get(); - constant_dict["value"] = t->constant_map[F->get()]; + constant_dict["name"] = F; + constant_dict["value"] = t->constant_map[F]; } if (!constants.is_empty()) { @@ -168,12 +168,12 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array signals; - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + for (const StringName &F : snames) { Dictionary signal_dict; signals.push_back(signal_dict); - MethodInfo &mi = t->signal_map[F->get()]; - signal_dict["name"] = F->get(); + MethodInfo &mi = t->signal_map[F]; + signal_dict["name"] = F; Array arguments; signal_dict["arguments"] = arguments; @@ -203,13 +203,13 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array properties; - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { + for (const StringName &F : snames) { Dictionary property_dict; properties.push_back(property_dict); - ClassDB::PropertySetGet *psg = t->property_setget.getptr(F->get()); + ClassDB::PropertySetGet *psg = t->property_setget.getptr(F); - property_dict["name"] = F->get(); + property_dict["name"] = F; property_dict["setter"] = psg->setter; property_dict["getter"] = psg->getter; } @@ -222,15 +222,15 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { Array property_list; //property list - for (List<PropertyInfo>::Element *F = t->property_list.front(); F; F = F->next()) { + for (const PropertyInfo &F : t->property_list) { Dictionary property_dict; property_list.push_back(property_dict); - property_dict["name"] = F->get().name; - property_dict["type"] = F->get().type; - property_dict["hint"] = F->get().hint; - property_dict["hint_string"] = F->get().hint_string; - property_dict["usage"] = F->get().usage; + property_dict["name"] = F.name; + property_dict["type"] = F.type; + property_dict["hint"] = F.hint; + property_dict["hint_string"] = F.hint_string; + property_dict["usage"] = F.usage; } if (!property_list.is_empty()) { diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 80675feb3b..520262c0eb 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -145,8 +145,8 @@ void CSharpLanguage::finalize() { finalizing = true; // Make sure all script binding gchandles are released before finalizing GDMono - for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { - CSharpScriptBinding &script_binding = E->value(); + for (KeyValue<Object *, CSharpScriptBinding> &E : script_bindings) { + CSharpScriptBinding &script_binding = E.value; if (!script_binding.gchandle.is_released()) { script_binding.gchandle.release(); @@ -163,8 +163,8 @@ void CSharpLanguage::finalize() { script_bindings.clear(); #ifdef DEBUG_ENABLED - for (Map<ObjectID, int>::Element *E = unsafe_object_references.front(); E; E = E->next()) { - const ObjectID &id = E->key(); + for (const KeyValue<ObjectID, int> &E : unsafe_object_references) { + const ObjectID &id = E.key; Object *obj = ObjectDB::get_instance(id); if (obj) { @@ -864,8 +864,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // We need to keep reference instances alive during reloading List<Ref<RefCounted>> rc_instances; - for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { - CSharpScriptBinding &script_binding = E->value(); + for (const KeyValue<Object *, CSharpScriptBinding> &E : script_bindings) { + const CSharpScriptBinding &script_binding = E.value; RefCounted *rc = Object::cast_to<RefCounted>(script_binding.owner); if (rc) { rc_instances.push_back(Ref<RefCounted>(rc)); @@ -874,8 +874,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // As scripts are going to be reloaded, must proceed without locking here - for (List<Ref<CSharpScript>>::Element *E = scripts.front(); E; E = E->next()) { - Ref<CSharpScript> &script = E->get(); + for (Ref<CSharpScript> &script : scripts) { + // If someone removes a script from a node, deletes the script, builds, adds a script to the + // same node, then builds again, the script might have no path and also no script_class. In + // that case, we can't (and don't need to) reload it. + if (script->get_path().is_empty() && !script->script_class) { + continue; + } to_reload.push_back(script); @@ -887,8 +892,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 (Set<Object *>::Element *F = script->instances.front(); F; F = F->next()) { - Object *obj = F->get(); + for (Object *&obj : script->instances) { script->pending_reload_instances.insert(obj->get_instance_id()); RefCounted *rc = Object::cast_to<RefCounted>(obj); @@ -898,8 +902,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { } #ifdef TOOLS_ENABLED - for (Set<PlaceHolderScriptInstance *>::Element *F = script->placeholders.front(); F; F = F->next()) { - Object *obj = F->get()->get_owner(); + for (PlaceHolderScriptInstance *&script_instance : script->placeholders) { + Object *obj = script_instance->get_owner(); script->pending_reload_instances.insert(obj->get_instance_id()); RefCounted *rc = Object::cast_to<RefCounted>(obj); @@ -912,9 +916,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { // Save state and remove script from instances Map<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state; - for (Set<Object *>::Element *F = script->instances.front(); F; F = F->next()) { - Object *obj = F->get(); - + for (Object *&obj : script->instances) { ERR_CONTINUE(!obj->get_script_instance()); CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance()); @@ -936,9 +938,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { } // After the state of all instances is saved, clear scripts and script instances - for (List<Ref<CSharpScript>>::Element *E = scripts.front(); E; E = E->next()) { - Ref<CSharpScript> &script = E->get(); - + for (Ref<CSharpScript> &script : scripts) { while (script->instances.front()) { Object *obj = script->instances.front()->get(); obj->set_script(REF()); // Remove script and existing script instances (placeholder are not removed before domain reload) @@ -951,11 +951,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { if (gdmono->reload_scripts_domain() != OK) { // Failed to reload the scripts domain // Make sure to add the scripts back to their owners before returning - for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) { - Ref<CSharpScript> scr = E->get(); - - for (const Map<ObjectID, CSharpScript::StateBackup>::Element *F = scr->pending_reload_state.front(); F; F = F->next()) { - Object *obj = ObjectDB::get_instance(F->key()); + for (Ref<CSharpScript> &scr : to_reload) { + for (const KeyValue<ObjectID, CSharpScript::StateBackup> &F : scr->pending_reload_state) { + Object *obj = ObjectDB::get_instance(F.key); if (!obj) { continue; @@ -975,8 +973,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { #endif // Restore Variant properties state, it will be kept by the placeholder until the next script reloading - for (List<Pair<StringName, Variant>>::Element *G = scr->pending_reload_state[obj_id].properties.front(); G; G = G->next()) { - placeholder->property_set_fallback(G->get().first, G->get().second, nullptr); + for (const Pair<StringName, Variant> &G : scr->pending_reload_state[obj_id].properties) { + placeholder->property_set_fallback(G.first, G.second, nullptr); } scr->pending_reload_state.erase(obj_id); @@ -988,9 +986,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { List<Ref<CSharpScript>> to_reload_state; - for (List<Ref<CSharpScript>>::Element *E = to_reload.front(); E; E = E->next()) { - Ref<CSharpScript> script = E->get(); - + for (Ref<CSharpScript> &script : to_reload) { #ifdef TOOLS_ENABLED script->exports_invalidated = true; #endif @@ -1043,8 +1039,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { StringName native_name = NATIVE_GDMONOCLASS_NAME(script->native); { - for (Set<ObjectID>::Element *F = script->pending_reload_instances.front(); F; F = F->next()) { - ObjectID obj_id = F->get(); + for (const ObjectID &obj_id : script->pending_reload_instances) { Object *obj = ObjectDB::get_instance(obj_id); if (!obj) { @@ -1095,11 +1090,8 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { to_reload_state.push_back(script); } - for (List<Ref<CSharpScript>>::Element *E = to_reload_state.front(); E; E = E->next()) { - Ref<CSharpScript> script = E->get(); - - for (Set<ObjectID>::Element *F = script->pending_reload_instances.front(); F; F = F->next()) { - ObjectID obj_id = F->get(); + for (Ref<CSharpScript> &script : to_reload_state) { + for (const ObjectID &obj_id : script->pending_reload_instances) { Object *obj = ObjectDB::get_instance(obj_id); if (!obj) { @@ -1113,16 +1105,16 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id]; - for (List<Pair<StringName, Variant>>::Element *G = state_backup.properties.front(); G; G = G->next()) { - obj->get_script_instance()->set(G->get().first, G->get().second); + for (const Pair<StringName, Variant> &G : state_backup.properties) { + obj->get_script_instance()->set(G.first, G.second); } CSharpInstance *csi = CAST_CSHARP_INSTANCE(obj->get_script_instance()); if (csi) { - for (List<Pair<StringName, Array>>::Element *G = state_backup.event_signals.front(); G; G = G->next()) { - const StringName &name = G->get().first; - const Array &serialized_data = G->get().second; + for (const Pair<StringName, Array> &G : state_backup.event_signals) { + const StringName &name = G.first; + const Array &serialized_data = G.second; Map<StringName, CSharpScript::EventSignal>::Element *match = script->event_signals.find(name); @@ -1166,9 +1158,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { { MutexLock lock(ManagedCallable::instances_mutex); - for (Map<ManagedCallable *, Array>::Element *elem = ManagedCallable::instances_pending_reload.front(); elem; elem = elem->next()) { - ManagedCallable *managed_callable = elem->key(); - const Array &serialized_data = elem->value(); + for (const KeyValue<ManagedCallable *, Array> &elem : ManagedCallable::instances_pending_reload) { + ManagedCallable *managed_callable = elem.key; + const Array &serialized_data = elem.value; MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data); MonoDelegate *delegate = nullptr; @@ -1312,8 +1304,8 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) { } void CSharpLanguage::_on_scripts_domain_unloaded() { - for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { - CSharpScriptBinding &script_binding = E->value(); + for (KeyValue<Object *, CSharpScriptBinding> &E : script_bindings) { + CSharpScriptBinding &script_binding = E.value; script_binding.gchandle.release(); script_binding.inited = false; } @@ -1738,12 +1730,12 @@ bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const { } void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state) { - List<PropertyInfo> pinfo; - get_property_list(&pinfo); + List<PropertyInfo> property_list; + get_property_list(&property_list); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { + for (const PropertyInfo &prop_info : property_list) { Pair<StringName, Variant> state_pair; - state_pair.first = E->get().name; + state_pair.first = prop_info.name; ManagedType managedType; @@ -1766,8 +1758,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, MonoObject *owner_managed = get_mono_object(); ERR_FAIL_NULL(owner_managed); - for (const Map<StringName, CSharpScript::EventSignal>::Element *E = script->event_signals.front(); E; E = E->next()) { - const CSharpScript::EventSignal &event_signal = E->value(); + for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) { + const CSharpScript::EventSignal &event_signal = E.value; MonoDelegate *delegate_field_value = (MonoDelegate *)event_signal.field->get_value(owner_managed); if (!delegate_field_value) { @@ -1794,8 +1786,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, } void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const { - for (Map<StringName, PropertyInfo>::Element *E = script->member_info.front(); E; E = E->next()) { - p_properties->push_back(E->value()); + for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) { + p_properties->push_back(E.value); } // Call _get_property_list @@ -2034,8 +2026,8 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f } void CSharpInstance::connect_event_signals() { - for (const Map<StringName, CSharpScript::EventSignal>::Element *E = script->event_signals.front(); E; E = E->next()) { - const CSharpScript::EventSignal &event_signal = E->value(); + for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) { + const CSharpScript::EventSignal &event_signal = E.value; StringName signal_name = event_signal.field->get_name(); @@ -2049,8 +2041,7 @@ void CSharpInstance::connect_event_signals() { } void CSharpInstance::disconnect_event_signals() { - for (const List<Callable>::Element *E = connected_event_signals.front(); E; E = E->next()) { - const Callable &callable = E->get(); + for (const Callable &callable : connected_event_signals) { const EventSignalCallable *event_signal_callable = static_cast<const EventSignalCallable *>(callable.get_custom()); owner->disconnect(event_signal_callable->get_signal(), callable); } @@ -2320,12 +2311,12 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List base_cache->_update_exports_values(values, propnames); } - for (Map<StringName, Variant>::Element *E = exported_members_defval_cache.front(); E; E = E->next()) { - values[E->key()] = E->get(); + for (const KeyValue<StringName, Variant> &E : exported_members_defval_cache) { + values[E.key] = E.value; } - for (List<PropertyInfo>::Element *E = exported_members_cache.front(); E; E = E->next()) { - propnames.push_back(E->get()); + for (const PropertyInfo &prop_info : exported_members_cache) { + propnames.push_back(prop_info); } } @@ -2556,8 +2547,8 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda _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 *&script_instance : placeholders) { + script_instance->update(propnames, values); } } else { p_instance_to_update->update(propnames, values); @@ -3389,11 +3380,11 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const { } void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { - for (const Map<StringName, Vector<SignalParameter>>::Element *E = _signals.front(); E; E = E->next()) { + for (const KeyValue<StringName, Vector<SignalParameter>> &E : _signals) { MethodInfo mi; - mi.name = E->key(); + mi.name = E.key; - const Vector<SignalParameter> ¶ms = E->value(); + const Vector<SignalParameter> ¶ms = E.value; for (int i = 0; i < params.size(); i++) { const SignalParameter ¶m = params[i]; @@ -3408,11 +3399,11 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const { r_signals->push_back(mi); } - for (const Map<StringName, EventSignal>::Element *E = event_signals.front(); E; E = E->next()) { + for (const KeyValue<StringName, EventSignal> &E : event_signals) { MethodInfo mi; - mi.name = E->key(); + mi.name = E.key; - const EventSignal &event_signal = E->value(); + const EventSignal &event_signal = E.value; const Vector<SignalParameter> ¶ms = event_signal.parameters; for (int i = 0; i < params.size(); i++) { const SignalParameter ¶m = params[i]; @@ -3452,8 +3443,8 @@ Ref<Script> CSharpScript::get_base_script() const { } void CSharpScript::get_script_property_list(List<PropertyInfo> *p_list) const { - for (Map<StringName, PropertyInfo>::Element *E = member_info.front(); E; E = E->next()) { - p_list->push_back(E->value()); + for (const KeyValue<StringName, PropertyInfo> &E : member_info) { + p_list->push_back(E.value); } } @@ -3536,8 +3527,8 @@ CSharpScript::~CSharpScript() { void CSharpScript::get_members(Set<StringName> *p_members) { #if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED) if (p_members) { - for (Set<StringName>::Element *E = exported_members_names.front(); E; E = E->next()) { - p_members->insert(E->get()); + for (const StringName &member_name : exported_members_names) { + p_members->insert(member_name); } } #endif diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj index 224d7e5b5a..11d8e0f72b 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj @@ -15,8 +15,9 @@ <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl> <PackageLicenseExpression>MIT</PackageLicenseExpression> - <GeneratePackageOnBuild>true</GeneratePackageOnBuild> <!-- Generates a package at build --> - <IncludeBuildOutput>false</IncludeBuildOutput> <!-- Do not include the generator as a lib dependency --> + <GeneratePackageOnBuild>true</GeneratePackageOnBuild> + <!-- Do not include the generator as a lib dependency --> + <IncludeBuildOutput>false</IncludeBuildOutput> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" /> diff --git a/modules/mono/editor/GodotTools/.gitignore b/modules/mono/editor/GodotTools/.gitignore index 48e2f914d8..a41d1c89b5 100644 --- a/modules/mono/editor/GodotTools/.gitignore +++ b/modules/mono/editor/GodotTools/.gitignore @@ -353,4 +353,3 @@ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ - diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/Program.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/Program.cs index 4db71500da..450c4bf0cb 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/Program.cs +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/Program.cs @@ -113,8 +113,7 @@ namespace GodotTools.IdeMessaging.CLI } } - ExitMainLoop: - + ExitMainLoop: await forwarder.WriteLineToOutput("Event=Quit"); } diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs index cc0da44a13..284e94810a 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs @@ -150,8 +150,8 @@ EndProject"; {"Tools|Any CPU", "ExportRelease|Any CPU"} }; - var regex = new Regex(string.Join("|",dict.Keys.Select(Regex.Escape))); - var result = regex.Replace(input,m => dict[m.Value]); + var regex = new Regex(string.Join("|", dict.Keys.Select(Regex.Escape))); + var result = regex.Replace(input, m => dict[m.Value]); if (result != input) { diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs index ed69c2b833..897f1b2822 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs @@ -11,6 +11,7 @@ namespace GodotTools.Build { public BuildOutputView BuildOutputView { get; private set; } + private MenuButton buildMenuBtn; private Button errorsBtn; private Button warningsBtn; private Button viewLogBtn; @@ -131,7 +132,7 @@ namespace GodotTools.Build var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill}; AddChild(toolBarHBox); - var buildMenuBtn = new MenuButton {Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons")}; + buildMenuBtn = new MenuButton {Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons")}; toolBarHBox.AddChild(buildMenuBtn); var buildMenu = buildMenuBtn.GetPopup(); @@ -177,5 +178,16 @@ namespace GodotTools.Build BuildOutputView = new BuildOutputView(); AddChild(BuildOutputView); } + + public override void _Notification(int what) + { + base._Notification(what); + + if (what == NotificationThemeChanged) { + buildMenuBtn.Icon = GetThemeIcon("Play", "EditorIcons"); + errorsBtn.Icon = GetThemeIcon("StatusError", "EditorIcons"); + warningsBtn.Icon = GetThemeIcon("NodeWarning", "EditorIcons"); + } + } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index 5bb8d444c2..f69307104f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -577,27 +577,27 @@ MONO_AOT_MODE_LAST = 1000, { case OS.Platforms.Windows: case OS.Platforms.UWP: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"windows-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"windows-{arch}"; + } case OS.Platforms.MacOS: - { - Debug.Assert(bits == null || bits == "64"); - string arch = "x86_64"; - return $"{platform}-{arch}"; - } + { + Debug.Assert(bits == null || bits == "64"); + string arch = "x86_64"; + return $"{platform}-{arch}"; + } case OS.Platforms.LinuxBSD: case OS.Platforms.Server: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"linux-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"linux-{arch}"; + } case OS.Platforms.Haiku: - { - string arch = bits == "64" ? "x86_64" : "i686"; - return $"{platform}-{arch}"; - } + { + string arch = bits == "64" ? "x86_64" : "i686"; + return $"{platform}-{arch}"; + } default: throw new NotSupportedException($"Platform not supported: {platform}"); } diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 270be8b6bf..0b5aa72a81 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -76,9 +76,9 @@ namespace GodotTools.Export GlobalDef("mono/export/aot/use_interpreter", true); // --aot or --aot=opt1,opt2 (use 'mono --aot=help AuxAssembly.dll' to list AOT options) - GlobalDef("mono/export/aot/extra_aot_options", new string[] { }); + GlobalDef("mono/export/aot/extra_aot_options", Array.Empty<string>()); // --optimize/-O=opt1,opt2 (use 'mono --list-opt'' to list optimize options) - GlobalDef("mono/export/aot/extra_optimizer_options", new string[] { }); + GlobalDef("mono/export/aot/extra_optimizer_options", Array.Empty<string>()); GlobalDef("mono/export/aot/android_toolchain_path", ""); } @@ -188,7 +188,7 @@ namespace GodotTools.Export // However, at least in the case of 'WebAssembly.Net.Http' for some reason the BCL assemblies // reference a different version even though the assembly is the same, for some weird reason. - var wasmFrameworkAssemblies = new[] {"WebAssembly.Bindings", "WebAssembly.Net.WebSockets"}; + var wasmFrameworkAssemblies = new[] { "WebAssembly.Bindings", "WebAssembly.Net.WebSockets" }; foreach (string thisWasmFrameworkAssemblyName in wasmFrameworkAssemblies) { @@ -298,8 +298,8 @@ namespace GodotTools.Export LLVMOutputPath = "", FullAot = platform == OS.Platforms.iOS || (bool)(ProjectSettings.GetSetting("mono/export/aot/full_aot") ?? false), UseInterpreter = (bool)ProjectSettings.GetSetting("mono/export/aot/use_interpreter"), - ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ?? new string[] { }, - ExtraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ?? new string[] { }, + ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ?? Array.Empty<string>(), + ExtraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ?? Array.Empty<string>(), ToolchainPath = aotToolchainPath }; @@ -381,7 +381,7 @@ namespace GodotTools.Export private static bool PlatformHasTemplateDir(string platform) { // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest. - return !new[] {OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5}.Contains(platform); + return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform); } private static bool DeterminePlatformFromFeatures(IEnumerable<string> features, out string platform) @@ -430,7 +430,7 @@ namespace GodotTools.Export /// </summary> private static bool PlatformRequiresCustomBcl(string platform) { - if (new[] {OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5}.Contains(platform)) + if (new[] { OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform)) return true; // The 'net_4_x' BCL is not compatible between Windows and the other platforms. diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 3f14629b11..b9aa760f4d 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -3,7 +3,8 @@ <ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid> <TargetFramework>net472</TargetFramework> <LangVersion>7.2</LangVersion> - <GodotApiConfiguration>Debug</GodotApiConfiguration> <!-- The Godot editor uses the Debug Godot API assemblies --> + <!-- The Godot editor uses the Debug Godot API assemblies --> + <GodotApiConfiguration>Debug</GodotApiConfiguration> <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath> <GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir> <GodotApiAssembliesDir>$(GodotOutputDataDir)/Api/$(GodotApiConfiguration)</GodotApiAssembliesDir> diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs index 94fc5da425..821532f759 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs @@ -47,7 +47,7 @@ namespace GodotTools.Ides.Rider GD.PushWarning(e.Message); } - return new RiderInfo[0]; + return Array.Empty<RiderInfo>(); } private static RiderInfo[] CollectAllRiderPathsLinux() @@ -249,7 +249,7 @@ namespace GodotTools.Ides.Rider bool isMac) { if (!Directory.Exists(toolboxRiderRootPath)) - return new string[0]; + return Array.Empty<string>(); var channelDirs = Directory.GetDirectories(toolboxRiderRootPath); var paths = channelDirs.SelectMany(channelDir => @@ -295,7 +295,7 @@ namespace GodotTools.Ides.Rider Logger.Warn($"Failed to get RiderPath from {channelDir}", e); } - return new string[0]; + return Array.Empty<string>(); }) .Where(c => !string.IsNullOrEmpty(c)) .ToArray(); @@ -306,7 +306,7 @@ namespace GodotTools.Ides.Rider { var folder = new DirectoryInfo(Path.Combine(buildDir, dirName)); if (!folder.Exists) - return new string[0]; + return Array.Empty<string>(); if (!isMac) return new[] { Path.Combine(folder.FullName, searchPattern) }.Where(File.Exists).ToArray(); diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs index ed25cdaa63..60dd565ef2 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs @@ -57,7 +57,7 @@ namespace GodotTools.Ides.Rider public static bool IsExternalEditorSetToRider(EditorSettings editorSettings) { - return editorSettings.HasSetting(EditorPathSettingName) && IsRider((string) editorSettings.GetSetting(EditorPathSettingName)); + return editorSettings.HasSetting(EditorPathSettingName) && IsRider((string)editorSettings.GetSetting(EditorPathSettingName)); } public static bool IsRider(string path) diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index e745966435..4624439665 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -74,10 +74,10 @@ namespace GodotTools.Utils } private static readonly IEnumerable<string> LinuxBSDPlatforms = - new[] {Names.Linux, Names.FreeBSD, Names.NetBSD, Names.BSD}; + new[] { Names.Linux, Names.FreeBSD, Names.NetBSD, Names.BSD }; private static readonly IEnumerable<string> UnixLikePlatforms = - new[] {Names.MacOS, Names.Server, Names.Haiku, Names.Android, Names.iOS} + new[] { Names.MacOS, Names.Server, Names.Haiku, Names.Android, Names.iOS } .Concat(LinuxBSDPlatforms).ToArray(); private static readonly Lazy<bool> _isWindows = new Lazy<bool>(() => IsOS(Names.Windows)); @@ -111,13 +111,22 @@ namespace GodotTools.Utils private static string PathWhichWindows([NotNull] string name) { - string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? new string[] { }; + string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? Array.Empty<string>(); string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep); + char[] invalidPathChars = Path.GetInvalidPathChars(); var searchDirs = new List<string>(); if (pathDirs != null) - searchDirs.AddRange(pathDirs); + { + foreach (var pathDir in pathDirs) + { + if (pathDir.IndexOfAny(invalidPathChars) != -1) + continue; + + searchDirs.Add(pathDir); + } + } string nameExt = Path.GetExtension(name); bool hasPathExt = !string.IsNullOrEmpty(nameExt) && windowsExts.Contains(nameExt, StringComparer.OrdinalIgnoreCase); @@ -128,20 +137,29 @@ namespace GodotTools.Utils return searchDirs.Select(dir => Path.Combine(dir, name)).FirstOrDefault(File.Exists); return (from dir in searchDirs - select Path.Combine(dir, name) + select Path.Combine(dir, name) into path - from ext in windowsExts - select path + ext).FirstOrDefault(File.Exists); + from ext in windowsExts + select path + ext).FirstOrDefault(File.Exists); } private static string PathWhichUnix([NotNull] string name) { string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep); + char[] invalidPathChars = Path.GetInvalidPathChars(); var searchDirs = new List<string>(); if (pathDirs != null) - searchDirs.AddRange(pathDirs); + { + foreach (var pathDir in pathDirs) + { + if (pathDir.IndexOfAny(invalidPathChars) != -1) + continue; + + searchDirs.Add(pathDir); + } + } searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list @@ -196,7 +214,7 @@ namespace GodotTools.Utils startInfo.UseShellExecute = false; - using (var process = new Process {StartInfo = startInfo}) + using (var process = new Process { StartInfo = startInfo }) { process.Start(); process.WaitForExit(); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 620b031ddb..632f7d61cc 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -416,8 +416,8 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf // Try to find as global enum constant const EnumInterface *target_ienum = nullptr; - for (const List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { - target_ienum = &E->get(); + for (const EnumInterface &ienum : global_enums) { + target_ienum = &ienum; target_iconst = find_constant_by_name(target_name, target_ienum->constants); if (target_iconst) { break; @@ -455,8 +455,8 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf // Try to find as enum constant in the current class const EnumInterface *target_ienum = nullptr; - for (const List<EnumInterface>::Element *E = target_itype->enums.front(); E; E = E->next()) { - target_ienum = &E->get(); + for (const EnumInterface &ienum : target_itype->enums) { + target_ienum = &ienum; target_iconst = find_constant_by_name(target_name, target_ienum->constants); if (target_iconst) { break; @@ -655,9 +655,7 @@ int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { return 0; } - for (const List<ConstantInterface>::Element *E = p_ienum.constants.front()->next(); E; E = E->next()) { - const ConstantInterface &iconstant = E->get(); - + for (const ConstantInterface &iconstant : p_ienum.constants) { Vector<String> parts = iconstant.name.split("_", /* p_allow_empty: */ true); int i; @@ -682,12 +680,10 @@ int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumInterface &p_ienum, int p_prefix_length) { if (p_prefix_length > 0) { - for (List<ConstantInterface>::Element *E = p_ienum.constants.front(); E; E = E->next()) { + for (ConstantInterface &iconstant : p_ienum.constants) { int curr_prefix_length = p_prefix_length; - ConstantInterface &curr_const = E->get(); - - String constant_name = curr_const.name; + String constant_name = iconstant.name; Vector<String> parts = constant_name.split("_", /* p_allow_empty: */ true); @@ -713,15 +709,13 @@ void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumI constant_name += parts[i]; } - curr_const.proxy_name = snake_to_pascal_case(constant_name, true); + iconstant.proxy_name = snake_to_pascal_case(constant_name, true); } } } void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { - for (const List<MethodInterface>::Element *E = p_itype.methods.front(); E; E = E->next()) { - const MethodInterface &imethod = E->get(); - + for (const MethodInterface &imethod : p_itype.methods) { if (imethod.is_virtual) { continue; } @@ -735,8 +729,8 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { // Get arguments information int i = 0; - for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) { - const TypeInterface *arg_type = _get_type_or_placeholder(F->get().type); + for (const ArgumentInterface &iarg : imethod.arguments) { + const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); im_sig += ", "; im_sig += arg_type->im_type_in; @@ -776,10 +770,10 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { if (p_itype.api_type != ClassDB::API_EDITOR) { match->get().editor_only = false; } - method_icalls_map.insert(&E->get(), &match->get()); + method_icalls_map.insert(&imethod, &match->get()); } else { List<InternalCall>::Element *added = method_icalls.push_back(im_icall); - method_icalls_map.insert(&E->get(), &added->get()); + method_icalls_map.insert(&imethod, &added->get()); } } } @@ -859,9 +853,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK); p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{"); - for (const List<ConstantInterface>::Element *E = global_constants.front(); E; E = E->next()) { - const ConstantInterface &iconstant = E->get(); - + for (const ConstantInterface &iconstant : global_constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), nullptr); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); @@ -894,9 +886,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { // Enums - for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { - const EnumInterface &ienum = E->get(); - + for (const EnumInterface &ienum : global_enums) { CRASH_COND(ienum.constants.is_empty()); String enum_proxy_name = ienum.cname.operator String(); @@ -921,9 +911,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { p_output.append(enum_proxy_name); p_output.append("\n" INDENT1 OPEN_BLOCK); - for (const List<ConstantInterface>::Element *F = ienum.constants.front(); F; F = F->next()) { - const ConstantInterface &iconstant = F->get(); - + const ConstantInterface &last = ienum.constants.back()->get(); + for (const ConstantInterface &iconstant : ienum.constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), nullptr); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); @@ -945,7 +934,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { p_output.append(iconstant.proxy_name); p_output.append(" = "); p_output.append(itos(iconstant.value)); - p_output.append(F != ienum.constants.back() ? ",\n" : "\n"); + p_output.append(&iconstant != &last ? ",\n" : "\n"); } p_output.append(INDENT1 CLOSE_BLOCK); @@ -1053,11 +1042,11 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { cs_icalls_content.append(m_icall.im_sig + ");\n"); \ } - for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next()) { - ADD_INTERNAL_CALL(E->get()); + for (const InternalCall &internal_call : core_custom_icalls) { + ADD_INTERNAL_CALL(internal_call); } - for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) { - ADD_INTERNAL_CALL(E->get()); + for (const InternalCall &internal_call : method_icalls) { + ADD_INTERNAL_CALL(internal_call); } #undef ADD_INTERNAL_CALL @@ -1161,11 +1150,11 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { cs_icalls_content.append(m_icall.im_sig + ");\n"); \ } - for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next()) { - ADD_INTERNAL_CALL(E->get()); + for (const InternalCall &internal_call : editor_custom_icalls) { + ADD_INTERNAL_CALL(internal_call); } - for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) { - ADD_INTERNAL_CALL(E->get()); + for (const InternalCall &internal_call : method_icalls) { + ADD_INTERNAL_CALL(internal_call); } #undef ADD_INTERNAL_CALL @@ -1327,9 +1316,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add constants - for (const List<ConstantInterface>::Element *E = itype.constants.front(); E; E = E->next()) { - const ConstantInterface &iconstant = E->get(); - + for (const ConstantInterface &iconstant : itype.constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); @@ -1360,18 +1347,15 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add enums - for (const List<EnumInterface>::Element *E = itype.enums.front(); E; E = E->next()) { - const EnumInterface &ienum = E->get(); - + for (const EnumInterface &ienum : itype.enums) { ERR_FAIL_COND_V(ienum.constants.is_empty(), ERR_BUG); output.append(MEMBER_BEGIN "public enum "); output.append(ienum.cname.operator String()); output.append(MEMBER_BEGIN OPEN_BLOCK); - for (const List<ConstantInterface>::Element *F = ienum.constants.front(); F; F = F->next()) { - const ConstantInterface &iconstant = F->get(); - + const ConstantInterface &last = ienum.constants.back()->get(); + for (const ConstantInterface &iconstant : ienum.constants) { if (iconstant.const_doc && iconstant.const_doc->description.size()) { String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype); Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>(); @@ -1393,7 +1377,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.append(iconstant.proxy_name); output.append(" = "); output.append(itos(iconstant.value)); - output.append(F != ienum.constants.back() ? ",\n" : "\n"); + output.append(&iconstant != &last ? ",\n" : "\n"); } output.append(INDENT2 CLOSE_BLOCK); @@ -1401,8 +1385,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str // Add properties - for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) { - const PropertyInterface &iprop = E->get(); + for (const PropertyInterface &iprop : itype.properties) { Error prop_err = _generate_cs_property(itype, iprop, output); ERR_FAIL_COND_V_MSG(prop_err != OK, prop_err, "Failed to generate property '" + iprop.cname.operator String() + @@ -1463,15 +1446,13 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str } int method_bind_count = 0; - for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) { - const MethodInterface &imethod = E->get(); + for (const MethodInterface &imethod : itype.methods) { Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output); ERR_FAIL_COND_V_MSG(method_err != OK, method_err, "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'."); } - for (const List<SignalInterface>::Element *E = itype.signals_.front(); E; E = E->next()) { - const SignalInterface &isignal = E->get(); + for (const SignalInterface &isignal : itype.signals_) { Error method_err = _generate_cs_signal(itype, isignal, output); ERR_FAIL_COND_V_MSG(method_err != OK, method_err, "Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'."); @@ -1678,8 +1659,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf StringBuilder default_args_doc; // Retrieve information from the arguments - for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) { - const ArgumentInterface &iarg = F->get(); + const ArgumentInterface &first = p_imethod.arguments.front()->get(); + for (const ArgumentInterface &iarg : p_imethod.arguments) { const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG, @@ -1699,7 +1680,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Add the current arguments to the signature // If the argument has a default value which is not a constant, we will make it Nullable { - if (F != p_imethod.arguments.front()) { + if (&iarg != &first) { arguments_sig += ", "; } @@ -1754,7 +1735,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf cs_in_statements += " : "; } - String def_arg = sformat(iarg.default_argument, arg_type->cs_type); + String cs_type = arg_type->cs_type; + if (cs_type.ends_with("[]")) { + cs_type = cs_type.substr(0, cs_type.length() - 2); + } + + String def_arg = sformat(iarg.default_argument, cs_type); cs_in_statements += def_arg; cs_in_statements += ";\n" INDENT3; @@ -1763,8 +1749,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf // Apparently the name attribute must not include the @ String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name; + // 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 " + def_arg + "</param>"); + 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>"); } else { icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name); } @@ -1855,9 +1843,9 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf p_output.append(p_imethod.name); p_output.append("\""); - for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) { + for (const ArgumentInterface &iarg : p_imethod.arguments) { p_output.append(", "); - p_output.append(F->get().name); + p_output.append(iarg.name); } p_output.append(");\n" CLOSE_BLOCK_L2); @@ -1899,8 +1887,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf String arguments_sig; // Retrieve information from the arguments - for (const List<ArgumentInterface>::Element *F = p_isignal.arguments.front(); F; F = F->next()) { - const ArgumentInterface &iarg = F->get(); + const ArgumentInterface &first = p_isignal.arguments.front()->get(); + for (const ArgumentInterface &iarg : p_isignal.arguments) { const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG, @@ -1914,7 +1902,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf // Add the current arguments to the signature - if (F != p_isignal.arguments.front()) { + if (&iarg != &first) { arguments_sig += ", "; } @@ -2042,8 +2030,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types - for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) { - const MethodInterface &imethod = E->get(); + for (const MethodInterface &imethod : itype.methods) { Error method_err = _generate_glue_method(itype, imethod, output); ERR_FAIL_COND_V_MSG(method_err != OK, method_err, "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'."); @@ -2114,20 +2101,20 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { } bool tools_sequence = false; - for (const List<InternalCall>::Element *E = core_custom_icalls.front(); E; E = E->next()) { + for (const InternalCall &internal_call : core_custom_icalls) { if (tools_sequence) { - if (!E->get().editor_only) { + if (!internal_call.editor_only) { tools_sequence = false; output.append("#endif\n"); } } else { - if (E->get().editor_only) { + if (internal_call.editor_only) { output.append("#ifdef TOOLS_ENABLED\n"); tools_sequence = true; } } - ADD_INTERNAL_CALL_REGISTRATION(E->get()); + ADD_INTERNAL_CALL_REGISTRATION(internal_call); } if (tools_sequence) { @@ -2136,24 +2123,24 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) { } output.append("#ifdef TOOLS_ENABLED\n"); - for (const List<InternalCall>::Element *E = editor_custom_icalls.front(); E; E = E->next()) - ADD_INTERNAL_CALL_REGISTRATION(E->get()); + for (const InternalCall &internal_call : editor_custom_icalls) + ADD_INTERNAL_CALL_REGISTRATION(internal_call); output.append("#endif // TOOLS_ENABLED\n"); - for (const List<InternalCall>::Element *E = method_icalls.front(); E; E = E->next()) { + for (const InternalCall &internal_call : method_icalls) { if (tools_sequence) { - if (!E->get().editor_only) { + if (!internal_call.editor_only) { tools_sequence = false; output.append("#endif\n"); } } else { - if (E->get().editor_only) { + if (internal_call.editor_only) { output.append("#ifdef TOOLS_ENABLED\n"); tools_sequence = true; } } - ADD_INTERNAL_CALL_REGISTRATION(E->get()); + ADD_INTERNAL_CALL_REGISTRATION(internal_call); } if (tools_sequence) { @@ -2209,8 +2196,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte // Get arguments information int i = 0; - for (const List<ArgumentInterface>::Element *F = p_imethod.arguments.front(); F; F = F->next()) { - const ArgumentInterface &iarg = F->get(); + for (const ArgumentInterface &iarg : p_imethod.arguments) { const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type); String c_param_name = "arg" + itos(i + 1); @@ -2623,9 +2609,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { Map<StringName, StringName> accessor_methods; - for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { - const PropertyInfo &property = E->get(); - + for (const PropertyInfo &property : property_list) { if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY) { continue; } @@ -2684,9 +2668,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { ClassDB::get_method_list(type_cname, &method_list, true); method_list.sort(); - for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) { - const MethodInfo &method_info = E->get(); - + for (const MethodInfo &method_info : method_list) { int argc = method_info.arguments.size(); if (method_info.name.is_empty()) { @@ -2840,9 +2822,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { // Classes starting with an underscore are ignored unless they're used as a property setter or getter if (!imethod.is_virtual && imethod.name[0] == '_') { - for (const List<PropertyInterface>::Element *F = itype.properties.front(); F; F = F->next()) { - const PropertyInterface &iprop = F->get(); - + for (const PropertyInterface &iprop : itype.properties) { if (iprop.setter == imethod.name || iprop.getter == imethod.name) { imethod.is_internal = true; itype.methods.push_back(imethod); @@ -2952,8 +2932,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { } EnumInterface ienum(enum_proxy_cname); const List<StringName> &enum_constants = enum_map.get(*k); - for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { - const StringName &constant_cname = E->get(); + for (const StringName &constant_cname : enum_constants) { String constant_name = constant_cname.operator String(); int *value = class_info->constant_map.getptr(constant_cname); ERR_FAIL_NULL_V(value, false); @@ -2989,9 +2968,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() { enum_types.insert(enum_itype.cname, enum_itype); } - for (const List<String>::Element *E = constants.front(); E; E = E->next()) { - const String &constant_name = E->get(); - int *value = class_info->constant_map.getptr(StringName(E->get())); + for (const String &constant_name : constants) { + int *value = class_info->constant_map.getptr(StringName(constant_name)); ERR_FAIL_NULL_V(value, false); ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value); @@ -3099,6 +3077,9 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar r_iarg.default_argument = "null"; break; case Variant::ARRAY: + r_iarg.default_argument = "new %s { }"; + r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; + break; case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: @@ -3108,7 +3089,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: - r_iarg.default_argument = "new %s {}"; + r_iarg.default_argument = "Array.Empty<%s>()"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF; break; case Variant::TRANSFORM2D: { @@ -3539,9 +3520,7 @@ void BindingsGenerator::_populate_global_constants() { } } - for (List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) { - EnumInterface &ienum = E->get(); - + for (EnumInterface &ienum : global_enums) { TypeInterface enum_itype; enum_itype.is_enum = true; enum_itype.name = ienum.cname.operator String(); @@ -3571,13 +3550,13 @@ void BindingsGenerator::_populate_global_constants() { hardcoded_enums.push_back("Vector2i.Axis"); hardcoded_enums.push_back("Vector3.Axis"); hardcoded_enums.push_back("Vector3i.Axis"); - for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) { + for (const StringName &enum_cname : hardcoded_enums) { // These enums are not generated and must be written manually (e.g.: Vector3.Axis) // Here, we assume core types do not begin with underscore TypeInterface enum_itype; enum_itype.is_enum = true; - enum_itype.name = E->get().operator String(); - enum_itype.cname = E->get(); + enum_itype.name = enum_cname.operator String(); + enum_itype.cname = enum_cname; enum_itype.proxy_name = enum_itype.name; TypeInterface::postsetup_enum_type(enum_itype); enum_types.insert(enum_itype.cname, enum_itype); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 48c0e02723..a649181b20 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -357,9 +357,9 @@ class BindingsGenerator { List<SignalInterface> signals_; const MethodInterface *find_method_by_name(const StringName &p_cname) const { - for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().cname == p_cname) { - return &E->get(); + for (const MethodInterface &E : methods) { + if (E.cname == p_cname) { + return &E; } } @@ -367,9 +367,9 @@ class BindingsGenerator { } const PropertyInterface *find_property_by_name(const StringName &p_cname) const { - for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().cname == p_cname) { - return &E->get(); + for (const PropertyInterface &E : properties) { + if (E.cname == p_cname) { + return &E; } } @@ -377,9 +377,9 @@ class BindingsGenerator { } const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const { - for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().proxy_name == p_proxy_name) { - return &E->get(); + for (const PropertyInterface &E : properties) { + if (E.proxy_name == p_proxy_name) { + return &E; } } @@ -387,9 +387,9 @@ class BindingsGenerator { } const MethodInterface *find_method_by_proxy_name(const String &p_proxy_name) const { - for (const List<MethodInterface>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().proxy_name == p_proxy_name) { - return &E->get(); + for (const MethodInterface &E : methods) { + if (E.proxy_name == p_proxy_name) { + return &E; } } @@ -613,9 +613,9 @@ class BindingsGenerator { } const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const { - for (const List<ConstantInterface>::Element *E = p_constants.front(); E; E = E->next()) { - if (E->get().name == p_name) { - return &E->get(); + for (const ConstantInterface &E : p_constants) { + if (E.name == p_name) { + return &E; } } diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index bbfba83e6f..b7b36a92d8 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -109,9 +109,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<PropertyInfo> project_props; ProjectSettings::get_singleton()->get_property_list(&project_props); - for (List<PropertyInfo>::Element *E = project_props.front(); E; E = E->next()) { - const PropertyInfo &prop = E->get(); - + for (const PropertyInfo &prop : project_props) { if (!prop.name.begins_with("input/")) { continue; } @@ -125,8 +123,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr // AutoLoads Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (Map<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))); } } @@ -187,8 +185,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr ClassDB::get_signal_list(native, &signals, /* p_no_inheritance: */ false); } - for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { - const String &signal = E->get().name; + for (const MethodInfo &E : signals) { + const String &signal = E.name; suggestions.push_back(quoted(signal)); } } break; @@ -199,8 +197,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<StringName> sn; Theme::get_default()->get_color_list(base->get_class(), &sn); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - suggestions.push_back(quoted(E->get())); + for (const StringName &E : sn) { + suggestions.push_back(quoted(E)); } } } break; @@ -211,8 +209,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<StringName> sn; Theme::get_default()->get_constant_list(base->get_class(), &sn); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - suggestions.push_back(quoted(E->get())); + for (const StringName &E : sn) { + suggestions.push_back(quoted(E)); } } } break; @@ -223,8 +221,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<StringName> sn; Theme::get_default()->get_font_list(base->get_class(), &sn); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - suggestions.push_back(quoted(E->get())); + for (const StringName &E : sn) { + suggestions.push_back(quoted(E)); } } } break; @@ -235,8 +233,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<StringName> sn; Theme::get_default()->get_font_size_list(base->get_class(), &sn); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - suggestions.push_back(quoted(E->get())); + for (const StringName &E : sn) { + suggestions.push_back(quoted(E)); } } } break; @@ -247,8 +245,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr List<StringName> sn; Theme::get_default()->get_stylebox_list(base->get_class(), &sn); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - suggestions.push_back(quoted(E->get())); + for (const StringName &E : sn) { + suggestions.push_back(quoted(E)); } } } break; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index 2b641a8937..1a3b81487f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -1,16 +1,10 @@ -// file: core/math/aabb.h -// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 -// file: core/math/aabb.cpp -// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0 -// file: core/variant_call.cpp -// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -676,20 +670,12 @@ namespace Godot public override string ToString() { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } public string ToString(string format) { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(format), - _size.ToString(format) - }); + return $"{_position.ToString(format)}, {_size.ToString(format)}"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs index ce613f7ef9..f52a767018 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -25,16 +25,30 @@ namespace Godot.Collections } } + /// <summary> + /// Wrapper around Godot's Array class, an array of Variant + /// typed elements allocated in the engine in C++. Useful when + /// interfacing with the engine. Otherwise prefer .NET collections + /// such as <see cref="System.Array"/> or <see cref="List{T}"/>. + /// </summary> public class Array : IList, IDisposable { ArraySafeHandle safeHandle; bool disposed = false; + /// <summary> + /// Constructs a new empty <see cref="Array"/>. + /// </summary> public Array() { safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor()); } + /// <summary> + /// Constructs a new <see cref="Array"/> from the given collection's elements. + /// </summary> + /// <param name="collection">The collection of elements to construct from.</param> + /// <returns>A new Godot Array.</returns> public Array(IEnumerable collection) : this() { if (collection == null) @@ -44,6 +58,11 @@ namespace Godot.Collections Add(element); } + /// <summary> + /// Constructs a new <see cref="Array"/> from the given objects. + /// </summary> + /// <param name="array">The objects to put in the new array.</param> + /// <returns>A new Godot Array.</returns> public Array(params object[] array) : this() { if (array == null) @@ -71,21 +90,40 @@ namespace Godot.Collections return safeHandle.DangerousGetHandle(); } + /// <summary> + /// Duplicates this <see cref="Array"/>. + /// </summary> + /// <param name="deep">If true, performs a deep copy.</param> + /// <returns>A new Godot Array.</returns> public Array Duplicate(bool deep = false) { return new Array(godot_icall_Array_Duplicate(GetPtr(), deep)); } + /// <summary> + /// Resizes this <see cref="Array"/> to the given size. + /// </summary> + /// <param name="newSize">The new size of the array.</param> + /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns> public Error Resize(int newSize) { return godot_icall_Array_Resize(GetPtr(), newSize); } + /// <summary> + /// Shuffles the contents of this <see cref="Array"/> into a random order. + /// </summary> public void Shuffle() { godot_icall_Array_Shuffle(GetPtr()); } + /// <summary> + /// Concatenates these two <see cref="Array"/>s. + /// </summary> + /// <param name="left">The first array.</param> + /// <param name="right">The second array.</param> + /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array operator +(Array left, Array right) { return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr())); @@ -93,6 +131,9 @@ namespace Godot.Collections // IDisposable + /// <summary> + /// Disposes of this <see cref="Array"/>. + /// </summary> public void Dispose() { if (disposed) @@ -109,38 +150,90 @@ namespace Godot.Collections // IList - public bool IsReadOnly => false; + bool IList.IsReadOnly => false; - public bool IsFixedSize => false; + bool IList.IsFixedSize => false; + /// <summary> + /// Returns the object at the given index. + /// </summary> + /// <value>The object at the given index.</value> public object this[int index] { get => godot_icall_Array_At(GetPtr(), index); set => godot_icall_Array_SetAt(GetPtr(), index, value); } + /// <summary> + /// Adds an object to the end of this <see cref="Array"/>. + /// This is the same as `append` or `push_back` in GDScript. + /// </summary> + /// <param name="value">The object to add.</param> + /// <returns>The new size after adding the object.</returns> public int Add(object value) => godot_icall_Array_Add(GetPtr(), value); + /// <summary> + /// Checks if this <see cref="Array"/> contains the given object. + /// </summary> + /// <param name="value">The item to look for.</param> + /// <returns>Whether or not this array contains the given object.</returns> public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value); + /// <summary> + /// Erases all items from this <see cref="Array"/>. + /// </summary> public void Clear() => godot_icall_Array_Clear(GetPtr()); + /// <summary> + /// Searches this <see cref="Array"/> for an object + /// and returns its index or -1 if not found. + /// </summary> + /// <param name="value">The object to search for.</param> + /// <returns>The index of the object, or -1 if not found.</returns> public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value); + /// <summary> + /// Inserts a new object at a given position in the array. + /// The position must be a valid position of an existing item, + /// or the position at the end of the array. + /// Existing items will be moved to the right. + /// </summary> + /// <param name="index">The index to insert at.</param> + /// <param name="value">The object to insert.</param> public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value); + /// <summary> + /// Removes the first occurrence of the specified value + /// from this <see cref="Array"/>. + /// </summary> + /// <param name="value">The value to remove.</param> public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value); + /// <summary> + /// Removes an element from this <see cref="Array"/> by index. + /// </summary> + /// <param name="index">The index of the element to remove.</param> public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index); // ICollection + /// <summary> + /// Returns the number of elements in this <see cref="Array"/>. + /// This is also known as the size or length of the array. + /// </summary> + /// <returns>The number of elements.</returns> public int Count => godot_icall_Array_Count(GetPtr()); - public object SyncRoot => this; + object ICollection.SyncRoot => this; - public bool IsSynchronized => false; + bool ICollection.IsSynchronized => false; + /// <summary> + /// Copies the elements of this <see cref="Array"/> to the given + /// untyped C# array, starting at the given index. + /// </summary> + /// <param name="array">The array to copy to.</param> + /// <param name="index">The index to start at.</param> public void CopyTo(System.Array array, int index) { if (array == null) @@ -155,6 +248,10 @@ namespace Godot.Collections // IEnumerable + /// <summary> + /// Gets an enumerator for this <see cref="Array"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IEnumerator GetEnumerator() { int count = Count; @@ -165,6 +262,10 @@ namespace Godot.Collections } } + /// <summary> + /// Converts this <see cref="Array"/> to a string. + /// </summary> + /// <returns>A string representation of this array.</returns> public override string ToString() { return godot_icall_Array_ToString(GetPtr()); @@ -234,6 +335,13 @@ namespace Godot.Collections internal extern static string godot_icall_Array_ToString(IntPtr ptr); } + /// <summary> + /// Typed wrapper around Godot's Array class, an array of Variant + /// typed elements allocated in the engine in C++. Useful when + /// interfacing with the engine. Otherwise prefer .NET collections + /// such as arrays or <see cref="List{T}"/>. + /// </summary> + /// <typeparam name="T">The type of the array.</typeparam> public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> { Array objectArray; @@ -246,11 +354,19 @@ namespace Godot.Collections Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass); } + /// <summary> + /// Constructs a new empty <see cref="Array{T}"/>. + /// </summary> public Array() { objectArray = new Array(); } + /// <summary> + /// Constructs a new <see cref="Array{T}"/> from the given collection's elements. + /// </summary> + /// <param name="collection">The collection of elements to construct from.</param> + /// <returns>A new Godot Array.</returns> public Array(IEnumerable<T> collection) { if (collection == null) @@ -259,6 +375,11 @@ namespace Godot.Collections objectArray = new Array(collection); } + /// <summary> + /// Constructs a new <see cref="Array{T}"/> from the given items. + /// </summary> + /// <param name="array">The items to put in the new array.</param> + /// <returns>A new Godot Array.</returns> public Array(params T[] array) : this() { if (array == null) @@ -268,6 +389,10 @@ namespace Godot.Collections objectArray = new Array(array); } + /// <summary> + /// Constructs a typed <see cref="Array{T}"/> from an untyped <see cref="Array"/>. + /// </summary> + /// <param name="array">The untyped array to construct from.</param> public Array(Array array) { objectArray = array; @@ -288,26 +413,49 @@ namespace Godot.Collections return objectArray.GetPtr(); } + /// <summary> + /// Converts this typed <see cref="Array{T}"/> to an untyped <see cref="Array"/>. + /// </summary> + /// <param name="from">The typed array to convert.</param> public static explicit operator Array(Array<T> from) { return from.objectArray; } + /// <summary> + /// Duplicates this <see cref="Array{T}"/>. + /// </summary> + /// <param name="deep">If true, performs a deep copy.</param> + /// <returns>A new Godot Array.</returns> public Array<T> Duplicate(bool deep = false) { return new Array<T>(objectArray.Duplicate(deep)); } + /// <summary> + /// Resizes this <see cref="Array{T}"/> to the given size. + /// </summary> + /// <param name="newSize">The new size of the array.</param> + /// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns> public Error Resize(int newSize) { return objectArray.Resize(newSize); } + /// <summary> + /// Shuffles the contents of this <see cref="Array{T}"/> into a random order. + /// </summary> public void Shuffle() { objectArray.Shuffle(); } + /// <summary> + /// Concatenates these two <see cref="Array{T}"/>s. + /// </summary> + /// <param name="left">The first array.</param> + /// <param name="right">The second array.</param> + /// <returns>A new Godot Array with the contents of both arrays.</returns> public static Array<T> operator +(Array<T> left, Array<T> right) { return new Array<T>(left.objectArray + right.objectArray); @@ -315,22 +463,44 @@ namespace Godot.Collections // IList<T> + /// <summary> + /// Returns the value at the given index. + /// </summary> + /// <value>The value at the given index.</value> public T this[int index] { get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); } set { objectArray[index] = value; } } + /// <summary> + /// Searches this <see cref="Array{T}"/> for an item + /// and returns its index or -1 if not found. + /// </summary> + /// <param name="item">The item to search for.</param> + /// <returns>The index of the item, or -1 if not found.</returns> public int IndexOf(T item) { return objectArray.IndexOf(item); } + /// <summary> + /// Inserts a new item at a given position in the <see cref="Array{T}"/>. + /// The position must be a valid position of an existing item, + /// or the position at the end of the array. + /// Existing items will be moved to the right. + /// </summary> + /// <param name="index">The index to insert at.</param> + /// <param name="item">The item to insert.</param> public void Insert(int index, T item) { objectArray.Insert(index, item); } + /// <summary> + /// Removes an element from this <see cref="Array{T}"/> by index. + /// </summary> + /// <param name="index">The index of the element to remove.</param> public void RemoveAt(int index) { objectArray.RemoveAt(index); @@ -338,31 +508,53 @@ namespace Godot.Collections // ICollection<T> + /// <summary> + /// Returns the number of elements in this <see cref="Array{T}"/>. + /// This is also known as the size or length of the array. + /// </summary> + /// <returns>The number of elements.</returns> public int Count { get { return objectArray.Count; } } - public bool IsReadOnly - { - get { return objectArray.IsReadOnly; } - } + bool ICollection<T>.IsReadOnly => false; + /// <summary> + /// Adds an item to the end of this <see cref="Array{T}"/>. + /// This is the same as `append` or `push_back` in GDScript. + /// </summary> + /// <param name="item">The item to add.</param> + /// <returns>The new size after adding the item.</returns> public void Add(T item) { objectArray.Add(item); } + /// <summary> + /// Erases all items from this <see cref="Array{T}"/>. + /// </summary> public void Clear() { objectArray.Clear(); } + /// <summary> + /// Checks if this <see cref="Array{T}"/> contains the given item. + /// </summary> + /// <param name="item">The item to look for.</param> + /// <returns>Whether or not this array contains the given item.</returns> public bool Contains(T item) { return objectArray.Contains(item); } + /// <summary> + /// Copies the elements of this <see cref="Array{T}"/> to the given + /// C# array, starting at the given index. + /// </summary> + /// <param name="array">The C# array to copy to.</param> + /// <param name="arrayIndex">The index to start at.</param> public void CopyTo(T[] array, int arrayIndex) { if (array == null) @@ -386,6 +578,12 @@ namespace Godot.Collections } } + /// <summary> + /// Removes the first occurrence of the specified value + /// from this <see cref="Array{T}"/>. + /// </summary> + /// <param name="item">The value to remove.</param> + /// <returns>A bool indicating success or failure.</returns> public bool Remove(T item) { return Array.godot_icall_Array_Remove(GetPtr(), item); @@ -393,6 +591,10 @@ namespace Godot.Collections // IEnumerable<T> + /// <summary> + /// Gets an enumerator for this <see cref="Array{T}"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IEnumerator<T> GetEnumerator() { int count = objectArray.Count; @@ -408,6 +610,10 @@ namespace Godot.Collections return GetEnumerator(); } + /// <summary> + /// Converts this <see cref="Array{T}"/> to a string. + /// </summary> + /// <returns>A string representation of this array.</returns> public override string ToString() => objectArray.ToString(); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 5dbf5d5657..8271b43b48 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -863,16 +863,12 @@ namespace Godot public override string ToString() { - return "[X: " + x.ToString() + - ", Y: " + y.ToString() + - ", Z: " + z.ToString() + "]"; + return $"[X: {x}, Y: {y}, Z: {z}]"; } public string ToString(string format) { - return "[X: " + x.ToString(format) + - ", Y: " + y.ToString(format) + - ", Z: " + z.ToString(format) + "]"; + return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, Z: {z.ToString(format)}]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 155ffcff32..b9a98ba9c7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -1010,12 +1010,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2}, {3})", r.ToString(), g.ToString(), b.ToString(), a.ToString()); + return $"({r}, {g}, {b}, {a})"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2}, {3})", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); + return $"({r.ToString(format)}, {g.ToString(format)}, {b.ToString(format)}, {a.ToString(format)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs index 4bb727bd35..d64c8b563e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Godot diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs index 785e87a043..1dca9e6ea7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs @@ -61,7 +61,7 @@ namespace Godot using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { - writer.Write((ulong) TargetKind.Static); + writer.Write((ulong)TargetKind.Static); SerializeType(writer, @delegate.GetType()); @@ -77,8 +77,8 @@ namespace Godot using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { - writer.Write((ulong) TargetKind.GodotObject); - writer.Write((ulong) godotObject.GetInstanceId()); + writer.Write((ulong)TargetKind.GodotObject); + writer.Write((ulong)godotObject.GetInstanceId()); SerializeType(writer, @delegate.GetType()); @@ -100,7 +100,7 @@ namespace Godot using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { - writer.Write((ulong) TargetKind.CompilerGenerated); + writer.Write((ulong)TargetKind.CompilerGenerated); SerializeType(writer, targetType); SerializeType(writer, @delegate.GetType()); @@ -149,14 +149,14 @@ namespace Godot int flags = 0; if (methodInfo.IsPublic) - flags |= (int) BindingFlags.Public; + flags |= (int)BindingFlags.Public; else - flags |= (int) BindingFlags.NonPublic; + flags |= (int)BindingFlags.NonPublic; if (methodInfo.IsStatic) - flags |= (int) BindingFlags.Static; + flags |= (int)BindingFlags.Static; else - flags |= (int) BindingFlags.Instance; + flags |= (int)BindingFlags.Instance; writer.Write(flags); @@ -238,7 +238,7 @@ namespace Godot } else { - if (TryDeserializeSingleDelegate((byte[]) elem, out Delegate oneDelegate)) + if (TryDeserializeSingleDelegate((byte[])elem, out Delegate oneDelegate)) delegates.Add(oneDelegate); } } @@ -257,7 +257,7 @@ namespace Godot using (var stream = new MemoryStream(buffer, writable: false)) using (var reader = new BinaryReader(stream)) { - var targetKind = (TargetKind) reader.ReadUInt64(); + var targetKind = (TargetKind)reader.ReadUInt64(); switch (targetKind) { @@ -353,11 +353,11 @@ namespace Godot parameterTypes[i] = parameterType; } - methodInfo = declaringType.GetMethod(methodName, (BindingFlags) flags, null, parameterTypes, null); + methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags, null, parameterTypes, null); return methodInfo != null && methodInfo.ReturnType == returnType; } - methodInfo = declaringType.GetMethod(methodName, (BindingFlags) flags); + methodInfo = declaringType.GetMethod(methodName, (BindingFlags)flags); return methodInfo != null && methodInfo.ReturnType == returnType; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs index c4c911b863..0c21bcaa3f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs @@ -1,4 +1,3 @@ - using System; using System.Collections.Generic; using System.Dynamic; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 6699c5992c..a6f7a80d64 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; - #endif +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; // TODO: Add comments describing what this class does. It is not obvious. @@ -26,17 +25,17 @@ namespace Godot public static real_t Db2Linear(real_t db) { - return (real_t) Math.Exp(db * 0.11512925464970228420089957273422); + return (real_t)Math.Exp(db * 0.11512925464970228420089957273422); } - public static real_t DecTime(real_t value, real_t amount, real_t step) + private static object[] GetPrintParams(object[] parameters) { - real_t sgn = Mathf.Sign(value); - real_t val = Mathf.Abs(value); - val -= amount * step; - if (val < 0) - val = 0; - return val * sgn; + if (parameters == null) + { + return new[] { "null" }; + } + + return Array.ConvertAll(parameters, x => x?.ToString() ?? "null"); } public static int Hash(object var) @@ -51,7 +50,7 @@ namespace Godot public static real_t Linear2Db(real_t linear) { - return (real_t) (Math.Log(linear) * 8.6858896380650365530225783783321); + return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321); } public static Resource Load(string path) @@ -76,7 +75,7 @@ namespace Godot public static void Print(params object[] what) { - godot_icall_GD_print(Array.ConvertAll(what ?? new object[]{"null"}, x => x != null ? x.ToString() : "null")); + godot_icall_GD_print(GetPrintParams(what)); } public static void PrintStack() @@ -86,22 +85,22 @@ namespace Godot public static void PrintErr(params object[] what) { - godot_icall_GD_printerr(Array.ConvertAll(what ?? new object[]{"null"}, x => x != null ? x.ToString() : "null")); + godot_icall_GD_printerr(GetPrintParams(what)); } public static void PrintRaw(params object[] what) { - godot_icall_GD_printraw(Array.ConvertAll(what ?? new object[]{"null"}, x => x != null ? x.ToString() : "null")); + godot_icall_GD_printraw(GetPrintParams(what)); } public static void PrintS(params object[] what) { - godot_icall_GD_prints(Array.ConvertAll(what ?? new object[]{"null"}, x => x != null ? x.ToString() : "null")); + godot_icall_GD_prints(GetPrintParams(what)); } public static void PrintT(params object[] what) { - godot_icall_GD_printt(Array.ConvertAll(what ?? new object[]{"null"}, x => x != null ? x.ToString() : "null")); + godot_icall_GD_printt(GetPrintParams(what)); } public static float Randf() diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs index f1a00ae0fa..a566b53659 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs @@ -1,4 +1,3 @@ -using System; using System.Diagnostics; namespace Godot diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs index 702a6c76ba..729529d093 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Godot { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs index c59d083080..f508211f68 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs @@ -1,12 +1,8 @@ using System; -using System.Collections; using System.Collections.Generic; namespace Godot { - using Array = Godot.Collections.Array; - using Dictionary = Godot.Collections.Dictionary; - static class MarshalUtils { /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index c3f372d415..213f84ad73 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -1,9 +1,9 @@ -using System; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; namespace Godot { @@ -14,13 +14,15 @@ namespace Godot /// <summary> /// The circle constant, the circumference of the unit circle in radians. /// </summary> - public const real_t Tau = (real_t) 6.2831853071795864769252867666M; // 6.2831855f and 6.28318530717959 + // 6.2831855f and 6.28318530717959 + public const real_t Tau = (real_t)6.2831853071795864769252867666M; /// <summary> /// Constant that represents how many times the diameter of a circle /// fits around its perimeter. This is equivalent to `Mathf.Tau / 2`. /// </summary> - public const real_t Pi = (real_t) 3.1415926535897932384626433833M; // 3.1415927f and 3.14159265358979 + // 3.1415927f and 3.14159265358979 + public const real_t Pi = (real_t)3.1415926535897932384626433833M; /// <summary> /// Positive infinity. For negative infinity, use `-Mathf.Inf`. @@ -34,8 +36,10 @@ namespace Godot /// </summary> public const real_t NaN = real_t.NaN; - private const real_t Deg2RadConst = (real_t) 0.0174532925199432957692369077M; // 0.0174532924f and 0.0174532925199433 - private const real_t Rad2DegConst = (real_t) 57.295779513082320876798154814M; // 57.29578f and 57.2957795130823 + // 0.0174532924f and 0.0174532925199433 + private const real_t Deg2RadConst = (real_t)0.0174532925199432957692369077M; + // 57.29578f and 57.2957795130823 + private const real_t Rad2DegConst = (real_t)57.295779513082320876798154814M; /// <summary> /// Returns the absolute value of `s` (i.e. positive value). @@ -515,7 +519,8 @@ namespace Godot /// <returns>One of three possible values: `1`, `-1`, or `0`.</returns> public static int Sign(int s) { - if (s == 0) return 0; + if (s == 0) + return 0; return s < 0 ? -1 : 1; } @@ -526,7 +531,8 @@ namespace Godot /// <returns>One of three possible values: `1`, `-1`, or `0`.</returns> public static int Sign(real_t s) { - if (s == 0) return 0; + if (s == 0) + return 0; return s < 0 ? -1 : 1; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index c2f4701b5f..0888e33090 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs @@ -1,10 +1,9 @@ -using System; - #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; namespace Godot { @@ -15,12 +14,12 @@ namespace Godot /// <summary> /// The natural number `e`. /// </summary> - public const real_t E = (real_t) 2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045 + public const real_t E = (real_t)2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045 /// <summary> /// The square root of 2. /// </summary> - public const real_t Sqrt2 = (real_t) 1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 + public const real_t Sqrt2 = (real_t)1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 /// <summary> /// A very small number used for float comparison with error tolerance. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index ad6ca51e8b..6972102730 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -177,7 +177,7 @@ namespace Godot return null; } - return from + dir * -dist; + return from - (dir * dist); } /// <summary> @@ -206,7 +206,7 @@ namespace Godot return null; } - return begin + segment * -dist; + return begin - (segment * dist); } /// <summary> @@ -355,20 +355,12 @@ namespace Godot public override string ToString() { - return String.Format("{0}, {1}", new object[] - { - _normal.ToString(), - D.ToString() - }); + return $"{_normal}, {D}"; } public string ToString(string format) { - return String.Format("{0}, {1}", new object[] - { - _normal.ToString(format), - D.ToString(format) - }); + return $"{_normal.ToString(format)}, {D.ToString(format)}"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 817103994a..0fed55cc30 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -547,12 +547,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2}, {3})", x.ToString(), y.ToString(), z.ToString(), w.ToString()); + return $"({x}, {y}, {z}, {w})"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2}, {3})", x.ToString(format), y.ToString(format), z.ToString(format), w.ToString(format)); + return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index 612fb64a3d..dec69c7f94 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -405,20 +405,12 @@ namespace Godot public override string ToString() { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } public string ToString(string format) { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(format), - _size.ToString(format) - }); + return $"{_position.ToString(format)}, {_size.ToString(format)}"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs index c27af74866..7fb6614d2c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs @@ -383,20 +383,12 @@ namespace Godot public override string ToString() { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } public string ToString(string format) { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(format), - _size.ToString(format) - }); + return $"{_position.ToString(format)}, {_size.ToString(format)}"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 98efa89ef0..d9665cbf2b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -61,9 +61,9 @@ namespace Godot return string.Empty; } - // <summary> - // If the string is a path to a file, return the path to the file without the extension. - // </summary> + /// <summary> + /// If the string is a path to a file, return the path to the file without the extension. + /// </summary> public static string BaseName(this string instance) { int index = instance.LastIndexOf('.'); @@ -74,17 +74,17 @@ namespace Godot return instance; } - // <summary> - // Return true if the strings begins with the given string. - // </summary> + /// <summary> + /// Return <see langword="true"/> if the strings begins with the given string. + /// </summary> public static bool BeginsWith(this string instance, string text) { return instance.StartsWith(text); } - // <summary> - // Return the bigrams (pairs of consecutive letters) of this string. - // </summary> + /// <summary> + /// Return the bigrams (pairs of consecutive letters) of this string. + /// </summary> public static string[] Bigrams(this string instance) { var b = new string[instance.Length - 1]; @@ -124,12 +124,12 @@ namespace Godot instance = instance.Substring(2); } - return sign * Convert.ToInt32(instance, 2);; + return sign * Convert.ToInt32(instance, 2); } - // <summary> - // Return the amount of substrings in string. - // </summary> + /// <summary> + /// Return the amount of substrings in string. + /// </summary> public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0) { if (what.Length == 0) @@ -187,9 +187,9 @@ namespace Godot return c; } - // <summary> - // Return a copy of the string with special characters escaped using the C language standard. - // </summary> + /// <summary> + /// Return a copy of the string with special characters escaped using the C language standard. + /// </summary> public static string CEscape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -209,9 +209,10 @@ namespace Godot return sb.ToString(); } - // <summary> - // Return a copy of the string with escaped characters replaced by their meanings according to the C language standard. - // </summary> + /// <summary> + /// Return a copy of the string with escaped characters replaced by their meanings + /// according to the C language standard. + /// </summary> public static string CUnescape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -231,9 +232,12 @@ namespace Godot return sb.ToString(); } - // <summary> - // Change the case of some letters. Replace underscores with spaces, convert all letters to lowercase then capitalize first and every letter following the space character. For [code]capitalize camelCase mixed_with_underscores[/code] it will return [code]Capitalize Camelcase Mixed With Underscores[/code]. - // </summary> + /// <summary> + /// Change the case of some letters. Replace underscores with spaces, convert all letters + /// to lowercase then capitalize first and every letter following the space character. + /// For <c>capitalize camelCase mixed_with_underscores</c> it will return + /// <c>Capitalize Camelcase Mixed With Underscores</c>. + /// </summary> public static string Capitalize(this string instance) { string aux = instance.Replace("_", " ").ToLower(); @@ -254,17 +258,17 @@ namespace Godot return cap; } - // <summary> - // Perform a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. - // </summary> + /// <summary> + /// Perform a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// </summary> public static int CasecmpTo(this string instance, string to) { return instance.CompareTo(to, caseSensitive: true); } - // <summary> - // Perform a comparison to another string, return -1 if less, 0 if equal and +1 if greater. - // </summary> + /// <summary> + /// Perform a comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// </summary> public static int CompareTo(this string instance, string to, bool caseSensitive = true) { if (string.IsNullOrEmpty(instance)) @@ -316,25 +320,25 @@ namespace Godot } } - // <summary> - // Return true if the strings ends with the given string. - // </summary> + /// <summary> + /// Return <see langword="true"/> if the strings ends with the given string. + /// </summary> public static bool EndsWith(this string instance, string text) { return instance.EndsWith(text); } - // <summary> - // Erase [code]chars[/code] characters from the string starting from [code]pos[/code]. - // </summary> + /// <summary> + /// Erase <paramref name="chars"/> characters from the string starting from <paramref name="pos"/>. + /// </summary> public static void Erase(this StringBuilder instance, int pos, int chars) { instance.Remove(pos, chars); } - // <summary> - // If the string is a path to a file, return the extension. - // </summary> + /// <summary> + /// If the string is a path to a file, return the extension. + /// </summary> public static string Extension(this string instance) { int pos = instance.FindLast("."); @@ -345,14 +349,18 @@ namespace Godot return instance.Substring(pos + 1); } - /// <summary>Find the first occurrence of a substring. Optionally, the search starting position can be passed.</summary> + /// <summary> + /// Find the first occurrence of a substring. Optionally, the search starting position can be passed. + /// </summary> /// <returns>The starting position of the substring, or -1 if not found.</returns> public static int Find(this string instance, string what, int from = 0, bool caseSensitive = true) { return instance.IndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } - /// <summary>Find the first occurrence of a char. Optionally, the search starting position can be passed.</summary> + /// <summary> + /// Find the first occurrence of a char. Optionally, the search starting position can be passed. + /// </summary> /// <returns>The first instance of the char, or -1 if not found.</returns> public static int Find(this string instance, char what, int from = 0, bool caseSensitive = true) { @@ -375,16 +383,19 @@ namespace Godot return instance.LastIndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } - /// <summary>Find the first occurrence of a substring but search as case-insensitive. Optionally, the search starting position can be passed.</summary> + /// <summary> + /// Find the first occurrence of a substring but search as case-insensitive. + /// Optionally, the search starting position can be passed. + /// </summary> /// <returns>The starting position of the substring, or -1 if not found.</returns> public static int FindN(this string instance, string what, int from = 0) { return instance.IndexOf(what, from, StringComparison.OrdinalIgnoreCase); } - // <summary> - // If the string is a path to a file, return the base directory. - // </summary> + /// <summary> + /// If the string is a path to a file, return the base directory. + /// </summary> public static string GetBaseDir(this string instance) { int basepos = instance.Find("://"); @@ -419,9 +430,9 @@ namespace Godot return @base + rs.Substr(0, sep); } - // <summary> - // If the string is a path to a file, return the file and ignore the base directory. - // </summary> + /// <summary> + /// If the string is a path to a file, return the file and ignore the base directory. + /// </summary> public static string GetFile(this string instance) { int sep = Mathf.Max(instance.FindLast("/"), instance.FindLast("\\")); @@ -461,14 +472,14 @@ namespace Godot return Encoding.UTF8.GetString(bytes); } - // <summary> - // Hash the string and return a 32 bits unsigned integer. - // </summary> + /// <summary> + /// Hash the string and return a 32 bits unsigned integer. + /// </summary> public static uint Hash(this string instance) { uint hash = 5381; - foreach(uint c in instance) + foreach (uint c in instance) { hash = (hash << 5) + hash + c; // hash * 33 + c } @@ -553,17 +564,17 @@ namespace Godot return sign * int.Parse(instance, NumberStyles.HexNumber); } - // <summary> - // Insert a substring at a given position. - // </summary> + /// <summary> + /// Insert a substring at a given position. + /// </summary> public static string Insert(this string instance, int pos, string what) { return instance.Insert(pos, what); } - // <summary> - // If the string is a path to a file or directory, return true if the path is absolute. - // </summary> + /// <summary> + /// If the string is a path to a file or directory, return <see langword="true"/> if the path is absolute. + /// </summary> public static bool IsAbsPath(this string instance) { if (string.IsNullOrEmpty(instance)) @@ -574,17 +585,17 @@ namespace Godot return instance[0] == '/' || instance[0] == '\\'; } - // <summary> - // If the string is a path to a file or directory, return true if the path is relative. - // </summary> + /// <summary> + /// If the string is a path to a file or directory, return <see langword="true"/> if the path is relative. + /// </summary> public static bool IsRelPath(this string instance) { return !IsAbsPath(instance); } - // <summary> - // Check whether this string is a subsequence of the given string. - // </summary> + /// <summary> + /// Check whether this string is a subsequence of the given string. + /// </summary> public static bool IsSubsequenceOf(this string instance, string text, bool caseSensitive = true) { int len = instance.Length; @@ -625,34 +636,36 @@ namespace Godot return false; } - // <summary> - // Check whether this string is a subsequence of the given string, ignoring case differences. - // </summary> + /// <summary> + /// Check whether this string is a subsequence of the given string, ignoring case differences. + /// </summary> public static bool IsSubsequenceOfI(this string instance, string text) { return instance.IsSubsequenceOf(text, caseSensitive: false); } - // <summary> - // Check whether the string contains a valid float. - // </summary> + /// <summary> + /// Check whether the string contains a valid <see langword="float"/>. + /// </summary> public static bool IsValidFloat(this string instance) { float f; return float.TryParse(instance, out f); } - // <summary> - // Check whether the string contains a valid color in HTML notation. - // </summary> + /// <summary> + /// Check whether the string contains a valid color in HTML notation. + /// </summary> public static bool IsValidHtmlColor(this string instance) { return Color.HtmlIsValid(instance); } - // <summary> - // Check whether the string is a valid identifier. As is common in programming languages, a valid identifier may contain only letters, digits and underscores (_) and the first character may not be a digit. - // </summary> + /// <summary> + /// Check whether the string is a valid identifier. As is common in + /// programming languages, a valid identifier may contain only letters, + /// digits and underscores (_) and the first character may not be a digit. + /// </summary> public static bool IsValidIdentifier(this string instance) { int len = instance.Length; @@ -680,18 +693,18 @@ namespace Godot return true; } - // <summary> - // Check whether the string contains a valid integer. - // </summary> + /// <summary> + /// Check whether the string contains a valid integer. + /// </summary> public static bool IsValidInteger(this string instance) { int f; return int.TryParse(instance, out f); } - // <summary> - // Check whether the string contains a valid IP address. - // </summary> + /// <summary> + /// Check whether the string contains a valid IP address. + /// </summary> public static bool IsValidIPAddress(this string instance) { // TODO: Support IPv6 addresses @@ -714,9 +727,9 @@ namespace Godot return true; } - // <summary> - // Return a copy of the string with special characters escaped using the JSON standard. - // </summary> + /// <summary> + /// Return a copy of the string with special characters escaped using the JSON standard. + /// </summary> public static string JSONEscape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -733,9 +746,9 @@ namespace Godot return sb.ToString(); } - // <summary> - // Return an amount of characters from the left of the string. - // </summary> + /// <summary> + /// Return an amount of characters from the left of the string. + /// </summary> public static string Left(this string instance, int pos) { if (pos <= 0) @@ -783,7 +796,8 @@ namespace Godot } /// <summary> - /// Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'. + /// Do a simple expression match, where '*' matches zero or more + /// arbitrary characters and '?' matches any single character except '.'. /// </summary> private static bool ExprMatch(this string instance, string expr, bool caseSensitive) { @@ -798,13 +812,17 @@ namespace Godot case '?': return instance.Length > 0 && instance[0] != '.' && ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive); default: - if (instance.Length == 0) return false; - return (caseSensitive ? instance[0] == expr[0] : char.ToUpper(instance[0]) == char.ToUpper(expr[0])) && ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive); + if (instance.Length == 0) + return false; + if (caseSensitive) + return instance[0] == expr[0]; + return (char.ToUpper(instance[0]) == char.ToUpper(expr[0])) && ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive); } } /// <summary> - /// Do a simple case sensitive expression match, using ? and * wildcards (see [method expr_match]). + /// Do a simple case sensitive expression match, using ? and * wildcards + /// (see <see cref="ExprMatch(string, string, bool)"/>). /// </summary> public static bool Match(this string instance, string expr, bool caseSensitive = true) { @@ -815,7 +833,8 @@ namespace Godot } /// <summary> - /// Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]). + /// Do a simple case insensitive expression match, using ? and * wildcards + /// (see <see cref="ExprMatch(string, string, bool)"/>). /// </summary> public static bool MatchN(this string instance, string expr) { @@ -825,9 +844,9 @@ namespace Godot return instance.ExprMatch(expr, caseSensitive: false); } - // <summary> - // Return the MD5 hash of the string as an array of bytes. - // </summary> + /// <summary> + /// Return the MD5 hash of the string as an array of bytes. + /// </summary> public static byte[] MD5Buffer(this string instance) { return godot_icall_String_md5_buffer(instance); @@ -836,9 +855,9 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static byte[] godot_icall_String_md5_buffer(string str); - // <summary> - // Return the MD5 hash of the string as a string. - // </summary> + /// <summary> + /// Return the MD5 hash of the string as a string. + /// </summary> public static string MD5Text(this string instance) { return godot_icall_String_md5_text(instance); @@ -847,25 +866,25 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static string godot_icall_String_md5_text(string str); - // <summary> - // Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. - // </summary> + /// <summary> + /// Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// </summary> public static int NocasecmpTo(this string instance, string to) { return instance.CompareTo(to, caseSensitive: false); } - // <summary> - // Return the character code at position [code]at[/code]. - // </summary> + /// <summary> + /// Return the character code at position <paramref name="at"/>. + /// </summary> public static int OrdAt(this string instance, int at) { return instance[at]; } - // <summary> - // Format a number to have an exact number of [code]digits[/code] after the decimal point. - // </summary> + /// <summary> + /// Format a number to have an exact number of <paramref name="digits"/> after the decimal point. + /// </summary> public static string PadDecimals(this string instance, int digits) { int c = instance.Find("."); @@ -899,9 +918,9 @@ namespace Godot return instance; } - // <summary> - // Format a number to have an exact number of [code]digits[/code] before the decimal point. - // </summary> + /// <summary> + /// Format a number to have an exact number of <paramref name="digits"/> before the decimal point. + /// </summary> public static string PadZeros(this string instance, int digits) { string s = instance; @@ -932,9 +951,10 @@ namespace Godot return s; } - // <summary> - // If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code]. - // </summary> + /// <summary> + /// If the string is a path, this concatenates <paramref name="file"/> at the end of the string as a subpath. + /// E.g. <c>"this/is".PlusFile("path") == "this/is/path"</c>. + /// </summary> public static string PlusFile(this string instance, string file) { if (instance.Length > 0 && instance[instance.Length - 1] == '/') @@ -942,25 +962,25 @@ namespace Godot return instance + "/" + file; } - // <summary> - // Replace occurrences of a substring for different ones inside the string. - // </summary> + /// <summary> + /// Replace occurrences of a substring for different ones inside the string. + /// </summary> public static string Replace(this string instance, string what, string forwhat) { return instance.Replace(what, forwhat); } - // <summary> - // Replace occurrences of a substring for different ones inside the string, but search case-insensitive. - // </summary> + /// <summary> + /// Replace occurrences of a substring for different ones inside the string, but search case-insensitive. + /// </summary> public static string ReplaceN(this string instance, string what, string forwhat) { return Regex.Replace(instance, what, forwhat, RegexOptions.IgnoreCase); } - // <summary> - // Perform a search for a substring, but start from the end of the string instead of the beginning. - // </summary> + /// <summary> + /// Perform a search for a substring, but start from the end of the string instead of the beginning. + /// </summary> public static int RFind(this string instance, string what, int from = -1) { return godot_icall_String_rfind(instance, what, from); @@ -969,9 +989,10 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static int godot_icall_String_rfind(string str, string what, int from); - // <summary> - // Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive. - // </summary> + /// <summary> + /// Perform a search for a substring, but start from the end of the string instead of the beginning. + /// Also search case-insensitive. + /// </summary> public static int RFindN(this string instance, string what, int from = -1) { return godot_icall_String_rfindn(instance, what, from); @@ -980,9 +1001,9 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static int godot_icall_String_rfindn(string str, string what, int from); - // <summary> - // Return the right side of the string from a given position. - // </summary> + /// <summary> + /// Return the right side of the string from a given position. + /// </summary> public static string Right(this string instance, int pos) { if (pos >= instance.Length) @@ -1029,9 +1050,9 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static byte[] godot_icall_String_sha256_buffer(string str); - // <summary> - // Return the SHA-256 hash of the string as a string. - // </summary> + /// <summary> + /// Return the SHA-256 hash of the string as a string. + /// </summary> public static string SHA256Text(this string instance) { return godot_icall_String_sha256_text(instance); @@ -1040,9 +1061,10 @@ namespace Godot [MethodImpl(MethodImplOptions.InternalCall)] internal extern static string godot_icall_String_sha256_text(string str); - // <summary> - // Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar. - // </summary> + /// <summary> + /// Return the similarity index of the text compared to this string. + /// 1 means totally similar and 0 means totally dissimilar. + /// </summary> public static float Similarity(this string instance, string text) { if (instance == text) @@ -1080,17 +1102,19 @@ namespace Godot return 2.0f * inter / sum; } - // <summary> - // Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". - // </summary> + /// <summary> + /// Split the string by a divisor string, return an array of the substrings. + /// Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". + /// </summary> public static string[] Split(this string instance, string divisor, bool allowEmpty = true) { - return instance.Split(new[] { divisor }, StringSplitOptions.RemoveEmptyEntries); + return instance.Split(new[] { divisor }, allowEmpty ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries); } - // <summary> - // Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",". - // </summary> + /// <summary> + /// Split the string in floats by using a divisor string, return an array of the substrings. + /// Example "1,2.5,3" will return [1,2.5,3] if split by ",". + /// </summary> public static float[] SplitFloats(this string instance, string divisor, bool allowEmpty = true) { var ret = new List<float>(); @@ -1122,9 +1146,10 @@ namespace Godot (char)30, (char)31, (char)32 }; - // <summary> - // Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively. - // </summary> + /// <summary> + /// Return a copy of the string stripped of any non-printable character at the beginning and the end. + /// The optional arguments are used to toggle stripping on the left and right edges respectively. + /// </summary> public static string StripEdges(this string instance, bool left = true, bool right = true) { if (left) @@ -1137,58 +1162,62 @@ namespace Godot return instance.TrimEnd(_nonPrintable); } - // <summary> - // Return part of the string from the position [code]from[/code], with length [code]len[/code]. - // </summary> + /// <summary> + /// Return part of the string from the position <paramref name="from"/>, with length <paramref name="len"/>. + /// </summary> public static string Substr(this string instance, int from, int len) { int max = instance.Length - from; return instance.Substring(from, len > max ? max : len); } - // <summary> - // Convert the String (which is a character array) to PackedByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters. - // </summary> + /// <summary> + /// Convert the String (which is a character array) to PackedByteArray (which is an array of bytes). + /// The conversion is speeded up in comparison to <see cref="ToUTF8(string)"/> with the assumption + /// that all the characters the String contains are only ASCII characters. + /// </summary> public static byte[] ToAscii(this string instance) { return Encoding.ASCII.GetBytes(instance); } - // <summary> - // Convert a string, containing a decimal number, into a [code]float[/code]. - // </summary> + /// <summary> + /// Convert a string, containing a decimal number, into a <see langword="float" />. + /// </summary> public static float ToFloat(this string instance) { return float.Parse(instance); } - // <summary> - // Convert a string, containing an integer number, into an [code]int[/code]. - // </summary> + /// <summary> + /// Convert a string, containing an integer number, into an <see langword="int" />. + /// </summary> public static int ToInt(this string instance) { return int.Parse(instance); } - // <summary> - // Return the string converted to lowercase. - // </summary> + /// <summary> + /// Return the string converted to lowercase. + /// </summary> public static string ToLower(this string instance) { return instance.ToLower(); } - // <summary> - // Return the string converted to uppercase. - // </summary> + /// <summary> + /// Return the string converted to uppercase. + /// </summary> public static string ToUpper(this string instance) { return instance.ToUpper(); } - // <summary> - // Convert the String (which is an array of characters) to PackedByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii(). - // </summary> + /// <summary> + /// Convert the String (which is an array of characters) to PackedByteArray (which is an array of bytes). + /// The conversion is a bit slower than <see cref="ToAscii(string)"/>, but supports all UTF-8 characters. + /// Therefore, you should prefer this function over <see cref="ToAscii(string)"/>. + /// </summary> public static byte[] ToUTF8(this string instance) { return Encoding.UTF8.GetBytes(instance); @@ -1221,17 +1250,18 @@ namespace Godot return Uri.EscapeDataString(instance); } - // <summary> - // Return a copy of the string with special characters escaped using the XML standard. - // </summary> + /// <summary> + /// Return a copy of the string with special characters escaped using the XML standard. + /// </summary> public static string XMLEscape(this string instance) { return SecurityElement.Escape(instance); } - // <summary> - // Return a copy of the string with escaped characters replaced by their meanings according to the XML standard. - // </summary> + /// <summary> + /// Return a copy of the string with escaped characters replaced by their meanings + /// according to the XML standard. + /// </summary> public static string XMLUnescape(this string instance) { return SecurityElement.FromString(instance).Text; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index fe93592667..62a6fe6959 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -492,16 +492,12 @@ namespace Godot public override string ToString() { - return "[X: " + x.ToString() + - ", Y: " + y.ToString() + - ", O: " + origin.ToString() + "]"; + return $"[X: {x}, Y: {y}, O: {origin}]"; } public string ToString(string format) { - return "[X: " + x.ToString(format) + - ", Y: " + y.ToString(format) + - ", O: " + origin.ToString(format) + "]"; + return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, O: {origin.ToString(format)}]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 26b1a9e8b2..1b717fb4ae 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -1,10 +1,10 @@ -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -393,18 +393,12 @@ namespace Godot public override string ToString() { - return "[X: " + basis.x.ToString() + - ", Y: " + basis.y.ToString() + - ", Z: " + basis.z.ToString() + - ", O: " + origin.ToString() + "]"; + return $"[X: {basis.x}, Y: {basis.y}, Z: {basis.z}, O: {origin}]"; } public string ToString(string format) { - return "[X: " + basis.x.ToString(format) + - ", Y: " + basis.y.ToString(format) + - ", Z: " + basis.z.ToString(format) + - ", O: " + origin.ToString(format) + "]"; + return $"[X: {basis.x.ToString(format)}, Y: {basis.y.ToString(format)}, Z: {basis.z.ToString(format)}, O: {origin.ToString(format)}]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index af053bd263..8bb5e90a68 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -1,16 +1,10 @@ -// file: core/math/math_2d.h -// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 -// file: core/math/math_2d.cpp -// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 -// file: core/variant_call.cpp -// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -757,20 +751,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - x.ToString(), - y.ToString() - }); + return $"({x}, {y})"; } public string ToString(string format) { - return String.Format("({0}, {1})", new object[] - { - x.ToString(format), - y.ToString(format) - }); + return $"({x.ToString(format)}, {y.ToString(format)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs index 9068593fd8..959f262f52 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs @@ -1,11 +1,10 @@ -using System; -using System.Runtime.InteropServices; - #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -509,20 +508,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - this.x.ToString(), - this.y.ToString() - }); + return $"({x}, {y})"; } public string ToString(string format) { - return String.Format("({0}, {1})", new object[] - { - this.x.ToString(format), - this.y.ToString(format) - }); + return $"({x.ToString(format)}, {y.ToString(format)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 31a9af2d9e..bdf64159e9 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -1,16 +1,10 @@ -// file: core/math/vector3.h -// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0 -// file: core/math/vector3.cpp -// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451 -// file: core/variant_call.cpp -// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685 -using System; -using System.Runtime.InteropServices; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -851,22 +845,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(), - y.ToString(), - z.ToString() - }); + return $"({x}, {y}, {z})"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(format), - y.ToString(format), - z.ToString(format) - }); + return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs index e727afa3ff..c96a7cf1b0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs @@ -1,11 +1,10 @@ -using System; -using System.Runtime.InteropServices; - #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; +using System.Runtime.InteropServices; namespace Godot { @@ -512,22 +511,12 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - this.x.ToString(), - this.y.ToString(), - this.z.ToString() - }); + return $"({x}, {y}, {z})"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - this.x.ToString(format), - this.y.ToString(format), - this.z.ToString(format) - }); + return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)})"; } } } diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 2d04cedb9b..a99dff8432 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -177,8 +177,8 @@ MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) { MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size()); int i = 0; - for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { - MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name); + for (const PropertyInfo &E : property_list) { + MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E.name); mono_array_setref(result, i, boxed); i++; } diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 02d875f669..299344bb93 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -100,8 +100,8 @@ void gd_mono_setup_runtime_main_args() { main_args.write[0] = execpath.ptrw(); int i = 1; - for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { - CharString &stored = cmdline_args_utf8.push_back(E->get().utf8())->get(); + for (const String &E : cmdline_args) { + CharString &stored = cmdline_args_utf8.push_back(E.utf8())->get(); main_args.write[i] = stored.ptrw(); i++; } diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index 67d6f3ef29..67f38bf127 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -330,8 +330,8 @@ no_pdb: void GDMonoAssembly::unload() { ERR_FAIL_NULL(image); // Should not be called if already unloaded - for (Map<MonoClass *, GDMonoClass *>::Element *E = cached_raw.front(); E; E = E->next()) { - memdelete(E->value()); + for (const KeyValue<MonoClass *, GDMonoClass *> &E : cached_raw) { + memdelete(E.value); } cached_classes.clear(); diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index f9fddd931b..27b4ac7fa7 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -522,12 +522,12 @@ GDMonoClass::~GDMonoClass() { mono_custom_attrs_free(attributes); } - for (Map<StringName, GDMonoField *>::Element *E = fields.front(); E; E = E->next()) { - memdelete(E->value()); + for (const KeyValue<StringName, GDMonoField *> &E : fields) { + memdelete(E.value); } - for (Map<StringName, GDMonoProperty *>::Element *E = properties.front(); E; E = E->next()) { - memdelete(E->value()); + for (const KeyValue<StringName, GDMonoProperty *> &E : properties) { + memdelete(E.value); } { diff --git a/modules/navigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/navigation_mesh_editor_plugin.cpp index 8f4203e260..587e56f593 100644 --- a/modules/navigation/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/navigation_mesh_editor_plugin.cpp @@ -65,7 +65,7 @@ void NavigationMeshEditor::_bake_pressed() { NavigationMeshGenerator::get_singleton()->clear(node->get_navigation_mesh()); NavigationMeshGenerator::get_singleton()->bake(node->get_navigation_mesh(), node); - node->update_gizmo(); + node->update_gizmos(); } void NavigationMeshEditor::_clear_pressed() { @@ -77,7 +77,7 @@ void NavigationMeshEditor::_clear_pressed() { bake_info->set_text(""); if (node) { - node->update_gizmo(); + node->update_gizmos(); } } diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 7aeb9e1858..41cd75fd22 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -514,11 +514,11 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) } Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); - for (const List<Node *>::Element *E = parse_nodes.front(); E; E = E->next()) { + for (Node *E : parse_nodes) { int geometry_type = p_nav_mesh->get_parsed_geometry_type(); uint32_t collision_mask = p_nav_mesh->get_collision_mask(); bool recurse_children = p_nav_mesh->get_source_geometry_mode() != NavigationMesh::SOURCE_GEOMETRY_GROUPS_EXPLICIT; - _parse_geometry(navmesh_xform, E->get(), vertices, indices, geometry_type, collision_mask, recurse_children); + _parse_geometry(navmesh_xform, E, vertices, indices, geometry_type, collision_mask, recurse_children); } if (vertices.size() > 0 && indices.size() > 0) { diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index 4d45e41cc3..c470f3e1ab 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -25,90 +25,66 @@ </tutorials> <methods> <method name="get_image" qualifiers="const"> - <return type="Image"> - </return> - <argument index="0" name="width" type="int"> - </argument> - <argument index="1" name="height" type="int"> - </argument> - <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)"> - </argument> + <return type="Image" /> + <argument index="0" name="width" type="int" /> + <argument index="1" name="height" type="int" /> + <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)" /> <description> Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise. </description> </method> <method name="get_noise_1d" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="x" type="float"> - </argument> + <return type="float" /> + <argument index="0" name="x" type="float" /> <description> Returns the 1D noise value [code][-1,1][/code] at the given x-coordinate. [b]Note:[/b] This method actually returns the 2D noise value [code][-1,1][/code] with fixed y-coordinate value 0.0. </description> </method> <method name="get_noise_2d" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="x" type="float"> - </argument> - <argument index="1" name="y" type="float"> - </argument> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <argument index="1" name="y" type="float" /> <description> Returns the 2D noise value [code][-1,1][/code] at the given position. </description> </method> <method name="get_noise_2dv" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="pos" type="Vector2"> - </argument> + <return type="float" /> + <argument index="0" name="pos" type="Vector2" /> <description> Returns the 2D noise value [code][-1,1][/code] at the given position. </description> </method> <method name="get_noise_3d" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="x" type="float"> - </argument> - <argument index="1" name="y" type="float"> - </argument> - <argument index="2" name="z" type="float"> - </argument> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <argument index="1" name="y" type="float" /> + <argument index="2" name="z" type="float" /> <description> Returns the 3D noise value [code][-1,1][/code] at the given position. </description> </method> <method name="get_noise_3dv" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="pos" type="Vector3"> - </argument> + <return type="float" /> + <argument index="0" name="pos" type="Vector3" /> <description> Returns the 3D noise value [code][-1,1][/code] at the given position. </description> </method> <method name="get_noise_4d" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="x" type="float"> - </argument> - <argument index="1" name="y" type="float"> - </argument> - <argument index="2" name="z" type="float"> - </argument> - <argument index="3" name="w" type="float"> - </argument> + <return type="float" /> + <argument index="0" name="x" type="float" /> + <argument index="1" name="y" type="float" /> + <argument index="2" name="z" type="float" /> + <argument index="3" name="w" type="float" /> <description> Returns the 4D noise value [code][-1,1][/code] at the given position. </description> </method> <method name="get_seamless_image" qualifiers="const"> - <return type="Image"> - </return> - <argument index="0" name="size" type="int"> - </argument> + <return type="Image" /> + <argument index="0" name="size" type="int" /> <description> Generate a tileable noise image in [constant Image.FORMAT_L8] format, based on the current noise parameters. Generated seamless images are always square ([code]size[/code] × [code]size[/code]). [b]Note:[/b] Seamless noise has a lower contrast compared to non-seamless noise. This is due to the way noise uses higher dimensions for generating seamless noise. diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index 7f5a0dfecb..9c84974ff6 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -50,88 +50,67 @@ </tutorials> <methods> <method name="clear"> - <return type="void"> - </return> + <return type="void" /> <description> This method resets the state of the object, as if it was freshly created. Namely, it unassigns the regular expression of this object. </description> </method> <method name="compile"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="pattern" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="pattern" type="String" /> <description> Compiles and assign the search pattern to use. Returns [constant OK] if the compilation is successful. If an error is encountered, details are printed to standard output and an error is returned. </description> </method> <method name="get_group_count" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the number of capturing groups in compiled pattern. </description> </method> <method name="get_names" qualifiers="const"> - <return type="Array"> - </return> + <return type="Array" /> <description> Returns an array of names of named capturing groups in the compiled pattern. They are ordered by appearance. </description> </method> <method name="get_pattern" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the original search pattern that was compiled. </description> </method> <method name="is_valid" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns whether this object has a valid search pattern assigned. </description> </method> <method name="search" qualifiers="const"> - <return type="RegExMatch"> - </return> - <argument index="0" name="subject" type="String"> - </argument> - <argument index="1" name="offset" type="int" default="0"> - </argument> - <argument index="2" name="end" type="int" default="-1"> - </argument> + <return type="RegExMatch" /> + <argument index="0" name="subject" type="String" /> + <argument index="1" name="offset" type="int" default="0" /> + <argument index="2" name="end" type="int" default="-1" /> <description> Searches the text for the compiled pattern. Returns a [RegExMatch] container of the first matching result if found, otherwise [code]null[/code]. The region to search within can be specified without modifying where the start and end anchor would be. </description> </method> <method name="search_all" qualifiers="const"> - <return type="Array"> - </return> - <argument index="0" name="subject" type="String"> - </argument> - <argument index="1" name="offset" type="int" default="0"> - </argument> - <argument index="2" name="end" type="int" default="-1"> - </argument> + <return type="Array" /> + <argument index="0" name="subject" type="String" /> + <argument index="1" name="offset" type="int" default="0" /> + <argument index="2" name="end" type="int" default="-1" /> <description> Searches the text for the compiled pattern. Returns an array of [RegExMatch] containers for each non-overlapping result. If no results were found, an empty array is returned instead. The region to search within can be specified without modifying where the start and end anchor would be. </description> </method> <method name="sub" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="subject" type="String"> - </argument> - <argument index="1" name="replacement" type="String"> - </argument> - <argument index="2" name="all" type="bool" default="false"> - </argument> - <argument index="3" name="offset" type="int" default="0"> - </argument> - <argument index="4" name="end" type="int" default="-1"> - </argument> + <return type="String" /> + <argument index="0" name="subject" type="String" /> + <argument index="1" name="replacement" type="String" /> + <argument index="2" name="all" type="bool" default="false" /> + <argument index="3" name="offset" type="int" default="0" /> + <argument index="4" name="end" type="int" default="-1" /> <description> Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default, only the first instance is replaced, but it can be changed for all instances (global replacement). The region to search within can be specified without modifying where the start and end anchor would be. </description> diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml index 492519d3d9..3cde2836cc 100644 --- a/modules/regex/doc_classes/RegExMatch.xml +++ b/modules/regex/doc_classes/RegExMatch.xml @@ -10,37 +10,30 @@ </tutorials> <methods> <method name="get_end" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="name" type="Variant" default="0"> - </argument> + <return type="int" /> + <argument index="0" name="name" type="Variant" default="0" /> <description> Returns the end position of the match within the source string. The end position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. Returns -1 if the group did not match or doesn't exist. </description> </method> <method name="get_group_count" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the number of capturing groups. </description> </method> <method name="get_start" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="name" type="Variant" default="0"> - </argument> + <return type="int" /> + <argument index="0" name="name" type="Variant" default="0" /> <description> Returns the starting position of the match within the source string. The starting position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. Returns -1 if the group did not match or doesn't exist. </description> </method> <method name="get_string" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="name" type="Variant" default="0"> - </argument> + <return type="String" /> + <argument index="0" name="name" type="Variant" default="0" /> <description> Returns the substring of the match from the source string. Capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern. Returns an empty string if the group did not match or doesn't exist. diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 2513039e8e..fa4888f843 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -927,14 +927,14 @@ void TextServerAdvanced::font_set_oversampling(float p_oversampling) { oversampling = p_oversampling; List<RID> fonts; font_owner.get_owned_list(&fonts); - for (List<RID>::Element *E = fonts.front(); E; E = E->next()) { - font_owner.getornull(E->get())->clear_cache(); + for (const RID &E : fonts) { + font_owner.getornull(E)->clear_cache(); } List<RID> text_bufs; shaped_owner.get_owned_list(&text_bufs); - for (List<RID>::Element *E = text_bufs.front(); E; E = E->next()) { - invalidate(shaped_owner.getornull(E->get())); + for (const RID &E : text_bufs) { + invalidate(shaped_owner.getornull(E)); } } } diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 9ad7dabbcc..004cbc2bb3 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -473,8 +473,8 @@ void TextServerFallback::font_set_oversampling(float p_oversampling) { oversampling = p_oversampling; List<RID> fonts; font_owner.get_owned_list(&fonts); - for (List<RID>::Element *E = fonts.front(); E; E = E->next()) { - font_owner.getornull(E->get())->clear_cache(); + for (const RID &E : fonts) { + font_owner.getornull(E)->clear_cache(); } } } diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml index cb8852d5ef..e7bf9b202d 100644 --- a/modules/theora/doc_classes/VideoStreamTheora.xml +++ b/modules/theora/doc_classes/VideoStreamTheora.xml @@ -11,17 +11,14 @@ </tutorials> <methods> <method name="get_file"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the Ogg Theora video file handled by this [VideoStreamTheora]. </description> </method> <method name="set_file"> - <return type="void"> - </return> - <argument index="0" name="file" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="file" type="String" /> <description> Sets the Ogg Theora video file that this [VideoStreamTheora] resource handles. The [code]file[/code] name should have the [code].ogv[/code] extension. </description> diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index 09a2c8a88c..5b1d9dbfd1 100644 --- a/modules/upnp/doc_classes/UPNP.xml +++ b/modules/upnp/doc_classes/UPNP.xml @@ -21,27 +21,19 @@ </tutorials> <methods> <method name="add_device"> - <return type="void"> - </return> - <argument index="0" name="device" type="UPNPDevice"> - </argument> + <return type="void" /> + <argument index="0" name="device" type="UPNPDevice" /> <description> Adds the given [UPNPDevice] to the list of discovered devices. </description> </method> <method name="add_port_mapping" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="port_internal" type="int" default="0"> - </argument> - <argument index="2" name="desc" type="String" default=""""> - </argument> - <argument index="3" name="proto" type="String" default=""UDP""> - </argument> - <argument index="4" name="duration" type="int" default="0"> - </argument> + <return type="int" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="port_internal" type="int" default="0" /> + <argument index="2" name="desc" type="String" default="""" /> + <argument index="3" name="proto" type="String" default=""UDP"" /> + <argument index="4" name="duration" type="int" default="0" /> <description> Adds a mapping to forward the external [code]port[/code] (between 1 and 65535) on the default gateway (see [method get_gateway]) to the [code]internal_port[/code] on the local machine for the given protocol [code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP being the default). If a port mapping for the given port and protocol combination already exists on that gateway device, this method tries to overwrite it. If that is not desired, you can retrieve the gateway manually with [method get_gateway] and call [method add_port_mapping] on it, if any. If [code]internal_port[/code] is [code]0[/code] (the default), the same port number is used for both the external and the internal port (the [code]port[/code] value). @@ -50,32 +42,24 @@ </description> </method> <method name="clear_devices"> - <return type="void"> - </return> + <return type="void" /> <description> Clears the list of discovered devices. </description> </method> <method name="delete_port_mapping" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="proto" type="String" default=""UDP""> - </argument> + <return type="int" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="proto" type="String" default=""UDP"" /> <description> Deletes the port mapping for the given port and protocol combination on the default gateway (see [method get_gateway]) if one exists. [code]port[/code] must be a valid port between 1 and 65535, [code]proto[/code] can be either [code]TCP[/code] or [code]UDP[/code]. See [enum UPNPResult] for possible return values. </description> </method> <method name="discover"> - <return type="int"> - </return> - <argument index="0" name="timeout" type="int" default="2000"> - </argument> - <argument index="1" name="ttl" type="int" default="2"> - </argument> - <argument index="2" name="device_filter" type="String" default=""InternetGatewayDevice""> - </argument> + <return type="int" /> + <argument index="0" name="timeout" type="int" default="2000" /> + <argument index="1" name="ttl" type="int" default="2" /> + <argument index="2" name="device_filter" type="String" default=""InternetGatewayDevice"" /> <description> Discovers local [UPNPDevice]s. Clears the list of previously discovered devices. Filters for IGD (InternetGatewayDevice) type devices by default, as those manage port forwarding. [code]timeout[/code] is the time to wait for responses in milliseconds. [code]ttl[/code] is the time-to-live; only touch this if you know what you're doing. @@ -83,51 +67,41 @@ </description> </method> <method name="get_device" qualifiers="const"> - <return type="UPNPDevice"> - </return> - <argument index="0" name="index" type="int"> - </argument> + <return type="UPNPDevice" /> + <argument index="0" name="index" type="int" /> <description> Returns the [UPNPDevice] at the given [code]index[/code]. </description> </method> <method name="get_device_count" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the number of discovered [UPNPDevice]s. </description> </method> <method name="get_gateway" qualifiers="const"> - <return type="UPNPDevice"> - </return> + <return type="UPNPDevice" /> <description> Returns the default gateway. That is the first discovered [UPNPDevice] that is also a valid IGD (InternetGatewayDevice). </description> </method> <method name="query_external_address" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the external [IP] address of the default gateway (see [method get_gateway]) as string. Returns an empty string on error. </description> </method> <method name="remove_device"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> <description> Removes the device at [code]index[/code] from the list of discovered devices. </description> </method> <method name="set_device"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="device" type="UPNPDevice"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> + <argument index="1" name="device" type="UPNPDevice" /> <description> Sets the device at [code]index[/code] from the list of discovered devices to [code]device[/code]. </description> diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index f7b5386d86..b7c2ff7dd7 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -10,43 +10,32 @@ </tutorials> <methods> <method name="add_port_mapping" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="port_internal" type="int" default="0"> - </argument> - <argument index="2" name="desc" type="String" default=""""> - </argument> - <argument index="3" name="proto" type="String" default=""UDP""> - </argument> - <argument index="4" name="duration" type="int" default="0"> - </argument> + <return type="int" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="port_internal" type="int" default="0" /> + <argument index="2" name="desc" type="String" default="""" /> + <argument index="3" name="proto" type="String" default=""UDP"" /> + <argument index="4" name="duration" type="int" default="0" /> <description> Adds a port mapping to forward the given external port on this [UPNPDevice] for the given protocol to the local machine. See [method UPNP.add_port_mapping]. </description> </method> <method name="delete_port_mapping" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="proto" type="String" default=""UDP""> - </argument> + <return type="int" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="proto" type="String" default=""UDP"" /> <description> Deletes the port mapping identified by the given port and protocol combination on this device. See [method UPNP.delete_port_mapping]. </description> </method> <method name="is_valid_gateway" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this is a valid IGD (InternetGatewayDevice) which potentially supports port forwarding. </description> </method> <method name="query_external_address" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the external IP address of this [UPNPDevice] or an empty string. </description> diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index 9d51bd86a2..2327fc0009 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -13,456 +13,334 @@ </tutorials> <methods> <method name="add_custom_signal"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> <description> Add a custom signal with the specified name to the VisualScript. </description> </method> <method name="add_function"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="func_node_id" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="func_node_id" type="int" /> <description> Add a function with the specified name to the VisualScript, and assign the root [VisualScriptFunction] node's id as [code]func_node_id[/code]. </description> </method> <method name="add_node"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="node" type="VisualScriptNode"> - </argument> - <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> - </argument> + <return type="void" /> + <argument index="0" name="id" type="int" /> + <argument index="1" name="node" type="VisualScriptNode" /> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" /> <description> Add a node to the VisualScript. </description> </method> <method name="add_variable"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="default_value" type="Variant" default="null"> - </argument> - <argument index="2" name="export" type="bool" default="false"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="default_value" type="Variant" default="null" /> + <argument index="2" name="export" type="bool" default="false" /> <description> Add a variable to the VisualScript, optionally giving it a default value or marking it as exported. </description> </method> <method name="custom_signal_add_argument"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="type" type="int" enum="Variant.Type"> - </argument> - <argument index="2" name="argname" type="String"> - </argument> - <argument index="3" name="index" type="int" default="-1"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="type" type="int" enum="Variant.Type" /> + <argument index="2" name="argname" type="String" /> + <argument index="3" name="index" type="int" default="-1" /> <description> Add an argument to a custom signal added with [method add_custom_signal]. </description> </method> <method name="custom_signal_get_argument_count" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="int" /> + <argument index="0" name="name" type="StringName" /> <description> Get the count of a custom signal's arguments. </description> </method> <method name="custom_signal_get_argument_name" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> <description> Get the name of a custom signal's argument. </description> </method> <method name="custom_signal_get_argument_type" qualifiers="const"> - <return type="int" enum="Variant.Type"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> + <return type="int" enum="Variant.Type" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> <description> Get the type of a custom signal's argument. </description> </method> <method name="custom_signal_remove_argument"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> <description> Remove a specific custom signal's argument. </description> </method> <method name="custom_signal_set_argument_name"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> - <argument index="2" name="argname" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> + <argument index="2" name="argname" type="String" /> <description> Rename a custom signal's argument. </description> </method> <method name="custom_signal_set_argument_type"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> - <argument index="2" name="type" type="int" enum="Variant.Type"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> + <argument index="2" name="type" type="int" enum="Variant.Type" /> <description> Change the type of a custom signal's argument. </description> </method> <method name="custom_signal_swap_argument"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="argidx" type="int"> - </argument> - <argument index="2" name="withidx" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="argidx" type="int" /> + <argument index="2" name="withidx" type="int" /> <description> Swap two of the arguments of a custom signal. </description> </method> <method name="data_connect"> - <return type="void"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_port" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> - <argument index="3" name="to_port" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_port" type="int" /> + <argument index="2" name="to_node" type="int" /> + <argument index="3" name="to_port" type="int" /> <description> Connect two data ports. The value of [code]from_node[/code]'s [code]from_port[/code] would be fed into [code]to_node[/code]'s [code]to_port[/code]. </description> </method> <method name="data_disconnect"> - <return type="void"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_port" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> - <argument index="3" name="to_port" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_port" type="int" /> + <argument index="2" name="to_node" type="int" /> + <argument index="3" name="to_port" type="int" /> <description> Disconnect two data ports previously connected with [method data_connect]. </description> </method> <method name="get_function_node_id" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="int" /> + <argument index="0" name="name" type="StringName" /> <description> Returns the id of a function's entry point node. </description> </method> <method name="get_node" qualifiers="const"> - <return type="VisualScriptNode"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="VisualScriptNode" /> + <argument index="0" name="id" type="int" /> <description> Returns a node given its id. </description> </method> <method name="get_node_position" qualifiers="const"> - <return type="Vector2"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="Vector2" /> + <argument index="0" name="id" type="int" /> <description> Returns a node's position in pixels. </description> </method> <method name="get_scroll" qualifiers="const"> - <return type="Vector2"> - </return> + <return type="Vector2" /> <description> Returns the current position of the center of the screen. </description> </method> <method name="get_variable_default_value" qualifiers="const"> - <return type="Variant"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="Variant" /> + <argument index="0" name="name" type="StringName" /> <description> Returns the default (initial) value of a variable. </description> </method> <method name="get_variable_export" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> <description> Returns whether a variable is exported. </description> </method> <method name="get_variable_info" qualifiers="const"> - <return type="Dictionary"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="Dictionary" /> + <argument index="0" name="name" type="StringName" /> <description> Returns the information for a given variable as a dictionary. The information includes its name, type, hint and usage. </description> </method> <method name="has_custom_signal" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> <description> Returns whether a signal exists with the specified name. </description> </method> <method name="has_data_connection" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_port" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> - <argument index="3" name="to_port" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_port" type="int" /> + <argument index="2" name="to_node" type="int" /> + <argument index="3" name="to_port" type="int" /> <description> Returns whether the specified data ports are connected. </description> </method> <method name="has_function" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> <description> Returns whether a function exists with the specified name. </description> </method> <method name="has_node" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="id" type="int" /> <description> Returns whether a node exists with the given id. </description> </method> <method name="has_sequence_connection" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_output" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_output" type="int" /> + <argument index="2" name="to_node" type="int" /> <description> Returns whether the specified sequence ports are connected. </description> </method> <method name="has_variable" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> <description> Returns whether a variable exists with the specified name. </description> </method> <method name="remove_custom_signal"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> <description> Remove a custom signal with the given name. </description> </method> <method name="remove_function"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> <description> Remove a specific function and its nodes from the script. </description> </method> <method name="remove_node"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="id" type="int" /> <description> Remove the node with the specified id. </description> </method> <method name="remove_variable"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> <description> Remove a variable with the given name. </description> </method> <method name="rename_custom_signal"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="new_name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="new_name" type="StringName" /> <description> Change the name of a custom signal. </description> </method> <method name="rename_function"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="new_name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="new_name" type="StringName" /> <description> Change the name of a function. </description> </method> <method name="rename_variable"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="new_name" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="new_name" type="StringName" /> <description> Change the name of a variable. </description> </method> <method name="sequence_connect"> - <return type="void"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_output" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_output" type="int" /> + <argument index="2" name="to_node" type="int" /> <description> Connect two sequence ports. The execution will flow from of [code]from_node[/code]'s [code]from_output[/code] into [code]to_node[/code]. Unlike [method data_connect], there isn't a [code]to_port[/code], since the target node can have only one sequence port. </description> </method> <method name="sequence_disconnect"> - <return type="void"> - </return> - <argument index="0" name="from_node" type="int"> - </argument> - <argument index="1" name="from_output" type="int"> - </argument> - <argument index="2" name="to_node" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="from_node" type="int" /> + <argument index="1" name="from_output" type="int" /> + <argument index="2" name="to_node" type="int" /> <description> Disconnect two sequence ports previously connected with [method sequence_connect]. </description> </method> <method name="set_instance_base_type"> - <return type="void"> - </return> - <argument index="0" name="type" type="StringName"> - </argument> + <return type="void" /> + <argument index="0" name="type" type="StringName" /> <description> Set the base type of the script. </description> </method> <method name="set_node_position"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="position" type="Vector2"> - </argument> + <return type="void" /> + <argument index="0" name="id" type="int" /> + <argument index="1" name="position" type="Vector2" /> <description> Set the node position in the VisualScript graph. </description> </method> <method name="set_scroll"> - <return type="void"> - </return> - <argument index="0" name="ofs" type="Vector2"> - </argument> + <return type="void" /> + <argument index="0" name="ofs" type="Vector2" /> <description> Set the screen center to the given position. </description> </method> <method name="set_variable_default_value"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="value" type="Variant"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="value" type="Variant" /> <description> Change the default (initial) value of a variable. </description> </method> <method name="set_variable_export"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="enable" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="enable" type="bool" /> <description> Change whether a variable is exported. </description> </method> <method name="set_variable_info"> - <return type="void"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <argument index="1" name="value" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="value" type="Dictionary" /> <description> Set a variable's info, using the same format as [method get_variable_info]. </description> @@ -470,8 +348,7 @@ </methods> <signals> <signal name="node_ports_changed"> - <argument index="0" name="id" type="int"> - </argument> + <argument index="0" name="id" type="int" /> <description> Emitted when the ports of a node are changed. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml index 219ffd01d3..195d766c1d 100644 --- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml +++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml @@ -105,117 +105,114 @@ <constant name="MATH_MOVE_TOWARD" value="29" enum="BuiltinFunc"> Moves the number toward a value, based on the third input. </constant> - <constant name="MATH_DECTIME" value="30" enum="BuiltinFunc"> - Return the result of [code]value[/code] decreased by [code]step[/code] * [code]amount[/code]. - </constant> - <constant name="MATH_RANDOMIZE" value="31" enum="BuiltinFunc"> + <constant name="MATH_RANDOMIZE" value="30" enum="BuiltinFunc"> Randomize the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time. </constant> - <constant name="MATH_RANDI" value="32" enum="BuiltinFunc"> + <constant name="MATH_RANDI" value="31" enum="BuiltinFunc"> Return a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function. </constant> - <constant name="MATH_RANDF" value="33" enum="BuiltinFunc"> + <constant name="MATH_RANDF" value="32" enum="BuiltinFunc"> Return a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication. </constant> - <constant name="MATH_RANDF_RANGE" value="34" enum="BuiltinFunc"> + <constant name="MATH_RANDF_RANGE" value="33" enum="BuiltinFunc"> Return a random floating-point value between the two inputs. </constant> - <constant name="MATH_RANDI_RANGE" value="35" enum="BuiltinFunc"> + <constant name="MATH_RANDI_RANGE" value="34" enum="BuiltinFunc"> Return a random 32-bit integer value between the two inputs. </constant> - <constant name="MATH_SEED" value="36" enum="BuiltinFunc"> + <constant name="MATH_SEED" value="35" enum="BuiltinFunc"> Set the seed for the random number generator. </constant> - <constant name="MATH_RANDSEED" value="37" enum="BuiltinFunc"> + <constant name="MATH_RANDSEED" value="36" enum="BuiltinFunc"> Return a random value from the given seed, along with the new seed. </constant> - <constant name="MATH_DEG2RAD" value="38" enum="BuiltinFunc"> + <constant name="MATH_DEG2RAD" value="37" enum="BuiltinFunc"> Convert the input from degrees to radians. </constant> - <constant name="MATH_RAD2DEG" value="39" enum="BuiltinFunc"> + <constant name="MATH_RAD2DEG" value="38" enum="BuiltinFunc"> Convert the input from radians to degrees. </constant> - <constant name="MATH_LINEAR2DB" value="40" enum="BuiltinFunc"> + <constant name="MATH_LINEAR2DB" value="39" enum="BuiltinFunc"> Convert the input from linear volume to decibel volume. </constant> - <constant name="MATH_DB2LINEAR" value="41" enum="BuiltinFunc"> + <constant name="MATH_DB2LINEAR" value="40" enum="BuiltinFunc"> Convert the input from decibel volume to linear volume. </constant> - <constant name="MATH_POLAR2CARTESIAN" value="42" enum="BuiltinFunc"> + <constant name="MATH_POLAR2CARTESIAN" value="41" enum="BuiltinFunc"> Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis). </constant> - <constant name="MATH_CARTESIAN2POLAR" value="43" enum="BuiltinFunc"> + <constant name="MATH_CARTESIAN2POLAR" value="42" enum="BuiltinFunc"> Converts a 2D point expressed in the cartesian coordinate system (X and Y axis) to the polar coordinate system (a distance from the origin and an angle). </constant> - <constant name="MATH_WRAP" value="44" enum="BuiltinFunc"> + <constant name="MATH_WRAP" value="43" enum="BuiltinFunc"> </constant> - <constant name="MATH_WRAPF" value="45" enum="BuiltinFunc"> + <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc"> </constant> - <constant name="LOGIC_MAX" value="46" enum="BuiltinFunc"> + <constant name="LOGIC_MAX" value="45" enum="BuiltinFunc"> Return the greater of the two numbers, also known as their maximum. </constant> - <constant name="LOGIC_MIN" value="47" enum="BuiltinFunc"> + <constant name="LOGIC_MIN" value="46" enum="BuiltinFunc"> Return the lesser of the two numbers, also known as their minimum. </constant> - <constant name="LOGIC_CLAMP" value="48" enum="BuiltinFunc"> + <constant name="LOGIC_CLAMP" value="47" enum="BuiltinFunc"> Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code]. </constant> - <constant name="LOGIC_NEAREST_PO2" value="49" enum="BuiltinFunc"> + <constant name="LOGIC_NEAREST_PO2" value="48" enum="BuiltinFunc"> Return the nearest power of 2 to the input. </constant> - <constant name="OBJ_WEAKREF" value="50" enum="BuiltinFunc"> + <constant name="OBJ_WEAKREF" value="49" enum="BuiltinFunc"> Create a [WeakRef] from the input. </constant> - <constant name="TYPE_CONVERT" value="51" enum="BuiltinFunc"> + <constant name="TYPE_CONVERT" value="50" enum="BuiltinFunc"> Convert between types. </constant> - <constant name="TYPE_OF" value="52" enum="BuiltinFunc"> + <constant name="TYPE_OF" value="51" enum="BuiltinFunc"> Return the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned. </constant> - <constant name="TYPE_EXISTS" value="53" enum="BuiltinFunc"> + <constant name="TYPE_EXISTS" value="52" enum="BuiltinFunc"> Checks if a type is registered in the [ClassDB]. </constant> - <constant name="TEXT_CHAR" value="54" enum="BuiltinFunc"> + <constant name="TEXT_CHAR" value="53" enum="BuiltinFunc"> Return a character with the given ascii value. </constant> - <constant name="TEXT_STR" value="55" enum="BuiltinFunc"> + <constant name="TEXT_STR" value="54" enum="BuiltinFunc"> Convert the input to a string. </constant> - <constant name="TEXT_PRINT" value="56" enum="BuiltinFunc"> + <constant name="TEXT_PRINT" value="55" enum="BuiltinFunc"> Print the given string to the output window. </constant> - <constant name="TEXT_PRINTERR" value="57" enum="BuiltinFunc"> + <constant name="TEXT_PRINTERR" value="56" enum="BuiltinFunc"> Print the given string to the standard error output. </constant> - <constant name="TEXT_PRINTRAW" value="58" enum="BuiltinFunc"> + <constant name="TEXT_PRINTRAW" value="57" enum="BuiltinFunc"> Print the given string to the standard output, without adding a newline. </constant> - <constant name="VAR_TO_STR" value="59" enum="BuiltinFunc"> + <constant name="VAR_TO_STR" value="58" enum="BuiltinFunc"> Serialize a [Variant] to a string. </constant> - <constant name="STR_TO_VAR" value="60" enum="BuiltinFunc"> + <constant name="STR_TO_VAR" value="59" enum="BuiltinFunc"> Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR]. </constant> - <constant name="VAR_TO_BYTES" value="61" enum="BuiltinFunc"> + <constant name="VAR_TO_BYTES" value="60" enum="BuiltinFunc"> Serialize a [Variant] to a [PackedByteArray]. </constant> - <constant name="BYTES_TO_VAR" value="62" enum="BuiltinFunc"> + <constant name="BYTES_TO_VAR" value="61" enum="BuiltinFunc"> Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES]. </constant> - <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc"> + <constant name="MATH_SMOOTHSTEP" value="62" enum="BuiltinFunc"> Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula: [codeblock] var t = clamp((weight - from) / (to - from), 0.0, 1.0) return t * t * (3.0 - 2.0 * t) [/codeblock] </constant> - <constant name="MATH_POSMOD" value="64" enum="BuiltinFunc"> + <constant name="MATH_POSMOD" value="63" enum="BuiltinFunc"> </constant> - <constant name="MATH_LERP_ANGLE" value="65" enum="BuiltinFunc"> + <constant name="MATH_LERP_ANGLE" value="64" enum="BuiltinFunc"> </constant> - <constant name="TEXT_ORD" value="66" enum="BuiltinFunc"> + <constant name="TEXT_ORD" value="65" enum="BuiltinFunc"> </constant> - <constant name="FUNC_MAX" value="67" enum="BuiltinFunc"> + <constant name="FUNC_MAX" value="66" enum="BuiltinFunc"> Represents the size of the [enum BuiltinFunc] enum. </constant> </constants> diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml index 2f162e78b6..4743594ec3 100644 --- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml +++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml @@ -10,30 +10,24 @@ </tutorials> <methods> <method name="get_constructor" qualifiers="const"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> </description> </method> <method name="get_constructor_type" qualifiers="const"> - <return type="int" enum="Variant.Type"> - </return> + <return type="int" enum="Variant.Type" /> <description> </description> </method> <method name="set_constructor"> - <return type="void"> - </return> - <argument index="0" name="constructor" type="Dictionary"> - </argument> + <return type="void" /> + <argument index="0" name="constructor" type="Dictionary" /> <description> </description> </method> <method name="set_constructor_type"> - <return type="void"> - </return> - <argument index="0" name="type" type="int" enum="Variant.Type"> - </argument> + <return type="void" /> + <argument index="0" name="type" type="int" enum="Variant.Type" /> <description> </description> </method> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml index ba4eba26fd..8aa34f8cae 100644 --- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml @@ -10,153 +10,122 @@ </tutorials> <methods> <method name="_get_caption" qualifiers="virtual"> - <return type="String"> - </return> + <return type="String" /> <description> Return the node's title. </description> </method> <method name="_get_category" qualifiers="virtual"> - <return type="String"> - </return> + <return type="String" /> <description> Return the node's category. </description> </method> <method name="_get_input_value_port_count" qualifiers="virtual"> - <return type="int"> - </return> + <return type="int" /> <description> Return the count of input value ports. </description> </method> <method name="_get_input_value_port_hint" qualifiers="virtual"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints. </description> </method> <method name="_get_input_value_port_hint_string" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified input port's hint string. </description> </method> <method name="_get_input_value_port_name" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified input port's name. </description> </method> <method name="_get_input_value_port_type" qualifiers="virtual"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified input port's type. See the [enum Variant.Type] values. </description> </method> <method name="_get_output_sequence_port_count" qualifiers="virtual"> - <return type="int"> - </return> + <return type="int" /> <description> Return the amount of output [b]sequence[/b] ports. </description> </method> <method name="_get_output_sequence_port_text" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified [b]sequence[/b] output's name. </description> </method> <method name="_get_output_value_port_count" qualifiers="virtual"> - <return type="int"> - </return> + <return type="int" /> <description> Return the amount of output value ports. </description> </method> <method name="_get_output_value_port_hint" qualifiers="virtual"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints. </description> </method> <method name="_get_output_value_port_hint_string" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified output port's hint string. </description> </method> <method name="_get_output_value_port_name" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified output port's name. </description> </method> <method name="_get_output_value_port_type" qualifiers="virtual"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="idx" type="int" /> <description> Return the specified output port's type. See the [enum Variant.Type] values. </description> </method> <method name="_get_text" qualifiers="virtual"> - <return type="String"> - </return> + <return type="String" /> <description> Return the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it). </description> </method> <method name="_get_working_memory_size" qualifiers="virtual"> - <return type="int"> - </return> + <return type="int" /> <description> Return the size of the custom node's working memory. See [method _step] for more details. </description> </method> <method name="_has_input_sequence_port" qualifiers="virtual"> - <return type="bool"> - </return> + <return type="bool" /> <description> Return whether the custom node has an input [b]sequence[/b] port. </description> </method> <method name="_step" qualifiers="virtual"> - <return type="Variant"> - </return> - <argument index="0" name="inputs" type="Array"> - </argument> - <argument index="1" name="outputs" type="Array"> - </argument> - <argument index="2" name="start_mode" type="int"> - </argument> - <argument index="3" name="working_mem" type="Array"> - </argument> + <return type="Variant" /> + <argument index="0" name="inputs" type="Array" /> + <argument index="1" name="outputs" type="Array" /> + <argument index="2" name="start_mode" type="int" /> + <argument index="3" name="working_mem" type="Array" /> <description> Execute the custom node's logic, returning the index of the output sequence port to use or a [String] when there is an error. The [code]inputs[/code] array contains the values of the input ports. diff --git a/modules/visual_script/doc_classes/VisualScriptEditor.xml b/modules/visual_script/doc_classes/VisualScriptEditor.xml index 186cd21239..9ea889c77b 100644 --- a/modules/visual_script/doc_classes/VisualScriptEditor.xml +++ b/modules/visual_script/doc_classes/VisualScriptEditor.xml @@ -8,25 +8,18 @@ </tutorials> <methods> <method name="add_custom_node"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="category" type="String"> - </argument> - <argument index="2" name="script" type="Script"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="String" /> + <argument index="1" name="category" type="String" /> + <argument index="2" name="script" type="Script" /> <description> Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter. </description> </method> <method name="remove_custom_node"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="category" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="name" type="String" /> + <argument index="1" name="category" type="String" /> <description> Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml index 54a02bf270..18c3826df8 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml @@ -10,30 +10,23 @@ </tutorials> <methods> <method name="connect_to_signal"> - <return type="void"> - </return> - <argument index="0" name="obj" type="Object"> - </argument> - <argument index="1" name="signals" type="String"> - </argument> - <argument index="2" name="args" type="Array"> - </argument> + <return type="void" /> + <argument index="0" name="obj" type="Object" /> + <argument index="1" name="signals" type="String" /> + <argument index="2" name="args" type="Array" /> <description> Connects this [VisualScriptFunctionState] to a signal in the given object to automatically resume when it's emitted. </description> </method> <method name="is_valid" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns whether the function state is valid. </description> </method> <method name="resume"> - <return type="Variant"> - </return> - <argument index="0" name="args" type="Array" default="[]"> - </argument> + <return type="Variant" /> + <argument index="0" name="args" type="Array" default="[]" /> <description> Resumes the function to run from the point it was yielded. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml index 671c427228..d5bff1341a 100644 --- a/modules/visual_script/doc_classes/VisualScriptLists.xml +++ b/modules/visual_script/doc_classes/VisualScriptLists.xml @@ -10,89 +10,65 @@ </tutorials> <methods> <method name="add_input_data_port"> - <return type="void"> - </return> - <argument index="0" name="type" type="int" enum="Variant.Type"> - </argument> - <argument index="1" name="name" type="String"> - </argument> - <argument index="2" name="index" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="type" type="int" enum="Variant.Type" /> + <argument index="1" name="name" type="String" /> + <argument index="2" name="index" type="int" /> <description> Adds an input port to the Visual Script node. </description> </method> <method name="add_output_data_port"> - <return type="void"> - </return> - <argument index="0" name="type" type="int" enum="Variant.Type"> - </argument> - <argument index="1" name="name" type="String"> - </argument> - <argument index="2" name="index" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="type" type="int" enum="Variant.Type" /> + <argument index="1" name="name" type="String" /> + <argument index="2" name="index" type="int" /> <description> Adds an output port to the Visual Script node. </description> </method> <method name="remove_input_data_port"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> <description> Removes an input port from the Visual Script node. </description> </method> <method name="remove_output_data_port"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> <description> Removes an output port from the Visual Script node. </description> </method> <method name="set_input_data_port_name"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="name" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> + <argument index="1" name="name" type="String" /> <description> Sets the name of an input port. </description> </method> <method name="set_input_data_port_type"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="type" type="int" enum="Variant.Type"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> + <argument index="1" name="type" type="int" enum="Variant.Type" /> <description> Sets the type of an input port. </description> </method> <method name="set_output_data_port_name"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="name" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> + <argument index="1" name="name" type="String" /> <description> Sets the name of an output port. </description> </method> <method name="set_output_data_port_type"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="type" type="int" enum="Variant.Type"> - </argument> + <return type="void" /> + <argument index="0" name="index" type="int" /> + <argument index="1" name="type" type="int" enum="Variant.Type" /> <description> Sets the type of an output port. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml index 82a023f3e4..23574a5ea8 100644 --- a/modules/visual_script/doc_classes/VisualScriptNode.xml +++ b/modules/visual_script/doc_classes/VisualScriptNode.xml @@ -10,35 +10,28 @@ </tutorials> <methods> <method name="get_default_input_value" qualifiers="const"> - <return type="Variant"> - </return> - <argument index="0" name="port_idx" type="int"> - </argument> + <return type="Variant" /> + <argument index="0" name="port_idx" type="int" /> <description> Returns the default value of a given port. The default value is used when nothing is connected to the port. </description> </method> <method name="get_visual_script" qualifiers="const"> - <return type="VisualScript"> - </return> + <return type="VisualScript" /> <description> Returns the [VisualScript] instance the node is bound to. </description> </method> <method name="ports_changed_notify"> - <return type="void"> - </return> + <return type="void" /> <description> Notify that the node's ports have changed. Usually used in conjunction with [VisualScriptCustomNode] . </description> </method> <method name="set_default_input_value"> - <return type="void"> - </return> - <argument index="0" name="port_idx" type="int"> - </argument> - <argument index="1" name="value" type="Variant"> - </argument> + <return type="void" /> + <argument index="0" name="port_idx" type="int" /> + <argument index="1" name="value" type="Variant" /> <description> Change the default value of a given port. </description> diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml index 89a10edde4..374e7d0f35 100644 --- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml @@ -10,10 +10,8 @@ </tutorials> <methods> <method name="_subcall" qualifiers="virtual"> - <return type="Variant"> - </return> - <argument index="0" name="arguments" type="Variant"> - </argument> + <return type="Variant" /> + <argument index="0" name="arguments" type="Variant" /> <description> Called by this node. </description> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 0de39512ae..86793af77f 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -271,6 +271,7 @@ void VisualScript::_node_ports_changed(int p_id) { void VisualScript::add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos) { ERR_FAIL_COND(instances.size()); ERR_FAIL_COND(nodes.has(p_id)); // ID can exist only one in script. + ERR_FAIL_COND(p_node.is_null()); NodeData nd; nd.node = p_node; @@ -588,14 +589,14 @@ void VisualScript::rename_variable(const StringName &p_name, const StringName &p variables.erase(p_name); List<int> ids; get_node_list(&ids); - for (List<int>::Element *E = ids.front(); E; E = E->next()) { - Ref<VisualScriptVariableGet> nodeget = get_node(E->get()); + for (int &E : ids) { + Ref<VisualScriptVariableGet> nodeget = get_node(E); if (nodeget.is_valid()) { if (nodeget->get_variable() == p_name) { nodeget->set_variable(p_new_name); } } else { - Ref<VisualScriptVariableSet> nodeset = get_node(E->get()); + Ref<VisualScriptVariableSet> nodeset = get_node(E); if (nodeset.is_valid()) { if (nodeset->get_variable() == p_name) { nodeset->set_variable(p_new_name); @@ -715,9 +716,9 @@ int VisualScript::get_available_id() const { List<int> nds; nodes.get_key_list(&nds); int max = -1; - for (const List<int>::Element *E = nds.front(); E; E = E->next()) { - if (E->get() > max) { - max = E->get(); + for (const int &E : nds) { + if (E > max) { + max = E; } } return (max + 1); @@ -752,15 +753,15 @@ void VisualScript::_update_placeholders() { List<StringName> keys; variables.get_key_list(&keys); - for (List<StringName>::Element *E = keys.front(); E; E = E->next()) { - if (!variables[E->get()]._export) { + for (const StringName &E : keys) { + if (!variables[E]._export) { continue; } - PropertyInfo p = variables[E->get()].info; - p.name = String(E->get()); + PropertyInfo p = variables[E].info; + p.name = String(E); pinfo.push_back(p); - values[p.name] = variables[E->get()].default_value; + values[p.name] = variables[E].default_value; } for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { @@ -783,15 +784,15 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) { List<StringName> keys; variables.get_key_list(&keys); - for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) { - if (!variables[E->get()]._export) { + for (const StringName &E : keys) { + if (!variables[E]._export) { continue; } - PropertyInfo p = variables[E->get()].info; - p.name = String(E->get()); + PropertyInfo p = variables[E].info; + p.name = String(E); pinfo.push_back(p); - values[p.name] = variables[E->get()].default_value; + values[p.name] = variables[E].default_value; } sins->update(pinfo, values); @@ -874,11 +875,11 @@ void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const { List<StringName> funcs; functions.get_key_list(&funcs); - for (List<StringName>::Element *E = funcs.front(); E; E = E->next()) { + for (const StringName &E : funcs) { MethodInfo mi; - mi.name = E->get(); - if (functions[E->get()].func_id >= 0) { - Ref<VisualScriptFunction> func = nodes[functions[E->get()].func_id].node; + mi.name = E; + if (functions[E].func_id >= 0) { + Ref<VisualScriptFunction> func = nodes[functions[E].func_id].node; if (func.is_valid()) { for (int i = 0; i < func->get_argument_count(); i++) { PropertyInfo arg; @@ -928,10 +929,10 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { List<StringName> vars; get_variable_list(&vars); - for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { - //if (!variables[E->get()]._export) + for (const StringName &E : vars) { + //if (!variables[E]._export) // continue; - PropertyInfo pi = variables[E->get()].info; + PropertyInfo pi = variables[E].info; pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_list->push_back(pi); } @@ -945,8 +946,8 @@ int VisualScript::get_member_line(const StringName &p_member) const { bool VisualScript::are_subnodes_edited() const { List<int> keys; nodes.get_key_list(&keys); - for (const List<int>::Element *F = keys.front(); F; F = F->next()) { - if (nodes[F->get()].node->is_edited()) { + for (const int &F : keys) { + if (nodes[F].node->is_edited()) { return true; } } @@ -1017,13 +1018,13 @@ void VisualScript::_set_data(const Dictionary &p_data) { rpc_functions.clear(); List<StringName> fns; functions.get_key_list(&fns); - for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) { - if (functions[E->get()].func_id >= 0 && nodes.has(functions[E->get()].func_id)) { - Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node; + 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; if (vsf.is_valid()) { if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { MultiplayerAPI::RPCConfig nd; - nd.name = E->get(); + nd.name = E; nd.rpc_mode = vsf->get_rpc_mode(); nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO if (rpc_functions.find(nd) == -1) { @@ -1045,11 +1046,11 @@ Dictionary VisualScript::_get_data() const { Array vars; List<StringName> var_names; variables.get_key_list(&var_names); - for (const List<StringName>::Element *E = var_names.front(); E; E = E->next()) { - Dictionary var = _get_variable_info(E->get()); - var["name"] = E->get(); // Make sure it's the right one. - var["default_value"] = variables[E->get()].default_value; - var["export"] = variables[E->get()]._export; + 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; vars.push_back(var); } d["variables"] = vars; @@ -1073,10 +1074,10 @@ Dictionary VisualScript::_get_data() const { Array funcs; List<StringName> func_names; functions.get_key_list(&func_names); - for (const List<StringName>::Element *E = func_names.front(); E; E = E->next()) { + for (const StringName &E : func_names) { Dictionary func; - func["name"] = E->get(); - func["function_id"] = functions[E->get()].func_id; + func["name"] = E; + func["function_id"] = functions[E].func_id; funcs.push_back(func); } d["functions"] = funcs; @@ -1084,10 +1085,10 @@ Dictionary VisualScript::_get_data() const { Array nds; List<int> node_ids; nodes.get_key_list(&node_ids); - for (const List<int>::Element *F = node_ids.front(); F; F = F->next()) { - nds.push_back(F->get()); - nds.push_back(nodes[F->get()].pos); - nds.push_back(nodes[F->get()].node); + for (const int &F : node_ids) { + nds.push_back(F); + nds.push_back(nodes[F].pos); + nds.push_back(nodes[F].node); } d["nodes"] = nds; @@ -1202,8 +1203,8 @@ VisualScript::~VisualScript() { // Remove all nodes and stuff that hold data refs. List<int> nds; nodes.get_key_list(&nds); - for (const List<int>::Element *E = nds.front(); E; E = E->next()) { - remove_node(E->get()); + for (const int &E : nds) { + remove_node(E); } } @@ -1233,12 +1234,12 @@ bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const { void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { List<StringName> vars; script->variables.get_key_list(&vars); - for (const List<StringName>::Element *E = vars.front(); E; E = E->next()) { - if (!script->variables[E->get()]._export) { + for (const StringName &E : vars) { + if (!script->variables[E]._export) { continue; } - PropertyInfo p = script->variables[E->get()].info; - p.name = String(E->get()); + PropertyInfo p = script->variables[E].info; + p.name = String(E); p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; p_properties->push_back(p); } @@ -1262,11 +1263,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 List<StringName>::Element *E = fns.front(); E; E = E->next()) { + for (const StringName &E : fns) { MethodInfo mi; - mi.name = E->get(); - if (script->functions[E->get()].func_id >= 0 && script->nodes.has(script->functions[E->get()].func_id)) { - Ref<VisualScriptFunction> vsf = script->nodes[script->functions[E->get()].func_id].node; + 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; if (vsf.is_valid()) { for (int i = 0; i < vsf->get_argument_count(); i++) { PropertyInfo arg; @@ -1868,8 +1869,8 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o { List<StringName> keys; script->variables.get_key_list(&keys); - for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) { - variables[E->get()] = script->variables[E->get()].default_value; + for (const StringName &E : keys) { + variables[E] = script->variables[E].default_value; } } @@ -1877,8 +1878,8 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o { List<StringName> keys; script->functions.get_key_list(&keys); - for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) { - const VisualScript::Function vsfn = p_script->functions[E->get()]; + for (const StringName &E : keys) { + const VisualScript::Function vsfn = p_script->functions[E]; Function function; function.node = vsfn.func_id; function.max_stack = 0; @@ -1889,7 +1890,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o Map<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->get())); + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E)); ERR_CONTINUE(function.node < 0); } @@ -1897,7 +1898,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->get())); + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E)); } ERR_CONTINUE(!func_node.is_valid()); @@ -1938,12 +1939,12 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o while (!nd_queue.is_empty()) { int ky = nd_queue.front()->get(); dc_lut[ky].get_key_list(&dc_keys); - for (const List<int>::Element *F = dc_keys.front(); F; F = F->next()) { + for (const int &F : dc_keys) { VisualScript::DataConnection dc; - dc.from_node = dc_lut[ky][F->get()].first; - dc.from_port = dc_lut[ky][F->get()].second; + dc.from_node = dc_lut[ky][F].first; + dc.from_port = dc_lut[ky][F].second; dc.to_node = ky; - dc.to_port = F->get(); + dc.to_port = F; dataconns.insert(dc); nd_queue.push_back(dc.from_node); node_ids.insert(dc.from_node); @@ -2093,7 +2094,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o } } - functions[E->get()] = function; + functions[E] = function; } } } @@ -2467,10 +2468,10 @@ void VisualScriptLanguage::debug_get_stack_level_members(int p_level, List<Strin List<StringName> vars; vs->get_variable_list(&vars); - for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { + for (const StringName &E : vars) { Variant v; - if (_call_stack[l].instance->get_variable(E->get(), &v)) { - p_members->push_back("variables/" + E->get()); + if (_call_stack[l].instance->get_variable(E, &v)) { + p_members->push_back("variables/" + E); p_values->push_back(v); } } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index f17ad62531..c61c3ae272 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -68,7 +68,6 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "inverse_lerp", "range_lerp", "move_toward", - "dectime", "randomize", "randi", "randf", @@ -206,7 +205,6 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case MATH_INVERSE_LERP: case MATH_SMOOTHSTEP: case MATH_MOVE_TOWARD: - case MATH_DECTIME: case MATH_WRAP: case MATH_WRAPF: case LOGIC_CLAMP: @@ -349,15 +347,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const return PropertyInfo(Variant::FLOAT, "delta"); } } break; - case MATH_DECTIME: { - if (p_idx == 0) { - return PropertyInfo(Variant::FLOAT, "value"); - } else if (p_idx == 1) { - return PropertyInfo(Variant::FLOAT, "amount"); - } else { - return PropertyInfo(Variant::FLOAT, "step"); - } - } break; case MATH_RANDOMIZE: case MATH_RANDI: case MATH_RANDF: { @@ -536,10 +525,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case MATH_RANGE_LERP: case MATH_SMOOTHSTEP: case MATH_MOVE_TOWARD: - case MATH_DECTIME: { - t = Variant::FLOAT; - - } break; case MATH_RANDOMIZE: { } break; case MATH_RANDI: { @@ -837,12 +822,6 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(2); *r_return = Math::move_toward((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); } break; - case VisualScriptBuiltinFunc::MATH_DECTIME: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - *r_return = Math::dectime((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); - } break; case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { Math::randomize(); @@ -1239,7 +1218,6 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_INVERSE_LERP); BIND_ENUM_CONSTANT(MATH_RANGE_LERP); BIND_ENUM_CONSTANT(MATH_MOVE_TOWARD); - BIND_ENUM_CONSTANT(MATH_DECTIME); BIND_ENUM_CONSTANT(MATH_RANDOMIZE); BIND_ENUM_CONSTANT(MATH_RANDI); BIND_ENUM_CONSTANT(MATH_RANDF); @@ -1330,7 +1308,6 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/move_toward", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_MOVE_TOWARD>); - VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 7196d4b46a..f59a7a0f0c 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -68,7 +68,6 @@ public: MATH_INVERSE_LERP, MATH_RANGE_LERP, MATH_MOVE_TOWARD, - MATH_DECTIME, MATH_RANDOMIZE, MATH_RANDI, MATH_RANDF, diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ed0583a133..a802e8022d 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -561,18 +561,16 @@ void VisualScriptEditor::_update_graph_connections() { List<VisualScript::SequenceConnection> sequence_conns; script->get_sequence_connection_list(&sequence_conns); - for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) { - graph->connect_node(itos(E->get().from_node), E->get().from_output, itos(E->get().to_node), 0); + for (const VisualScript::SequenceConnection &E : sequence_conns) { + graph->connect_node(itos(E.from_node), E.from_output, itos(E.to_node), 0); } List<VisualScript::DataConnection> data_conns; script->get_data_connection_list(&data_conns); - for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) { - VisualScript::DataConnection dc = E->get(); - - Ref<VisualScriptNode> from_node = script->get_node(E->get().from_node); - Ref<VisualScriptNode> to_node = script->get_node(E->get().to_node); + for (VisualScript::DataConnection &dc : data_conns) { + Ref<VisualScriptNode> from_node = script->get_node(dc.from_node); + Ref<VisualScriptNode> to_node = script->get_node(dc.to_node); if (to_node->has_input_sequence_port()) { dc.to_port++; @@ -580,7 +578,7 @@ void VisualScriptEditor::_update_graph_connections() { dc.from_port += from_node->get_output_sequence_port_count(); - graph->connect_node(itos(E->get().from_node), dc.from_port, itos(E->get().to_node), dc.to_port); + graph->connect_node(itos(dc.from_node), dc.from_port, itos(dc.to_node), dc.to_port); } } @@ -656,27 +654,27 @@ void VisualScriptEditor::_update_graph(int p_only_id) { script->get_node_list(&ids); StringName editor_icons = "EditorIcons"; - for (List<int>::Element *E = ids.front(); E; E = E->next()) { - if (p_only_id >= 0 && p_only_id != E->get()) { + for (int &E : ids) { + if (p_only_id >= 0 && p_only_id != E) { continue; } - Ref<VisualScriptNode> node = script->get_node(E->get()); - Vector2 pos = script->get_node_position(E->get()); + Ref<VisualScriptNode> node = script->get_node(E); + Vector2 pos = script->get_node_position(E); GraphNode *gnode = memnew(GraphNode); gnode->set_title(node->get_caption()); gnode->set_position_offset(pos * EDSCALE); - if (error_line == E->get()) { + if (error_line == E) { gnode->set_overlay(GraphNode::OVERLAY_POSITION); } else if (node->is_breakpoint()) { gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT); } gnode->set_meta("__vnode", node); - gnode->set_name(itos(E->get())); - gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved), varray(E->get())); - gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node), varray(E->get()), CONNECT_DEFERRED); + gnode->set_name(itos(E)); + gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved), varray(E)); + gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node), varray(E), CONNECT_DEFERRED); { Ref<VisualScriptFunction> v = node; @@ -696,7 +694,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Button *btn = memnew(Button); btn->set_text(TTR("Add Input Port")); hbnc->add_child(btn); - btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port), varray(E->get()), CONNECT_DEFERRED); + btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port), varray(E), CONNECT_DEFERRED); } if (nd_list->is_output_port_editable()) { if (nd_list->is_input_port_editable()) { @@ -706,7 +704,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Button *btn = memnew(Button); btn->set_text(TTR("Add Output Port")); hbnc->add_child(btn); - btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port), varray(E->get()), CONNECT_DEFERRED); + btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port), varray(E), CONNECT_DEFERRED); } gnode->add_child(hbnc); } else if (Object::cast_to<VisualScriptExpression>(node.ptr())) { @@ -716,7 +714,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { line_edit->set_expand_to_text_length_enabled(true); line_edit->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts"))); gnode->add_child(line_edit); - line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get())); + line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E)); } else { String text = node->get_text(); if (!text.is_empty()) { @@ -732,7 +730,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { gnode->set_comment(true); gnode->set_resizable(true); gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE); - gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized), varray(E->get())); + gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized), varray(E)); } if (node_styles.has(node->get_category())) { @@ -835,8 +833,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); name_box->set_text(left_name); name_box->set_expand_to_text_length_enabled(true); - name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get())); - name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true)); + name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E)); + name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E, i, true)); } else { hbc->add_child(memnew(Label(left_name))); } @@ -849,18 +847,18 @@ void VisualScriptEditor::_update_graph(int p_only_id) { opbtn->select(left_type); opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); hbc->add_child(opbtn); - opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, true), CONNECT_DEFERRED); + opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E, i, true), CONNECT_DEFERRED); } Button *rmbtn = memnew(Button); rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); hbc->add_child(rmbtn); - rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E->get(), i), CONNECT_DEFERRED); + rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E, i), CONNECT_DEFERRED); } else { hbc->add_child(memnew(Label(left_name))); } - if (left_type != Variant::NIL && !script->is_input_value_port_connected(E->get(), i)) { + if (left_type != Variant::NIL && !script->is_input_value_port_connected(E, i)) { PropertyInfo pi = node->get_input_value_port_info(i); Button *button = memnew(Button); Variant value = node->get_default_input_value(i); @@ -887,7 +885,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { } else { button->set_text(value); } - button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited), varray(button, E->get(), i)); + button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited), varray(button, E, i)); hbc2->add_child(button); } } else { @@ -911,7 +909,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Button *rmbtn = memnew(Button); rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); hbc->add_child(rmbtn); - rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E->get(), i), CONNECT_DEFERRED); + rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E, i), CONNECT_DEFERRED); if (nd_list->is_output_port_type_editable()) { OptionButton *opbtn = memnew(OptionButton); @@ -921,7 +919,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { opbtn->select(right_type); opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); hbc->add_child(opbtn); - opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E->get(), i, false), CONNECT_DEFERRED); + opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E, i, false), CONNECT_DEFERRED); } if (nd_list->is_output_port_name_editable()) { @@ -930,8 +928,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0)); name_box->set_text(right_name); name_box->set_expand_to_text_length_enabled(true); - name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get())); - name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false)); + name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E)); + name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E, i, false)); } else { hbc->add_child(memnew(Label(right_name))); } @@ -986,7 +984,7 @@ void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, b return; } - undo_redo->create_action("Change Port Type"); + undo_redo->create_action(TTR("Change Port Type")); if (is_input) { undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_type", p_port, Variant::Type(p_select)); undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_type", p_port, vsn->get_input_value_port_info(p_port).type); @@ -1018,7 +1016,7 @@ void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, return; } - undo_redo->create_action("Change Port Name"); + undo_redo->create_action(TTR("Change Port Name")); if (is_input) { undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_name", p_port, text); undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_name", p_port, vsn->get_input_value_port_info(p_port).name); @@ -1047,13 +1045,13 @@ void VisualScriptEditor::_update_members() { List<StringName> func_names; script->get_function_list(&func_names); func_names.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = func_names.front(); E; E = E->next()) { + for (const StringName &E : func_names) { TreeItem *ti = members->create_item(functions); - ti->set_text(0, E->get()); + ti->set_text(0, E); ti->set_selectable(0, true); - ti->set_metadata(0, E->get()); + ti->set_metadata(0, E); ti->add_button(0, Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), 0); - if (selected == E->get()) { + if (selected == E) { ti->select(0); } } @@ -1101,18 +1099,18 @@ void VisualScriptEditor::_update_members() { List<StringName> var_names; script->get_variable_list(&var_names); - for (List<StringName>::Element *E = var_names.front(); E; E = E->next()) { + for (const StringName &E : var_names) { TreeItem *ti = members->create_item(variables); - ti->set_text(0, E->get()); + ti->set_text(0, E); - ti->set_suffix(0, "= " + _sanitized_variant_text(E->get())); - ti->set_icon(0, type_icons[script->get_variable_info(E->get()).type]); + ti->set_suffix(0, "= " + _sanitized_variant_text(E)); + ti->set_icon(0, type_icons[script->get_variable_info(E).type]); ti->set_selectable(0, true); ti->set_editable(0, true); - ti->set_metadata(0, E->get()); - if (selected == E->get()) { + ti->set_metadata(0, E); + if (selected == E) { ti->select(0); } } @@ -1125,13 +1123,13 @@ void VisualScriptEditor::_update_members() { List<StringName> signal_names; script->get_custom_signal_list(&signal_names); - for (List<StringName>::Element *E = signal_names.front(); E; E = E->next()) { + for (const StringName &E : signal_names) { TreeItem *ti = members->create_item(_signals); - ti->set_text(0, E->get()); + ti->set_text(0, E); ti->set_selectable(0, true); ti->set_editable(0, true); - ti->set_metadata(0, E->get()); - if (selected == E->get()) { + ti->set_metadata(0, E); + if (selected == E) { ti->select(0); } } @@ -1237,8 +1235,8 @@ void VisualScriptEditor::_member_edited() { // Also fix all function calls. List<int> lst; script->get_node_list(&lst); - for (List<int>::Element *F = lst.front(); F; F = F->next()) { - Ref<VisualScriptFunctionCall> fncall = script->get_node(F->get()); + for (int &F : lst) { + Ref<VisualScriptFunctionCall> fncall = script->get_node(F); if (!fncall.is_valid()) { continue; } @@ -1572,13 +1570,13 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { script->get_data_connection_list(&data_connections); HashMap<int, Set<int>> conn_map; - for (const List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (E->get().from_node == p_id && E->get().from_port == p_port) { + 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->get().to_node)) { - conn_map.set(E->get().to_node, Set<int>()); + if (!conn_map.has(E.to_node)) { + conn_map.set(E.to_node, Set<int>()); } - conn_map[E->get().to_node].insert(E->get().to_port); + conn_map[E.to_node].insert(E.to_port); } } @@ -1587,9 +1585,9 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) { List<int> keys; conn_map.get_key_list(&keys); - for (const List<int>::Element *E = keys.front(); E; E = E->next()) { - for (const Set<int>::Element *F = conn_map[E->get()].front(); F; F = F->next()) { - undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E->get(), F->get()); + 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); } } @@ -1642,8 +1640,8 @@ Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) c bool exists = false; List<int> existing; script->get_node_list(&existing); - for (List<int>::Element *E = existing.front(); E; E = E->next()) { - Point2 pos = script->get_node_position(E->get()); + for (int &E : existing) { + Point2 pos = script->get_node_position(E); if (pos.distance_to(p_pos) < 50) { p_pos += Vector2(graph->get_snap(), graph->get_snap()); exists = true; @@ -1698,8 +1696,8 @@ void VisualScriptEditor::_on_nodes_delete() { undo_redo->create_action(TTR("Remove VisualScript Nodes")); - for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { - int cr_node = F->get(); + for (int &F : to_erase) { + int cr_node = F; undo_redo->add_do_method(script.ptr(), "remove_node", cr_node); undo_redo->add_undo_method(script.ptr(), "add_node", cr_node, script->get_node(cr_node), script->get_node_position(cr_node)); @@ -1707,18 +1705,18 @@ void VisualScriptEditor::_on_nodes_delete() { List<VisualScript::SequenceConnection> sequence_conns; script->get_sequence_connection_list(&sequence_conns); - for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) { - if (E->get().from_node == cr_node || E->get().to_node == cr_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 : sequence_conns) { + if (E.from_node == cr_node || E.to_node == cr_node) { + undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); } } List<VisualScript::DataConnection> data_conns; script->get_data_connection_list(&data_conns); - for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) { - if (E->get().from_node == F->get() || E->get().to_node == F->get()) { - 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 : data_conns) { + if (E.from_node == F || E.to_node == F) { + undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); } } } @@ -1767,17 +1765,17 @@ void VisualScriptEditor::_on_nodes_duplicate() { List<VisualScript::SequenceConnection> seqs; script->get_sequence_connection_list(&seqs); - for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) { - if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]); + for (const VisualScript::SequenceConnection &E : seqs) { + if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]); } } List<VisualScript::DataConnection> data; script->get_data_connection_list(&data); - for (List<VisualScript::DataConnection>::Element *E = data.front(); E; E = E->next()) { - if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) { - 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); + for (const VisualScript::DataConnection &E : data) { + if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) { + undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port); } } @@ -1903,8 +1901,8 @@ void VisualScriptEditor::_rename_function(const String &name, const String &new_ // Also fix all function calls. List<int> lst; script->get_node_list(&lst); - for (List<int>::Element *F = lst.front(); F; F = F->next()) { - Ref<VisualScriptFunctionCall> fncall = script->get_node(F->get()); + for (int &F : lst) { + Ref<VisualScriptFunctionCall> fncall = script->get_node(F); if (!fncall.is_valid()) { continue; } @@ -2188,7 +2186,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da int new_id = script->get_available_id(); if (files.size()) { - undo_redo->create_action(TTR("Add Preload Node")); + undo_redo->create_action(TTR("Add Node(s)")); for (int i = 0; i < files.size(); i++) { Ref<Resource> res = ResourceLoader::load(files[i]); @@ -2221,8 +2219,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da undo_redo->commit_action(); } - for (List<int>::Element *E = new_ids.front(); E; E = E->next()) { - Node *node = graph->get_node(itos(E->get())); + for (int &E : new_ids) { + Node *node = graph->get_node(itos(E)); if (node) { graph->set_selected(node); _node_selected(node); @@ -2554,12 +2552,12 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) { List<StringName> functions; script->get_function_list(&functions); - for (List<StringName>::Element *E = functions.front(); E; E = E->next()) { + for (const StringName &E : functions) { if (script->has_node(p_line)) { _update_graph(); _update_members(); - call_deferred(SNAME("call_deferred"), "_center_on_node", E->get(), p_line); //editor might be just created and size might not exist yet + call_deferred(SNAME("call_deferred"), "_center_on_node", E, p_line); //editor might be just created and size might not exist yet return; } } @@ -2600,13 +2598,13 @@ Array VisualScriptEditor::get_breakpoints() { Array breakpoints; List<StringName> functions; script->get_function_list(&functions); - for (List<StringName>::Element *E = functions.front(); E; E = E->next()) { + for (int i = 0; i < functions.size(); i++) { List<int> nodes; script->get_node_list(&nodes); - for (List<int>::Element *F = nodes.front(); F; F = F->next()) { - Ref<VisualScriptNode> vsn = script->get_node(F->get()); + for (int &F : nodes) { + Ref<VisualScriptNode> vsn = script->get_node(F); if (vsn->is_breakpoint()) { - breakpoints.push_back(F->get() - 1); // Subtract 1 because breakpoints in text start from zero. + breakpoints.push_back(F - 1); // Subtract 1 because breakpoints in text start from zero. } } } @@ -2775,18 +2773,18 @@ void VisualScriptEditor::_remove_node(int p_id) { List<VisualScript::SequenceConnection> sequence_conns; script->get_sequence_connection_list(&sequence_conns); - for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) { - if (E->get().from_node == p_id || E->get().to_node == p_id) { - 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 : sequence_conns) { + if (E.from_node == p_id || E.to_node == p_id) { + undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node); } } List<VisualScript::DataConnection> data_conns; script->get_data_connection_list(&data_conns); - for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) { - if (E->get().from_node == p_id || E->get().to_node == p_id) { - 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 : data_conns) { + if (E.from_node == p_id || E.to_node == p_id) { + undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port); } } @@ -2804,9 +2802,9 @@ bool VisualScriptEditor::node_has_sequence_connections(int p_id) { List<VisualScript::SequenceConnection> sequence_conns; script->get_sequence_connection_list(&sequence_conns); - for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) { - int from = E->get().from_node; - int to = E->get().to_node; + for (const VisualScript::SequenceConnection &E : sequence_conns) { + int from = E.from_node; + int to = E.to_node; if (to == p_id || from == p_id) { return true; @@ -3462,9 +3460,9 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons List<MethodInfo> methods; bool found = false; ClassDB::get_virtual_methods(script->get_instance_base_type(), &methods); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name == name) { - minfo = E->get(); + for (const MethodInfo &E : methods) { + if (E.name == name) { + minfo = E; found = true; } } @@ -3734,8 +3732,8 @@ void VisualScriptEditor::_menu_option(int p_what) { _update_graph(); - for (List<String>::Element *E = reselect.front(); E; E = E->next()) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E->get())); + for (const String &E : reselect) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E)); gn->set_selected(true); } @@ -3774,18 +3772,18 @@ void VisualScriptEditor::_menu_option(int p_what) { List<VisualScript::SequenceConnection> sequence_connections; script->get_sequence_connection_list(&sequence_connections); - for (List<VisualScript::SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) { - if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) { - clipboard->sequence_connections.insert(E->get()); + for (const VisualScript::SequenceConnection &E : sequence_connections) { + if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { + clipboard->sequence_connections.insert(E); } } List<VisualScript::DataConnection> data_connections; script->get_data_connection_list(&data_connections); - for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) { - if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) { - clipboard->data_connections.insert(E->get()); + for (const VisualScript::DataConnection &E : data_connections) { + if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) { + clipboard->data_connections.insert(E); } } if (p_what == EDIT_CUT_NODES) { @@ -3811,8 +3809,8 @@ void VisualScriptEditor::_menu_option(int p_what) { { List<int> nodes; script->get_node_list(&nodes); - for (List<int>::Element *E = nodes.front(); E; E = E->next()) { - Vector2 pos = script->get_node_position(E->get()).snapped(Vector2(2, 2)); + for (int &E : nodes) { + Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2)); existing_positions.insert(pos); } } @@ -3935,22 +3933,22 @@ void VisualScriptEditor::_menu_option(int p_what) { // Pick the node with input sequence. Set<int> nodes_from; Set<int> nodes_to; - for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) { - if (nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) { - seqmove.insert(E->get()); - nodes_from.insert(E->get().from_node); - } else if (nodes.has(E->get().from_node) && !nodes.has(E->get().to_node)) { - seqext.insert(E->get()); - } else if (!nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) { + for (const VisualScript::SequenceConnection &E : seqs) { + if (nodes.has(E.from_node) && nodes.has(E.to_node)) { + seqmove.insert(E); + nodes_from.insert(E.from_node); + } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) { + seqext.insert(E); + } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) { if (start_node == -1) { - seqext.insert(E->get()); - start_node = E->get().to_node; + seqext.insert(E); + start_node = E.to_node; } else { EditorNode::get_singleton()->show_warning(TTR("Try to only have one sequence input in selection.")); return; } } - nodes_to.insert(E->get().to_node); + nodes_to.insert(E.to_node); } // To use to add return nodes. @@ -3978,20 +3976,20 @@ void VisualScriptEditor::_menu_option(int p_what) { { List<VisualScript::DataConnection> dats; script->get_data_connection_list(&dats); - for (List<VisualScript::DataConnection>::Element *E = dats.front(); E; E = E->next()) { - if (nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) { - datamove.insert(E->get()); - } else if (!nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) { + for (const VisualScript::DataConnection &E : dats) { + if (nodes.has(E.from_node) && nodes.has(E.to_node)) { + datamove.insert(E); + } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) { // Add all these as inputs for the Function. - Ref<VisualScriptNode> node = script->get_node(E->get().to_node); + Ref<VisualScriptNode> node = script->get_node(E.to_node); if (node.is_valid()) { - dataext.insert(E->get()); - PropertyInfo pi = node->get_input_value_port_info(E->get().to_port); + dataext.insert(E); + PropertyInfo pi = node->get_input_value_port_info(E.to_port); inputs.push_back(pi.type); - input_connections.push_back(Pair<int, int>(E->get().to_node, E->get().to_port)); + input_connections.push_back(Pair<int, int>(E.to_node, E.to_port)); } - } else if (nodes.has(E->get().from_node) && !nodes.has(E->get().to_node)) { - dataext.insert(E->get()); + } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) { + dataext.insert(E); } } } @@ -4092,9 +4090,9 @@ void VisualScriptEditor::_menu_option(int p_what) { // 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) { - for (const List<VisualScript::SequenceConnection>::Element *E = p_seqs.front(); E; E = E->next()) { - int from = E->get().from_node; - int to = E->get().to_node; + for (const VisualScript::SequenceConnection &E : p_seqs) { + int from = E.from_node; + int to = E.to_node; if (from == p_node && p_selected.has(to)) { // This is an interior connection move forward to the to node. @@ -4168,16 +4166,16 @@ void VisualScriptEditor::_member_option(int p_option) { undo_redo->add_undo_method(script.ptr(), "add_node", fn_node, script->get_node(fn_node), script->get_node_position(fn_node)); List<VisualScript::SequenceConnection> seqcons; script->get_sequence_connection_list(&seqcons); - for (const List<VisualScript::SequenceConnection>::Element *E = seqcons.front(); E; E = E->next()) { - if (E->get().from_node == fn_node) { - undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E->get().from_output, E->get().to_node); + for (const VisualScript::SequenceConnection &E : seqcons) { + if (E.from_node == fn_node) { + undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E.from_output, E.to_node); } } List<VisualScript::DataConnection> datcons; script->get_data_connection_list(&datcons); - for (const List<VisualScript::DataConnection>::Element *E = datcons.front(); E; E = E->next()) { - if (E->get().from_node == fn_node) { - undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E->get().from_port, E->get().to_node, E->get().to_port); + for (const VisualScript::DataConnection &E : datcons) { + if (E.from_node == fn_node) { + undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E.from_port, E.to_node, E.to_port); } } undo_redo->add_do_method(this, "_update_members"); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index af86f90b25..62a4f465cb 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -852,11 +852,11 @@ void VisualScriptTypeCast::_bind_methods() { } String script_ext_hint; - for (List<String>::Element *E = script_extensions.front(); E; E = E->next()) { + for (const String &E : script_extensions) { if (script_ext_hint != String()) { script_ext_hint += ","; } - script_ext_hint += "*." + E->get(); + script_ext_hint += "*." + E; } ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type"); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 7b5ca56dcc..6ba5ad4fd6 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -538,11 +538,11 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const Engine::get_singleton()->get_singletons(&names); property.hint = PROPERTY_HINT_ENUM; String sl; - for (List<Engine::Singleton>::Element *E = names.front(); E; E = E->next()) { + for (const Engine::Singleton &E : names) { if (sl != String()) { sl += ","; } - sl += E->get().name; + sl += E.name; } property.hint_string = sl; } @@ -683,11 +683,11 @@ void VisualScriptFunctionCall::_bind_methods() { } String script_ext_hint; - for (List<String>::Element *E = script_extensions.front(); E; E = E->next()) { + for (const String &E : script_extensions) { if (script_ext_hint != String()) { script_ext_hint += ","; } - script_ext_hint += "*." + E->get(); + script_ext_hint += "*." + E; } ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode"); @@ -1004,13 +1004,13 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const List<PropertyInfo> props; ClassDB::get_property_list(_get_base_type(), &props, false); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (E->get().name == property) { + for (const PropertyInfo &E : props) { + if (E.name == property) { String detail_prop_name = property; if (index != StringName()) { detail_prop_name += "." + String(index); } - PropertyInfo pinfo = PropertyInfo(E->get().type, detail_prop_name, PROPERTY_HINT_TYPE_STRING, E->get().hint_string); + PropertyInfo pinfo = PropertyInfo(E.type, detail_prop_name, PROPERTY_HINT_TYPE_STRING, E.hint_string); _adjust_input_index(pinfo); return pinfo; } @@ -1135,9 +1135,9 @@ void VisualScriptPropertySet::_update_cache() { List<PropertyInfo> pinfo; v.get_property_list(&pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().name == property) { - type_cache = E->get(); + for (const PropertyInfo &E : pinfo) { + if (E.name == property) { + type_cache = E; } } @@ -1186,9 +1186,9 @@ void VisualScriptPropertySet::_update_cache() { script->get_script_property_list(&pinfo); } - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().name == property) { - type_cache = E->get(); + for (const PropertyInfo &E : pinfo) { + if (E.name == property) { + type_cache = E; return; } } @@ -1354,8 +1354,8 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { List<PropertyInfo> plist; v.get_property_list(&plist); String options = ""; - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - options += "," + E->get().name; + for (const PropertyInfo &E : plist) { + options += "," + E.name; } property.hint = PROPERTY_HINT_ENUM; @@ -1410,11 +1410,11 @@ void VisualScriptPropertySet::_bind_methods() { } String script_ext_hint; - for (List<String>::Element *E = script_extensions.front(); E; E = E->next()) { + for (const String &E : script_extensions) { if (script_ext_hint != String()) { script_ext_hint += ","; } - script_ext_hint += "*." + E->get(); + script_ext_hint += "*." + E; } ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); @@ -1820,9 +1820,9 @@ void VisualScriptPropertyGet::_update_cache() { List<PropertyInfo> pinfo; v.get_property_list(&pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().name == property) { - type_cache = E->get().type; + for (const PropertyInfo &E : pinfo) { + if (E.name == property) { + type_cache = E.type; return; } } @@ -2059,8 +2059,8 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { List<PropertyInfo> plist; v.get_property_list(&plist); String options = ""; - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - options += "," + E->get().name; + for (const PropertyInfo &E : plist) { + options += "," + E.name; } property.hint = PROPERTY_HINT_ENUM; @@ -2112,11 +2112,11 @@ void VisualScriptPropertyGet::_bind_methods() { } String script_ext_hint; - for (List<String>::Element *E = script_extensions.front(); E; E = E->next()) { + for (const String &E : script_extensions) { if (script_ext_hint != String()) { script_ext_hint += ","; } - script_ext_hint += "." + E->get(); + script_ext_hint += "." + E; } ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode"); @@ -2268,7 +2268,7 @@ int VisualScriptEmitSignal::get_input_value_port_count() const { } int VisualScriptEmitSignal::get_output_value_port_count() const { - return 1; + return 0; } String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const { @@ -2311,16 +2311,6 @@ StringName VisualScriptEmitSignal::get_signal() const { return name; } -void VisualScriptEmitSignal::_adjust_input_index(PropertyInfo &pinfo) const { - if (index != StringName()) { - Variant v; - Callable::CallError ce; - Variant::construct(pinfo.type, v, nullptr, 0, ce); - Variant i = v.get(index); - pinfo.type = i.get_type(); - } -} - void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { if (property.name == "signal") { property.hint = PROPERTY_HINT_ENUM; @@ -2333,11 +2323,11 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const { } String ml; - for (List<StringName>::Element *E = sigs.front(); E; E = E->next()) { + for (const StringName &E : sigs) { if (ml != String()) { ml += ","; } - ml += E->get(); + ml += E; } property.hint_string = ml; @@ -2428,8 +2418,8 @@ void register_visual_script_func_nodes() { List<MethodInfo> ml; vt.get_method_list(&ml); - for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) { - VisualScriptLanguage::singleton->add_register_func("functions/by_type/" + type_name + "/" + E->get().name, create_basic_type_call_node); + for (const MethodInfo &E : ml) { + VisualScriptLanguage::singleton->add_register_func("functions/by_type/" + type_name + "/" + E.name, create_basic_type_call_node); } } } diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 37a707d108..cca08455f9 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -328,9 +328,6 @@ class VisualScriptEmitSignal : public VisualScriptNode { private: StringName name; - StringName index; - - void _adjust_input_index(PropertyInfo &pinfo) const; protected: virtual void _validate_property(PropertyInfo &property) const override; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 86d8050acb..c517d89aa5 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -1306,12 +1306,12 @@ void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const { vs->get_variable_list(&vars); String vhint; - for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { + for (const StringName &E : vars) { if (vhint != String()) { vhint += ","; } - vhint += E->get().operator String(); + vhint += E.operator String(); } property.hint = PROPERTY_HINT_ENUM; @@ -1416,12 +1416,12 @@ void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const { vs->get_variable_list(&vars); String vhint; - for (List<StringName>::Element *E = vars.front(); E; E = E->next()) { + for (const StringName &E : vars) { if (vhint != String()) { vhint += ","; } - vhint += E->get().operator String(); + vhint += E.operator String(); } property.hint = PROPERTY_HINT_ENUM; @@ -1944,8 +1944,8 @@ void VisualScriptClassConstant::set_base_type(const StringName &p_which) { ClassDB::get_integer_constant_list(base_type, &constants, true); if (constants.size() > 0) { bool found_name = false; - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - if (E->get() == name) { + for (const String &E : constants) { + if (E == name) { found_name = true; break; } @@ -1993,11 +1993,11 @@ void VisualScriptClassConstant::_validate_property(PropertyInfo &property) const ClassDB::get_integer_constant_list(base_type, &constants, true); property.hint_string = ""; - for (List<String>::Element *E = constants.front(); E; E = E->next()) { + for (const String &E : constants) { if (property.hint_string != String()) { property.hint_string += ","; } - property.hint_string += E->get(); + property.hint_string += E; } } } @@ -2078,8 +2078,8 @@ void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) { Variant::get_constants_for_type(type, &constants); if (constants.size() > 0) { bool found_name = false; - for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { - if (E->get() == name) { + for (const StringName &E : constants) { + if (E == name) { found_name = true; break; } @@ -2131,11 +2131,11 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c return; } property.hint_string = ""; - for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { + for (const StringName &E : constants) { if (property.hint_string != String()) { property.hint_string += ","; } - property.hint_string += String(E->get()); + property.hint_string += String(E); } } } @@ -2358,15 +2358,15 @@ void VisualScriptEngineSingleton::_validate_property(PropertyInfo &property) con Engine::get_singleton()->get_singletons(&singletons); - for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) { - if (E->get().name == "VS" || E->get().name == "PS" || E->get().name == "PS2D" || E->get().name == "AS" || E->get().name == "TS" || E->get().name == "SS" || E->get().name == "SS2D") { + for (const Engine::Singleton &E : singletons) { + if (E.name == "VS" || E.name == "PS" || E.name == "PS2D" || E.name == "AS" || E.name == "TS" || E.name == "SS" || E.name == "SS2D") { continue; //skip these, too simple named } if (cc != String()) { cc += ","; } - cc += E->get().name; + cc += E.name; } property.hint = PROPERTY_HINT_ENUM; @@ -3749,9 +3749,7 @@ void VisualScriptInputAction::_validate_property(PropertyInfo &property) const { ProjectSettings::get_singleton()->get_property_list(&pinfo); Vector<String> al; - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - const PropertyInfo &pi = E->get(); - + for (const PropertyInfo &pi : pinfo) { if (!pi.name.begins_with("input/")) { continue; } @@ -3844,10 +3842,10 @@ void VisualScriptDeconstruct::_update_elements() { List<PropertyInfo> pinfo; v.get_property_list(&pinfo); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { + for (const PropertyInfo &E : pinfo) { Element e; - e.name = E->get().name; - e.type = E->get().type; + e.name = E.name; + e.type = E.type; elements.push_back(e); } } @@ -4025,24 +4023,24 @@ void register_visual_script_nodes() { List<MethodInfo> constructors; Variant::get_constructor_list(Variant::Type(i), &constructors); - for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) { - if (E->get().arguments.size() > 0) { + for (const MethodInfo &E : constructors) { + if (E.arguments.size() > 0) { String name = "functions/constructors/" + Variant::get_type_name(Variant::Type(i)) + "("; - for (int j = 0; j < E->get().arguments.size(); j++) { + for (int j = 0; j < E.arguments.size(); j++) { if (j > 0) { name += ", "; } - if (E->get().arguments.size() == 1) { - name += Variant::get_type_name(E->get().arguments[j].type); + if (E.arguments.size() == 1) { + name += Variant::get_type_name(E.arguments[j].type); } else { - name += E->get().arguments[j].name; + name += E.arguments[j].name; } } name += ")"; VisualScriptLanguage::singleton->add_register_func(name, create_constructor_node); Pair<Variant::Type, MethodInfo> pair; pair.first = Variant::Type(i); - pair.second = E->get(); + pair.second = E; constructor_map[name] = pair; } } diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index ccb2e2df75..8bf1c6cbfa 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -93,7 +93,7 @@ void VisualScriptPropertySelector::_update_search() { base = ClassDB::get_parent_class_nocheck(base); } - for (List<StringName>::Element *E = base_list.front(); E; E = E->next()) { + for (const StringName &E : base_list) { List<MethodInfo> methods; List<PropertyInfo> props; TreeItem *category = nullptr; @@ -135,7 +135,7 @@ void VisualScriptPropertySelector::_update_search() { vbc->get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons")) }; { - String b = String(E->get()); + String b = String(E); category = search_options->create_item(root); if (category) { category->set_text(0, b.replace_first("*", "")); @@ -154,30 +154,30 @@ void VisualScriptPropertySelector::_update_search() { if (Object::cast_to<Script>(obj)) { Object::cast_to<Script>(obj)->get_script_property_list(&props); } else { - ClassDB::get_property_list(E->get(), &props, true); + ClassDB::get_property_list(E, &props, true); } } - for (List<PropertyInfo>::Element *F = props.front(); F; F = F->next()) { - if (!(F->get().usage & PROPERTY_USAGE_EDITOR) && !(F->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE)) { + for (const PropertyInfo &F : props) { + if (!(F.usage & PROPERTY_USAGE_EDITOR) && !(F.usage & PROPERTY_USAGE_SCRIPT_VARIABLE)) { continue; } - if (type_filter.size() && type_filter.find(F->get().type) == -1) { + if (type_filter.size() && type_filter.find(F.type) == -1) { continue; } // capitalize() also converts underscore to space, we'll match again both possible styles - String get_text_raw = String(vformat(TTR("Get %s"), F->get().name)); + String get_text_raw = String(vformat(TTR("Get %s"), F.name)); String get_text = get_text_raw.capitalize(); - String set_text_raw = String(vformat(TTR("Set %s"), F->get().name)); + String set_text_raw = String(vformat(TTR("Set %s"), F.name)); String set_text = set_text_raw.capitalize(); String input = search_box->get_text().capitalize(); if (input == String() || get_text_raw.findn(input) != -1 || get_text.findn(input) != -1) { TreeItem *item = search_options->create_item(category ? category : root); item->set_text(0, get_text); - item->set_metadata(0, F->get().name); - item->set_icon(0, type_icons[F->get().type]); + item->set_metadata(0, F.name); + item->set_icon(0, type_icons[F.type]); item->set_metadata(1, "get"); item->set_collapsed(true); item->set_selectable(0, true); @@ -189,8 +189,8 @@ void VisualScriptPropertySelector::_update_search() { if (input == String() || set_text_raw.findn(input) != -1 || set_text.findn(input) != -1) { TreeItem *item = search_options->create_item(category ? category : root); item->set_text(0, set_text); - item->set_metadata(0, F->get().name); - item->set_icon(0, type_icons[F->get().type]); + item->set_metadata(0, F.name); + item->set_icon(0, type_icons[F.type]); item->set_metadata(1, "set"); item->set_selectable(0, true); item->set_selectable(1, false); @@ -211,7 +211,7 @@ void VisualScriptPropertySelector::_update_search() { Object::cast_to<Script>(obj)->get_script_method_list(&methods); } - ClassDB::get_method_list(E->get(), &methods, true, true); + ClassDB::get_method_list(E, &methods, true, true); } } for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) { @@ -340,11 +340,11 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt List<String> fnodes; VisualScriptLanguage::singleton->get_registered_node_names(&fnodes); - for (List<String>::Element *E = fnodes.front(); E; E = E->next()) { - if (!E->get().begins_with(root_filter)) { + for (const String &E : fnodes) { + if (!E.begins_with(root_filter)) { continue; } - Vector<String> path = E->get().split("/"); + Vector<String> path = E.split("/"); // check if the name has the filter bool in_filter = false; @@ -355,7 +355,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt } else { in_filter = false; } - if (E->get().findn(tx_filters[i]) != -1) { + if (E.findn(tx_filters[i]) != -1) { in_filter = true; break; } @@ -366,7 +366,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt bool in_modifier = p_modifiers.is_empty(); for (Set<String>::Element *F = p_modifiers.front(); F && in_modifier; F = F->next()) { - if (E->get().findn(F->get()) != -1) { + if (E.findn(F->get()) != -1) { in_modifier = true; } } @@ -375,7 +375,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt } TreeItem *item = search_options->create_item(root); - Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(E->get()); + Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(E); Ref<VisualScriptOperator> vnode_operator = vnode; String type_name; if (vnode_operator.is_valid()) { @@ -409,7 +409,7 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt item->set_text(0, type_name + String("").join(desc)); item->set_icon(0, vbc->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"))); item->set_selectable(0, true); - item->set_metadata(0, E->get()); + item->set_metadata(0, E); item->set_selectable(0, true); item->set_metadata(1, "visualscript"); item->set_selectable(1, false); diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index d8bc926a1d..9fa49b8a1d 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -438,21 +438,21 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { ClassDB::get_signal_list(_get_base_type(), &methods); List<String> mstring; - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("_")) { + for (const MethodInfo &E : methods) { + if (E.name.begins_with("_")) { continue; } - mstring.push_back(E->get().name.get_slice(":", 0)); + mstring.push_back(E.name.get_slice(":", 0)); } mstring.sort(); String ml; - for (List<String>::Element *E = mstring.front(); E; E = E->next()) { + for (const String &E : mstring) { if (ml != String()) { ml += ","; } - ml += E->get(); + ml += E; } property.hint_string = ml; diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml index f3e13ba31a..3b9acfd873 100644 --- a/modules/webm/doc_classes/VideoStreamWebm.xml +++ b/modules/webm/doc_classes/VideoStreamWebm.xml @@ -12,17 +12,14 @@ </tutorials> <methods> <method name="get_file"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the WebM video file handled by this [VideoStreamWebm]. </description> </method> <method name="set_file"> - <return type="void"> - </return> - <argument index="0" name="file" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="file" type="String" /> <description> Sets the WebM video file that this [VideoStreamWebm] resource handles. The [code]file[/code] name should have the [code].webm[/code] extension. </description> diff --git a/modules/webrtc/doc_classes/WebRTCDataChannel.xml b/modules/webrtc/doc_classes/WebRTCDataChannel.xml index 3435dda982..cf5735bab5 100644 --- a/modules/webrtc/doc_classes/WebRTCDataChannel.xml +++ b/modules/webrtc/doc_classes/WebRTCDataChannel.xml @@ -8,88 +8,76 @@ </tutorials> <methods> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Closes this data channel, notifying the other peer. </description> </method> <method name="get_buffered_amount" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the number of bytes currently queued to be sent over this channel. </description> </method> <method name="get_id" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the id assigned to this channel during creation (or auto-assigned during negotiation). If the channel is not negotiated out-of-band the id will only be available after the connection is established (will return [code]65535[/code] until then). </description> </method> <method name="get_label" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the label assigned to this channel during creation. </description> </method> <method name="get_max_packet_life_time" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the [code]maxPacketLifeTime[/code] value assigned to this channel during creation. Will be [code]65535[/code] if not specified. </description> </method> <method name="get_max_retransmits" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the [code]maxRetransmits[/code] value assigned to this channel during creation. Will be [code]65535[/code] if not specified. </description> </method> <method name="get_protocol" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the sub-protocol assigned to this channel during creation. An empty string if not specified. </description> </method> <method name="get_ready_state" qualifiers="const"> - <return type="int" enum="WebRTCDataChannel.ChannelState"> - </return> + <return type="int" enum="WebRTCDataChannel.ChannelState" /> <description> Returns the current state of this channel, see [enum ChannelState]. </description> </method> <method name="is_negotiated" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this channel was created with out-of-band configuration. </description> </method> <method name="is_ordered" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this channel was created with ordering enabled (default). </description> </method> <method name="poll"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Reserved, but not used for now. </description> </method> <method name="was_string_packet" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the last received packet was transferred as text. See [member write_mode]. </description> diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 26c5bfa6ce..c53af22ae1 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -12,69 +12,56 @@ </tutorials> <methods> <method name="add_peer"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="peer" type="WebRTCPeerConnection"> - </argument> - <argument index="1" name="peer_id" type="int"> - </argument> - <argument index="2" name="unreliable_lifetime" type="int" default="1"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="peer" type="WebRTCPeerConnection" /> + <argument index="1" name="peer_id" type="int" /> + <argument index="2" name="unreliable_lifetime" type="int" default="1" /> <description> Add a new peer to the mesh with the given [code]peer_id[/code]. The [WebRTCPeerConnection] must be in state [constant WebRTCPeerConnection.STATE_NEW]. Three channels will be created for reliable, unreliable, and ordered transport. The value of [code]unreliable_lifetime[/code] will be passed to the [code]maxPacketLifetime[/code] option when creating unreliable and ordered channels (see [method WebRTCPeerConnection.create_data_channel]). </description> </method> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Close all the add peer connections and channels, freeing all resources. </description> </method> <method name="get_peer"> - <return type="Dictionary"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="Dictionary" /> + <argument index="0" name="peer_id" type="int" /> <description> Return a dictionary representation of the peer with given [code]peer_id[/code] with three keys. [code]connection[/code] containing the [WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three [WebRTCDataChannel], and [code]connected[/code] a boolean representing if the peer connection is currently connected (all three channels are open). </description> </method> <method name="get_peers"> - <return type="Dictionary"> - </return> + <return type="Dictionary" /> <description> Returns a dictionary which keys are the peer ids and values the peer representation as in [method get_peer]. </description> </method> <method name="has_peer"> - <return type="bool"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="peer_id" type="int" /> <description> Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers map (it might not be connected though). </description> </method> <method name="initialize"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> - <argument index="1" name="server_compatibility" type="bool" default="false"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="peer_id" type="int" /> + <argument index="1" name="server_compatibility" type="bool" default="false" /> + <argument index="2" name="channels_config" type="Array" default="[]" /> <description> Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647). If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted. If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED]. + You can optionally specify a [code]channels_config[/code] array of [enum MultiplayerPeer.TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel). </description> </method> <method name="remove_peer"> - <return type="void"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="void" /> + <argument index="0" name="peer_id" type="int" /> <description> Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal MultiplayerPeer.peer_connected] was emitted for it, then [signal MultiplayerPeer.peer_disconnected] will be emitted. </description> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index 62e524825d..f6f360503f 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -15,33 +15,25 @@ </tutorials> <methods> <method name="add_ice_candidate"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="media" type="String"> - </argument> - <argument index="1" name="index" type="int"> - </argument> - <argument index="2" name="name" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="media" type="String" /> + <argument index="1" name="index" type="int" /> + <argument index="2" name="name" type="String" /> <description> Add an ice candidate generated by a remote peer (and received over the signaling server). See [signal ice_candidate_created]. </description> </method> <method name="close"> - <return type="void"> - </return> + <return type="void" /> <description> Close the peer connection and all data channels associated with it. Note, you cannot reuse this object for a new connection unless you call [method initialize]. </description> </method> <method name="create_data_channel"> - <return type="WebRTCDataChannel"> - </return> - <argument index="0" name="label" type="String"> - </argument> + <return type="WebRTCDataChannel" /> + <argument index="0" name="label" type="String" /> <argument index="1" name="options" type="Dictionary" default="{ -}"> - </argument> +}" /> <description> Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with given [code]label[/code] and optionally configured via the [code]options[/code] dictionary. This method can only be called when the connection is in state [constant STATE_NEW]. There are two ways to create a working data channel: either call [method create_data_channel] on only one of the peer and listen to [signal data_channel_received] on the other, or call [method create_data_channel] on both peers, with the same values, and the [code]negotiated[/code] option set to [code]true[/code]. @@ -63,26 +55,22 @@ </description> </method> <method name="create_offer"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Creates a new SDP offer to start a WebRTC connection with a remote peer. At least one [WebRTCDataChannel] must have been created before calling this method. If this functions returns [constant OK], [signal session_description_created] will be called when the session is ready to be sent. </description> </method> <method name="get_connection_state" qualifiers="const"> - <return type="int" enum="WebRTCPeerConnection.ConnectionState"> - </return> + <return type="int" enum="WebRTCPeerConnection.ConnectionState" /> <description> Returns the connection state. See [enum ConnectionState]. </description> </method> <method name="initialize"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <argument index="0" name="configuration" type="Dictionary" default="{ -}"> - </argument> +}" /> <description> Re-initialize this peer connection, closing any previously active connection, and going back to state [constant STATE_NEW]. A dictionary of [code]options[/code] can be passed to configure the peer connection. Valid [code]options[/code] are: @@ -103,31 +91,24 @@ </description> </method> <method name="poll"> - <return type="int" enum="Error"> - </return> + <return type="int" enum="Error" /> <description> Call this method frequently (e.g. in [method Node._process] or [method Node._physics_process]) to properly receive signals. </description> </method> <method name="set_local_description"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Sets the SDP description of the local peer. This should be called in response to [signal session_description_created]. After calling this function the peer will start emitting [signal ice_candidate_created] (unless an [enum Error] different from [constant OK] is returned). </description> </method> <method name="set_remote_description"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Sets the SDP description of the remote peer. This should be called with the values generated by a remote peer and received over the signaling server. If [code]type[/code] is [code]offer[/code] the peer will emit [signal session_description_created] with the appropriate answer. @@ -137,29 +118,23 @@ </methods> <signals> <signal name="data_channel_received"> - <argument index="0" name="channel" type="Object"> - </argument> + <argument index="0" name="channel" type="Object" /> <description> Emitted when a new in-band channel is received, i.e. when the channel was created with [code]negotiated: false[/code] (default). The object will be an instance of [WebRTCDataChannel]. You must keep a reference of it or it will be closed automatically. See [method create_data_channel]. </description> </signal> <signal name="ice_candidate_created"> - <argument index="0" name="media" type="String"> - </argument> - <argument index="1" name="index" type="int"> - </argument> - <argument index="2" name="name" type="String"> - </argument> + <argument index="0" name="media" type="String" /> + <argument index="1" name="index" type="int" /> + <argument index="2" name="name" type="String" /> <description> Emitted when a new ICE candidate has been created. The three parameters are meant to be passed to the remote peer over the signaling server. </description> </signal> <signal name="session_description_created"> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="sdp" type="String"> - </argument> + <argument index="0" name="type" type="String" /> + <argument index="1" name="sdp" type="String" /> <description> Emitted after a successful call to [method create_offer] or [method set_remote_description] (when it generates an answer). The parameters are meant to be passed to [method set_local_description] on this object, and sent to the remote peer over the signaling server. </description> diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 51101e3124..95c8c13449 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -34,7 +34,7 @@ #include "core/os/os.h" void WebRTCMultiplayerPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility", "channels_config"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false), DEFVAL(Array())); ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1)); ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer); ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer); @@ -43,6 +43,14 @@ void WebRTCMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } +void WebRTCMultiplayerPeer::set_transfer_channel(int p_channel) { + transfer_channel = p_channel; +} + +int WebRTCMultiplayerPeer::get_transfer_channel() const { + return transfer_channel; +} + void WebRTCMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } @@ -112,22 +120,22 @@ void WebRTCMultiplayerPeer::poll() { } } // Remove disconnected peers - for (List<int>::Element *E = remove.front(); E; E = E->next()) { - remove_peer(E->get()); - if (next_packet_peer == E->get()) { + for (int &E : remove) { + remove_peer(E); + if (next_packet_peer == E) { next_packet_peer = 0; } } // Signal newly connected peers - for (List<int>::Element *E = add.front(); E; E = E->next()) { + for (int &E : add) { // Already connected to server: simply notify new peer. // NOTE: Mesh is always connected. if (connection_status == CONNECTION_CONNECTED) { - emit_signal(SNAME("peer_connected"), E->get()); + emit_signal(SNAME("peer_connected"), E); } // Server emulation mode suppresses peer_conencted until server connects. - if (server_compat && E->get() == TARGET_PEER_SERVER) { + if (server_compat && E == TARGET_PEER_SERVER) { // Server connected. connection_status = CONNECTION_CONNECTED; emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER); @@ -154,8 +162,8 @@ void WebRTCMultiplayerPeer::_find_next_peer() { } // After last. while (E) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - if (F->get()->get_available_packet_count()) { + for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + if (F->get_available_packet_count()) { next_packet_peer = E->key(); return; } @@ -165,8 +173,8 @@ void WebRTCMultiplayerPeer::_find_next_peer() { E = peer_map.front(); // Before last while (E) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - if (F->get()->get_available_packet_count()) { + for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + if (F->get_available_packet_count()) { next_packet_peer = E->key(); return; } @@ -192,8 +200,34 @@ MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() return connection_status; } -Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat) { - ERR_FAIL_COND_V(p_self_id < 0 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); +Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Array p_channels_config) { + ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); + channels_config.clear(); + for (int i = 0; i < p_channels_config.size(); i++) { + ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'"); + int mode = p_channels_config[i].operator int(); + // Initialize data channel configurations. + Dictionary cfg; + cfg["id"] = CH_RESERVED_MAX + i + 1; + cfg["negotiated"] = true; + cfg["ordered"] = true; + + switch (mode) { + case TRANSFER_MODE_UNRELIABLE_ORDERED: + cfg["maxPacketLifetime"] = 1; + break; + case TRANSFER_MODE_UNRELIABLE: + cfg["maxPacketLifetime"] = 1; + cfg["ordered"] = false; + break; + case TRANSFER_MODE_RELIABLE: + break; + default: + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'. Got: %d", mode)); + } + channels_config.push_back(cfg); + } + unique_id = p_self_id; server_compat = p_server_compat; @@ -213,8 +247,8 @@ int WebRTCMultiplayerPeer::get_unique_id() const { void WebRTCMultiplayerPeer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { Array channels; - for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) { - channels.push_back(F->get()); + for (Ref<WebRTCDataChannel> &F : p_connected_peer->channels) { + channels.push_back(F); } r_dict["connection"] = p_connected_peer->connection; r_dict["connected"] = p_connected_peer->connected; @@ -260,17 +294,23 @@ Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_pe cfg["id"] = 1; peer->channels[CH_RELIABLE] = p_peer->create_data_channel("reliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_RELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_RELIABLE].is_null(), FAILED); cfg["id"] = 2; cfg["maxPacketLifetime"] = p_unreliable_lifetime; peer->channels[CH_ORDERED] = p_peer->create_data_channel("ordered", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_ORDERED].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_ORDERED].is_null(), FAILED); cfg["id"] = 3; cfg["ordered"] = false; peer->channels[CH_UNRELIABLE] = p_peer->create_data_channel("unreliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_UNRELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_UNRELIABLE].is_null(), FAILED); + + for (const Dictionary &dict : channels_config) { + Ref<WebRTCDataChannel> ch = p_peer->create_data_channel(String::num_int64(dict["id"]), dict); + ERR_FAIL_COND_V(ch.is_null(), FAILED); + peer->channels.push_back(ch); + } peer_map[p_peer_id] = peer; // add the new peer connection to the peer_map @@ -297,9 +337,9 @@ Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_ _find_next_peer(); ERR_FAIL_V(ERR_UNAVAILABLE); } - for (List<Ref<WebRTCDataChannel>>::Element *E = peer_map[next_packet_peer]->channels.front(); E; E = E->next()) { - if (E->get()->get_available_packet_count()) { - Error err = E->get()->get_packet(r_buffer, r_buffer_size); + for (Ref<WebRTCDataChannel> &E : peer_map[next_packet_peer]->channels) { + if (E->get_available_packet_count()) { + Error err = E->get_packet(r_buffer, r_buffer_size); _find_next_peer(); return err; } @@ -312,17 +352,21 @@ Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); - int ch = CH_RELIABLE; - switch (transfer_mode) { - case TRANSFER_MODE_RELIABLE: - ch = CH_RELIABLE; - break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: - ch = CH_ORDERED; - break; - case TRANSFER_MODE_UNRELIABLE: - ch = CH_UNRELIABLE; - break; + int ch = transfer_channel; + if (ch == 0) { + switch (transfer_mode) { + case TRANSFER_MODE_RELIABLE: + ch = CH_RELIABLE; + break; + case TRANSFER_MODE_UNRELIABLE_ORDERED: + ch = CH_ORDERED; + break; + case TRANSFER_MODE_UNRELIABLE: + ch = CH_UNRELIABLE; + break; + } + } else { + ch += CH_RESERVED_MAX - 1; } Map<int, Ref<ConnectedPeer>>::Element *E = nullptr; @@ -331,8 +375,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si 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(E->value()->channels.size() <= ch, ERR_BUG); - ERR_FAIL_COND_V(!E->value()->channels[ch].is_valid(), ERR_BUG); + 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 { @@ -344,7 +388,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si continue; } - ERR_CONTINUE(F->value()->channels.size() <= ch || !F->value()->channels[ch].is_valid()); + ERR_CONTINUE_MSG(F->value()->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_CONTINUE(F->value()->channels[ch].is_null()); F->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); } } @@ -357,8 +402,8 @@ int WebRTCMultiplayerPeer::get_available_packet_count() const { } int size = 0; for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { - for (List<Ref<WebRTCDataChannel>>::Element *F = E->get()->channels.front(); F; F = F->next()) { - size += F->get()->get_available_packet_count(); + for (const Ref<WebRTCDataChannel> &F : E->get()->channels) { + size += F->get_available_packet_count(); } } return size; @@ -370,23 +415,13 @@ int WebRTCMultiplayerPeer::get_max_packet_size() const { void WebRTCMultiplayerPeer::close() { peer_map.clear(); + channels_config.clear(); unique_id = 0; next_packet_peer = 0; target_peer = 0; connection_status = CONNECTION_DISCONNECTED; } -WebRTCMultiplayerPeer::WebRTCMultiplayerPeer() { - unique_id = 0; - next_packet_peer = 0; - target_peer = 0; - client_count = 0; - transfer_mode = TRANSFER_MODE_RELIABLE; - refuse_connections = false; - connection_status = CONNECTION_DISCONNECTED; - server_compat = false; -} - WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() { close(); } diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 1d9387b6dc..ef4fe1678c 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -62,25 +62,27 @@ private: } }; - uint32_t unique_id; - int target_peer; - int client_count; - bool refuse_connections; - ConnectionStatus connection_status; - TransferMode transfer_mode; - int next_packet_peer; - bool server_compat; + uint32_t unique_id = 0; + int target_peer = 0; + int client_count = 0; + bool refuse_connections = false; + ConnectionStatus connection_status = CONNECTION_DISCONNECTED; + int transfer_channel = 0; + TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; + int next_packet_peer = 0; + bool server_compat = false; Map<int, Ref<ConnectedPeer>> peer_map; + List<Dictionary> channels_config; void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict); void _find_next_peer(); public: - WebRTCMultiplayerPeer(); + WebRTCMultiplayerPeer() {} ~WebRTCMultiplayerPeer(); - Error initialize(int p_self_id, bool p_server_compat = false); + Error initialize(int p_self_id, bool p_server_compat = false, Array p_channels_config = Array()); Error add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime = 1); void remove_peer(int p_peer_id); bool has_peer(int p_peer_id); @@ -95,6 +97,8 @@ public: int get_max_packet_size() const override; // MultiplayerPeer + void set_transfer_channel(int p_channel) override; + int get_transfer_channel() const override; void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_peer_id) override; diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index 40c0ad17ad..1549a907b4 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -13,16 +13,11 @@ </tutorials> <methods> <method name="connect_to_url"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="url" type="String"> - </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> - </argument> - <argument index="2" name="gd_mp_api" type="bool" default="false"> - </argument> - <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="url" type="String" /> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" /> + <argument index="2" name="gd_mp_api" type="bool" default="false" /> + <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" /> <description> Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested. If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted. @@ -33,26 +28,21 @@ </description> </method> <method name="disconnect_from_host"> - <return type="void"> - </return> - <argument index="0" name="code" type="int" default="1000"> - </argument> - <argument index="1" name="reason" type="String" default=""""> - </argument> + <return type="void" /> + <argument index="0" name="code" type="int" default="1000" /> + <argument index="1" name="reason" type="String" default="""" /> <description> Disconnects this client from the connected host. See [method WebSocketPeer.close] for more information. </description> </method> <method name="get_connected_host" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Return the IP address of the currently connected host. </description> </method> <method name="get_connected_port" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Return the IP port of the currently connected host. </description> @@ -70,8 +60,7 @@ </members> <signals> <signal name="connection_closed"> - <argument index="0" name="was_clean_close" type="bool"> - </argument> + <argument index="0" name="was_clean_close" type="bool" /> <description> Emitted when the connection to the server is closed. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly. </description> @@ -82,8 +71,7 @@ </description> </signal> <signal name="connection_established"> - <argument index="0" name="protocol" type="String"> - </argument> + <argument index="0" name="protocol" type="String" /> <description> Emitted when a connection with the server is established, [code]protocol[/code] will contain the sub-protocol agreed with the server. </description> @@ -95,10 +83,8 @@ </description> </signal> <signal name="server_close_request"> - <argument index="0" name="code" type="int"> - </argument> - <argument index="1" name="reason" type="String"> - </argument> + <argument index="0" name="code" type="int" /> + <argument index="1" name="reason" type="String" /> <description> Emitted when the server requests a clean close. You should keep polling until you get a [signal connection_closed] signal to achieve the clean close. See [method WebSocketPeer.close] for more details. </description> diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index ee1b60f739..cd41e9a1fb 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -10,25 +10,18 @@ </tutorials> <methods> <method name="get_peer" qualifiers="const"> - <return type="WebSocketPeer"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> + <return type="WebSocketPeer" /> + <argument index="0" name="peer_id" type="int" /> <description> Returns the [WebSocketPeer] associated to the given [code]peer_id[/code]. </description> </method> <method name="set_buffers"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="input_buffer_size_kb" type="int"> - </argument> - <argument index="1" name="input_max_packets" type="int"> - </argument> - <argument index="2" name="output_buffer_size_kb" type="int"> - </argument> - <argument index="3" name="output_max_packets" type="int"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="input_buffer_size_kb" type="int" /> + <argument index="1" name="input_max_packets" type="int" /> + <argument index="2" name="output_buffer_size_kb" type="int" /> + <argument index="3" name="output_max_packets" type="int" /> <description> Configures the buffer sizes for this WebSocket peer. Default values can be specified in the Project Settings under [code]network/limits[/code]. For server, values are meant per connected peer. The first two parameters define the size and queued packets limits of the input buffer, the last two of the output buffer. @@ -43,8 +36,7 @@ </members> <signals> <signal name="peer_packet"> - <argument index="0" name="peer_source" type="int"> - </argument> + <argument index="0" name="peer_source" type="int" /> <description> Emitted when a packet is received from a peer. [b]Note:[/b] This signal is only emitted when the client or server is configured to use Godot multiplayer API. diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml index 5125956416..ab7ef6c4d0 100644 --- a/modules/websocket/doc_classes/WebSocketPeer.xml +++ b/modules/websocket/doc_classes/WebSocketPeer.xml @@ -11,12 +11,9 @@ </tutorials> <methods> <method name="close"> - <return type="void"> - </return> - <argument index="0" name="code" type="int" default="1000"> - </argument> - <argument index="1" name="reason" type="String" default=""""> - </argument> + <return type="void" /> + <argument index="0" name="code" type="int" default="1000" /> + <argument index="1" name="reason" type="String" default="""" /> <description> Closes this WebSocket connection. [code]code[/code] is the status code for the closure (see RFC 6455 section 7.4 for a list of valid status codes). [code]reason[/code] is the human readable reason for closing the connection (can be any UTF-8 string that's smaller than 123 bytes). [b]Note:[/b] To achieve a clean close, you will need to keep polling until either [signal WebSocketClient.connection_closed] or [signal WebSocketServer.client_disconnected] is received. @@ -24,57 +21,54 @@ </description> </method> <method name="get_connected_host" qualifiers="const"> - <return type="String"> - </return> + <return type="String" /> <description> Returns the IP address of the connected peer. [b]Note:[/b] Not available in the HTML5 export. </description> </method> <method name="get_connected_port" qualifiers="const"> - <return type="int"> - </return> + <return type="int" /> <description> Returns the remote port of the connected peer. [b]Note:[/b] Not available in the HTML5 export. </description> </method> + <method name="get_current_outbound_buffered_amount" qualifiers="const"> + <return type="int" /> + <description> + Returns the current amount of data in the outbound websocket buffer. [b]Note:[/b] HTML5 exports use WebSocket.bufferedAmount, while other platforms use an internal buffer. + </description> + </method> <method name="get_write_mode" qualifiers="const"> - <return type="int" enum="WebSocketPeer.WriteMode"> - </return> + <return type="int" enum="WebSocketPeer.WriteMode" /> <description> Gets the current selected write mode. See [enum WriteMode]. </description> </method> <method name="is_connected_to_host" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if this peer is currently connected. </description> </method> <method name="set_no_delay"> - <return type="void"> - </return> - <argument index="0" name="enabled" type="bool"> - </argument> + <return type="void" /> + <argument index="0" name="enabled" type="bool" /> <description> Disable Nagle's algorithm on the underling TCP socket (default). See [method StreamPeerTCP.set_no_delay] for more information. [b]Note:[/b] Not available in the HTML5 export. </description> </method> <method name="set_write_mode"> - <return type="void"> - </return> - <argument index="0" name="mode" type="int" enum="WebSocketPeer.WriteMode"> - </argument> + <return type="void" /> + <argument index="0" name="mode" type="int" enum="WebSocketPeer.WriteMode" /> <description> Sets the socket to use the given [enum WriteMode]. </description> </method> <method name="was_string_packet" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the last received packet was sent as a text payload. See [enum WriteMode]. </description> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index 5491f7de15..90182de4c2 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -12,61 +12,46 @@ </tutorials> <methods> <method name="disconnect_peer"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="code" type="int" default="1000"> - </argument> - <argument index="2" name="reason" type="String" default=""""> - </argument> + <return type="void" /> + <argument index="0" name="id" type="int" /> + <argument index="1" name="code" type="int" default="1000" /> + <argument index="2" name="reason" type="String" default="""" /> <description> Disconnects the peer identified by [code]id[/code] from the server. See [method WebSocketPeer.close] for more information. </description> </method> <method name="get_peer_address" qualifiers="const"> - <return type="String"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="String" /> + <argument index="0" name="id" type="int" /> <description> Returns the IP address of the given peer. </description> </method> <method name="get_peer_port" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="int" /> + <argument index="0" name="id" type="int" /> <description> Returns the remote port of the given peer. </description> </method> <method name="has_peer" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="id" type="int"> - </argument> + <return type="bool" /> + <argument index="0" name="id" type="int" /> <description> Returns [code]true[/code] if a peer with the given ID is connected. </description> </method> <method name="is_listening" qualifiers="const"> - <return type="bool"> - </return> + <return type="bool" /> <description> Returns [code]true[/code] if the server is actively listening on a port. </description> </method> <method name="listen"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="port" type="int"> - </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> - </argument> - <argument index="2" name="gd_mp_api" type="bool" default="false"> - </argument> + <return type="int" enum="Error" /> + <argument index="0" name="port" type="int" /> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" /> + <argument index="2" name="gd_mp_api" type="bool" default="false" /> <description> Starts listening on the given port. You can specify the desired subprotocols via the "protocols" array. If the list empty (default), no sub-protocol will be requested. @@ -75,8 +60,7 @@ </description> </method> <method name="stop"> - <return type="void"> - </return> + <return type="void" /> <description> Stops the server and clear its state. </description> @@ -101,40 +85,31 @@ </members> <signals> <signal name="client_close_request"> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="code" type="int"> - </argument> - <argument index="2" name="reason" type="String"> - </argument> + <argument index="0" name="id" type="int" /> + <argument index="1" name="code" type="int" /> + <argument index="2" name="reason" type="String" /> <description> Emitted when a client requests a clean close. You should keep polling until you get a [signal client_disconnected] signal with the same [code]id[/code] to achieve the clean close. See [method WebSocketPeer.close] for more details. </description> </signal> <signal name="client_connected"> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="protocol" type="String"> - </argument> - <argument index="2" name="resource_name" type="String"> - </argument> + <argument index="0" name="id" type="int" /> + <argument index="1" name="protocol" type="String" /> + <argument index="2" name="resource_name" type="String" /> <description> Emitted when a new client connects. "protocol" will be the sub-protocol agreed with the client, and "resource_name" will be the resource name of the URI the peer used. "resource_name" is a path (at the very least a single forward slash) and potentially a query string. </description> </signal> <signal name="client_disconnected"> - <argument index="0" name="id" type="int"> - </argument> - <argument index="1" name="was_clean_close" type="bool"> - </argument> + <argument index="0" name="id" type="int" /> + <argument index="1" name="was_clean_close" type="bool" /> <description> Emitted when a client disconnects. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly. </description> </signal> <signal name="data_received"> - <argument index="0" name="id" type="int"> - </argument> + <argument index="0" name="id" type="int" /> <description> Emitted when a new message is received. [b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level multiplayer peer. diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 744053b6e2..5cd94e978f 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -79,7 +79,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, String str = "ws://"; if (p_custom_headers.size()) { - WARN_PRINT_ONCE("Custom headers are not supported in in HTML5 platform."); + WARN_PRINT_ONCE("Custom headers are not supported in HTML5 platform."); } if (p_ssl) { str = "wss://"; @@ -95,7 +95,7 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, return FAILED; } - static_cast<Ref<EMWSPeer>>(_peer)->set_sock(_js_id, _in_buf_size, _in_pkt_size); + static_cast<Ref<EMWSPeer>>(_peer)->set_sock(_js_id, _in_buf_size, _in_pkt_size, _out_buf_size); return OK; } @@ -136,6 +136,7 @@ int EMWSClient::get_max_packet_size() const { Error EMWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) { _in_buf_size = nearest_shift(p_in_buffer - 1) + 10; _in_pkt_size = nearest_shift(p_in_packets - 1); + _out_buf_size = nearest_shift(p_out_buffer - 1) + 10; return OK; } diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h index ca2d7ed986..3b0b8395b9 100644 --- a/modules/websocket/emws_client.h +++ b/modules/websocket/emws_client.h @@ -45,6 +45,7 @@ private: bool _is_connecting = false; int _in_buf_size = DEF_BUF_SHIFT; int _in_pkt_size = DEF_PKT_SHIFT; + int _out_buf_size = DEF_BUF_SHIFT; static void _esws_on_connect(void *obj, char *proto); static void _esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string); diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 05f9e12ae1..69822f6ff3 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -33,10 +33,11 @@ #include "emws_peer.h" #include "core/io/ip.h" -void EMWSPeer::set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size) { +void EMWSPeer::set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size) { peer_sock = p_sock; _in_buffer.resize(p_in_pkt_size, p_in_buf_size); _packet_buffer.resize((1 << p_in_buf_size)); + _out_buf_size = p_out_buf_size; } void EMWSPeer::set_write_mode(WriteMode p_mode) { @@ -53,7 +54,10 @@ Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_strin } Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { + ERR_FAIL_COND_V(_out_buf_size && (godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); + int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0; + godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, is_bin); return OK; } @@ -76,6 +80,13 @@ int EMWSPeer::get_available_packet_count() const { return _in_buffer.packets_left(); } +int EMWSPeer::get_current_outbound_buffered_amount() const { + if (peer_sock != -1) { + return godot_js_websocket_buffered_amount(peer_sock); + } + return 0; +} + bool EMWSPeer::was_string_packet() const { return _is_string; } diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h index 73e701720b..6e93ea31a2 100644 --- a/modules/websocket/emws_peer.h +++ b/modules/websocket/emws_peer.h @@ -48,6 +48,7 @@ typedef void (*WSOnError)(void *p_ref); extern int godot_js_websocket_create(void *p_ref, const char *p_url, const char *p_proto, WSOnOpen p_on_open, WSOnMessage p_on_message, WSOnError p_on_error, WSOnClose p_on_close); extern int godot_js_websocket_send(int p_id, const uint8_t *p_buf, int p_buf_len, int p_raw); +extern int godot_js_websocket_buffered_amount(int p_id); extern void godot_js_websocket_close(int p_id, int p_code, const char *p_reason); extern void godot_js_websocket_destroy(int p_id); } @@ -62,14 +63,16 @@ private: Vector<uint8_t> _packet_buffer; PacketBuffer<uint8_t> _in_buffer; uint8_t _is_string = 0; + int _out_buf_size = 0; public: Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string); - void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size); + void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size); virtual int get_available_packet_count() const; virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const; virtual void close(int p_code = 1000, String p_reason = ""); virtual bool is_connected_to_host() const; diff --git a/modules/websocket/library_godot_websocket.js b/modules/websocket/library_godot_websocket.js index b182d1ecde..dd2fd1e94f 100644 --- a/modules/websocket/library_godot_websocket.js +++ b/modules/websocket/library_godot_websocket.js @@ -101,6 +101,15 @@ const GodotWebSocket = { return 0; }, + // Get current bufferedAmount + bufferedAmount: function (p_id) { + const ref = IDHandler.get(p_id); + if (!ref) { + return 0; // Godot object is gone. + } + return ref.bufferedAmount; + }, + create: function (socket, p_on_open, p_on_message, p_on_error, p_on_close) { const id = IDHandler.add(socket); socket.onopen = GodotWebSocket._onopen.bind(null, id, p_on_open); @@ -171,6 +180,11 @@ const GodotWebSocket = { return GodotWebSocket.send(p_id, out); }, + godot_js_websocket_buffered_amount__sig: 'ii', + godot_js_websocket_buffered_amount: function (p_id) { + return GodotWebSocket.bufferedAmount(p_id); + }, + godot_js_websocket_close__sig: 'viii', godot_js_websocket_close: function (p_id, p_code, p_reason) { const code = p_code; diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index ddd8e190df..163cc7706b 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -39,35 +39,15 @@ WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() { _clear(); } -int WebSocketMultiplayerPeer::_gen_unique_id() const { - uint32_t hash = 0; - - while (hash == 0 || hash == 1) { - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_ticks_usec()); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_unix_time(), hash); - hash = hash_djb2_one_32( - (uint32_t)OS::get_singleton()->get_data_path().hash64(), hash); - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)this), hash); //rely on aslr heap - hash = hash_djb2_one_32( - (uint32_t)((uint64_t)&hash), hash); //rely on aslr stack - hash = hash & 0x7FFFFFFF; // make it compatible with unsigned, since negative id is used for exclusion - } - - return hash; -} - void WebSocketMultiplayerPeer::_clear() { _peer_map.clear(); if (_current_packet.data != nullptr) { memfree(_current_packet.data); } - for (List<Packet>::Element *E = _incoming_packets.front(); E; E = E->next()) { - memfree(E->get().data); - E->get().data = nullptr; + for (Packet &E : _incoming_packets) { + memfree(E.data); + E.data = nullptr; } _incoming_packets.clear(); @@ -125,6 +105,14 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer // // MultiplayerPeer // +void WebSocketMultiplayerPeer::set_transfer_channel(int p_channel) { + // Websocket does not have channels. +} + +int WebSocketMultiplayerPeer::get_transfer_channel() const { + return 0; +} + void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { // Websocket uses TCP, reliable } diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index e3ccd1a795..0fee196f41 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -75,10 +75,11 @@ protected: void _send_add(int32_t p_peer_id); void _send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id); void _send_del(int32_t p_peer_id); - int _gen_unique_id() const; public: /* MultiplayerPeer */ + void set_transfer_channel(int p_channel) override; + int get_transfer_channel() const override; void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_target_peer) override; diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp index e77fdcfed2..ee13040821 100644 --- a/modules/websocket/websocket_peer.cpp +++ b/modules/websocket/websocket_peer.cpp @@ -47,6 +47,7 @@ void WebSocketPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_connected_host"), &WebSocketPeer::get_connected_host); ClassDB::bind_method(D_METHOD("get_connected_port"), &WebSocketPeer::get_connected_port); ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &WebSocketPeer::set_no_delay); + ClassDB::bind_method(D_METHOD("get_current_outbound_buffered_amount"), &WebSocketPeer::get_current_outbound_buffered_amount); BIND_ENUM_CONSTANT(WRITE_MODE_TEXT); BIND_ENUM_CONSTANT(WRITE_MODE_BINARY); diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h index e9bb20f21f..517b8600d6 100644 --- a/modules/websocket/websocket_peer.h +++ b/modules/websocket/websocket_peer.h @@ -59,6 +59,7 @@ public: virtual uint16_t get_connected_port() const = 0; virtual bool was_string_packet() const = 0; virtual void set_no_delay(bool p_enabled) = 0; + virtual int get_current_outbound_buffered_amount() const = 0; WebSocketPeer(); ~WebSocketPeer(); diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index 1dbadfed74..7f027e1c0d 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -205,7 +205,9 @@ void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigne ERR_FAIL_COND(p_data == nullptr); _in_buffer.resize(p_in_pkt_size, p_in_buf_size); - _packet_buffer.resize((1 << MAX(p_in_buf_size, p_out_buf_size))); + _packet_buffer.resize(1 << p_in_buf_size); + _out_buf_size = p_out_buf_size; + _out_pkt_size = p_out_pkt_size; _data = p_data; _data->peer = this; @@ -239,6 +241,8 @@ void WSLPeer::poll() { Error WSLPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); + ERR_FAIL_COND_V(_out_pkt_size && (wslay_event_get_queued_msg_count(_data->ctx) >= (1ULL << _out_pkt_size)), ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(_out_buf_size && (wslay_event_get_queued_msg_length(_data->ctx) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); struct wslay_event_msg msg; // Should I use fragmented? msg.opcode = write_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME; @@ -280,6 +284,12 @@ int WSLPeer::get_available_packet_count() const { return _in_buffer.packets_left(); } +int WSLPeer::get_current_outbound_buffered_amount() const { + ERR_FAIL_COND_V(!_data, 0); + + return wslay_event_get_queued_msg_length(_data->ctx); +} + bool WSLPeer::was_string_packet() const { return _is_string; } diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h index f1ea98d384..260d4b183d 100644 --- a/modules/websocket/wsl_peer.h +++ b/modules/websocket/wsl_peer.h @@ -77,6 +77,9 @@ private: WriteMode write_mode = WRITE_MODE_BINARY; + int _out_buf_size = 0; + int _out_pkt_size = 0; + public: int close_code = -1; String close_reason; @@ -86,6 +89,7 @@ public: virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); virtual int get_max_packet_size() const { return _packet_buffer.size(); }; + virtual int get_current_outbound_buffered_amount() const; virtual void close_now(); virtual void close(int p_code = 1000, String p_reason = ""); diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index 5f794415af..7402bbb46e 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -190,15 +190,15 @@ void WSLServer::poll() { remove_ids.push_back(E->key()); } } - for (List<int>::Element *E = remove_ids.front(); E; E = E->next()) { - _peer_map.erase(E->get()); + for (int &E : remove_ids) { + _peer_map.erase(E); } remove_ids.clear(); List<Ref<PendingPeer>> remove_peers; - for (List<Ref<PendingPeer>>::Element *E = _pending.front(); E; E = E->next()) { + for (const Ref<PendingPeer> &E : _pending) { String resource_name; - Ref<PendingPeer> ppeer = E->get(); + Ref<PendingPeer> ppeer = E; Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name); if (err == ERR_BUSY) { continue; @@ -207,7 +207,7 @@ void WSLServer::poll() { continue; } // Creating new peer - int32_t id = _gen_unique_id(); + int32_t id = generate_unique_id(); WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData); data->obj = this; @@ -224,8 +224,8 @@ void WSLServer::poll() { remove_peers.push_back(ppeer); _on_connect(id, ppeer->protocol, resource_name); } - for (List<Ref<PendingPeer>>::Element *E = remove_peers.front(); E; E = E->next()) { - _pending.erase(E->get()); + for (const Ref<PendingPeer> &E : remove_peers) { + _pending.erase(E); } remove_peers.clear(); diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index 9b3a063ef5..ff7c46bbae 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -88,17 +88,15 @@ - Using [XRController3D] nodes and their [signal XRController3D.button_pressed] and [signal XRController3D.button_released] signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url]. - Using [method Node._unhandled_input] and [InputEventJoypadButton] or [InputEventJoypadMotion]. This works the same as normal joypads, except the [member InputEvent.device] starts at 100, so the left controller is 100 and the right controller is 101, and the button codes are also defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url]. - Using the [signal select], [signal squeeze] and related signals. This method will work for both advanced VR controllers, and non-traditional "controllers" like a tap on the screen, a spoken voice command or a button press on the device itself. The [code]controller_id[/code] passed to these signals is the same id as used in [member XRController3D.controller_id]. - You can use one or all of these methods to allow your game or app to support a wider or narrower set of devices and input methods, or to allow more advanced interations with more advanced devices. + You can use one or all of these methods to allow your game or app to support a wider or narrower set of devices and input methods, or to allow more advanced interactions with more advanced devices. </description> <tutorials> <link title="How to make a VR game for WebXR with Godot">https://www.snopekgames.com/blog/2020/how-make-vr-game-webxr-godot</link> </tutorials> <methods> <method name="get_controller" qualifiers="const"> - <return type="XRPositionalTracker"> - </return> - <argument index="0" name="controller_id" type="int"> - </argument> + <return type="XRPositionalTracker" /> + <argument index="0" name="controller_id" type="int" /> <description> Gets an [XRPositionalTracker] for the given [code]controller_id[/code]. In the context of WebXR, a "controller" can be an advanced VR controller like the Oculus Touch or Index controllers, or even a tap on the screen, a spoken voice command or a button press on the device itself. When a non-traditional controller is used, interpret the position and orientation of the [XRPositionalTracker] as a ray pointing at the object the user wishes to interact with. @@ -112,10 +110,8 @@ </description> </method> <method name="is_session_supported"> - <return type="void"> - </return> - <argument index="0" name="session_mode" type="String"> - </argument> + <return type="void" /> + <argument index="0" name="session_mode" type="String" /> <description> Checks if the given [code]session_mode[/code] is supported by the user's browser. Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code]. @@ -170,24 +166,21 @@ </description> </signal> <signal name="select"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted after one of the "controllers" has finished its "primary action". Use [method get_controller] to get more information about the controller. </description> </signal> <signal name="selectend"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted when one of the "controllers" has finished its "primary action". Use [method get_controller] to get more information about the controller. </description> </signal> <signal name="selectstart"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted when one of the "controllers" has started its "primary action". Use [method get_controller] to get more information about the controller. @@ -200,8 +193,7 @@ </description> </signal> <signal name="session_failed"> - <argument index="0" name="message" type="String"> - </argument> + <argument index="0" name="message" type="String" /> <description> Emitted by [method XRInterface.initialize] if the session fails to start. [code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available. @@ -214,33 +206,28 @@ </description> </signal> <signal name="session_supported"> - <argument index="0" name="session_mode" type="String"> - </argument> - <argument index="1" name="supported" type="bool"> - </argument> + <argument index="0" name="session_mode" type="String" /> + <argument index="1" name="supported" type="bool" /> <description> Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not. </description> </signal> <signal name="squeeze"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted after one of the "controllers" has finished its "primary squeeze action". Use [method get_controller] to get more information about the controller. </description> </signal> <signal name="squeezeend"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted when one of the "controllers" has finished its "primary squeeze action". Use [method get_controller] to get more information about the controller. </description> </signal> <signal name="squeezestart"> - <argument index="0" name="controller_id" type="int"> - </argument> + <argument index="0" name="controller_id" type="int" /> <description> Emitted when one of the "controllers" has started its "primary squeeze action". Use [method get_controller] to get more information about the controller. |