diff options
Diffstat (limited to 'modules/mono/glue')
50 files changed, 4246 insertions, 1978 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index 3aecce50f5..8b12537f7f 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 { @@ -26,7 +20,7 @@ namespace Godot private Vector3 _size; /// <summary> - /// Beginning corner. Typically has values lower than End. + /// Beginning corner. Typically has values lower than <see cref="End"/>. /// </summary> /// <value>Directly uses a private field.</value> public Vector3 Position @@ -36,7 +30,7 @@ namespace Godot } /// <summary> - /// Size from Position to End. Typically all components are positive. + /// Size from <see cref="Position"/> to <see cref="End"/>. Typically all components are positive. /// If the size is negative, you can use <see cref="Abs"/> to fix it. /// </summary> /// <value>Directly uses a private field.</value> @@ -50,7 +44,10 @@ namespace Godot /// Ending corner. This is calculated as <see cref="Position"/> plus /// <see cref="Size"/>. Setting this value will change the size. /// </summary> - /// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value> + /// <value> + /// Getting is equivalent to <paramref name="value"/> = <see cref="Position"/> + <see cref="Size"/>, + /// setting is equivalent to <see cref="Size"/> = <paramref name="value"/> - <see cref="Position"/> + /// </value> public Vector3 End { get { return _position + _size; } @@ -58,10 +55,10 @@ namespace Godot } /// <summary> - /// Returns an AABB with equivalent position and size, modified so that + /// Returns an <see cref="AABB"/> with equivalent position and size, modified so that /// the most-negative corner is the origin and the size is positive. /// </summary> - /// <returns>The modified AABB.</returns> + /// <returns>The modified <see cref="AABB"/>.</returns> public AABB Abs() { Vector3 end = End; @@ -70,30 +67,32 @@ namespace Godot } /// <summary> - /// Returns true if this AABB completely encloses another one. + /// Returns <see langword="true"/> if this <see cref="AABB"/> completely encloses another one. /// </summary> - /// <param name="with">The other AABB that may be enclosed.</param> - /// <returns>A bool for whether or not this AABB encloses `b`.</returns> + /// <param name="with">The other <see cref="AABB"/> that may be enclosed.</param> + /// <returns> + /// A <see langword="bool"/> for whether or not this <see cref="AABB"/> encloses <paramref name="with"/>. + /// </returns> public bool Encloses(AABB with) { - Vector3 src_min = _position; - Vector3 src_max = _position + _size; - Vector3 dst_min = with._position; - Vector3 dst_max = with._position + with._size; + Vector3 srcMin = _position; + Vector3 srcMax = _position + _size; + Vector3 dstMin = with._position; + Vector3 dstMax = with._position + with._size; - return src_min.x <= dst_min.x && - src_max.x > dst_max.x && - src_min.y <= dst_min.y && - src_max.y > dst_max.y && - src_min.z <= dst_min.z && - src_max.z > dst_max.z; + return srcMin.x <= dstMin.x && + srcMax.x > dstMax.x && + srcMin.y <= dstMin.y && + srcMax.y > dstMax.y && + srcMin.z <= dstMin.z && + srcMax.z > dstMax.z; } /// <summary> - /// Returns this AABB expanded to include a given point. + /// Returns this <see cref="AABB"/> expanded to include a given point. /// </summary> /// <param name="point">The point to include.</param> - /// <returns>The expanded AABB.</returns> + /// <returns>The expanded <see cref="AABB"/>.</returns> public AABB Expand(Vector3 point) { Vector3 begin = _position; @@ -129,7 +128,7 @@ namespace Godot } /// <summary> - /// Returns the area of the AABB. + /// Returns the area of the <see cref="AABB"/>. /// </summary> /// <returns>The area.</returns> public real_t GetArea() @@ -138,10 +137,10 @@ namespace Godot } /// <summary> - /// Gets the position of one of the 8 endpoints of the AABB. + /// Gets the position of one of the 8 endpoints of the <see cref="AABB"/>. /// </summary> /// <param name="idx">Which endpoint to get.</param> - /// <returns>An endpoint of the AABB.</returns> + /// <returns>An endpoint of the <see cref="AABB"/>.</returns> public Vector3 GetEndpoint(int idx) { switch (idx) @@ -163,26 +162,29 @@ namespace Godot case 7: return new Vector3(_position.x + _size.x, _position.y + _size.y, _position.z + _size.z); default: - throw new ArgumentOutOfRangeException(nameof(idx), String.Format("Index is {0}, but a value from 0 to 7 is expected.", idx)); + { + throw new ArgumentOutOfRangeException(nameof(idx), + $"Index is {idx}, but a value from 0 to 7 is expected."); + } } } /// <summary> - /// Returns the normalized longest axis of the AABB. + /// Returns the normalized longest axis of the <see cref="AABB"/>. /// </summary> - /// <returns>A vector representing the normalized longest axis of the AABB.</returns> + /// <returns>A vector representing the normalized longest axis of the <see cref="AABB"/>.</returns> public Vector3 GetLongestAxis() { var axis = new Vector3(1f, 0f, 0f); - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y > max_size) + if (_size.y > maxSize) { axis = new Vector3(0f, 1f, 0f); - max_size = _size.y; + maxSize = _size.y; } - if (_size.z > max_size) + if (_size.z > maxSize) { axis = new Vector3(0f, 0f, 1f); } @@ -191,21 +193,21 @@ namespace Godot } /// <summary> - /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the AABB. + /// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A <see cref="Vector3.Axis"/> index for which axis is longest.</returns> public Vector3.Axis GetLongestAxisIndex() { var axis = Vector3.Axis.X; - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y > max_size) + if (_size.y > maxSize) { axis = Vector3.Axis.Y; - max_size = _size.y; + maxSize = _size.y; } - if (_size.z > max_size) + if (_size.z > maxSize) { axis = Vector3.Axis.Z; } @@ -214,38 +216,38 @@ namespace Godot } /// <summary> - /// Returns the scalar length of the longest axis of the AABB. + /// Returns the scalar length of the longest axis of the <see cref="AABB"/>. /// </summary> - /// <returns>The scalar length of the longest axis of the AABB.</returns> + /// <returns>The scalar length of the longest axis of the <see cref="AABB"/>.</returns> public real_t GetLongestAxisSize() { - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y > max_size) - max_size = _size.y; + if (_size.y > maxSize) + maxSize = _size.y; - if (_size.z > max_size) - max_size = _size.z; + if (_size.z > maxSize) + maxSize = _size.z; - return max_size; + return maxSize; } /// <summary> - /// Returns the normalized shortest axis of the AABB. + /// Returns the normalized shortest axis of the <see cref="AABB"/>. /// </summary> - /// <returns>A vector representing the normalized shortest axis of the AABB.</returns> + /// <returns>A vector representing the normalized shortest axis of the <see cref="AABB"/>.</returns> public Vector3 GetShortestAxis() { var axis = new Vector3(1f, 0f, 0f); - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y < max_size) + if (_size.y < maxSize) { axis = new Vector3(0f, 1f, 0f); - max_size = _size.y; + maxSize = _size.y; } - if (_size.z < max_size) + if (_size.z < maxSize) { axis = new Vector3(0f, 0f, 1f); } @@ -254,21 +256,21 @@ namespace Godot } /// <summary> - /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the AABB. + /// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the <see cref="AABB"/>. /// </summary> /// <returns>A <see cref="Vector3.Axis"/> index for which axis is shortest.</returns> public Vector3.Axis GetShortestAxisIndex() { var axis = Vector3.Axis.X; - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y < max_size) + if (_size.y < maxSize) { axis = Vector3.Axis.Y; - max_size = _size.y; + maxSize = _size.y; } - if (_size.z < max_size) + if (_size.z < maxSize) { axis = Vector3.Axis.Z; } @@ -277,20 +279,20 @@ namespace Godot } /// <summary> - /// Returns the scalar length of the shortest axis of the AABB. + /// Returns the scalar length of the shortest axis of the <see cref="AABB"/>. /// </summary> - /// <returns>The scalar length of the shortest axis of the AABB.</returns> + /// <returns>The scalar length of the shortest axis of the <see cref="AABB"/>.</returns> public real_t GetShortestAxisSize() { - real_t max_size = _size.x; + real_t maxSize = _size.x; - if (_size.y < max_size) - max_size = _size.y; + if (_size.y < maxSize) + maxSize = _size.y; - if (_size.z < max_size) - max_size = _size.z; + if (_size.z < maxSize) + maxSize = _size.z; - return max_size; + return maxSize; } /// <summary> @@ -301,23 +303,23 @@ namespace Godot /// <returns>A vector representing the support.</returns> public Vector3 GetSupport(Vector3 dir) { - Vector3 half_extents = _size * 0.5f; - Vector3 ofs = _position + half_extents; + Vector3 halfExtents = _size * 0.5f; + Vector3 ofs = _position + halfExtents; return ofs + new Vector3( - dir.x > 0f ? -half_extents.x : half_extents.x, - dir.y > 0f ? -half_extents.y : half_extents.y, - dir.z > 0f ? -half_extents.z : half_extents.z); + dir.x > 0f ? -halfExtents.x : halfExtents.x, + dir.y > 0f ? -halfExtents.y : halfExtents.y, + dir.z > 0f ? -halfExtents.z : halfExtents.z); } /// <summary> - /// Returns a copy of the AABB grown a given amount of units towards all the sides. + /// Returns a copy of the <see cref="AABB"/> grown a given amount of units towards all the sides. /// </summary> /// <param name="by">The amount to grow by.</param> - /// <returns>The grown AABB.</returns> + /// <returns>The grown <see cref="AABB"/>.</returns> public AABB Grow(real_t by) { - var res = this; + AABB res = this; res._position.x -= by; res._position.y -= by; @@ -330,28 +332,37 @@ namespace Godot } /// <summary> - /// Returns true if the AABB is flat or empty, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="AABB"/> is flat or empty, + /// or <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool for whether or not the AABB has area.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has area. + /// </returns> public bool HasNoArea() { return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f; } /// <summary> - /// Returns true if the AABB has no surface (no size), or false otherwise. + /// Returns <see langword="true"/> if the <see cref="AABB"/> has no surface (no size), + /// or <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool for whether or not the AABB has area.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> has area. + /// </returns> public bool HasNoSurface() { return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f; } /// <summary> - /// Returns true if the AABB contains a point, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="AABB"/> contains a point, + /// or <see langword="false"/> otherwise. /// </summary> /// <param name="point">The point to check.</param> - /// <returns>A bool for whether or not the AABB contains `point`.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> contains <paramref name="point"/>. + /// </returns> public bool HasPoint(Vector3 point) { if (point.x < _position.x) @@ -371,56 +382,59 @@ namespace Godot } /// <summary> - /// Returns the intersection of this AABB and `b`. + /// Returns the intersection of this <see cref="AABB"/> and <paramref name="with"/>. /// </summary> - /// <param name="with">The other AABB.</param> - /// <returns>The clipped AABB.</returns> + /// <param name="with">The other <see cref="AABB"/>.</param> + /// <returns>The clipped <see cref="AABB"/>.</returns> public AABB Intersection(AABB with) { - Vector3 src_min = _position; - Vector3 src_max = _position + _size; - Vector3 dst_min = with._position; - Vector3 dst_max = with._position + with._size; + Vector3 srcMin = _position; + Vector3 srcMax = _position + _size; + Vector3 dstMin = with._position; + Vector3 dstMax = with._position + with._size; Vector3 min, max; - if (src_min.x > dst_max.x || src_max.x < dst_min.x) + if (srcMin.x > dstMax.x || srcMax.x < dstMin.x) { return new AABB(); } - min.x = src_min.x > dst_min.x ? src_min.x : dst_min.x; - max.x = src_max.x < dst_max.x ? src_max.x : dst_max.x; + min.x = srcMin.x > dstMin.x ? srcMin.x : dstMin.x; + max.x = srcMax.x < dstMax.x ? srcMax.x : dstMax.x; - if (src_min.y > dst_max.y || src_max.y < dst_min.y) + if (srcMin.y > dstMax.y || srcMax.y < dstMin.y) { return new AABB(); } - min.y = src_min.y > dst_min.y ? src_min.y : dst_min.y; - max.y = src_max.y < dst_max.y ? src_max.y : dst_max.y; + min.y = srcMin.y > dstMin.y ? srcMin.y : dstMin.y; + max.y = srcMax.y < dstMax.y ? srcMax.y : dstMax.y; - if (src_min.z > dst_max.z || src_max.z < dst_min.z) + if (srcMin.z > dstMax.z || srcMax.z < dstMin.z) { return new AABB(); } - min.z = src_min.z > dst_min.z ? src_min.z : dst_min.z; - max.z = src_max.z < dst_max.z ? src_max.z : dst_max.z; + min.z = srcMin.z > dstMin.z ? srcMin.z : dstMin.z; + max.z = srcMax.z < dstMax.z ? srcMax.z : dstMax.z; return new AABB(min, max - min); } /// <summary> - /// Returns true if the AABB overlaps with `b` + /// Returns <see langword="true"/> if the <see cref="AABB"/> overlaps with <paramref name="with"/> /// (i.e. they have at least one point in common). /// - /// If `includeBorders` is true, they will also be considered overlapping - /// if their borders touch, even without intersection. + /// If <paramref name="includeBorders"/> is <see langword="true"/>, + /// they will also be considered overlapping if their borders touch, + /// even without intersection. /// </summary> - /// <param name="with">The other AABB to check for intersections with.</param> + /// <param name="with">The other <see cref="AABB"/> to check for intersections with.</param> /// <param name="includeBorders">Whether or not to consider borders.</param> - /// <returns>A bool for whether or not they are intersecting.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not they are intersecting. + /// </returns> public bool Intersects(AABB with, bool includeBorders = false) { if (includeBorders) @@ -458,10 +472,12 @@ namespace Godot } /// <summary> - /// Returns true if the AABB is on both sides of `plane`. + /// Returns <see langword="true"/> if the <see cref="AABB"/> is on both sides of <paramref name="plane"/>. /// </summary> - /// <param name="plane">The plane to check for intersection.</param> - /// <returns>A bool for whether or not the AABB intersects the plane.</returns> + /// <param name="plane">The <see cref="Plane"/> to check for intersection.</param> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the <see cref="Plane"/>. + /// </returns> public bool IntersectsPlane(Plane plane) { Vector3[] points = @@ -495,11 +511,14 @@ namespace Godot } /// <summary> - /// Returns true if the AABB intersects the line segment between `from` and `to`. + /// Returns <see langword="true"/> if the <see cref="AABB"/> intersects + /// the line segment between <paramref name="from"/> and <paramref name="to"/>. /// </summary> /// <param name="from">The start of the line segment.</param> /// <param name="to">The end of the line segment.</param> - /// <returns>A bool for whether or not the AABB intersects the line segment.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="AABB"/> intersects the line segment. + /// </returns> public bool IntersectsSegment(Vector3 from, Vector3 to) { real_t min = 0f; @@ -555,10 +574,10 @@ namespace Godot } /// <summary> - /// Returns a larger AABB that contains this AABB and `b`. + /// Returns a larger <see cref="AABB"/> that contains this <see cref="AABB"/> and <paramref name="with"/>. /// </summary> - /// <param name="with">The other AABB.</param> - /// <returns>The merged AABB.</returns> + /// <param name="with">The other <see cref="AABB"/>.</param> + /// <returns>The merged <see cref="AABB"/>.</returns> public AABB Merge(AABB with) { Vector3 beg1 = _position; @@ -567,22 +586,22 @@ namespace Godot var end2 = new Vector3(with._size.x, with._size.y, with._size.z) + beg2; var min = new Vector3( - beg1.x < beg2.x ? beg1.x : beg2.x, - beg1.y < beg2.y ? beg1.y : beg2.y, - beg1.z < beg2.z ? beg1.z : beg2.z - ); + beg1.x < beg2.x ? beg1.x : beg2.x, + beg1.y < beg2.y ? beg1.y : beg2.y, + beg1.z < beg2.z ? beg1.z : beg2.z + ); var max = new Vector3( - end1.x > end2.x ? end1.x : end2.x, - end1.y > end2.y ? end1.y : end2.y, - end1.z > end2.z ? end1.z : end2.z - ); + end1.x > end2.x ? end1.x : end2.x, + end1.y > end2.y ? end1.y : end2.y, + end1.z > end2.z ? end1.z : end2.z + ); return new AABB(min, max - min); } /// <summary> - /// Constructs an AABB from a position and size. + /// Constructs an <see cref="AABB"/> from a position and size. /// </summary> /// <param name="position">The position.</param> /// <param name="size">The size, typically positive.</param> @@ -593,7 +612,8 @@ namespace Godot } /// <summary> - /// Constructs an AABB from a position, width, height, and depth. + /// Constructs an <see cref="AABB"/> from a <paramref name="position"/>, + /// <paramref name="width"/>, <paramref name="height"/>, and <paramref name="depth"/>. /// </summary> /// <param name="position">The position.</param> /// <param name="width">The width, typically positive.</param> @@ -606,7 +626,8 @@ namespace Godot } /// <summary> - /// Constructs an AABB from x, y, z, and size. + /// Constructs an <see cref="AABB"/> from <paramref name="x"/>, + /// <paramref name="y"/>, <paramref name="z"/>, and <paramref name="size"/>. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -619,7 +640,9 @@ namespace Godot } /// <summary> - /// Constructs an AABB from x, y, z, width, height, and depth. + /// Constructs an <see cref="AABB"/> from <paramref name="x"/>, + /// <paramref name="y"/>, <paramref name="z"/>, <paramref name="width"/>, + /// <paramref name="height"/>, and <paramref name="depth"/>. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -643,6 +666,11 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this AABB and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the AABB structure and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is AABB) @@ -653,43 +681,52 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this AABB and <paramref name="other"/> are equal + /// </summary> + /// <param name="other">The other AABB to compare.</param> + /// <returns>Whether or not the AABBs are equal.</returns> public bool Equals(AABB other) { return _position == other._position && _size == other._size; } /// <summary> - /// Returns true if this AABB and `other` are approximately equal, by running - /// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. + /// Returns <see langword="true"/> if this AABB and <paramref name="other"/> are approximately equal, + /// by running <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. /// </summary> /// <param name="other">The other AABB to compare.</param> - /// <returns>Whether or not the AABBs are approximately equal.</returns> + /// <returns>Whether or not the AABBs structures are approximately equal.</returns> public bool IsEqualApprox(AABB other) { return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size); } + /// <summary> + /// Serves as the hash function for <see cref="AABB"/>. + /// </summary> + /// <returns>A hash code for this AABB.</returns> public override int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } + /// <summary> + /// Converts this <see cref="AABB"/> to a string. + /// </summary> + /// <returns>A string representation of this AABB.</returns> public override string ToString() { - return String.Format("{0} - {1}", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } + /// <summary> + /// Converts this <see cref="AABB"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this AABB.</returns> 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..a412047196 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; namespace Godot.Collections { - class ArraySafeHandle : SafeHandle + internal class ArraySafeHandle : SafeHandle { public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) { @@ -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; + private ArraySafeHandle _safeHandle; + private bool _disposed = false; + /// <summary> + /// Constructs a new empty <see cref="Array"/>. + /// </summary> public Array() { - safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor()); + _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,48 +58,72 @@ 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) { throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); } - safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array)); + _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array)); } internal Array(ArraySafeHandle handle) { - safeHandle = handle; + _safeHandle = handle; } internal Array(IntPtr handle) { - safeHandle = new ArraySafeHandle(handle); + _safeHandle = new ArraySafeHandle(handle); } internal IntPtr GetPtr() { - if (disposed) + if (_disposed) throw new ObjectDisposedException(GetType().FullName); - return safeHandle.DangerousGetHandle(); + return _safeHandle.DangerousGetHandle(); } + /// <summary> + /// Duplicates this <see cref="Array"/>. + /// </summary> + /// <param name="deep">If <see langword="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,54 +131,109 @@ namespace Godot.Collections // IDisposable + /// <summary> + /// Disposes of this <see cref="Array"/>. + /// </summary> public void Dispose() { - if (disposed) + if (_disposed) return; - if (safeHandle != null) + if (_safeHandle != null) { - safeHandle.Dispose(); - safeHandle = null; + _safeHandle.Dispose(); + _safeHandle = null; } - disposed = true; + _disposed = true; } // IList - public bool IsReadOnly => false; + bool IList.IsReadOnly => false; - public bool IsFixedSize => false; + bool IList.IsFixedSize => false; + /// <summary> + /// Returns the object at the given <paramref name="index"/>. + /// </summary> + /// <value>The object at the given <paramref name="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 <c>append</c> or <c>push_back</c> 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 <paramref name="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,78 +262,89 @@ 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()); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Array_Ctor(); + internal static extern IntPtr godot_icall_Array_Ctor(); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array); + internal static extern IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_Dtor(IntPtr ptr); + internal static extern void godot_icall_Array_Dtor(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_Array_At(IntPtr ptr, int index); + internal static extern object godot_icall_Array_At(IntPtr ptr, int index); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); + internal static extern object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); + internal static extern void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_Array_Count(IntPtr ptr); + internal static extern int godot_icall_Array_Count(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_Array_Add(IntPtr ptr, object item); + internal static extern int godot_icall_Array_Add(IntPtr ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_Clear(IntPtr ptr); + internal static extern void godot_icall_Array_Clear(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right); + internal static extern IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item); + internal static extern bool godot_icall_Array_Contains(IntPtr ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex); + internal static extern void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep); + internal static extern IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item); + internal static extern int godot_icall_Array_IndexOf(IntPtr ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item); + internal static extern void godot_icall_Array_Insert(IntPtr ptr, int index, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item); + internal static extern bool godot_icall_Array_Remove(IntPtr ptr, object item); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + internal static extern void godot_icall_Array_RemoveAt(IntPtr ptr, int index); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize); + internal static extern Error godot_icall_Array_Resize(IntPtr ptr, int newSize); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static Error godot_icall_Array_Shuffle(IntPtr ptr); + internal static extern Error godot_icall_Array_Shuffle(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); + internal static extern void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_Array_ToString(IntPtr ptr); + internal static extern 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; + private Array _objectArray; internal static int elemTypeEncoding; internal static IntPtr elemTypeClass; @@ -246,123 +354,207 @@ 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(); + _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) throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'"); - objectArray = new Array(collection); + _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) { throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'"); } - objectArray = new Array(array); + _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; + _objectArray = array; } internal Array(IntPtr handle) { - objectArray = new Array(handle); + _objectArray = new Array(handle); } internal Array(ArraySafeHandle handle) { - objectArray = new Array(handle); + _objectArray = new Array(handle); } internal IntPtr GetPtr() { - return objectArray.GetPtr(); + 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; + return from._objectArray; } + /// <summary> + /// Duplicates this <see cref="Array{T}"/>. + /// </summary> + /// <param name="deep">If <see langword="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)); + 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); + return _objectArray.Resize(newSize); } + /// <summary> + /// Shuffles the contents of this <see cref="Array{T}"/> into a random order. + /// </summary> public void Shuffle() { - objectArray.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); + return new Array<T>(left._objectArray + right._objectArray); } // IList<T> + /// <summary> + /// Returns the value at the given <paramref name="index"/>. + /// </summary> + /// <value>The value at the given <paramref name="index"/>.</value> public T this[int index] { get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); } - set { objectArray[index] = value; } + 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); + 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); + _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); + _objectArray.RemoveAt(index); } // 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; } + 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 <c>append</c> or <c>push_back</c> 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); + _objectArray.Add(item); } + /// <summary> + /// Erases all items from this <see cref="Array{T}"/>. + /// </summary> public void Clear() { - objectArray.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); + 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) @@ -374,7 +566,7 @@ namespace Godot.Collections // TODO This may be quite slow because every element access is an internal call. // It could be moved entirely to an internal call if we find out how to do the cast there. - int count = objectArray.Count; + int count = _objectArray.Count; if (array.Length < (arrayIndex + count)) throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -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 <see langword="bool"/> indicating success or failure.</returns> public bool Remove(T item) { return Array.godot_icall_Array_Remove(GetPtr(), item); @@ -393,9 +591,13 @@ 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; + int count = _objectArray.Count; for (int i = 0; i < count; i++) { @@ -408,6 +610,10 @@ namespace Godot.Collections return GetEnumerator(); } - public override string ToString() => objectArray.ToString(); + /// <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/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs new file mode 100644 index 0000000000..ef135da51a --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs @@ -0,0 +1,22 @@ +using System; + +namespace Godot +{ + [AttributeUsage(AttributeTargets.Assembly)] + public class AssemblyHasScriptsAttribute : Attribute + { + private readonly bool requiresLookup; + private readonly System.Type[] scriptTypes; + + public AssemblyHasScriptsAttribute() + { + requiresLookup = true; + } + + public AssemblyHasScriptsAttribute(System.Type[] scriptTypes) + { + requiresLookup = false; + this.scriptTypes = scriptTypes; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs new file mode 100644 index 0000000000..e93bc89811 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace Godot +{ + [AttributeUsage(AttributeTargets.Class)] + public class DisableGodotGeneratorsAttribute : Attribute { } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs index 8fc430b6bc..2dedba2be3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs @@ -2,21 +2,9 @@ using System; namespace Godot { - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class RemoteAttribute : Attribute {} + [AttributeUsage(AttributeTargets.Method)] + public class RemoteAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class MasterAttribute : Attribute {} - - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class PuppetAttribute : Attribute {} - - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class RemoteSyncAttribute : Attribute {} - - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class MasterSyncAttribute : Attribute {} - - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public class PuppetSyncAttribute : Attribute {} + [AttributeUsage(AttributeTargets.Method)] + public class PuppetAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs new file mode 100644 index 0000000000..12eb1035c3 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Godot +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class ScriptPathAttribute : Attribute + { + private string path; + + public ScriptPathAttribute(string path) + { + this.path = path; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs index 39d5782db8..07a214f543 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs @@ -3,7 +3,5 @@ using System; namespace Godot { [AttributeUsage(AttributeTargets.Delegate | AttributeTargets.Event)] - public class SignalAttribute : Attribute - { - } + public class SignalAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs index d0437409af..d2344389f4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs @@ -3,5 +3,5 @@ using System; namespace Godot { [AttributeUsage(AttributeTargets.Class)] - public class ToolAttribute : Attribute {} + public class ToolAttribute : Attribute { } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 3f1120575f..0fb1df6c2f 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 { @@ -31,7 +31,7 @@ namespace Godot /// <summary> /// The basis matrix's X vector (column 0). /// </summary> - /// <value>Equivalent to <see cref="Column0"/> and array index `[0]`.</value> + /// <value>Equivalent to <see cref="Column0"/> and array index <c>[0]</c>.</value> public Vector3 x { get => Column0; @@ -41,7 +41,7 @@ namespace Godot /// <summary> /// The basis matrix's Y vector (column 1). /// </summary> - /// <value>Equivalent to <see cref="Column1"/> and array index `[1]`.</value> + /// <value>Equivalent to <see cref="Column1"/> and array index <c>[1]</c>.</value> public Vector3 y { get => Column1; @@ -51,7 +51,7 @@ namespace Godot /// <summary> /// The basis matrix's Z vector (column 2). /// </summary> - /// <value>Equivalent to <see cref="Column2"/> and array index `[2]`.</value> + /// <value>Equivalent to <see cref="Column2"/> and array index <c>[2]</c>.</value> public Vector3 z { get => Column2; @@ -82,45 +82,45 @@ namespace Godot /// <summary> /// Column 0 of the basis matrix (the X vector). /// </summary> - /// <value>Equivalent to <see cref="x"/> and array index `[0]`.</value> + /// <value>Equivalent to <see cref="x"/> and array index <c>[0]</c>.</value> public Vector3 Column0 { get => new Vector3(Row0.x, Row1.x, Row2.x); set { - this.Row0.x = value.x; - this.Row1.x = value.y; - this.Row2.x = value.z; + Row0.x = value.x; + Row1.x = value.y; + Row2.x = value.z; } } /// <summary> /// Column 1 of the basis matrix (the Y vector). /// </summary> - /// <value>Equivalent to <see cref="y"/> and array index `[1]`.</value> + /// <value>Equivalent to <see cref="y"/> and array index <c>[1]</c>.</value> public Vector3 Column1 { get => new Vector3(Row0.y, Row1.y, Row2.y); set { - this.Row0.y = value.x; - this.Row1.y = value.y; - this.Row2.y = value.z; + Row0.y = value.x; + Row1.y = value.y; + Row2.y = value.z; } } /// <summary> /// Column 2 of the basis matrix (the Z vector). /// </summary> - /// <value>Equivalent to <see cref="z"/> and array index `[2]`.</value> + /// <value>Equivalent to <see cref="z"/> and array index <c>[2]</c>.</value> public Vector3 Column2 { get => new Vector3(Row0.z, Row1.z, Row2.z); set { - this.Row0.z = value.x; - this.Row1.z = value.y; - this.Row2.z = value.z; + Row0.z = value.x; + Row1.z = value.y; + Row2.z = value.z; } } @@ -150,9 +150,10 @@ namespace Godot } /// <summary> - /// Access whole columns in the form of Vector3. + /// Access whole columns in the form of <see cref="Vector3"/>. /// </summary> /// <param name="column">Which column vector.</param> + /// <value>The basis column.</value> public Vector3 this[int column] { get @@ -193,6 +194,7 @@ namespace Godot /// </summary> /// <param name="column">Which column, the matrix horizontal position.</param> /// <param name="row">Which row, the matrix vertical position.</param> + /// <value>The matrix element.</value> public real_t this[int column, int row] { get @@ -207,7 +209,14 @@ namespace Godot } } - public Quat RotationQuat() + /// <summary> + /// Returns the <see cref="Basis"/>'s rotation in the form of a + /// <see cref="Quaternion"/>. See <see cref="GetEuler"/> if you + /// need Euler angles, but keep in mind quaternions should generally + /// be preferred to Euler angles. + /// </summary> + /// <returns>The basis rotation.</returns> + public Quaternion GetRotationQuaternion() { Basis orthonormalizedBasis = Orthonormalized(); real_t det = orthonormalizedBasis.Determinant(); @@ -218,18 +227,18 @@ namespace Godot orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One); } - return orthonormalizedBasis.Quat(); + return orthonormalizedBasis.Quaternion(); } - internal void SetQuatScale(Quat quat, Vector3 scale) + internal void SetQuaternionScale(Quaternion quaternion, Vector3 scale) { SetDiagonal(scale); - Rotate(quat); + Rotate(quaternion); } - private void Rotate(Quat quat) + private void Rotate(Quaternion quaternion) { - this *= new Basis(quat); + this *= new Basis(quaternion); } private void SetDiagonal(Vector3 diagonal) @@ -263,10 +272,10 @@ namespace Godot /// The returned vector contains the rotation angles in /// the format (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis.Quat()"/> method instead, which - /// returns a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Quaternion()"/> method instead, which + /// returns a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> - /// <returns>A Vector3 representing the basis rotation in Euler angles.</returns> + /// <returns>A <see cref="Vector3"/> representing the basis rotation in Euler angles.</returns> public Vector3 GetEuler() { Basis m = Orthonormalized(); @@ -304,7 +313,10 @@ namespace Godot /// but are more efficient for some internal calculations. /// </summary> /// <param name="index">Which row.</param> - /// <returns>One of `Row0`, `Row1`, or `Row2`.</returns> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the <paramref name="index"/> is not 0, 1 or 2. + /// </exception> + /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns> public Vector3 GetRow(int index) { switch (index) @@ -326,6 +338,9 @@ namespace Godot /// </summary> /// <param name="index">Which row.</param> /// <param name="value">The vector to set the row to.</param> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the <paramref name="index"/> is not 0, 1 or 2. + /// </exception> public void SetRow(int index, Vector3 value) { switch (index) @@ -452,8 +467,8 @@ namespace Godot } /// <summary> - /// Introduce an additional rotation around the given `axis` - /// by `phi` (in radians). The axis must be a normalized vector. + /// Introduce an additional rotation around the given <paramref name="axis"/> + /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate, in radians.</param> @@ -486,8 +501,8 @@ namespace Godot /// <returns>The resulting basis matrix of the interpolation.</returns> public Basis Slerp(Basis target, real_t weight) { - Quat from = new Quat(this); - Quat to = new Quat(target); + Quaternion from = new Quaternion(this); + Quaternion to = new Quaternion(target); Basis b = new Basis(from.Slerp(to, weight)); b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight); @@ -504,7 +519,7 @@ namespace Godot /// <returns>The resulting dot product.</returns> public real_t Tdotx(Vector3 with) { - return this.Row0[0] * with[0] + this.Row1[0] * with[1] + this.Row2[0] * with[2]; + return Row0[0] * with[0] + Row1[0] * with[1] + Row2[0] * with[2]; } /// <summary> @@ -514,7 +529,7 @@ namespace Godot /// <returns>The resulting dot product.</returns> public real_t Tdoty(Vector3 with) { - return this.Row0[1] * with[0] + this.Row1[1] * with[1] + this.Row2[1] * with[2]; + return Row0[1] * with[0] + Row1[1] * with[1] + Row2[1] * with[2]; } /// <summary> @@ -524,7 +539,7 @@ namespace Godot /// <returns>The resulting dot product.</returns> public real_t Tdotz(Vector3 with) { - return this.Row0[2] * with[0] + this.Row1[2] * with[1] + this.Row2[2] * with[2]; + return Row0[2] * with[0] + Row1[2] * with[1] + Row2[2] * with[2]; } /// <summary> @@ -533,7 +548,7 @@ namespace Godot /// <returns>The transposed basis matrix.</returns> public Basis Transposed() { - var tr = this; + Basis tr = this; real_t temp = tr.Row0[1]; tr.Row0[1] = tr.Row1[0]; @@ -553,15 +568,16 @@ namespace Godot /// <summary> /// Returns a vector transformed (multiplied) by the basis matrix. /// </summary> + /// <seealso cref="XformInv(Vector3)"/> /// <param name="v">A vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector3 Xform(Vector3 v) { return new Vector3 ( - this.Row0.Dot(v), - this.Row1.Dot(v), - this.Row2.Dot(v) + Row0.Dot(v), + Row1.Dot(v), + Row2.Dot(v) ); } @@ -571,15 +587,16 @@ namespace Godot /// Note: This results in a multiplication by the inverse of the /// basis matrix only if it represents a rotation-reflection. /// </summary> + /// <seealso cref="Xform(Vector3)"/> /// <param name="v">A vector to inversely transform.</param> /// <returns>The inversely transformed vector.</returns> public Vector3 XformInv(Vector3 v) { return new Vector3 ( - this.Row0[0] * v.x + this.Row1[0] * v.y + this.Row2[0] * v.z, - this.Row0[1] * v.x + this.Row1[1] * v.y + this.Row2[1] * v.z, - this.Row0[2] * v.x + this.Row1[2] * v.y + this.Row2[2] * v.z + Row0[0] * v.x + Row1[0] * v.y + Row2[0] * v.z, + Row0[1] * v.x + Row1[1] * v.y + Row2[1] * v.z, + Row0[2] * v.x + Row1[2] * v.y + Row2[2] * v.z ); } @@ -588,8 +605,8 @@ namespace Godot /// See <see cref="GetEuler()"/> if you need Euler angles, but keep in /// mind that quaternions should generally be preferred to Euler angles. /// </summary> - /// <returns>A <see cref="Godot.Quat"/> representing the basis's rotation.</returns> - public Quat Quat() + /// <returns>A <see cref="Godot.Quaternion"/> representing the basis's rotation.</returns> + public Quaternion Quaternion() { real_t trace = Row0[0] + Row1[1] + Row2[2]; @@ -597,7 +614,7 @@ namespace Godot { real_t s = Mathf.Sqrt(trace + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row2[1] - Row1[2]) * inv_s, (Row0[2] - Row2[0]) * inv_s, (Row1[0] - Row0[1]) * inv_s, @@ -609,7 +626,7 @@ namespace Godot { real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( s * 0.25f, (Row0[1] + Row1[0]) * inv_s, (Row0[2] + Row2[0]) * inv_s, @@ -621,7 +638,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[1] + Row1[0]) * inv_s, s * 0.25f, (Row1[2] + Row2[1]) * inv_s, @@ -632,7 +649,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[2] + Row2[0]) * inv_s, (Row1[2] + Row2[1]) * inv_s, s * 0.25f, @@ -675,47 +692,47 @@ namespace Godot /// <summary> /// The identity basis, with no rotation or scaling applied. - /// This is used as a replacement for `Basis()` in GDScript. - /// Do not use `new Basis()` with no arguments in C#, because it sets all values to zero. + /// This is used as a replacement for <c>Basis()</c> in GDScript. + /// Do not use <c>new Basis()</c> with no arguments in C#, because it sets all values to zero. /// </summary> - /// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Up, Vector3.Back)`.</value> + /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Up, Vector3.Back)</c>.</value> public static Basis Identity { get { return _identity; } } /// <summary> /// The basis that will flip something along the X axis when used in a transformation. /// </summary> - /// <value>Equivalent to `new Basis(Vector3.Left, Vector3.Up, Vector3.Back)`.</value> + /// <value>Equivalent to <c>new Basis(Vector3.Left, Vector3.Up, Vector3.Back)</c>.</value> public static Basis FlipX { get { return _flipX; } } /// <summary> /// The basis that will flip something along the Y axis when used in a transformation. /// </summary> - /// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Down, Vector3.Back)`.</value> + /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Down, Vector3.Back)</c>.</value> public static Basis FlipY { get { return _flipY; } } /// <summary> /// The basis that will flip something along the Z axis when used in a transformation. /// </summary> - /// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Up, Vector3.Forward)`.</value> + /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Up, Vector3.Forward)</c>.</value> public static Basis FlipZ { get { return _flipZ; } } /// <summary> /// Constructs a pure rotation basis matrix from the given quaternion. /// </summary> - /// <param name="quat">The quaternion to create the basis from.</param> - public Basis(Quat quat) + /// <param name="quaternion">The quaternion to create the basis from.</param> + public Basis(Quaternion quaternion) { - real_t s = 2.0f / quat.LengthSquared; + real_t s = 2.0f / quaternion.LengthSquared; - real_t xs = quat.x * s; - real_t ys = quat.y * s; - real_t zs = quat.z * s; - real_t wx = quat.w * xs; - real_t wy = quat.w * ys; - real_t wz = quat.w * zs; - real_t xx = quat.x * xs; - real_t xy = quat.x * ys; - real_t xz = quat.x * zs; - real_t yy = quat.y * ys; - real_t yz = quat.y * zs; - real_t zz = quat.z * zs; + real_t xs = quaternion.x * s; + real_t ys = quaternion.y * s; + real_t zs = quaternion.z * s; + real_t wx = quaternion.w * xs; + real_t wy = quaternion.w * ys; + real_t wz = quaternion.w * zs; + real_t xx = quaternion.x * xs; + real_t xy = quaternion.x * ys; + real_t xz = quaternion.x * zs; + real_t yy = quaternion.y * ys; + real_t yz = quaternion.y * zs; + real_t zz = quaternion.z * zs; Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy); Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx); @@ -727,8 +744,8 @@ namespace Godot /// (in the YXZ convention: when *composing*, first Y, then X, and Z last), /// given in the vector format as (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis(Quat)"/> constructor instead, which - /// uses a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which + /// uses a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> /// <param name="eulerYXZ">The Euler angles to create the basis from.</param> public Basis(Vector3 eulerYXZ) @@ -752,8 +769,8 @@ namespace Godot } /// <summary> - /// Constructs a pure rotation basis matrix, rotated around the given `axis` - /// by `phi` (in radians). The axis must be a normalized vector. + /// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/> + /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate, in radians.</param> @@ -830,6 +847,11 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this basis and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the basis and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Basis) @@ -840,45 +862,52 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this basis and <paramref name="other"/> are equal + /// </summary> + /// <param name="other">The other basis to compare.</param> + /// <returns>Whether or not the bases are equal.</returns> public bool Equals(Basis other) { return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2); } /// <summary> - /// Returns true if this basis and `other` are approximately equal, by running - /// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. + /// Returns <see langword="true"/> if this basis and <paramref name="other"/> are approximately equal, + /// by running <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. /// </summary> /// <param name="other">The other basis to compare.</param> - /// <returns>Whether or not the matrices are approximately equal.</returns> + /// <returns>Whether or not the bases are approximately equal.</returns> public bool IsEqualApprox(Basis other) { return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2); } + /// <summary> + /// Serves as the hash function for <see cref="Basis"/>. + /// </summary> + /// <returns>A hash code for this basis.</returns> public override int GetHashCode() { return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Basis"/> to a string. + /// </summary> + /// <returns>A string representation of this basis.</returns> public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(), - Row1.ToString(), - Row2.ToString() - }); + return $"[X: {x}, Y: {y}, Z: {z}]"; } + /// <summary> + /// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this basis.</returns> public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(format), - Row1.ToString(format), - Row2.ToString(format) - }); + return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, Z: {z.ToString(format)}]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs index c85cc1884c..a28a46896b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs @@ -2,18 +2,58 @@ using System; namespace Godot { + /// <summary> + /// Callable is a first class object which can be held in variables and passed to functions. + /// It represents a given method in an Object, and is typically used for signal callbacks. + /// </summary> + /// <example> + /// <code> + /// public void PrintArgs(object ar1, object arg2, object arg3 = null) + /// { + /// GD.PrintS(arg1, arg2, arg3); + /// } + /// + /// public void Test() + /// { + /// // This Callable object will call the PrintArgs method defined above. + /// Callable callable = new Callable(this, nameof(PrintArgs)); + /// callable.Call("hello", "world"); // Prints "hello world null". + /// callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs". + /// callable.Call("invalid"); // Invalid call, should have at least 2 arguments. + /// } + /// </code> + /// </example> public struct Callable { private readonly Object _target; private readonly StringName _method; private readonly Delegate _delegate; + /// <summary> + /// Object that contains the method. + /// </summary> public Object Target => _target; + /// <summary> + /// Name of the method that will be called. + /// </summary> public StringName Method => _method; + /// <summary> + /// Delegate of the method that will be called. + /// </summary> public Delegate Delegate => _delegate; + /// <summary> + /// Converts a <see cref="Delegate"/> to a <see cref="Callable"/>. + /// </summary> + /// <param name="delegate">The delegate to convert.</param> public static implicit operator Callable(Delegate @delegate) => new Callable(@delegate); + /// <summary> + /// Constructs a new <see cref="Callable"/> for the method called <paramref name="method"/> + /// in the specified <paramref name="target"/>. + /// </summary> + /// <param name="target">Object that contains the method.</param> + /// <param name="method">Name of the method that will be called.</param> public Callable(Object target, StringName method) { _target = target; @@ -21,6 +61,10 @@ namespace Godot _delegate = null; } + /// <summary> + /// Constructs a new <see cref="Callable"/> for the given <paramref name="delegate"/>. + /// </summary> + /// <param name="delegate">Delegate method that will be called.</param> public Callable(Delegate @delegate) { _target = null; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 0c333d06ef..2a869bc335 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -7,11 +7,11 @@ namespace Godot /// A color represented by red, green, blue, and alpha (RGBA) components. /// The alpha component is often used for transparency. /// Values are in floating-point and usually range from 0 to 1. - /// Some properties (such as CanvasItem.modulate) may accept values + /// Some properties (such as <see cref="CanvasItem.Modulate"/>) may accept values /// greater than 1 (overbright or HDR colors). /// /// If you want to supply values in a range of 0 to 255, you should use - /// <see cref="Color8"/> and the `r8`/`g8`/`b8`/`a8` properties. + /// <see cref="Color8"/> and the <c>r8</c>/<c>g8</c>/<c>b8</c>/<c>a8</c> properties. /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] @@ -127,11 +127,11 @@ namespace Godot } else if (g == max) { - h = 2 + (b - r) / delta; // Between cyan & yellow + h = 2 + ((b - r) / delta); // Between cyan & yellow } else { - h = 4 + (r - g) / delta; // Between magenta & cyan + h = 4 + ((r - g) / delta); // Between magenta & cyan } h /= 6.0f; @@ -173,7 +173,7 @@ namespace Godot /// <summary> /// The HSV value (brightness) of this color, on the range 0 to 1. /// </summary> - /// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHSV"/>.</value> + /// <value>Getting is equivalent to using <see cref="Math.Max(float, float)"/> on the RGB components. Setting uses <see cref="FromHSV"/>.</value> public float v { get @@ -189,7 +189,12 @@ namespace Godot /// <summary> /// Access color components using their index. /// </summary> - /// <value>`[0]` is equivalent to `.r`, `[1]` is equivalent to `.g`, `[2]` is equivalent to `.b`, `[3]` is equivalent to `.a`.</value> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="r"/>, + /// <c>[1]</c> is equivalent to <see cref="g"/>, + /// <c>[2]</c> is equivalent to <see cref="b"/>, + /// <c>[3]</c> is equivalent to <see cref="a"/>. + /// </value> public float this[int index] { get @@ -236,27 +241,48 @@ namespace Godot /// The second color may have a range of alpha values. /// </summary> /// <param name="over">The color to blend over.</param> - /// <returns>This color blended over `over`.</returns> + /// <returns>This color blended over <paramref name="over"/>.</returns> public Color Blend(Color over) { Color res; float sa = 1.0f - over.a; - res.a = a * sa + over.a; + res.a = (a * sa) + over.a; if (res.a == 0) { return new Color(0, 0, 0, 0); } - res.r = (r * a * sa + over.r * over.a) / res.a; - res.g = (g * a * sa + over.g * over.a) / res.a; - res.b = (b * a * sa + over.b * over.a) / res.a; + res.r = ((r * a * sa) + (over.r * over.a)) / res.a; + res.g = ((g * a * sa) + (over.g * over.a)) / res.a; + res.b = ((b * a * sa) + (over.b * over.a)) / res.a; return res; } /// <summary> + /// Returns a new color with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> + /// using <see cref="Mathf.Clamp(float, float, float)"/>. + /// </summary> + /// <param name="min">The color with minimum allowed values.</param> + /// <param name="max">The color with maximum allowed values.</param> + /// <returns>The color with all components clamped.</returns> + public Color Clamp(Color? min = null, Color? max = null) + { + Color minimum = min ?? new Color(0, 0, 0, 0); + Color maximum = max ?? new Color(1, 1, 1, 1); + return new Color + ( + (float)Mathf.Clamp(r, minimum.r, maximum.r), + (float)Mathf.Clamp(g, minimum.g, maximum.g), + (float)Mathf.Clamp(b, minimum.b, maximum.b), + (float)Mathf.Clamp(a, minimum.a, maximum.a) + ); + } + + /// <summary> /// Returns a new color resulting from making this color darker /// by the specified ratio (on the range of 0 to 1). /// </summary> @@ -265,14 +291,14 @@ namespace Godot public Color Darkened(float amount) { Color res = this; - res.r = res.r * (1.0f - amount); - res.g = res.g * (1.0f - amount); - res.b = res.b * (1.0f - amount); + res.r *= 1.0f - amount; + res.g *= 1.0f - amount; + res.b *= 1.0f - amount; return res; } /// <summary> - /// Returns the inverted color: `(1 - r, 1 - g, 1 - b, a)`. + /// Returns the inverted color: <c>(1 - r, 1 - g, 1 - b, a)</c>. /// </summary> /// <returns>The inverted color.</returns> public Color Inverted() @@ -294,15 +320,15 @@ namespace Godot public Color Lightened(float amount) { Color res = this; - res.r = res.r + (1.0f - res.r) * amount; - res.g = res.g + (1.0f - res.g) * amount; - res.b = res.b + (1.0f - res.b) * amount; + res.r += (1.0f - res.r) * amount; + res.g += (1.0f - res.g) * amount; + res.b += (1.0f - res.b) * amount; return res; } /// <summary> /// Returns the result of the linear interpolation between - /// this color and `to` by amount `weight`. + /// this color and <paramref name="to"/> by amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination color for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -320,7 +346,7 @@ namespace Godot /// <summary> /// Returns the result of the linear interpolation between - /// this color and `to` by color amount `weight`. + /// this color and <paramref name="to"/> by color amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination color for interpolation.</param> /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -341,7 +367,7 @@ namespace Godot /// format (each byte represents a color channel). /// ABGR is the reversed version of the default format. /// </summary> - /// <returns>A uint representing this color in ABGR32 format.</returns> + /// <returns>A <see langword="uint"/> representing this color in ABGR32 format.</returns> public uint ToAbgr32() { uint c = (byte)Math.Round(a * 255); @@ -360,7 +386,7 @@ namespace Godot /// format (each word represents a color channel). /// ABGR is the reversed version of the default format. /// </summary> - /// <returns>A ulong representing this color in ABGR64 format.</returns> + /// <returns>A <see langword="ulong"/> representing this color in ABGR64 format.</returns> public ulong ToAbgr64() { ulong c = (ushort)Math.Round(a * 65535); @@ -379,7 +405,7 @@ namespace Godot /// format (each byte represents a color channel). /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> - /// <returns>A uint representing this color in ARGB32 format.</returns> + /// <returns>A <see langword="uint"/> representing this color in ARGB32 format.</returns> public uint ToArgb32() { uint c = (byte)Math.Round(a * 255); @@ -398,7 +424,7 @@ namespace Godot /// format (each word represents a color channel). /// ARGB is more compatible with DirectX, but not used much in Godot. /// </summary> - /// <returns>A ulong representing this color in ARGB64 format.</returns> + /// <returns>A <see langword="ulong"/> representing this color in ARGB64 format.</returns> public ulong ToArgb64() { ulong c = (ushort)Math.Round(a * 65535); @@ -417,7 +443,7 @@ namespace Godot /// format (each byte represents a color channel). /// RGBA is Godot's default and recommended format. /// </summary> - /// <returns>A uint representing this color in RGBA32 format.</returns> + /// <returns>A <see langword="uint"/> representing this color in RGBA32 format.</returns> public uint ToRgba32() { uint c = (byte)Math.Round(r * 255); @@ -436,7 +462,7 @@ namespace Godot /// format (each word represents a color channel). /// RGBA is Godot's default and recommended format. /// </summary> - /// <returns>A ulong representing this color in RGBA64 format.</returns> + /// <returns>A <see langword="ulong"/> representing this color in RGBA64 format.</returns> public ulong ToRgba64() { ulong c = (ushort)Math.Round(r * 65535); @@ -453,11 +479,13 @@ namespace Godot /// <summary> /// Returns the color's HTML hexadecimal color string in RGBA format. /// </summary> - /// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param> + /// <param name="includeAlpha"> + /// Whether or not to include alpha. If <see langword="false"/>, the color is RGB instead of RGBA. + /// </param> /// <returns>A string for the HTML hexadecimal representation of this color.</returns> public string ToHTML(bool includeAlpha = true) { - var txt = string.Empty; + string txt = string.Empty; txt += ToHex32(r); txt += ToHex32(g); @@ -472,7 +500,7 @@ namespace Godot } /// <summary> - /// Constructs a color from RGBA values, typically on the range of 0 to 1. + /// Constructs a <see cref="Color"/> from RGBA values, typically on the range of 0 to 1. /// </summary> /// <param name="r">The color's red component, typically on the range of 0 to 1.</param> /// <param name="g">The color's green component, typically on the range of 0 to 1.</param> @@ -487,7 +515,7 @@ namespace Godot } /// <summary> - /// Constructs a color from an existing color and an alpha value. + /// Constructs a <see cref="Color"/> from an existing color and an alpha value. /// </summary> /// <param name="c">The color to construct from. Only its RGB values are used.</param> /// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param> @@ -500,10 +528,10 @@ namespace Godot } /// <summary> - /// Constructs a color from an unsigned 32-bit integer in RGBA format + /// Constructs a <see cref="Color"/> from an unsigned 32-bit integer in RGBA format /// (each byte represents a color channel). /// </summary> - /// <param name="rgba">The uint representing the color.</param> + /// <param name="rgba">The <see langword="uint"/> representing the color.</param> public Color(uint rgba) { a = (rgba & 0xFF) / 255.0f; @@ -516,10 +544,10 @@ namespace Godot } /// <summary> - /// Constructs a color from an unsigned 64-bit integer in RGBA format + /// Constructs a <see cref="Color"/> from an unsigned 64-bit integer in RGBA format /// (each word represents a color channel). /// </summary> - /// <param name="rgba">The ulong representing the color.</param> + /// <param name="rgba">The <see langword="ulong"/> representing the color.</param> public Color(ulong rgba) { a = (rgba & 0xFFFF) / 65535.0f; @@ -532,9 +560,9 @@ namespace Godot } /// <summary> - /// Constructs a color either from an HTML color code or from a - /// standardized color name. Supported - /// color names are the same as the <see cref="Colors"/> constants. + /// Constructs a <see cref="Color"/> either from an HTML color code or from a + /// standardized color name. Supported color names are the same as the + /// <see cref="Colors"/> constants. /// </summary> /// <param name="code">The HTML color code or color name to construct from.</param> public Color(string code) @@ -550,8 +578,8 @@ namespace Godot } /// <summary> - /// Constructs a color either from an HTML color code or from a - /// standardized color name, with `alpha` on the range of 0 to 1. Supported + /// Constructs a <see cref="Color"/> either from an HTML color code or from a + /// standardized color name, with <paramref name="alpha"/> on the range of 0 to 1. Supported /// color names are the same as the <see cref="Colors"/> constants. /// </summary> /// <param name="code">The HTML color code or color name to construct from.</param> @@ -563,9 +591,12 @@ namespace Godot } /// <summary> - /// Constructs a color from the HTML hexadecimal color string in RGBA format. + /// Constructs a <see cref="Color"/> from the HTML hexadecimal color string in RGBA format. /// </summary> /// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param> + /// <exception name="ArgumentOutOfRangeException"> + /// Thrown when the given <paramref name="rgba"/> color code is invalid. + /// </exception> private static Color FromHTML(string rgba) { Color c; @@ -606,7 +637,8 @@ namespace Godot } else { - throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba); + throw new ArgumentOutOfRangeException( + $"Invalid color code. Length is {rgba.Length}, but a length of 6 or 8 is expected: {rgba}"); } c.a = 1.0f; @@ -676,12 +708,12 @@ namespace Godot /// <returns>The constructed color.</returns> private static Color Named(string name) { - name = name.Replace(" ", String.Empty); - name = name.Replace("-", String.Empty); - name = name.Replace("_", String.Empty); - name = name.Replace("'", String.Empty); - name = name.Replace(".", String.Empty); - name = name.ToLower(); + name = name.Replace(" ", string.Empty); + name = name.Replace("-", string.Empty); + name = name.Replace("_", string.Empty); + name = name.Replace("'", string.Empty); + name = name.Replace(".", string.Empty); + name = name.ToUpper(); if (!Colors.namedColors.ContainsKey(name)) { @@ -694,7 +726,7 @@ namespace Godot /// <summary> /// Constructs a color from an HSV profile, with values on the /// range of 0 to 1. This is equivalent to using each of - /// the `h`/`s`/`v` properties, but much more efficient. + /// the <c>h</c>/<c>s</c>/<c>v</c> properties, but much more efficient. /// </summary> /// <param name="hue">The HSV hue, typically on the range of 0 to 1.</param> /// <param name="saturation">The HSV saturation, typically on the range of 0 to 1.</param> @@ -718,8 +750,8 @@ namespace Godot f = hue - i; p = value * (1 - saturation); - q = value * (1 - saturation * f); - t = value * (1 - saturation * (1 - f)); + q = value * (1 - (saturation * f)); + t = value * (1 - (saturation * (1 - f))); switch (i) { @@ -740,7 +772,7 @@ namespace Godot /// <summary> /// Converts a color to HSV values. This is equivalent to using each of - /// the `h`/`s`/`v` properties, but much more efficient. + /// the <c>h</c>/<c>s</c>/<c>v</c> properties, but much more efficient. /// </summary> /// <param name="hue">Output parameter for the HSV hue.</param> /// <param name="saturation">Output parameter for the HSV saturation.</param> @@ -764,22 +796,24 @@ namespace Godot } else if (g == max) { - hue = 2 + (b - r) / delta; // Between cyan & yellow + hue = 2 + ((b - r) / delta); // Between cyan & yellow } else { - hue = 4 + (r - g) / delta; // Between magenta & cyan + hue = 4 + ((r - g) / delta); // Between magenta & cyan } hue /= 6.0f; if (hue < 0) - { hue += 1.0f; - } } - saturation = max == 0 ? 0 : 1f - 1f * min / max; + if (max == 0) + saturation = 0; + else + saturation = 1 - (min / max); + value = max; } @@ -956,6 +990,11 @@ namespace Godot return left.r > right.r; } + /// <summary> + /// Returns <see langword="true"/> if this color and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the color and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Color) @@ -966,14 +1005,19 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this color and <paramref name="other"/> are equal + /// </summary> + /// <param name="other">The other color to compare.</param> + /// <returns>Whether or not the colors are equal.</returns> public bool Equals(Color other) { return r == other.r && g == other.g && b == other.b && a == other.a; } /// <summary> - /// Returns true if this color and `other` are approximately equal, by running - /// <see cref="Godot.Mathf.IsEqualApprox(float, float)"/> on each component. + /// Returns <see langword="true"/> if this color and <paramref name="other"/> are approximately equal, + /// by running <see cref="Mathf.IsEqualApprox(float, float)"/> on each component. /// </summary> /// <param name="other">The other color to compare.</param> /// <returns>Whether or not the colors are approximately equal.</returns> @@ -982,19 +1026,31 @@ namespace Godot return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a); } + /// <summary> + /// Serves as the hash function for <see cref="Color"/>. + /// </summary> + /// <returns>A hash code for this color.</returns> public override int GetHashCode() { return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Color"/> to a string. + /// </summary> + /// <returns>A string representation of this color.</returns> public override string ToString() { - return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString()); + return $"({r}, {g}, {b}, {a})"; } + /// <summary> + /// Converts this <see cref="Color"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this color.</returns> 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 d05a0414aa..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 @@ -9,301 +8,301 @@ namespace Godot /// </summary> public static class Colors { - // Color names and values are derived from core/color_names.inc + // Color names and values are derived from core/math/color_names.inc internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> { - {"aliceblue", new Color(0.94f, 0.97f, 1.00f)}, - {"antiquewhite", new Color(0.98f, 0.92f, 0.84f)}, - {"aqua", new Color(0.00f, 1.00f, 1.00f)}, - {"aquamarine", new Color(0.50f, 1.00f, 0.83f)}, - {"azure", new Color(0.94f, 1.00f, 1.00f)}, - {"beige", new Color(0.96f, 0.96f, 0.86f)}, - {"bisque", new Color(1.00f, 0.89f, 0.77f)}, - {"black", new Color(0.00f, 0.00f, 0.00f)}, - {"blanchedalmond", new Color(1.00f, 0.92f, 0.80f)}, - {"blue", new Color(0.00f, 0.00f, 1.00f)}, - {"blueviolet", new Color(0.54f, 0.17f, 0.89f)}, - {"brown", new Color(0.65f, 0.16f, 0.16f)}, - {"burlywood", new Color(0.87f, 0.72f, 0.53f)}, - {"cadetblue", new Color(0.37f, 0.62f, 0.63f)}, - {"chartreuse", new Color(0.50f, 1.00f, 0.00f)}, - {"chocolate", new Color(0.82f, 0.41f, 0.12f)}, - {"coral", new Color(1.00f, 0.50f, 0.31f)}, - {"cornflower", new Color(0.39f, 0.58f, 0.93f)}, - {"cornsilk", new Color(1.00f, 0.97f, 0.86f)}, - {"crimson", new Color(0.86f, 0.08f, 0.24f)}, - {"cyan", new Color(0.00f, 1.00f, 1.00f)}, - {"darkblue", new Color(0.00f, 0.00f, 0.55f)}, - {"darkcyan", new Color(0.00f, 0.55f, 0.55f)}, - {"darkgoldenrod", new Color(0.72f, 0.53f, 0.04f)}, - {"darkgray", new Color(0.66f, 0.66f, 0.66f)}, - {"darkgreen", new Color(0.00f, 0.39f, 0.00f)}, - {"darkkhaki", new Color(0.74f, 0.72f, 0.42f)}, - {"darkmagenta", new Color(0.55f, 0.00f, 0.55f)}, - {"darkolivegreen", new Color(0.33f, 0.42f, 0.18f)}, - {"darkorange", new Color(1.00f, 0.55f, 0.00f)}, - {"darkorchid", new Color(0.60f, 0.20f, 0.80f)}, - {"darkred", new Color(0.55f, 0.00f, 0.00f)}, - {"darksalmon", new Color(0.91f, 0.59f, 0.48f)}, - {"darkseagreen", new Color(0.56f, 0.74f, 0.56f)}, - {"darkslateblue", new Color(0.28f, 0.24f, 0.55f)}, - {"darkslategray", new Color(0.18f, 0.31f, 0.31f)}, - {"darkturquoise", new Color(0.00f, 0.81f, 0.82f)}, - {"darkviolet", new Color(0.58f, 0.00f, 0.83f)}, - {"deeppink", new Color(1.00f, 0.08f, 0.58f)}, - {"deepskyblue", new Color(0.00f, 0.75f, 1.00f)}, - {"dimgray", new Color(0.41f, 0.41f, 0.41f)}, - {"dodgerblue", new Color(0.12f, 0.56f, 1.00f)}, - {"firebrick", new Color(0.70f, 0.13f, 0.13f)}, - {"floralwhite", new Color(1.00f, 0.98f, 0.94f)}, - {"forestgreen", new Color(0.13f, 0.55f, 0.13f)}, - {"fuchsia", new Color(1.00f, 0.00f, 1.00f)}, - {"gainsboro", new Color(0.86f, 0.86f, 0.86f)}, - {"ghostwhite", new Color(0.97f, 0.97f, 1.00f)}, - {"gold", new Color(1.00f, 0.84f, 0.00f)}, - {"goldenrod", new Color(0.85f, 0.65f, 0.13f)}, - {"gray", new Color(0.75f, 0.75f, 0.75f)}, - {"green", new Color(0.00f, 1.00f, 0.00f)}, - {"greenyellow", new Color(0.68f, 1.00f, 0.18f)}, - {"honeydew", new Color(0.94f, 1.00f, 0.94f)}, - {"hotpink", new Color(1.00f, 0.41f, 0.71f)}, - {"indianred", new Color(0.80f, 0.36f, 0.36f)}, - {"indigo", new Color(0.29f, 0.00f, 0.51f)}, - {"ivory", new Color(1.00f, 1.00f, 0.94f)}, - {"khaki", new Color(0.94f, 0.90f, 0.55f)}, - {"lavender", new Color(0.90f, 0.90f, 0.98f)}, - {"lavenderblush", new Color(1.00f, 0.94f, 0.96f)}, - {"lawngreen", new Color(0.49f, 0.99f, 0.00f)}, - {"lemonchiffon", new Color(1.00f, 0.98f, 0.80f)}, - {"lightblue", new Color(0.68f, 0.85f, 0.90f)}, - {"lightcoral", new Color(0.94f, 0.50f, 0.50f)}, - {"lightcyan", new Color(0.88f, 1.00f, 1.00f)}, - {"lightgoldenrod", new Color(0.98f, 0.98f, 0.82f)}, - {"lightgray", new Color(0.83f, 0.83f, 0.83f)}, - {"lightgreen", new Color(0.56f, 0.93f, 0.56f)}, - {"lightpink", new Color(1.00f, 0.71f, 0.76f)}, - {"lightsalmon", new Color(1.00f, 0.63f, 0.48f)}, - {"lightseagreen", new Color(0.13f, 0.70f, 0.67f)}, - {"lightskyblue", new Color(0.53f, 0.81f, 0.98f)}, - {"lightslategray", new Color(0.47f, 0.53f, 0.60f)}, - {"lightsteelblue", new Color(0.69f, 0.77f, 0.87f)}, - {"lightyellow", new Color(1.00f, 1.00f, 0.88f)}, - {"lime", new Color(0.00f, 1.00f, 0.00f)}, - {"limegreen", new Color(0.20f, 0.80f, 0.20f)}, - {"linen", new Color(0.98f, 0.94f, 0.90f)}, - {"magenta", new Color(1.00f, 0.00f, 1.00f)}, - {"maroon", new Color(0.69f, 0.19f, 0.38f)}, - {"mediumaquamarine", new Color(0.40f, 0.80f, 0.67f)}, - {"mediumblue", new Color(0.00f, 0.00f, 0.80f)}, - {"mediumorchid", new Color(0.73f, 0.33f, 0.83f)}, - {"mediumpurple", new Color(0.58f, 0.44f, 0.86f)}, - {"mediumseagreen", new Color(0.24f, 0.70f, 0.44f)}, - {"mediumslateblue", new Color(0.48f, 0.41f, 0.93f)}, - {"mediumspringgreen", new Color(0.00f, 0.98f, 0.60f)}, - {"mediumturquoise", new Color(0.28f, 0.82f, 0.80f)}, - {"mediumvioletred", new Color(0.78f, 0.08f, 0.52f)}, - {"midnightblue", new Color(0.10f, 0.10f, 0.44f)}, - {"mintcream", new Color(0.96f, 1.00f, 0.98f)}, - {"mistyrose", new Color(1.00f, 0.89f, 0.88f)}, - {"moccasin", new Color(1.00f, 0.89f, 0.71f)}, - {"navajowhite", new Color(1.00f, 0.87f, 0.68f)}, - {"navyblue", new Color(0.00f, 0.00f, 0.50f)}, - {"oldlace", new Color(0.99f, 0.96f, 0.90f)}, - {"olive", new Color(0.50f, 0.50f, 0.00f)}, - {"olivedrab", new Color(0.42f, 0.56f, 0.14f)}, - {"orange", new Color(1.00f, 0.65f, 0.00f)}, - {"orangered", new Color(1.00f, 0.27f, 0.00f)}, - {"orchid", new Color(0.85f, 0.44f, 0.84f)}, - {"palegoldenrod", new Color(0.93f, 0.91f, 0.67f)}, - {"palegreen", new Color(0.60f, 0.98f, 0.60f)}, - {"paleturquoise", new Color(0.69f, 0.93f, 0.93f)}, - {"palevioletred", new Color(0.86f, 0.44f, 0.58f)}, - {"papayawhip", new Color(1.00f, 0.94f, 0.84f)}, - {"peachpuff", new Color(1.00f, 0.85f, 0.73f)}, - {"peru", new Color(0.80f, 0.52f, 0.25f)}, - {"pink", new Color(1.00f, 0.75f, 0.80f)}, - {"plum", new Color(0.87f, 0.63f, 0.87f)}, - {"powderblue", new Color(0.69f, 0.88f, 0.90f)}, - {"purple", new Color(0.63f, 0.13f, 0.94f)}, - {"rebeccapurple", new Color(0.40f, 0.20f, 0.60f)}, - {"red", new Color(1.00f, 0.00f, 0.00f)}, - {"rosybrown", new Color(0.74f, 0.56f, 0.56f)}, - {"royalblue", new Color(0.25f, 0.41f, 0.88f)}, - {"saddlebrown", new Color(0.55f, 0.27f, 0.07f)}, - {"salmon", new Color(0.98f, 0.50f, 0.45f)}, - {"sandybrown", new Color(0.96f, 0.64f, 0.38f)}, - {"seagreen", new Color(0.18f, 0.55f, 0.34f)}, - {"seashell", new Color(1.00f, 0.96f, 0.93f)}, - {"sienna", new Color(0.63f, 0.32f, 0.18f)}, - {"silver", new Color(0.75f, 0.75f, 0.75f)}, - {"skyblue", new Color(0.53f, 0.81f, 0.92f)}, - {"slateblue", new Color(0.42f, 0.35f, 0.80f)}, - {"slategray", new Color(0.44f, 0.50f, 0.56f)}, - {"snow", new Color(1.00f, 0.98f, 0.98f)}, - {"springgreen", new Color(0.00f, 1.00f, 0.50f)}, - {"steelblue", new Color(0.27f, 0.51f, 0.71f)}, - {"tan", new Color(0.82f, 0.71f, 0.55f)}, - {"teal", new Color(0.00f, 0.50f, 0.50f)}, - {"thistle", new Color(0.85f, 0.75f, 0.85f)}, - {"tomato", new Color(1.00f, 0.39f, 0.28f)}, - {"transparent", new Color(1.00f, 1.00f, 1.00f, 0.00f)}, - {"turquoise", new Color(0.25f, 0.88f, 0.82f)}, - {"violet", new Color(0.93f, 0.51f, 0.93f)}, - {"webgreen", new Color(0.00f, 0.50f, 0.00f)}, - {"webgray", new Color(0.50f, 0.50f, 0.50f)}, - {"webmaroon", new Color(0.50f, 0.00f, 0.00f)}, - {"webpurple", new Color(0.50f, 0.00f, 0.50f)}, - {"wheat", new Color(0.96f, 0.87f, 0.70f)}, - {"white", new Color(1.00f, 1.00f, 1.00f)}, - {"whitesmoke", new Color(0.96f, 0.96f, 0.96f)}, - {"yellow", new Color(1.00f, 1.00f, 0.00f)}, - {"yellowgreen", new Color(0.60f, 0.80f, 0.20f)}, + {"ALICEBLUE", new Color(0.94f, 0.97f, 1.00f)}, + {"ANTIQUEWHITE", new Color(0.98f, 0.92f, 0.84f)}, + {"AQUA", new Color(0.00f, 1.00f, 1.00f)}, + {"AQUAMARINE", new Color(0.50f, 1.00f, 0.83f)}, + {"AZURE", new Color(0.94f, 1.00f, 1.00f)}, + {"BEIGE", new Color(0.96f, 0.96f, 0.86f)}, + {"BISQUE", new Color(1.00f, 0.89f, 0.77f)}, + {"BLACK", new Color(0.00f, 0.00f, 0.00f)}, + {"BLANCHEDALMOND", new Color(1.00f, 0.92f, 0.80f)}, + {"BLUE", new Color(0.00f, 0.00f, 1.00f)}, + {"BLUEVIOLET", new Color(0.54f, 0.17f, 0.89f)}, + {"BROWN", new Color(0.65f, 0.16f, 0.16f)}, + {"BURLYWOOD", new Color(0.87f, 0.72f, 0.53f)}, + {"CADETBLUE", new Color(0.37f, 0.62f, 0.63f)}, + {"CHARTREUSE", new Color(0.50f, 1.00f, 0.00f)}, + {"CHOCOLATE", new Color(0.82f, 0.41f, 0.12f)}, + {"CORAL", new Color(1.00f, 0.50f, 0.31f)}, + {"CORNFLOWERBLUE", new Color(0.39f, 0.58f, 0.93f)}, + {"CORNSILK", new Color(1.00f, 0.97f, 0.86f)}, + {"CRIMSON", new Color(0.86f, 0.08f, 0.24f)}, + {"CYAN", new Color(0.00f, 1.00f, 1.00f)}, + {"DARKBLUE", new Color(0.00f, 0.00f, 0.55f)}, + {"DARKCYAN", new Color(0.00f, 0.55f, 0.55f)}, + {"DARKGOLDENROD", new Color(0.72f, 0.53f, 0.04f)}, + {"DARKGRAY", new Color(0.66f, 0.66f, 0.66f)}, + {"DARKGREEN", new Color(0.00f, 0.39f, 0.00f)}, + {"DARKKHAKI", new Color(0.74f, 0.72f, 0.42f)}, + {"DARKMAGENTA", new Color(0.55f, 0.00f, 0.55f)}, + {"DARKOLIVEGREEN", new Color(0.33f, 0.42f, 0.18f)}, + {"DARKORANGE", new Color(1.00f, 0.55f, 0.00f)}, + {"DARKORCHID", new Color(0.60f, 0.20f, 0.80f)}, + {"DARKRED", new Color(0.55f, 0.00f, 0.00f)}, + {"DARKSALMON", new Color(0.91f, 0.59f, 0.48f)}, + {"DARKSEAGREEN", new Color(0.56f, 0.74f, 0.56f)}, + {"DARKSLATEBLUE", new Color(0.28f, 0.24f, 0.55f)}, + {"DARKSLATEGRAY", new Color(0.18f, 0.31f, 0.31f)}, + {"DARKTURQUOISE", new Color(0.00f, 0.81f, 0.82f)}, + {"DARKVIOLET", new Color(0.58f, 0.00f, 0.83f)}, + {"DEEPPINK", new Color(1.00f, 0.08f, 0.58f)}, + {"DEEPSKYBLUE", new Color(0.00f, 0.75f, 1.00f)}, + {"DIMGRAY", new Color(0.41f, 0.41f, 0.41f)}, + {"DODGERBLUE", new Color(0.12f, 0.56f, 1.00f)}, + {"FIREBRICK", new Color(0.70f, 0.13f, 0.13f)}, + {"FLORALWHITE", new Color(1.00f, 0.98f, 0.94f)}, + {"FORESTGREEN", new Color(0.13f, 0.55f, 0.13f)}, + {"FUCHSIA", new Color(1.00f, 0.00f, 1.00f)}, + {"GAINSBORO", new Color(0.86f, 0.86f, 0.86f)}, + {"GHOSTWHITE", new Color(0.97f, 0.97f, 1.00f)}, + {"GOLD", new Color(1.00f, 0.84f, 0.00f)}, + {"GOLDENROD", new Color(0.85f, 0.65f, 0.13f)}, + {"GRAY", new Color(0.75f, 0.75f, 0.75f)}, + {"GREEN", new Color(0.00f, 1.00f, 0.00f)}, + {"GREENYELLOW", new Color(0.68f, 1.00f, 0.18f)}, + {"HONEYDEW", new Color(0.94f, 1.00f, 0.94f)}, + {"HOTPINK", new Color(1.00f, 0.41f, 0.71f)}, + {"INDIANRED", new Color(0.80f, 0.36f, 0.36f)}, + {"INDIGO", new Color(0.29f, 0.00f, 0.51f)}, + {"IVORY", new Color(1.00f, 1.00f, 0.94f)}, + {"KHAKI", new Color(0.94f, 0.90f, 0.55f)}, + {"LAVENDER", new Color(0.90f, 0.90f, 0.98f)}, + {"LAVENDERBLUSH", new Color(1.00f, 0.94f, 0.96f)}, + {"LAWNGREEN", new Color(0.49f, 0.99f, 0.00f)}, + {"LEMONCHIFFON", new Color(1.00f, 0.98f, 0.80f)}, + {"LIGHTBLUE", new Color(0.68f, 0.85f, 0.90f)}, + {"LIGHTCORAL", new Color(0.94f, 0.50f, 0.50f)}, + {"LIGHTCYAN", new Color(0.88f, 1.00f, 1.00f)}, + {"LIGHTGOLDENROD", new Color(0.98f, 0.98f, 0.82f)}, + {"LIGHTGRAY", new Color(0.83f, 0.83f, 0.83f)}, + {"LIGHTGREEN", new Color(0.56f, 0.93f, 0.56f)}, + {"LIGHTPINK", new Color(1.00f, 0.71f, 0.76f)}, + {"LIGHTSALMON", new Color(1.00f, 0.63f, 0.48f)}, + {"LIGHTSEAGREEN", new Color(0.13f, 0.70f, 0.67f)}, + {"LIGHTSKYBLUE", new Color(0.53f, 0.81f, 0.98f)}, + {"LIGHTSLATEGRAY", new Color(0.47f, 0.53f, 0.60f)}, + {"LIGHTSTEELBLUE", new Color(0.69f, 0.77f, 0.87f)}, + {"LIGHTYELLOW", new Color(1.00f, 1.00f, 0.88f)}, + {"LIME", new Color(0.00f, 1.00f, 0.00f)}, + {"LIMEGREEN", new Color(0.20f, 0.80f, 0.20f)}, + {"LINEN", new Color(0.98f, 0.94f, 0.90f)}, + {"MAGENTA", new Color(1.00f, 0.00f, 1.00f)}, + {"MAROON", new Color(0.69f, 0.19f, 0.38f)}, + {"MEDIUMAQUAMARINE", new Color(0.40f, 0.80f, 0.67f)}, + {"MEDIUMBLUE", new Color(0.00f, 0.00f, 0.80f)}, + {"MEDIUMORCHID", new Color(0.73f, 0.33f, 0.83f)}, + {"MEDIUMPURPLE", new Color(0.58f, 0.44f, 0.86f)}, + {"MEDIUMSEAGREEN", new Color(0.24f, 0.70f, 0.44f)}, + {"MEDIUMSLATEBLUE", new Color(0.48f, 0.41f, 0.93f)}, + {"MEDIUMSPRINGGREEN", new Color(0.00f, 0.98f, 0.60f)}, + {"MEDIUMTURQUOISE", new Color(0.28f, 0.82f, 0.80f)}, + {"MEDIUMVIOLETRED", new Color(0.78f, 0.08f, 0.52f)}, + {"MIDNIGHTBLUE", new Color(0.10f, 0.10f, 0.44f)}, + {"MINTCREAM", new Color(0.96f, 1.00f, 0.98f)}, + {"MISTYROSE", new Color(1.00f, 0.89f, 0.88f)}, + {"MOCCASIN", new Color(1.00f, 0.89f, 0.71f)}, + {"NAVAJOWHITE", new Color(1.00f, 0.87f, 0.68f)}, + {"NAVYBLUE", new Color(0.00f, 0.00f, 0.50f)}, + {"OLDLACE", new Color(0.99f, 0.96f, 0.90f)}, + {"OLIVE", new Color(0.50f, 0.50f, 0.00f)}, + {"OLIVEDRAB", new Color(0.42f, 0.56f, 0.14f)}, + {"ORANGE", new Color(1.00f, 0.65f, 0.00f)}, + {"ORANGERED", new Color(1.00f, 0.27f, 0.00f)}, + {"ORCHID", new Color(0.85f, 0.44f, 0.84f)}, + {"PALEGOLDENROD", new Color(0.93f, 0.91f, 0.67f)}, + {"PALEGREEN", new Color(0.60f, 0.98f, 0.60f)}, + {"PALETURQUOISE", new Color(0.69f, 0.93f, 0.93f)}, + {"PALEVIOLETRED", new Color(0.86f, 0.44f, 0.58f)}, + {"PAPAYAWHIP", new Color(1.00f, 0.94f, 0.84f)}, + {"PEACHPUFF", new Color(1.00f, 0.85f, 0.73f)}, + {"PERU", new Color(0.80f, 0.52f, 0.25f)}, + {"PINK", new Color(1.00f, 0.75f, 0.80f)}, + {"PLUM", new Color(0.87f, 0.63f, 0.87f)}, + {"POWDERBLUE", new Color(0.69f, 0.88f, 0.90f)}, + {"PURPLE", new Color(0.63f, 0.13f, 0.94f)}, + {"REBECCAPURPLE", new Color(0.40f, 0.20f, 0.60f)}, + {"RED", new Color(1.00f, 0.00f, 0.00f)}, + {"ROSYBROWN", new Color(0.74f, 0.56f, 0.56f)}, + {"ROYALBLUE", new Color(0.25f, 0.41f, 0.88f)}, + {"SADDLEBROWN", new Color(0.55f, 0.27f, 0.07f)}, + {"SALMON", new Color(0.98f, 0.50f, 0.45f)}, + {"SANDYBROWN", new Color(0.96f, 0.64f, 0.38f)}, + {"SEAGREEN", new Color(0.18f, 0.55f, 0.34f)}, + {"SEASHELL", new Color(1.00f, 0.96f, 0.93f)}, + {"SIENNA", new Color(0.63f, 0.32f, 0.18f)}, + {"SILVER", new Color(0.75f, 0.75f, 0.75f)}, + {"SKYBLUE", new Color(0.53f, 0.81f, 0.92f)}, + {"SLATEBLUE", new Color(0.42f, 0.35f, 0.80f)}, + {"SLATEGRAY", new Color(0.44f, 0.50f, 0.56f)}, + {"SNOW", new Color(1.00f, 0.98f, 0.98f)}, + {"SPRINGGREEN", new Color(0.00f, 1.00f, 0.50f)}, + {"STEELBLUE", new Color(0.27f, 0.51f, 0.71f)}, + {"TAN", new Color(0.82f, 0.71f, 0.55f)}, + {"TEAL", new Color(0.00f, 0.50f, 0.50f)}, + {"THISTLE", new Color(0.85f, 0.75f, 0.85f)}, + {"TOMATO", new Color(1.00f, 0.39f, 0.28f)}, + {"TRANSPARENT", new Color(1.00f, 1.00f, 1.00f, 0.00f)}, + {"TURQUOISE", new Color(0.25f, 0.88f, 0.82f)}, + {"VIOLET", new Color(0.93f, 0.51f, 0.93f)}, + {"WEBGRAY", new Color(0.50f, 0.50f, 0.50f)}, + {"WEBGREEN", new Color(0.00f, 0.50f, 0.00f)}, + {"WEBMAROON", new Color(0.50f, 0.00f, 0.00f)}, + {"WEBPURPLE", new Color(0.50f, 0.00f, 0.50f)}, + {"WHEAT", new Color(0.96f, 0.87f, 0.70f)}, + {"WHITE", new Color(1.00f, 1.00f, 1.00f)}, + {"WHITESMOKE", new Color(0.96f, 0.96f, 0.96f)}, + {"YELLOW", new Color(1.00f, 1.00f, 0.00f)}, + {"YELLOWGREEN", new Color(0.60f, 0.80f, 0.20f)}, }; - public static Color AliceBlue { get { return namedColors["aliceblue"]; } } - public static Color AntiqueWhite { get { return namedColors["antiquewhite"]; } } - public static Color Aqua { get { return namedColors["aqua"]; } } - public static Color Aquamarine { get { return namedColors["aquamarine"]; } } - public static Color Azure { get { return namedColors["azure"]; } } - public static Color Beige { get { return namedColors["beige"]; } } - public static Color Bisque { get { return namedColors["bisque"]; } } - public static Color Black { get { return namedColors["black"]; } } - public static Color BlanchedAlmond { get { return namedColors["blanchedalmond"]; } } - public static Color Blue { get { return namedColors["blue"]; } } - public static Color BlueViolet { get { return namedColors["blueviolet"]; } } - public static Color Brown { get { return namedColors["brown"]; } } - public static Color BurlyWood { get { return namedColors["burlywood"]; } } - public static Color CadetBlue { get { return namedColors["cadetblue"]; } } - public static Color Chartreuse { get { return namedColors["chartreuse"]; } } - public static Color Chocolate { get { return namedColors["chocolate"]; } } - public static Color Coral { get { return namedColors["coral"]; } } - public static Color Cornflower { get { return namedColors["cornflower"]; } } - public static Color Cornsilk { get { return namedColors["cornsilk"]; } } - public static Color Crimson { get { return namedColors["crimson"]; } } - public static Color Cyan { get { return namedColors["cyan"]; } } - public static Color DarkBlue { get { return namedColors["darkblue"]; } } - public static Color DarkCyan { get { return namedColors["darkcyan"]; } } - public static Color DarkGoldenrod { get { return namedColors["darkgoldenrod"]; } } - public static Color DarkGray { get { return namedColors["darkgray"]; } } - public static Color DarkGreen { get { return namedColors["darkgreen"]; } } - public static Color DarkKhaki { get { return namedColors["darkkhaki"]; } } - public static Color DarkMagenta { get { return namedColors["darkmagenta"]; } } - public static Color DarkOliveGreen { get { return namedColors["darkolivegreen"]; } } - public static Color DarkOrange { get { return namedColors["darkorange"]; } } - public static Color DarkOrchid { get { return namedColors["darkorchid"]; } } - public static Color DarkRed { get { return namedColors["darkred"]; } } - public static Color DarkSalmon { get { return namedColors["darksalmon"]; } } - public static Color DarkSeaGreen { get { return namedColors["darkseagreen"]; } } - public static Color DarkSlateBlue { get { return namedColors["darkslateblue"]; } } - public static Color DarkSlateGray { get { return namedColors["darkslategray"]; } } - public static Color DarkTurquoise { get { return namedColors["darkturquoise"]; } } - public static Color DarkViolet { get { return namedColors["darkviolet"]; } } - public static Color DeepPink { get { return namedColors["deeppink"]; } } - public static Color DeepSkyBlue { get { return namedColors["deepskyblue"]; } } - public static Color DimGray { get { return namedColors["dimgray"]; } } - public static Color DodgerBlue { get { return namedColors["dodgerblue"]; } } - public static Color Firebrick { get { return namedColors["firebrick"]; } } - public static Color FloralWhite { get { return namedColors["floralwhite"]; } } - public static Color ForestGreen { get { return namedColors["forestgreen"]; } } - public static Color Fuchsia { get { return namedColors["fuchsia"]; } } - public static Color Gainsboro { get { return namedColors["gainsboro"]; } } - public static Color GhostWhite { get { return namedColors["ghostwhite"]; } } - public static Color Gold { get { return namedColors["gold"]; } } - public static Color Goldenrod { get { return namedColors["goldenrod"]; } } - public static Color Gray { get { return namedColors["gray"]; } } - public static Color Green { get { return namedColors["green"]; } } - public static Color GreenYellow { get { return namedColors["greenyellow"]; } } - public static Color Honeydew { get { return namedColors["honeydew"]; } } - public static Color HotPink { get { return namedColors["hotpink"]; } } - public static Color IndianRed { get { return namedColors["indianred"]; } } - public static Color Indigo { get { return namedColors["indigo"]; } } - public static Color Ivory { get { return namedColors["ivory"]; } } - public static Color Khaki { get { return namedColors["khaki"]; } } - public static Color Lavender { get { return namedColors["lavender"]; } } - public static Color LavenderBlush { get { return namedColors["lavenderblush"]; } } - public static Color LawnGreen { get { return namedColors["lawngreen"]; } } - public static Color LemonChiffon { get { return namedColors["lemonchiffon"]; } } - public static Color LightBlue { get { return namedColors["lightblue"]; } } - public static Color LightCoral { get { return namedColors["lightcoral"]; } } - public static Color LightCyan { get { return namedColors["lightcyan"]; } } - public static Color LightGoldenrod { get { return namedColors["lightgoldenrod"]; } } - public static Color LightGray { get { return namedColors["lightgray"]; } } - public static Color LightGreen { get { return namedColors["lightgreen"]; } } - public static Color LightPink { get { return namedColors["lightpink"]; } } - public static Color LightSalmon { get { return namedColors["lightsalmon"]; } } - public static Color LightSeaGreen { get { return namedColors["lightseagreen"]; } } - public static Color LightSkyBlue { get { return namedColors["lightskyblue"]; } } - public static Color LightSlateGray { get { return namedColors["lightslategray"]; } } - public static Color LightSteelBlue { get { return namedColors["lightsteelblue"]; } } - public static Color LightYellow { get { return namedColors["lightyellow"]; } } - public static Color Lime { get { return namedColors["lime"]; } } - public static Color Limegreen { get { return namedColors["limegreen"]; } } - public static Color Linen { get { return namedColors["linen"]; } } - public static Color Magenta { get { return namedColors["magenta"]; } } - public static Color Maroon { get { return namedColors["maroon"]; } } - public static Color MediumAquamarine { get { return namedColors["mediumaquamarine"]; } } - public static Color MediumBlue { get { return namedColors["mediumblue"]; } } - public static Color MediumOrchid { get { return namedColors["mediumorchid"]; } } - public static Color MediumPurple { get { return namedColors["mediumpurple"]; } } - public static Color MediumSeaGreen { get { return namedColors["mediumseagreen"]; } } - public static Color MediumSlateBlue { get { return namedColors["mediumslateblue"]; } } - public static Color MediumSpringGreen { get { return namedColors["mediumspringgreen"]; } } - public static Color MediumTurquoise { get { return namedColors["mediumturquoise"]; } } - public static Color MediumVioletRed { get { return namedColors["mediumvioletred"]; } } - public static Color MidnightBlue { get { return namedColors["midnightblue"]; } } - public static Color MintCream { get { return namedColors["mintcream"]; } } - public static Color MistyRose { get { return namedColors["mistyrose"]; } } - public static Color Moccasin { get { return namedColors["moccasin"]; } } - public static Color NavajoWhite { get { return namedColors["navajowhite"]; } } - public static Color NavyBlue { get { return namedColors["navyblue"]; } } - public static Color OldLace { get { return namedColors["oldlace"]; } } - public static Color Olive { get { return namedColors["olive"]; } } - public static Color OliveDrab { get { return namedColors["olivedrab"]; } } - public static Color Orange { get { return namedColors["orange"]; } } - public static Color OrangeRed { get { return namedColors["orangered"]; } } - public static Color Orchid { get { return namedColors["orchid"]; } } - public static Color PaleGoldenrod { get { return namedColors["palegoldenrod"]; } } - public static Color PaleGreen { get { return namedColors["palegreen"]; } } - public static Color PaleTurquoise { get { return namedColors["paleturquoise"]; } } - public static Color PaleVioletRed { get { return namedColors["palevioletred"]; } } - public static Color PapayaWhip { get { return namedColors["papayawhip"]; } } - public static Color PeachPuff { get { return namedColors["peachpuff"]; } } - public static Color Peru { get { return namedColors["peru"]; } } - public static Color Pink { get { return namedColors["pink"]; } } - public static Color Plum { get { return namedColors["plum"]; } } - public static Color PowderBlue { get { return namedColors["powderblue"]; } } - public static Color Purple { get { return namedColors["purple"]; } } - public static Color RebeccaPurple { get { return namedColors["rebeccapurple"]; } } - public static Color Red { get { return namedColors["red"]; } } - public static Color RosyBrown { get { return namedColors["rosybrown"]; } } - public static Color RoyalBlue { get { return namedColors["royalblue"]; } } - public static Color SaddleBrown { get { return namedColors["saddlebrown"]; } } - public static Color Salmon { get { return namedColors["salmon"]; } } - public static Color SandyBrown { get { return namedColors["sandybrown"]; } } - public static Color SeaGreen { get { return namedColors["seagreen"]; } } - public static Color SeaShell { get { return namedColors["seashell"]; } } - public static Color Sienna { get { return namedColors["sienna"]; } } - public static Color Silver { get { return namedColors["silver"]; } } - public static Color SkyBlue { get { return namedColors["skyblue"]; } } - public static Color SlateBlue { get { return namedColors["slateblue"]; } } - public static Color SlateGray { get { return namedColors["slategray"]; } } - public static Color Snow { get { return namedColors["snow"]; } } - public static Color SpringGreen { get { return namedColors["springgreen"]; } } - public static Color SteelBlue { get { return namedColors["steelblue"]; } } - public static Color Tan { get { return namedColors["tan"]; } } - public static Color Teal { get { return namedColors["teal"]; } } - public static Color Thistle { get { return namedColors["thistle"]; } } - public static Color Tomato { get { return namedColors["tomato"]; } } - public static Color Transparent { get { return namedColors["transparent"]; } } - public static Color Turquoise { get { return namedColors["turquoise"]; } } - public static Color Violet { get { return namedColors["violet"]; } } - public static Color WebGreen { get { return namedColors["webgreen"]; } } - public static Color WebGray { get { return namedColors["webgray"]; } } - public static Color WebMaroon { get { return namedColors["webmaroon"]; } } - public static Color WebPurple { get { return namedColors["webpurple"]; } } - public static Color Wheat { get { return namedColors["wheat"]; } } - public static Color White { get { return namedColors["white"]; } } - public static Color WhiteSmoke { get { return namedColors["whitesmoke"]; } } - public static Color Yellow { get { return namedColors["yellow"]; } } - public static Color YellowGreen { get { return namedColors["yellowgreen"]; } } + public static Color AliceBlue { get { return namedColors["ALICEBLUE"]; } } + public static Color AntiqueWhite { get { return namedColors["ANTIQUEWHITE"]; } } + public static Color Aqua { get { return namedColors["AQUA"]; } } + public static Color Aquamarine { get { return namedColors["AQUAMARINE"]; } } + public static Color Azure { get { return namedColors["AZURE"]; } } + public static Color Beige { get { return namedColors["BEIGE"]; } } + public static Color Bisque { get { return namedColors["BISQUE"]; } } + public static Color Black { get { return namedColors["BLACK"]; } } + public static Color BlanchedAlmond { get { return namedColors["BLANCHEDALMOND"]; } } + public static Color Blue { get { return namedColors["BLUE"]; } } + public static Color BlueViolet { get { return namedColors["BLUEVIOLET"]; } } + public static Color Brown { get { return namedColors["BROWN"]; } } + public static Color Burlywood { get { return namedColors["BURLYWOOD"]; } } + public static Color CadetBlue { get { return namedColors["CADETBLUE"]; } } + public static Color Chartreuse { get { return namedColors["CHARTREUSE"]; } } + public static Color Chocolate { get { return namedColors["CHOCOLATE"]; } } + public static Color Coral { get { return namedColors["CORAL"]; } } + public static Color CornflowerBlue { get { return namedColors["CORNFLOWERBLUE"]; } } + public static Color Cornsilk { get { return namedColors["CORNSILK"]; } } + public static Color Crimson { get { return namedColors["CRIMSON"]; } } + public static Color Cyan { get { return namedColors["CYAN"]; } } + public static Color DarkBlue { get { return namedColors["DARKBLUE"]; } } + public static Color DarkCyan { get { return namedColors["DARKCYAN"]; } } + public static Color DarkGoldenrod { get { return namedColors["DARKGOLDENROD"]; } } + public static Color DarkGray { get { return namedColors["DARKGRAY"]; } } + public static Color DarkGreen { get { return namedColors["DARKGREEN"]; } } + public static Color DarkKhaki { get { return namedColors["DARKKHAKI"]; } } + public static Color DarkMagenta { get { return namedColors["DARKMAGENTA"]; } } + public static Color DarkOliveGreen { get { return namedColors["DARKOLIVEGREEN"]; } } + public static Color DarkOrange { get { return namedColors["DARKORANGE"]; } } + public static Color DarkOrchid { get { return namedColors["DARKORCHID"]; } } + public static Color DarkRed { get { return namedColors["DARKRED"]; } } + public static Color DarkSalmon { get { return namedColors["DARKSALMON"]; } } + public static Color DarkSeaGreen { get { return namedColors["DARKSEAGREEN"]; } } + public static Color DarkSlateBlue { get { return namedColors["DARKSLATEBLUE"]; } } + public static Color DarkSlateGray { get { return namedColors["DARKSLATEGRAY"]; } } + public static Color DarkTurquoise { get { return namedColors["DARKTURQUOISE"]; } } + public static Color DarkViolet { get { return namedColors["DARKVIOLET"]; } } + public static Color DeepPink { get { return namedColors["DEEPPINK"]; } } + public static Color DeepSkyBlue { get { return namedColors["DEEPSKYBLUE"]; } } + public static Color DimGray { get { return namedColors["DIMGRAY"]; } } + public static Color DodgerBlue { get { return namedColors["DODGERBLUE"]; } } + public static Color Firebrick { get { return namedColors["FIREBRICK"]; } } + public static Color FloralWhite { get { return namedColors["FLORALWHITE"]; } } + public static Color ForestGreen { get { return namedColors["FORESTGREEN"]; } } + public static Color Fuchsia { get { return namedColors["FUCHSIA"]; } } + public static Color Gainsboro { get { return namedColors["GAINSBORO"]; } } + public static Color GhostWhite { get { return namedColors["GHOSTWHITE"]; } } + public static Color Gold { get { return namedColors["GOLD"]; } } + public static Color Goldenrod { get { return namedColors["GOLDENROD"]; } } + public static Color Gray { get { return namedColors["GRAY"]; } } + public static Color Green { get { return namedColors["GREEN"]; } } + public static Color GreenYellow { get { return namedColors["GREENYELLOW"]; } } + public static Color Honeydew { get { return namedColors["HONEYDEW"]; } } + public static Color HotPink { get { return namedColors["HOTPINK"]; } } + public static Color IndianRed { get { return namedColors["INDIANRED"]; } } + public static Color Indigo { get { return namedColors["INDIGO"]; } } + public static Color Ivory { get { return namedColors["IVORY"]; } } + public static Color Khaki { get { return namedColors["KHAKI"]; } } + public static Color Lavender { get { return namedColors["LAVENDER"]; } } + public static Color LavenderBlush { get { return namedColors["LAVENDERBLUSH"]; } } + public static Color LawnGreen { get { return namedColors["LAWNGREEN"]; } } + public static Color LemonChiffon { get { return namedColors["LEMONCHIFFON"]; } } + public static Color LightBlue { get { return namedColors["LIGHTBLUE"]; } } + public static Color LightCoral { get { return namedColors["LIGHTCORAL"]; } } + public static Color LightCyan { get { return namedColors["LIGHTCYAN"]; } } + public static Color LightGoldenrod { get { return namedColors["LIGHTGOLDENROD"]; } } + public static Color LightGray { get { return namedColors["LIGHTGRAY"]; } } + public static Color LightGreen { get { return namedColors["LIGHTGREEN"]; } } + public static Color LightPink { get { return namedColors["LIGHTPINK"]; } } + public static Color LightSalmon { get { return namedColors["LIGHTSALMON"]; } } + public static Color LightSeaGreen { get { return namedColors["LIGHTSEAGREEN"]; } } + public static Color LightSkyBlue { get { return namedColors["LIGHTSKYBLUE"]; } } + public static Color LightSlateGray { get { return namedColors["LIGHTSLATEGRAY"]; } } + public static Color LightSteelBlue { get { return namedColors["LIGHTSTEELBLUE"]; } } + public static Color LightYellow { get { return namedColors["LIGHTYELLOW"]; } } + public static Color Lime { get { return namedColors["LIME"]; } } + public static Color LimeGreen { get { return namedColors["LIMEGREEN"]; } } + public static Color Linen { get { return namedColors["LINEN"]; } } + public static Color Magenta { get { return namedColors["MAGENTA"]; } } + public static Color Maroon { get { return namedColors["MAROON"]; } } + public static Color MediumAquamarine { get { return namedColors["MEDIUMAQUAMARINE"]; } } + public static Color MediumBlue { get { return namedColors["MEDIUMBLUE"]; } } + public static Color MediumOrchid { get { return namedColors["MEDIUMORCHID"]; } } + public static Color MediumPurple { get { return namedColors["MEDIUMPURPLE"]; } } + public static Color MediumSeaGreen { get { return namedColors["MEDIUMSEAGREEN"]; } } + public static Color MediumSlateBlue { get { return namedColors["MEDIUMSLATEBLUE"]; } } + public static Color MediumSpringGreen { get { return namedColors["MEDIUMSPRINGGREEN"]; } } + public static Color MediumTurquoise { get { return namedColors["MEDIUMTURQUOISE"]; } } + public static Color MediumVioletRed { get { return namedColors["MEDIUMVIOLETRED"]; } } + public static Color MidnightBlue { get { return namedColors["MIDNIGHTBLUE"]; } } + public static Color MintCream { get { return namedColors["MINTCREAM"]; } } + public static Color MistyRose { get { return namedColors["MISTYROSE"]; } } + public static Color Moccasin { get { return namedColors["MOCCASIN"]; } } + public static Color NavajoWhite { get { return namedColors["NAVAJOWHITE"]; } } + public static Color NavyBlue { get { return namedColors["NAVYBLUE"]; } } + public static Color OldLace { get { return namedColors["OLDLACE"]; } } + public static Color Olive { get { return namedColors["OLIVE"]; } } + public static Color OliveDrab { get { return namedColors["OLIVEDRAB"]; } } + public static Color Orange { get { return namedColors["ORANGE"]; } } + public static Color OrangeRed { get { return namedColors["ORANGERED"]; } } + public static Color Orchid { get { return namedColors["ORCHID"]; } } + public static Color PaleGoldenrod { get { return namedColors["PALEGOLDENROD"]; } } + public static Color PaleGreen { get { return namedColors["PALEGREEN"]; } } + public static Color PaleTurquoise { get { return namedColors["PALETURQUOISE"]; } } + public static Color PaleVioletRed { get { return namedColors["PALEVIOLETRED"]; } } + public static Color PapayaWhip { get { return namedColors["PAPAYAWHIP"]; } } + public static Color PeachPuff { get { return namedColors["PEACHPUFF"]; } } + public static Color Peru { get { return namedColors["PERU"]; } } + public static Color Pink { get { return namedColors["PINK"]; } } + public static Color Plum { get { return namedColors["PLUM"]; } } + public static Color PowderBlue { get { return namedColors["POWDERBLUE"]; } } + public static Color Purple { get { return namedColors["PURPLE"]; } } + public static Color RebeccaPurple { get { return namedColors["REBECCAPURPLE"]; } } + public static Color Red { get { return namedColors["RED"]; } } + public static Color RosyBrown { get { return namedColors["ROSYBROWN"]; } } + public static Color RoyalBlue { get { return namedColors["ROYALBLUE"]; } } + public static Color SaddleBrown { get { return namedColors["SADDLEBROWN"]; } } + public static Color Salmon { get { return namedColors["SALMON"]; } } + public static Color SandyBrown { get { return namedColors["SANDYBROWN"]; } } + public static Color SeaGreen { get { return namedColors["SEAGREEN"]; } } + public static Color Seashell { get { return namedColors["SEASHELL"]; } } + public static Color Sienna { get { return namedColors["SIENNA"]; } } + public static Color Silver { get { return namedColors["SILVER"]; } } + public static Color SkyBlue { get { return namedColors["SKYBLUE"]; } } + public static Color SlateBlue { get { return namedColors["SLATEBLUE"]; } } + public static Color SlateGray { get { return namedColors["SLATEGRAY"]; } } + public static Color Snow { get { return namedColors["SNOW"]; } } + public static Color SpringGreen { get { return namedColors["SPRINGGREEN"]; } } + public static Color SteelBlue { get { return namedColors["STEELBLUE"]; } } + public static Color Tan { get { return namedColors["TAN"]; } } + public static Color Teal { get { return namedColors["TEAL"]; } } + public static Color Thistle { get { return namedColors["THISTLE"]; } } + public static Color Tomato { get { return namedColors["TOMATO"]; } } + public static Color Transparent { get { return namedColors["TRANSPARENT"]; } } + public static Color Turquoise { get { return namedColors["TURQUOISE"]; } } + public static Color Violet { get { return namedColors["VIOLET"]; } } + public static Color WebGray { get { return namedColors["WEBGRAY"]; } } + public static Color WebGreen { get { return namedColors["WEBGREEN"]; } } + public static Color WebMaroon { get { return namedColors["WEBMAROON"]; } } + public static Color WebPurple { get { return namedColors["WEBPURPLE"]; } } + public static Color Wheat { get { return namedColors["WHEAT"]; } } + public static Color White { get { return namedColors["WHITE"]; } } + public static Color WhiteSmoke { get { return namedColors["WHITESMOKE"]; } } + public static Color Yellow { get { return namedColors["YELLOW"]; } } + public static Color YellowGreen { get { return namedColors["YELLOWGREEN"]; } } } } 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/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 213fc181c1..2dfe304aaa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; namespace Godot.Collections { - class DictionarySafeHandle : SafeHandle + internal class DictionarySafeHandle : SafeHandle { public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) { @@ -25,18 +26,29 @@ namespace Godot.Collections } } - public class Dictionary : - IDictionary, - IDisposable + /// <summary> + /// Wrapper around Godot's Dictionary class, a dictionary of Variant + /// typed elements allocated in the engine in C++. Useful when + /// interfacing with the engine. + /// </summary> + public class Dictionary : IDictionary, IDisposable { - DictionarySafeHandle safeHandle; - bool disposed = false; + private DictionarySafeHandle _safeHandle; + private bool _disposed = false; + /// <summary> + /// Constructs a new empty <see cref="Dictionary"/>. + /// </summary> public Dictionary() { - safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); + _safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); } + /// <summary> + /// Constructs a new <see cref="Dictionary"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary dictionary) : this() { if (dictionary == null) @@ -48,36 +60,44 @@ namespace Godot.Collections internal Dictionary(DictionarySafeHandle handle) { - safeHandle = handle; + _safeHandle = handle; } internal Dictionary(IntPtr handle) { - safeHandle = new DictionarySafeHandle(handle); + _safeHandle = new DictionarySafeHandle(handle); } internal IntPtr GetPtr() { - if (disposed) + if (_disposed) throw new ObjectDisposedException(GetType().FullName); - return safeHandle.DangerousGetHandle(); + return _safeHandle.DangerousGetHandle(); } + /// <summary> + /// Disposes of this <see cref="Dictionary"/>. + /// </summary> public void Dispose() { - if (disposed) + if (_disposed) return; - if (safeHandle != null) + if (_safeHandle != null) { - safeHandle.Dispose(); - safeHandle = null; + _safeHandle.Dispose(); + _safeHandle = null; } - disposed = true; + _disposed = true; } + /// <summary> + /// Duplicates this <see cref="Dictionary"/>. + /// </summary> + /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary Duplicate(bool deep = false) { return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep)); @@ -85,6 +105,9 @@ namespace Godot.Collections // IDictionary + /// <summary> + /// Gets the collection of keys in this <see cref="Dictionary"/>. + /// </summary> public ICollection Keys { get @@ -94,6 +117,9 @@ namespace Godot.Collections } } + /// <summary> + /// Gets the collection of elements in this <see cref="Dictionary"/>. + /// </summary> public ICollection Values { get @@ -103,47 +129,88 @@ namespace Godot.Collections } } - public bool IsFixedSize => false; + private (Array keys, Array values, int count) GetKeyValuePairs() + { + int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle); + Array keys = new Array(new ArraySafeHandle(keysHandle)); + Array values = new Array(new ArraySafeHandle(valuesHandle)); + return (keys, values, count); + } + + bool IDictionary.IsFixedSize => false; - public bool IsReadOnly => false; + bool IDictionary.IsReadOnly => false; + /// <summary> + /// Returns the object at the given <paramref name="key"/>. + /// </summary> + /// <value>The object at the given <paramref name="key"/>.</value> public object this[object key] { get => godot_icall_Dictionary_GetValue(GetPtr(), key); set => godot_icall_Dictionary_SetValue(GetPtr(), key, value); } + /// <summary> + /// Adds an object <paramref name="value"/> at key <paramref name="key"/> + /// to this <see cref="Dictionary"/>. + /// </summary> + /// <param name="key">The key at which to add the object.</param> + /// <param name="value">The object to add.</param> public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value); + /// <summary> + /// Erases all items from this <see cref="Dictionary"/>. + /// </summary> public void Clear() => godot_icall_Dictionary_Clear(GetPtr()); + /// <summary> + /// Checks if this <see cref="Dictionary"/> contains the given key. + /// </summary> + /// <param name="key">The key to look for.</param> + /// <returns>Whether or not this dictionary contains the given key.</returns> public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key); + /// <summary> + /// Gets an enumerator for this <see cref="Dictionary"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this); + /// <summary> + /// Removes an element from this <see cref="Dictionary"/> by key. + /// </summary> + /// <param name="key">The key of the element to remove.</param> public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key); // ICollection - public object SyncRoot => this; + object ICollection.SyncRoot => this; - public bool IsSynchronized => false; + bool ICollection.IsSynchronized => false; + /// <summary> + /// Returns the number of elements in this <see cref="Dictionary"/>. + /// This is also known as the size or length of the dictionary. + /// </summary> + /// <returns>The number of elements.</returns> public int Count => godot_icall_Dictionary_Count(GetPtr()); + /// <summary> + /// Copies the elements of this <see cref="Dictionary"/> 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) { - // TODO Can be done with single internal call - if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); if (index < 0) throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension."); - Array keys = (Array)Keys; - Array values = (Array)Values; - int count = Count; + var (keys, values, count) = GetKeyValuePairs(); if (array.Length < (index + count)) throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -161,24 +228,39 @@ namespace Godot.Collections private class DictionaryEnumerator : IDictionaryEnumerator { - Array keys; - Array values; - int count; - int index = -1; + private readonly Dictionary _dictionary; + private readonly int _count; + private int _index = -1; + private bool _dirty = true; + + private DictionaryEntry _entry; public DictionaryEnumerator(Dictionary dictionary) { - // TODO 3 internal calls, can reduce to 1 - keys = (Array)dictionary.Keys; - values = (Array)dictionary.Values; - count = dictionary.Count; + _dictionary = dictionary; + _count = dictionary.Count; } public object Current => Entry; - public DictionaryEntry Entry => - // TODO 2 internal calls, can reduce to 1 - new DictionaryEntry(keys[index], values[index]); + public DictionaryEntry Entry + { + get + { + if (_dirty) + { + UpdateEntry(); + } + return _entry; + } + } + + private void UpdateEntry() + { + _dirty = false; + godot_icall_Dictionary_KeyValuePairAt(_dictionary.GetPtr(), _index, out object key, out object value); + _entry = new DictionaryEntry(key, value); + } public object Key => Entry.Key; @@ -186,83 +268,102 @@ namespace Godot.Collections public bool MoveNext() { - index++; - return index < count; + _index++; + _dirty = true; + return _index < _count; } public void Reset() { - index = -1; + _index = -1; + _dirty = true; } } + /// <summary> + /// Converts this <see cref="Dictionary"/> to a string. + /// </summary> + /// <returns>A string representation of this dictionary.</returns> public override string ToString() { return godot_icall_Dictionary_ToString(GetPtr()); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Dictionary_Ctor(); + internal static extern IntPtr godot_icall_Dictionary_Ctor(); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr); + internal static extern void godot_icall_Dictionary_Dtor(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); + internal static extern object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); + internal static extern object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); + internal static extern void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); + internal static extern IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr); + internal static extern IntPtr godot_icall_Dictionary_Values(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_Dictionary_Count(IntPtr ptr); + internal static extern int godot_icall_Dictionary_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr); + internal static extern void godot_icall_Dictionary_Clear(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); + internal static extern bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); + internal static extern bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep); + internal static extern IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); + internal static extern bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); + internal static extern bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + internal static extern bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); + internal static extern bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); + internal static extern void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr); + internal static extern string godot_icall_Dictionary_ToString(IntPtr ptr); } - public class Dictionary<TKey, TValue> : - IDictionary<TKey, TValue> + /// <summary> + /// Typed wrapper around Godot's Dictionary class, a dictionary 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.Collections.Generic.Dictionary{TKey, TValue}"/>. + /// </summary> + /// <typeparam name="TKey">The type of the dictionary's keys.</typeparam> + /// <typeparam name="TValue">The type of the dictionary's values.</typeparam> + public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue> { - Dictionary objectDict; + private readonly Dictionary _objectDict; internal static int valTypeEncoding; internal static IntPtr valTypeClass; @@ -272,14 +373,22 @@ namespace Godot.Collections Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); } + /// <summary> + /// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public Dictionary() { - objectDict = new Dictionary(); + _objectDict = new Dictionary(); } + /// <summary> + /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary<TKey, TValue> dictionary) { - objectDict = new Dictionary(); + _objectDict = new Dictionary(); if (dictionary == null) throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'"); @@ -294,112 +403,173 @@ namespace Godot.Collections } } + /// <summary> + /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(Dictionary dictionary) { - objectDict = dictionary; + _objectDict = dictionary; } internal Dictionary(IntPtr handle) { - objectDict = new Dictionary(handle); + _objectDict = new Dictionary(handle); } internal Dictionary(DictionarySafeHandle handle) { - objectDict = new Dictionary(handle); + _objectDict = new Dictionary(handle); } + /// <summary> + /// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>. + /// </summary> + /// <param name="from">The typed dictionary to convert.</param> public static explicit operator Dictionary(Dictionary<TKey, TValue> from) { - return from.objectDict; + return from._objectDict; } internal IntPtr GetPtr() { - return objectDict.GetPtr(); + return _objectDict.GetPtr(); } + /// <summary> + /// Duplicates this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary<TKey, TValue> Duplicate(bool deep = false) { - return new Dictionary<TKey, TValue>(objectDict.Duplicate(deep)); + return new Dictionary<TKey, TValue>(_objectDict.Duplicate(deep)); } // IDictionary<TKey, TValue> + /// <summary> + /// Returns the value at the given <paramref name="key"/>. + /// </summary> + /// <value>The value at the given <paramref name="key"/>.</value> public TValue this[TKey key] { - get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } - set { objectDict[key] = value; } + get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(_objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } + set { _objectDict[key] = value; } } + /// <summary> + /// Gets the collection of keys in this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public ICollection<TKey> Keys { get { - IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr()); + IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(_objectDict.GetPtr()); return new Array<TKey>(new ArraySafeHandle(handle)); } } + /// <summary> + /// Gets the collection of elements in this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public ICollection<TValue> Values { get { - IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr()); + IntPtr handle = Dictionary.godot_icall_Dictionary_Values(_objectDict.GetPtr()); return new Array<TValue>(new ArraySafeHandle(handle)); } } + private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) + { + Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value); + return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); + } + + /// <summary> + /// Adds an object <paramref name="value"/> at key <paramref name="key"/> + /// to this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <param name="key">The key at which to add the object.</param> + /// <param name="value">The object to add.</param> public void Add(TKey key, TValue value) { - objectDict.Add(key, value); + _objectDict.Add(key, value); } + /// <summary> + /// Checks if this <see cref="Dictionary{TKey, TValue}"/> contains the given key. + /// </summary> + /// <param name="key">The key to look for.</param> + /// <returns>Whether or not this dictionary contains the given key.</returns> public bool ContainsKey(TKey key) { - return objectDict.Contains(key); + return _objectDict.Contains(key); } + /// <summary> + /// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key. + /// </summary> + /// <param name="key">The key of the element to remove.</param> public bool Remove(TKey key) { return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key); } - public bool TryGetValue(TKey key, out TValue value) + /// <summary> + /// Gets the object at the given <paramref name="key"/>. + /// </summary> + /// <param name="key">The key of the element to get.</param> + /// <param name="value">The value at the given <paramref name="key"/>.</param> + /// <returns>If an object was found for the given <paramref name="key"/>.</returns> + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - object retValue; - bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass); - value = found ? (TValue)retValue : default(TValue); + bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass); + value = found ? (TValue)retValue : default; return found; } // ICollection<KeyValuePair<TKey, TValue>> + /// <summary> + /// Returns the number of elements in this <see cref="Dictionary{TKey, TValue}"/>. + /// This is also known as the size or length of the dictionary. + /// </summary> + /// <returns>The number of elements.</returns> public int Count { - get { return objectDict.Count; } + get { return _objectDict.Count; } } - public bool IsReadOnly - { - get { return objectDict.IsReadOnly; } - } + bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false; - public void Add(KeyValuePair<TKey, TValue> item) + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) { - objectDict.Add(item.Key, item.Value); + _objectDict.Add(item.Key, item.Value); } + /// <summary> + /// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public void Clear() { - objectDict.Clear(); + _objectDict.Clear(); } - public bool Contains(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { - return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); + return _objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); } + /// <summary> + /// Copies the elements of this <see cref="Dictionary{TKey, TValue}"/> to the given + /// untyped C# array, starting at the given index. + /// </summary> + /// <param name="array">The array to copy to.</param> + /// <param name="arrayIndex">The index to start at.</param> public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { if (array == null) @@ -408,9 +578,6 @@ namespace Godot.Collections if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); - // TODO 3 internal calls, can reduce to 1 - Array<TKey> keys = (Array<TKey>)Keys; - Array<TValue> values = (Array<TValue>)Values; int count = Count; if (array.Length < (arrayIndex + count)) @@ -418,13 +585,12 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - // TODO 2 internal calls, can reduce to 1 - array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]); + array[arrayIndex] = GetKeyValuePair(i); arrayIndex++; } } - public bool Remove(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ; @@ -432,17 +598,15 @@ namespace Godot.Collections // IEnumerable<KeyValuePair<TKey, TValue>> + /// <summary> + /// Gets an enumerator for this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { - // TODO 3 internal calls, can reduce to 1 - Array<TKey> keys = (Array<TKey>)Keys; - Array<TValue> values = (Array<TValue>)Values; - int count = Count; - - for (int i = 0; i < count; i++) + for (int i = 0; i < Count; i++) { - // TODO 2 internal calls, can reduce to 1 - yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]); + yield return GetKeyValuePair(i); } } @@ -451,6 +615,10 @@ namespace Godot.Collections return GetEnumerator(); } - public override string ToString() => objectDict.ToString(); + /// <summary> + /// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string. + /// </summary> + /// <returns>A string representation of this dictionary.</returns> + public override string ToString() => _objectDict.ToString(); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs index c4c911b863..26d5f9c796 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; @@ -8,20 +7,20 @@ using System.Runtime.CompilerServices; namespace Godot { /// <summary> - /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API. + /// Represents an <see cref="Object"/> whose members can be dynamically accessed at runtime through the Variant API. /// </summary> /// <remarks> /// <para> - /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant - /// members of a <see cref="Godot.Object"/> instance at runtime. + /// The <see cref="DynamicGodotObject"/> class enables access to the Variant + /// members of a <see cref="Object"/> instance at runtime. /// </para> /// <para> /// This allows accessing the class members using their original names in the engine as well as the members from the - /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in. + /// script attached to the <see cref="Object"/>, regardless of the scripting language it was written in. /// </para> /// </remarks> /// <example> - /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>. + /// This sample shows how to use <see cref="DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Object"/>. /// <code> /// dynamic sprite = GetNode("Sprite2D").DynamicGodotObject; /// sprite.add_child(this); @@ -31,7 +30,7 @@ namespace Godot /// </code> /// </example> /// <example> - /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>. + /// This sample shows how to use <see cref="DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Object"/>. /// <code> /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject; /// @@ -55,32 +54,34 @@ namespace Godot public class DynamicGodotObject : DynamicObject { /// <summary> - /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>. + /// Gets the <see cref="Object"/> associated with this <see cref="DynamicGodotObject"/>. /// </summary> public Object Value { get; } /// <summary> - /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class. + /// Initializes a new instance of the <see cref="DynamicGodotObject"/> class. /// </summary> /// <param name="godotObject"> - /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>. + /// The <see cref="Object"/> that will be associated with this <see cref="DynamicGodotObject"/>. /// </param> - /// <exception cref="System.ArgumentNullException"> - /// Thrown when the <paramref name="godotObject"/> parameter is null. + /// <exception cref="ArgumentNullException"> + /// Thrown when the <paramref name="godotObject"/> parameter is <see langword="null"/>. /// </exception> public DynamicGodotObject(Object godotObject) { if (godotObject == null) throw new ArgumentNullException(nameof(godotObject)); - this.Value = godotObject; + Value = godotObject; } + /// <inheritdoc/> public override IEnumerable<string> GetDynamicMemberNames() { return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value)); } + /// <inheritdoc/> public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { switch (binder.Operation) @@ -122,6 +123,7 @@ namespace Godot return base.TryBinaryOperation(binder, arg, out result); } + /// <inheritdoc/> public override bool TryConvert(ConvertBinder binder, out object result) { if (binder.Type == typeof(Object)) @@ -140,6 +142,7 @@ namespace Godot return base.TryConvert(binder, out result); } + /// <inheritdoc/> public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes.Length == 1) @@ -153,16 +156,19 @@ namespace Godot return base.TryGetIndex(binder, indexes, out result); } + /// <inheritdoc/> public override bool TryGetMember(GetMemberBinder binder, out object result) { return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result); } + /// <inheritdoc/> public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result); } + /// <inheritdoc/> public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (indexes.Length == 1) @@ -176,22 +182,23 @@ namespace Godot return base.TrySetIndex(binder, indexes, value); } + /// <inheritdoc/> public override bool TrySetMember(SetMemberBinder binder, object value) { return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject); + internal static extern string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result); + internal static extern bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result); + internal static extern bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value); + internal static extern bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value); #region We don't override these methods diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs index 5d16260f5d..658582960f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs @@ -1,42 +1,190 @@ +using System; + namespace Godot { public partial class Node { + /// <summary> + /// Fetches a node. The <see cref="NodePath"/> can be either a relative path (from + /// the current node) or an absolute path (in the scene tree) to a node. If the path + /// does not exist, a <see langword="null"/> instance is returned and an error + /// is logged. Attempts to access methods on the return value will result in an + /// "Attempt to call <method> on a null instance." error. + /// Note: Fetching absolute paths only works when the node is inside the scene tree + /// (see <see cref="IsInsideTree"/>). + /// </summary> + /// <example> + /// Example: Assume your current node is Character and the following tree: + /// <code> + /// /root + /// /root/Character + /// /root/Character/Sword + /// /root/Character/Backpack/Dagger + /// /root/MyGame + /// /root/Swamp/Alligator + /// /root/Swamp/Mosquito + /// /root/Swamp/Goblin + /// </code> + /// Possible paths are: + /// <code> + /// GetNode("Sword"); + /// GetNode("Backpack/Dagger"); + /// GetNode("../Swamp/Alligator"); + /// GetNode("/root/MyGame"); + /// </code> + /// </example> + /// <seealso cref="GetNodeOrNull{T}(NodePath)"/> + /// <param name="path">The path to the node to fetch.</param> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The <see cref="Node"/> at the given <paramref name="path"/>. + /// </returns> public T GetNode<T>(NodePath path) where T : class { return (T)(object)GetNode(path); } + /// <summary> + /// Fetches a node. The <see cref="NodePath"/> can be either a relative path (from + /// the current node) or an absolute path (in the scene tree) to a node. If the path + /// does not exist, a <see langword="null"/> instance is returned and an error + /// is logged. Attempts to access methods on the return value will result in an + /// "Attempt to call <method> on a null instance." error. + /// Note: Fetching absolute paths only works when the node is inside the scene tree + /// (see <see cref="IsInsideTree"/>). + /// </summary> + /// <example> + /// Example: Assume your current node is Character and the following tree: + /// <code> + /// /root + /// /root/Character + /// /root/Character/Sword + /// /root/Character/Backpack/Dagger + /// /root/MyGame + /// /root/Swamp/Alligator + /// /root/Swamp/Mosquito + /// /root/Swamp/Goblin + /// </code> + /// Possible paths are: + /// <code> + /// GetNode("Sword"); + /// GetNode("Backpack/Dagger"); + /// GetNode("../Swamp/Alligator"); + /// GetNode("/root/MyGame"); + /// </code> + /// </example> + /// <seealso cref="GetNode{T}(NodePath)"/> + /// <param name="path">The path to the node to fetch.</param> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>/// ///////// <returns> + /// The <see cref="Node"/> at the given <paramref name="path"/>, or <see langword="null"/> if not found. + /// </returns> public T GetNodeOrNull<T>(NodePath path) where T : class { return GetNodeOrNull(path) as T; } + /// <summary> + /// Returns a child node by its index (see <see cref="GetChildCount"/>). + /// This method is often used for iterating all children of a node. + /// Negative indices access the children from the last one. + /// To access a child node via its name, use <see cref="GetNode"/>. + /// </summary> + /// <seealso cref="GetChildOrNull{T}(int)"/> + /// <param name="idx">Child index.</param> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>/// ///////// <returns> + /// The child <see cref="Node"/> at the given index <paramref name="idx"/>. + /// </returns> public T GetChild<T>(int idx) where T : class { return (T)(object)GetChild(idx); } + /// <summary> + /// Returns a child node by its index (see <see cref="GetChildCount"/>). + /// This method is often used for iterating all children of a node. + /// Negative indices access the children from the last one. + /// To access a child node via its name, use <see cref="GetNode"/>. + /// </summary> + /// <seealso cref="GetChild{T}(int)"/> + /// <param name="idx">Child index.</param> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The child <see cref="Node"/> at the given index <paramref name="idx"/>, or <see langword="null"/> if not found. + /// </returns> public T GetChildOrNull<T>(int idx) where T : class { return GetChild(idx) as T; } + /// <summary> + /// The node owner. A node can have any other node as owner (as long as it is + /// a valid parent, grandparent, etc. ascending in the tree). When saving a + /// node (using <see cref="PackedScene"/>), all the nodes it owns will be saved + /// with it. This allows for the creation of complex <see cref="SceneTree"/>s, + /// with instancing and subinstancing. + /// </summary> + /// <seealso cref="GetOwnerOrNull{T}"/> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The owner <see cref="Node"/>. + /// </returns> public T GetOwner<T>() where T : class { return (T)(object)Owner; } + /// <summary> + /// The node owner. A node can have any other node as owner (as long as it is + /// a valid parent, grandparent, etc. ascending in the tree). When saving a + /// node (using <see cref="PackedScene"/>), all the nodes it owns will be saved + /// with it. This allows for the creation of complex <see cref="SceneTree"/>s, + /// with instancing and subinstancing. + /// </summary> + /// <seealso cref="GetOwner{T}"/> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The owner <see cref="Node"/>, or <see langword="null"/> if there is no owner. + /// </returns> public T GetOwnerOrNull<T>() where T : class { return Owner as T; } + /// <summary> + /// Returns the parent node of the current node, or a <see langword="null"/> instance + /// if the node lacks a parent. + /// </summary> + /// <seealso cref="GetParentOrNull{T}"/> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The parent <see cref="Node"/>. + /// </returns> public T GetParent<T>() where T : class { return (T)(object)GetParent(); } + /// <summary> + /// Returns the parent node of the current node, or a <see langword="null"/> instance + /// if the node lacks a parent. + /// </summary> + /// <seealso cref="GetParent{T}"/> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns> + /// The parent <see cref="Node"/>, or <see langword="null"/> if the node has no parent. + /// </returns> public T GetParentOrNull<T>() where T : class { return GetParent() as T; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs index 9ef0959750..691fd85964 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs @@ -5,17 +5,37 @@ namespace Godot { public partial class Object { + /// <summary> + /// Returns whether <paramref name="instance"/> is a valid object + /// (e.g. has not been deleted from memory). + /// </summary> + /// <param name="instance">The instance to check.</param> + /// <returns>If the instance is a valid object.</returns> public static bool IsInstanceValid(Object instance) { return instance != null && instance.NativeInstance != IntPtr.Zero; } + /// <summary> + /// Returns a weak reference to an object, or <see langword="null"/> + /// if the argument is invalid. + /// A weak reference to an object is not enough to keep the object alive: + /// when the only remaining references to a referent are weak references, + /// garbage collection is free to destroy the referent and reuse its memory + /// for something else. However, until the object is actually destroyed the + /// weak reference may return the object even if there are no strong references + /// to it. + /// </summary> + /// <param name="obj">The object.</param> + /// <returns> + /// The <see cref="WeakRef"/> reference to the object or <see langword="null"/>. + /// </returns> public static WeakRef WeakRef(Object obj) { - return godot_icall_Object_weakref(Object.GetPtr(obj)); + return godot_icall_Object_weakref(GetPtr(obj)); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static WeakRef godot_icall_Object_weakref(IntPtr obj); + internal static extern WeakRef godot_icall_Object_weakref(IntPtr obj); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs index 763f470504..435b59d5f3 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs @@ -1,3 +1,5 @@ +using System; + namespace Godot { public partial class PackedScene @@ -5,23 +7,30 @@ namespace Godot /// <summary> /// Instantiates the scene's node hierarchy, erroring on failure. /// Triggers child scene instantiation(s). Triggers a - /// `Node.NotificationInstanced` notification on the root node. + /// <see cref="Node.NotificationInstanced"/> notification on the root node. /// </summary> - /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T Instance<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + /// <seealso cref="InstantiateOrNull{T}(GenEditState)"/> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the instantiated node can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns>The instantiated scene.</returns> + public T Instantiate<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return (T)(object)Instance(editState); + return (T)(object)Instantiate(editState); } /// <summary> - /// Instantiates the scene's node hierarchy, returning null on failure. + /// Instantiates the scene's node hierarchy, returning <see langword="null"/> on failure. /// Triggers child scene instantiation(s). Triggers a - /// `Node.NotificationInstanced` notification on the root node. + /// <see cref="Node.NotificationInstanced"/> notification on the root node. /// </summary> - /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T InstanceOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + /// <seealso cref="Instantiate{T}(GenEditState)"/> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> + /// <returns>The instantiated scene.</returns> + public T InstantiateOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return Instance(editState) as T; + return Instantiate(editState) as T; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs index 74fa05d1fd..25c11d5cf6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs @@ -1,10 +1,30 @@ +using System; + namespace Godot { public static partial class ResourceLoader { - public static T Load<T>(string path, string typeHint = null, CacheMode noCache = CacheMode.Reuse) where T : class + /// <summary> + /// Loads a resource at the given <paramref name="path"/>, caching the result + /// for further access. + /// The registered <see cref="ResourceFormatLoader"/> instances are queried sequentially + /// to find the first one which can handle the file's extension, and then attempt + /// loading. If loading fails, the remaining ResourceFormatLoaders are also attempted. + /// An optional <paramref name="typeHint"/> can be used to further specify the + /// <see cref="Resource"/> type that should be handled by the <see cref="ResourceFormatLoader"/>. + /// Anything that inherits from <see cref="Resource"/> can be used as a type hint, + /// for example <see cref="Image"/>. + /// The <paramref name="cacheMode"/> property defines whether and how the cache should + /// be used or updated when loading the resource. See <see cref="CacheMode"/> for details. + /// Returns an empty resource if no <see cref="ResourceFormatLoader"/> could handle the file. + /// </summary> + /// <exception cref="InvalidCastException"> + /// Thrown when the given the loaded resource can't be casted to the given type <typeparamref name="T"/>. + /// </exception> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Resource"/>.</typeparam> + public static T Load<T>(string path, string typeHint = null, CacheMode cacheMode = CacheMode.Reuse) where T : class { - return (T)(object)Load(path, typeHint, noCache); + return (T)(object)Load(path, typeHint, cacheMode); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs index 20b11a48dd..df130a5c77 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs @@ -6,12 +6,16 @@ namespace Godot { public partial class SceneTree { + /// <summary> + /// Returns a list of all nodes assigned to the given <paramref name="group"/>. + /// </summary> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam> public Array<T> GetNodesInGroup<T>(StringName group) where T : class { - return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(Object.GetPtr(this), StringName.GetPtr(group), typeof(T))); + return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), StringName.GetPtr(group), typeof(T))); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType); + internal static extern IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index 6699c5992c..ef42374041 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -1,149 +1,431 @@ -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 - -// TODO: Add comments describing what this class does. It is not obvious. +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Godot { + /// <summary> + /// Godot's global functions. + /// </summary> public static partial class GD { + /// <summary> + /// Decodes a byte array back to a <c>Variant</c> value. + /// If <paramref name="allowObjects"/> is <see langword="true"/> decoding objects is allowed. + /// + /// WARNING: Deserialized object can contain code which gets executed. + /// Do not set <paramref name="allowObjects"/> to <see langword="true"/> + /// if the serialized object comes from untrusted sources to avoid + /// potential security threats (remote code execution). + /// </summary> + /// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param> + /// <param name="allowObjects">If objects should be decoded.</param> + /// <returns>The decoded <c>Variant</c>.</returns> public static object Bytes2Var(byte[] bytes, bool allowObjects = false) { return godot_icall_GD_bytes2var(bytes, allowObjects); } + /// <summary> + /// Converts from a <c>Variant</c> type to another in the best way possible. + /// The <paramref name="type"/> parameter uses the <see cref="Variant.Type"/> values. + /// </summary> + /// <example> + /// <code> + /// var a = new Vector2(1, 0); + /// // Prints 1 + /// GD.Print(a.Length()); + /// var b = GD.Convert(a, Variant.Type.String) + /// // Prints 6 as "(1, 0)" is 6 characters + /// GD.Print(b.Length); + /// </code> + /// </example> + /// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns> public static object Convert(object what, Variant.Type type) { return godot_icall_GD_convert(what, type); } + /// <summary> + /// Converts from decibels to linear energy (audio). + /// </summary> + /// <seealso cref="Linear2Db(real_t)"/> + /// <param name="db">Decibels to convert.</param> + /// <returns>Audio volume as linear energy.</returns> 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"); } + /// <summary> + /// Returns the integer hash of the variable passed. + /// </summary> + /// <example> + /// <code> + /// GD.Print(GD.Hash("a")); // Prints 177670 + /// </code> + /// </example> + /// <param name="var">Variable that will be hashed.</param> + /// <returns>Hash of the variable passed.</returns> public static int Hash(object var) { return godot_icall_GD_hash(var); } + /// <summary> + /// Returns the <see cref="Object"/> that corresponds to <paramref name="instanceId"/>. + /// All Objects have a unique instance ID. + /// </summary> + /// <example> + /// <code> + /// public class MyNode : Node + /// { + /// public string foo = "bar"; + /// + /// public override void _Ready() + /// { + /// ulong id = GetInstanceId(); + /// var inst = (MyNode)GD.InstanceFromId(Id); + /// GD.Print(inst.foo); // Prints bar + /// } + /// } + /// </code> + /// </example> + /// <param name="instanceId">Instance ID of the Object to retrieve.</param> + /// <returns>The <see cref="Object"/> instance.</returns> public static Object InstanceFromId(ulong instanceId) { return godot_icall_GD_instance_from_id(instanceId); } + /// <summary> + /// Converts from linear energy to decibels (audio). + /// This can be used to implement volume sliders that behave as expected (since volume isn't linear). + /// </summary> + /// <seealso cref="Db2Linear(real_t)"/> + /// <example> + /// <code> + /// // "slider" refers to a node that inherits Range such as HSlider or VSlider. + /// // Its range must be configured to go from 0 to 1. + /// // Change the bus name if you'd like to change the volume of a specific bus only. + /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.Linear2Db(slider.value)); + /// </code> + /// </example> + /// <param name="linear">The linear energy to convert.</param> + /// <returns>Audio as decibels</returns> public static real_t Linear2Db(real_t linear) { - return (real_t) (Math.Log(linear) * 8.6858896380650365530225783783321); - } - + return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321); + } + + /// <summary> + /// Loads a resource from the filesystem located at <paramref name="path"/>. + /// 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. + /// + /// Note: 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. + /// + /// Important: The path must be absolute, a local path will just return <see langword="null"/>. + /// This method is a simplified version of <see cref="ResourceLoader.Load"/>, which can be used + /// for more advanced scenarios. + /// </summary> + /// <example> + /// <code> + /// // Load a scene called main located in the root of the project directory and cache it in a variable. + /// var main = GD.Load("res://main.tscn"); // main will contain a PackedScene resource. + /// </code> + /// </example> + /// <param name="path">Path of the <see cref="Resource"/> to load.</param> + /// <returns>The loaded <see cref="Resource"/>.</returns> public static Resource Load(string path) { return ResourceLoader.Load(path); } + /// <summary> + /// Loads a resource from the filesystem located at <paramref name="path"/>. + /// 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. + /// + /// Note: 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. + /// + /// Important: The path must be absolute, a local path will just return <see langword="null"/>. + /// This method is a simplified version of <see cref="ResourceLoader.Load"/>, which can be used + /// for more advanced scenarios. + /// </summary> + /// <example> + /// <code> + /// // Load a scene called main located in the root of the project directory and cache it in a variable. + /// var main = GD.Load<PackedScene>("res://main.tscn"); // main will contain a PackedScene resource. + /// </code> + /// </example> + /// <param name="path">Path of the <see cref="Resource"/> to load.</param> + /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Resource"/>.</typeparam> public static T Load<T>(string path) where T : class { return ResourceLoader.Load<T>(path); } + /// <summary> + /// Pushes an error message to Godot's built-in debugger and to the OS terminal. + /// + /// Note: Errors printed this way will not pause project execution. + /// To print an error message and pause project execution in debug builds, + /// use [code]assert(false, "test error")[/code] instead. + /// </summary> + /// <example> + /// <code> + /// GD.PushError("test_error"); // Prints "test error" to debugger and terminal as error call + /// </code> + /// </example> + /// <param name="message">Error message.</param> public static void PushError(string message) { godot_icall_GD_pusherror(message); } + /// <summary> + /// Pushes a warning message to Godot's built-in debugger and to the OS terminal. + /// </summary> + /// <example> + /// GD.PushWarning("test warning"); // Prints "test warning" to debugger and terminal as warning call + /// </example> + /// <param name="message">Warning message.</param> public static void PushWarning(string message) { godot_icall_GD_pushwarning(message); } + /// <summary> + /// Converts one or more arguments of any type to string in the best way possible + /// and prints them to the console. + /// + /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/> + /// to print error and warning messages instead of <see cref="Print(object[])"/>. + /// This distinguishes them from print messages used for debugging purposes, + /// while also displaying a stack trace when an error or warning is printed. + /// </summary> + /// <example> + /// <code> + /// var a = new int[] { 1, 2, 3 }; + /// GD.Print("a", "b", a); // Prints ab[1, 2, 3] + /// </code> + /// </example> + /// <param name="what">Arguments that will be printed.</param> 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)); } + /// <summary> + /// Prints the current stack trace information to the console. + /// </summary> public static void PrintStack() { Print(System.Environment.StackTrace); } + /// <summary> + /// Prints one or more arguments to strings in the best way possible to standard error line. + /// </summary> + /// <example> + /// <code> + /// GD.PrintErr("prints to stderr"); + /// </code> + /// </example> + /// <param name="what">Arguments that will be printed.</param> 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)); + } + + /// <summary> + /// Prints one or more arguments to strings in the best way possible to console. + /// No newline is added at the end. + /// + /// Note: Due to limitations with Godot's built-in console, this only prints to the terminal. + /// If you need to print in the editor, use another method, such as <see cref="Print(object[])"/>. + /// </summary> + /// <example> + /// <code> + /// GD.PrintRaw("A"); + /// GD.PrintRaw("B"); + /// // Prints AB + /// </code> + /// </example> + /// <param name="what">Arguments that will be printed.</param> 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)); } + /// <summary> + /// Prints one or more arguments to the console with a space between each argument. + /// </summary> + /// <example> + /// <code> + /// GD.PrintS("A", "B", "C"); // Prints A B C + /// </code> + /// </example> + /// <param name="what">Arguments that will be printed.</param> 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)); } + /// <summary> + /// Prints one or more arguments to the console with a tab between each argument. + /// </summary> + /// <example> + /// <code> + /// GD.PrintT("A", "B", "C"); // Prints A B C + /// </code> + /// </example> + /// <param name="what">Arguments that will be printed.</param> 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)); } + /// <summary> + /// Returns a random floating point value between <c>0.0</c> and <c>1.0</c> (inclusive). + /// </summary> + /// <example> + /// <code> + /// GD.Randf(); // Returns e.g. 0.375671 + /// </code> + /// </example> + /// <returns>A random <see langword="float"/> number.</returns> public static float Randf() { return godot_icall_GD_randf(); } + /// <summary> + /// Returns a random unsigned 32-bit integer. + /// Use remainder to obtain a random value in the interval <c>[0, N - 1]</c> (where N is smaller than 2^32). + /// </summary> + /// <example> + /// <code> + /// GD.Randi(); // Returns random integer between 0 and 2^32 - 1 + /// GD.Randi() % 20; // Returns random integer between 0 and 19 + /// GD.Randi() % 100; // Returns random integer between 0 and 99 + /// GD.Randi() % 100 + 1; // Returns random integer between 1 and 100 + /// </code> + /// </example> + /// <returns>A random <see langword="uint"/> number.</returns> public static uint Randi() { return godot_icall_GD_randi(); } + /// <summary> + /// Randomizes the seed (or the internal state) of the random number generator. + /// Current implementation reseeds using a number based on time. + /// + /// Note: This method is called automatically when the project is run. + /// If you need to fix the seed to have reproducible results, use <see cref="Seed(ulong)"/> + /// to initialize the random number generator. + /// </summary> public static void Randomize() { godot_icall_GD_randomize(); } + /// <summary> + /// Returns a random floating point value on the interval between <paramref name="from"/> + /// and <paramref name="to"/> (inclusive). + /// </summary> + /// <example> + /// <code> + /// GD.PrintS(GD.RandRange(-10.0, 10.0), GD.RandRange(-10.0, 10.0)); // Prints e.g. -3.844535 7.45315 + /// </code> + /// </example> + /// <returns>A random <see langword="double"/> number inside the given range.</returns> public static double RandRange(double from, double to) { return godot_icall_GD_randf_range(from, to); } + /// <summary> + /// Returns a random signed 32-bit integer between <paramref name="from"/> + /// and <paramref name="to"/> (inclusive). If <paramref name="to"/> is lesser than + /// <paramref name="from"/>, they are swapped. + /// </summary> + /// <example> + /// <code> + /// GD.Print(GD.RandRange(0, 1)); // Prints 0 or 1 + /// GD.Print(GD.RandRange(-10, 1000)); // Prints any number from -10 to 1000 + /// </code> + /// </example> + /// <returns>A random <see langword="int"/> number inside the given range.</returns> public static int RandRange(int from, int to) { return godot_icall_GD_randi_range(from, to); } - public static uint RandSeed(ulong seed, out ulong newSeed) + /// <summary> + /// Returns a random unsigned 32-bit integer, using the given <paramref name="seed"/>. + /// </summary> + /// <param name="seed"> + /// Seed to use to generate the random number. + /// If a different seed is used, its value will be modfied. + /// </param> + /// <returns>A random <see langword="uint"/> number.</returns> + public static uint RandFromSeed(ref ulong seed) { - return godot_icall_GD_rand_seed(seed, out newSeed); + return godot_icall_GD_rand_seed(seed, out seed); } + /// <summary> + /// Returns a <see cref="IEnumerable{T}"/> that iterates from + /// <c>0</c> to <paramref name="end"/> in steps of <c>1</c>. + /// </summary> + /// <param name="end">The last index.</param> public static IEnumerable<int> Range(int end) { return Range(0, end, 1); } + /// <summary> + /// Returns a <see cref="IEnumerable{T}"/> that iterates from + /// <paramref name="start"/> to <paramref name="end"/> in steps of <c>1</c>. + /// </summary> + /// <param name="start">The first index.</param> + /// <param name="end">The last index.</param> public static IEnumerable<int> Range(int start, int end) { return Range(start, end, 1); } + /// <summary> + /// Returns a <see cref="IEnumerable{T}"/> that iterates from + /// <paramref name="start"/> to <paramref name="end"/> in steps of <paramref name="step"/>. + /// </summary> + /// <param name="start">The first index.</param> + /// <param name="end">The last index.</param> + /// <param name="step">The amount by which to increment the index on each iteration.</param> public static IEnumerable<int> Range(int start, int end, int step) { if (end < start && step > 0) @@ -164,109 +446,164 @@ namespace Godot } } + /// <summary> + /// Sets seed for the random number generator. + /// </summary> + /// <param name="seed">Seed that will be used.</param> public static void Seed(ulong seed) { godot_icall_GD_seed(seed); } + /// <summary> + /// Converts one or more arguments of any type to string in the best way possible. + /// </summary> + /// <param name="what">Arguments that will converted to string.</param> + /// <returns>The string formed by the given arguments.</returns> public static string Str(params object[] what) { return godot_icall_GD_str(what); } + /// <summary> + /// Converts a formatted string that was returned by <see cref="Var2Str(object)"/> to the original value. + /// </summary> + /// <example> + /// <code> + /// string a = "{\"a\": 1, \"b\": 2 }"; + /// var b = (Godot.Collections.Dictionary)GD.Str2Var(a); + /// GD.Print(b["a"]); // Prints 1 + /// </code> + /// </example> + /// <param name="str">String that will be converted to Variant.</param> + /// <returns>The decoded <c>Variant</c>.</returns> public static object Str2Var(string str) { return godot_icall_GD_str2var(str); } + /// <summary> + /// Returns whether the given class exists in <see cref="ClassDB"/>. + /// </summary> + /// <returns>If the class exists in <see cref="ClassDB"/>.</returns> public static bool TypeExists(StringName type) { return godot_icall_GD_type_exists(StringName.GetPtr(type)); } + /// <summary> + /// Encodes a <c>Variant</c> value to a byte array. + /// If <paramref name="fullObjects"/> is <see langword="true"/> encoding objects is allowed + /// (and can potentially include code). + /// Deserialization can be done with <see cref="Bytes2Var(byte[], bool)"/>. + /// </summary> + /// <param name="var">Variant that will be encoded.</param> + /// <param name="fullObjects">If objects should be serialized.</param> + /// <returns>The <c>Variant</c> encoded as an array of bytes.</returns> public static byte[] Var2Bytes(object var, bool fullObjects = false) { return godot_icall_GD_var2bytes(var, fullObjects); } + /// <summary> + /// Converts a <c>Variant</c> <paramref name="var"/> to a formatted string that + /// can later be parsed using <see cref="Str2Var(string)"/>. + /// </summary> + /// <example> + /// <code> + /// var a = new Godot.Collections.Dictionary { ["a"] = 1, ["b"] = 2 }; + /// GD.Print(GD.Var2Str(a)); + /// // Prints + /// // { + /// // "a": 1, + /// // "b": 2 + /// // } + /// </code> + /// </example> + /// <param name="var">Variant that will be converted to string.</param> + /// <returns>The <c>Variant</c> encoded as a string.</returns> public static string Var2Str(object var) { return godot_icall_GD_var2str(var); } + /// <summary> + /// Get the <see cref="Variant.Type"/> that corresponds for the given <see cref="Type"/>. + /// </summary> + /// <returns>The <see cref="Variant.Type"/> for the given <paramref name="type"/>.</returns> public static Variant.Type TypeToVariantType(Type type) { return godot_icall_TypeToVariantType(type); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects); + internal static extern object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_GD_convert(object what, Variant.Type type); + internal static extern object godot_icall_GD_convert(object what, Variant.Type type); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_GD_hash(object var); + internal static extern int godot_icall_GD_hash(object var); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static Object godot_icall_GD_instance_from_id(ulong instanceId); + internal static extern Object godot_icall_GD_instance_from_id(ulong instanceId); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_print(object[] what); + internal static extern void godot_icall_GD_print(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_printerr(object[] what); + internal static extern void godot_icall_GD_printerr(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_printraw(object[] what); + internal static extern void godot_icall_GD_printraw(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_prints(object[] what); + internal static extern void godot_icall_GD_prints(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_printt(object[] what); + internal static extern void godot_icall_GD_printt(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static float godot_icall_GD_randf(); + internal static extern float godot_icall_GD_randf(); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static uint godot_icall_GD_randi(); + internal static extern uint godot_icall_GD_randi(); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_randomize(); + internal static extern void godot_icall_GD_randomize(); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static double godot_icall_GD_randf_range(double from, double to); + internal static extern double godot_icall_GD_randf_range(double from, double to); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_GD_randi_range(int from, int to); + internal static extern int godot_icall_GD_randi_range(int from, int to); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed); + internal static extern uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_seed(ulong seed); + internal static extern void godot_icall_GD_seed(ulong seed); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_GD_str(object[] what); + internal static extern string godot_icall_GD_str(object[] what); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static object godot_icall_GD_str2var(string str); + internal static extern object godot_icall_GD_str2var(string str); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static bool godot_icall_GD_type_exists(IntPtr type); + internal static extern bool godot_icall_GD_type_exists(IntPtr type); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static byte[] godot_icall_GD_var2bytes(object what, bool fullObjects); + internal static extern byte[] godot_icall_GD_var2bytes(object what, bool fullObjects); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_GD_var2str(object var); + internal static extern string godot_icall_GD_var2str(object var); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_pusherror(string type); + internal static extern void godot_icall_GD_pusherror(string type); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_GD_pushwarning(string type); + internal static extern void godot_icall_GD_pushwarning(string type); [MethodImpl(MethodImplOptions.InternalCall)] private static extern Variant.Type godot_icall_TypeToVariantType(Type type); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs index 4b5e3f8761..c01c926e82 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs @@ -6,7 +6,8 @@ namespace Godot { public class GodotSynchronizationContext : SynchronizationContext { - private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); + private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue = + new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); public override void Post(SendOrPostCallback d, object state) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs index f1a00ae0fa..9ccac1faaf 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 @@ -25,7 +24,7 @@ namespace Godot try { - var stackTrace = new StackTrace(true).ToString(); + string stackTrace = new StackTrace(true).ToString(); GD.PrintErr(stackTrace); } catch diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs new file mode 100644 index 0000000000..729529d093 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + public static partial class GD + { + /// <summary> + /// Fires when an unhandled exception occurs, regardless of project settings. + /// </summary> + public static event EventHandler<UnhandledExceptionArgs> UnhandledException; + + private static void OnUnhandledException(Exception e) + { + UnhandledException?.Invoke(null, new UnhandledExceptionArgs(e)); + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs index c59d083080..3051bcedc7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs @@ -1,66 +1,137 @@ using System; -using System.Collections; using System.Collections.Generic; namespace Godot { - using Array = Godot.Collections.Array; - using Dictionary = Godot.Collections.Dictionary; - - static class MarshalUtils + internal static class MarshalUtils { /// <summary> /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>. + /// is <see cref="Collections.Array{T}"/>; otherwise returns <see langword="false"/>. /// </summary> - /// <exception cref="System.InvalidOperationException"> - /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false. + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. /// </exception> - static bool TypeIsGenericArray(Type type) => - type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>); + private static bool TypeIsGenericArray(Type type) => + type.GetGenericTypeDefinition() == typeof(Collections.Array<>); /// <summary> /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> - /// is <see cref="Godot.Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. + /// is <see cref="Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. /// </summary> - /// <exception cref="System.InvalidOperationException"> - /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false. + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. /// </exception> - static bool TypeIsGenericDictionary(Type type) => - type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>); + private static bool TypeIsGenericDictionary(Type type) => + type.GetGenericTypeDefinition() == typeof(Collections.Dictionary<,>); - static bool TypeIsSystemGenericList(Type type) => - type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>); + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="List{T}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static bool TypeIsSystemGenericList(Type type) => + type.GetGenericTypeDefinition() == typeof(List<>); - static bool TypeIsSystemGenericDictionary(Type type) => - type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.Dictionary<,>); + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static bool TypeIsSystemGenericDictionary(Type type) => + type.GetGenericTypeDefinition() == typeof(Dictionary<,>); - static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>); + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="IEnumerable{T}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>); - static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>); + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="ICollection{T}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>); - static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>); + /// <summary> + /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/> + /// is <see cref="IDictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>. + /// </summary> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="type"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>); - static void ArrayGetElementType(Type arrayType, out Type elementType) + /// <summary> + /// Gets the element type for the given <paramref name="arrayType"/>. + /// </summary> + /// <param name="arrayType">Type for the generic array.</param> + /// <param name="elementType">Element type for the generic array.</param> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="arrayType"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static void ArrayGetElementType(Type arrayType, out Type elementType) { elementType = arrayType.GetGenericArguments()[0]; } - static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) + /// <summary> + /// Gets the key type and the value type for the given <paramref name="dictionaryType"/>. + /// </summary> + /// <param name="dictionaryType">The type for the generic dictionary.</param> + /// <param name="keyType">Key type for the generic dictionary.</param> + /// <param name="valueType">Value type for the generic dictionary.</param> + /// <exception cref="InvalidOperationException"> + /// Thrown when the given <paramref name="dictionaryType"/> is not a generic type. + /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>. + /// </exception> + private static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) { var genericArgs = dictionaryType.GetGenericArguments(); keyType = genericArgs[0]; valueType = genericArgs[1]; } - static Type MakeGenericArrayType(Type elemType) + /// <summary> + /// Constructs a new <see cref="Type"/> from <see cref="Collections.Array{T}"/> + /// where the generic type for the elements is <paramref name="elemType"/>. + /// </summary> + /// <param name="elemType">Element type for the array.</param> + /// <returns>The generic array type with the specified element type.</returns> + private static Type MakeGenericArrayType(Type elemType) { - return typeof(Godot.Collections.Array<>).MakeGenericType(elemType); + return typeof(Collections.Array<>).MakeGenericType(elemType); } - static Type MakeGenericDictionaryType(Type keyType, Type valueType) + /// <summary> + /// Constructs a new <see cref="Type"/> from <see cref="Collections.Dictionary{TKey, TValue}"/> + /// where the generic type for the keys is <paramref name="keyType"/> and + /// for the values is <paramref name="valueType"/>. + /// </summary> + /// <param name="keyType">Key type for the dictionary.</param> + /// <param name="valueType">Key type for the dictionary.</param> + /// <returns>The generic dictionary type with the specified key and value types.</returns> + private static Type MakeGenericDictionaryType(Type keyType, Type valueType) { - return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType); + return typeof(Collections.Dictionary<,>).MakeGenericType(keyType, valueType); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index c3f372d415..6f7fac7429 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -1,12 +1,15 @@ -using System; #if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif +using System; namespace Godot { + /// <summary> + /// Provides constants and static methods for common mathematical functions. + /// </summary> public static partial class Mathf { // Define constants with Decimal precision and cast down to double or float. @@ -14,122 +17,125 @@ 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`. + /// fits around its perimeter. This is equivalent to <c>Mathf.Tau / 2</c>. /// </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`. + /// Positive infinity. For negative infinity, use <c>-Mathf.Inf</c>. /// </summary> public const real_t Inf = real_t.PositiveInfinity; /// <summary> - /// "Not a Number", an invalid value. `NaN` has special properties, including + /// "Not a Number", an invalid value. <c>NaN</c> has special properties, including /// that it is not equal to itself. It is output by some invalid operations, /// such as dividing zero by zero. /// </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). + /// Returns the absolute value of <paramref name="s"/> (i.e. positive value). /// </summary> /// <param name="s">The input number.</param> - /// <returns>The absolute value of `s`.</returns> + /// <returns>The absolute value of <paramref name="s"/>.</returns> public static int Abs(int s) { return Math.Abs(s); } /// <summary> - /// Returns the absolute value of `s` (i.e. positive value). + /// Returns the absolute value of <paramref name="s"/> (i.e. positive value). /// </summary> /// <param name="s">The input number.</param> - /// <returns>The absolute value of `s`.</returns> + /// <returns>The absolute value of <paramref name="s"/>.</returns> public static real_t Abs(real_t s) { return Math.Abs(s); } /// <summary> - /// Returns the arc cosine of `s` in radians. Use to get the angle of cosine s. + /// Returns the arc cosine of <paramref name="s"/> in radians. + /// Use to get the angle of cosine <paramref name="s"/>. /// </summary> /// <param name="s">The input cosine value. Must be on the range of -1.0 to 1.0.</param> - /// <returns>An angle that would result in the given cosine value. On the range `0` to `Tau/2`.</returns> + /// <returns> + /// An angle that would result in the given cosine value. On the range <c>0</c> to <c>Tau/2</c>. + /// </returns> public static real_t Acos(real_t s) { return (real_t)Math.Acos(s); } /// <summary> - /// Returns the arc sine of `s` in radians. Use to get the angle of sine s. + /// Returns the arc sine of <paramref name="s"/> in radians. + /// Use to get the angle of sine <paramref name="s"/>. /// </summary> /// <param name="s">The input sine value. Must be on the range of -1.0 to 1.0.</param> - /// <returns>An angle that would result in the given sine value. On the range `-Tau/4` to `Tau/4`.</returns> + /// <returns> + /// An angle that would result in the given sine value. On the range <c>-Tau/4</c> to <c>Tau/4</c>. + /// </returns> public static real_t Asin(real_t s) { return (real_t)Math.Asin(s); } /// <summary> - /// Returns the arc tangent of `s` in radians. Use to get the angle of tangent s. + /// Returns the arc tangent of <paramref name="s"/> in radians. + /// Use to get the angle of tangent <paramref name="s"/>. /// /// The method cannot know in which quadrant the angle should fall. - /// See <see cref="Atan2(real_t, real_t)"/> if you have both `y` and `x`. + /// See <see cref="Atan2(real_t, real_t)"/> if you have both <c>y</c> and <c>x</c>. /// </summary> /// <param name="s">The input tangent value.</param> - /// <returns>An angle that would result in the given tangent value. On the range `-Tau/4` to `Tau/4`.</returns> + /// <returns> + /// An angle that would result in the given tangent value. On the range <c>-Tau/4</c> to <c>Tau/4</c>. + /// </returns> public static real_t Atan(real_t s) { return (real_t)Math.Atan(s); } /// <summary> - /// Returns the arc tangent of `y` and `x` in radians. Use to get the angle - /// of the tangent of `y/x`. To compute the value, the method takes into + /// Returns the arc tangent of <paramref name="y"/> and <paramref name="x"/> in radians. + /// Use to get the angle of the tangent of <c>y/x</c>. To compute the value, the method takes into /// account the sign of both arguments in order to determine the quadrant. /// /// Important note: The Y coordinate comes first, by convention. /// </summary> /// <param name="y">The Y coordinate of the point to find the angle to.</param> /// <param name="x">The X coordinate of the point to find the angle to.</param> - /// <returns>An angle that would result in the given tangent value. On the range `-Tau/2` to `Tau/2`.</returns> + /// <returns> + /// An angle that would result in the given tangent value. On the range <c>-Tau/2</c> to <c>Tau/2</c>. + /// </returns> public static real_t Atan2(real_t y, real_t x) { return (real_t)Math.Atan2(y, x); } /// <summary> - /// 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). - /// </summary> - /// <param name="x">The input X coordinate.</param> - /// <param name="y">The input Y coordinate.</param> - /// <returns>A <see cref="Vector2"/> with X representing the distance and Y representing the angle.</returns> - public static Vector2 Cartesian2Polar(real_t x, real_t y) - { - return new Vector2(Sqrt(x * x + y * y), Atan2(y, x)); - } - - /// <summary> - /// Rounds `s` upward (towards positive infinity). + /// Rounds <paramref name="s"/> upward (towards positive infinity). /// </summary> /// <param name="s">The number to ceil.</param> - /// <returns>The smallest whole number that is not less than `s`.</returns> + /// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns> public static real_t Ceil(real_t s) { return (real_t)Math.Ceiling(s); } /// <summary> - /// Clamps a `value` so that it is not less than `min` and not more than `max`. + /// Clamps a <paramref name="value"/> so that it is not less than <paramref name="min"/> + /// and not more than <paramref name="max"/>. /// </summary> /// <param name="value">The value to clamp.</param> /// <param name="min">The minimum allowed value.</param> @@ -141,7 +147,8 @@ namespace Godot } /// <summary> - /// Clamps a `value` so that it is not less than `min` and not more than `max`. + /// Clamps a <paramref name="value"/> so that it is not less than <paramref name="min"/> + /// and not more than <paramref name="max"/>. /// </summary> /// <param name="value">The value to clamp.</param> /// <param name="min">The minimum allowed value.</param> @@ -153,7 +160,7 @@ namespace Godot } /// <summary> - /// Returns the cosine of angle `s` in radians. + /// Returns the cosine of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The cosine of that angle.</returns> @@ -163,7 +170,7 @@ namespace Godot } /// <summary> - /// Returns the hyperbolic cosine of angle `s` in radians. + /// Returns the hyperbolic cosine of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The hyperbolic cosine of that angle.</returns> @@ -179,16 +186,18 @@ namespace Godot /// <returns>The same angle expressed in radians.</returns> public static real_t Deg2Rad(real_t deg) { - return deg * Deg2RadConst; + return deg * _deg2RadConst; } /// <summary> - /// Easing function, based on exponent. The curve values are: - /// `0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out. + /// Easing function, based on exponent. The <paramref name="curve"/> values are: + /// <c>0</c> is constant, <c>1</c> is linear, <c>0</c> to <c>1</c> is ease-in, <c>1</c> or more is ease-out. /// Negative values are in-out/out-in. /// </summary> /// <param name="s">The value to ease.</param> - /// <param name="curve">`0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out.</param> + /// <param name="curve"> + /// <c>0</c> is constant, <c>1</c> is linear, <c>0</c> to <c>1</c> is ease-in, <c>1</c> or more is ease-out. + /// </param> /// <returns>The eased value.</returns> public static real_t Ease(real_t s, real_t curve) { @@ -218,7 +227,7 @@ namespace Godot return Pow(s * 2.0f, -curve) * 0.5f; } - return (1.0f - Pow(1.0f - (s - 0.5f) * 2.0f, -curve)) * 0.5f + 0.5f; + return ((1.0f - Pow(1.0f - ((s - 0.5f) * 2.0f), -curve)) * 0.5f) + 0.5f; } return 0f; @@ -226,20 +235,20 @@ namespace Godot /// <summary> /// The natural exponential function. It raises the mathematical - /// constant `e` to the power of `s` and returns it. + /// constant <c>e</c> to the power of <paramref name="s"/> and returns it. /// </summary> - /// <param name="s">The exponent to raise `e` to.</param> - /// <returns>`e` raised to the power of `s`.</returns> + /// <param name="s">The exponent to raise <c>e</c> to.</param> + /// <returns><c>e</c> raised to the power of <paramref name="s"/>.</returns> public static real_t Exp(real_t s) { return (real_t)Math.Exp(s); } /// <summary> - /// Rounds `s` downward (towards negative infinity). + /// Rounds <paramref name="s"/> downward (towards negative infinity). /// </summary> /// <param name="s">The number to floor.</param> - /// <returns>The largest whole number that is not more than `s`.</returns> + /// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns> public static real_t Floor(real_t s) { return (real_t)Math.Floor(s); @@ -259,12 +268,13 @@ namespace Godot } /// <summary> - /// Returns true if `a` and `b` are approximately equal to each other. + /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately equal + /// to each other. /// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>. /// </summary> /// <param name="a">One of the values.</param> /// <param name="b">The other value.</param> - /// <returns>A bool for whether or not the two values are approximately equal.</returns> + /// <returns>A <see langword="bool"/> for whether or not the two values are approximately equal.</returns> public static bool IsEqualApprox(real_t a, real_t b) { // Check for exact equality first, required to handle "infinity" values. @@ -282,33 +292,33 @@ namespace Godot } /// <summary> - /// Returns whether `s` is an infinity value (either positive infinity or negative infinity). + /// Returns whether <paramref name="s"/> is an infinity value (either positive infinity or negative infinity). /// </summary> /// <param name="s">The value to check.</param> - /// <returns>A bool for whether or not the value is an infinity value.</returns> + /// <returns>A <see langword="bool"/> for whether or not the value is an infinity value.</returns> public static bool IsInf(real_t s) { return real_t.IsInfinity(s); } /// <summary> - /// Returns whether `s` is a `NaN` ("Not a Number" or invalid) value. + /// Returns whether <paramref name="s"/> is a <c>NaN</c> ("Not a Number" or invalid) value. /// </summary> /// <param name="s">The value to check.</param> - /// <returns>A bool for whether or not the value is a `NaN` value.</returns> + /// <returns>A <see langword="bool"/> for whether or not the value is a <c>NaN</c> value.</returns> public static bool IsNaN(real_t s) { return real_t.IsNaN(s); } /// <summary> - /// Returns true if `s` is approximately zero. + /// Returns <see langword="true"/> if <paramref name="s"/> is approximately zero. /// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>. /// /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero. /// </summary> /// <param name="s">The value to check.</param> - /// <returns>A bool for whether or not the value is nearly zero.</returns> + /// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns> public static bool IsZeroApprox(real_t s) { return Abs(s) < Epsilon; @@ -324,7 +334,7 @@ namespace Godot /// <returns>The resulting value of the interpolation.</returns> public static real_t Lerp(real_t from, real_t to, real_t weight) { - return from + (to - from) * weight; + return from + ((to - from) * weight); } /// <summary> @@ -341,7 +351,7 @@ namespace Godot { real_t difference = (to - from) % Mathf.Tau; real_t distance = ((2 * difference) % Mathf.Tau) - difference; - return from + distance * weight; + return from + (distance * weight); } /// <summary> @@ -350,7 +360,7 @@ namespace Godot /// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm. /// </summary> /// <param name="s">The input value.</param> - /// <returns>The natural log of `s`.</returns> + /// <returns>The natural log of <paramref name="s"/>.</returns> public static real_t Log(real_t s) { return (real_t)Math.Log(s); @@ -401,9 +411,9 @@ namespace Godot } /// <summary> - /// Moves `from` toward `to` by the `delta` value. + /// Moves <paramref name="from"/> toward <paramref name="to"/> by the <paramref name="delta"/> value. /// - /// Use a negative delta value to move away. + /// Use a negative <paramref name="delta"/> value to move away. /// </summary> /// <param name="from">The start value.</param> /// <param name="to">The value to move towards.</param> @@ -411,11 +421,14 @@ namespace Godot /// <returns>The value after moving.</returns> public static real_t MoveToward(real_t from, real_t to, real_t delta) { - return Abs(to - from) <= delta ? to : from + Sign(to - from) * delta; + if (Abs(to - from) <= delta) + return to; + + return from + (Sign(to - from) * delta); } /// <summary> - /// Returns the nearest larger power of 2 for the integer `value`. + /// Returns the nearest larger power of 2 for the integer <paramref name="value"/>. /// </summary> /// <param name="value">The input value.</param> /// <returns>The nearest larger power of 2.</returns> @@ -432,23 +445,10 @@ namespace Godot } /// <summary> - /// Converts a 2D point expressed in the polar coordinate - /// system (a distance from the origin `r` and an angle `th`) - /// to the cartesian coordinate system (X and Y axis). - /// </summary> - /// <param name="r">The distance from the origin.</param> - /// <param name="th">The angle of the point.</param> - /// <returns>A <see cref="Vector2"/> representing the cartesian coordinate.</returns> - public static Vector2 Polar2Cartesian(real_t r, real_t th) - { - return new Vector2(r * Cos(th), r * Sin(th)); - } - - /// <summary> - /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`. + /// Performs a canonical Modulus operation, where the output is on the range [0, <paramref name="b"/>). /// </summary> /// <param name="a">The dividend, the primary input.</param> - /// <param name="b">The divisor. The output is on the range `[0, b)`.</param> + /// <param name="b">The divisor. The output is on the range [0, <paramref name="b"/>).</param> /// <returns>The resulting output.</returns> public static int PosMod(int a, int b) { @@ -461,10 +461,10 @@ namespace Godot } /// <summary> - /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`. + /// Performs a canonical Modulus operation, where the output is on the range [0, <paramref name="b"/>). /// </summary> /// <param name="a">The dividend, the primary input.</param> - /// <param name="b">The divisor. The output is on the range `[0, b)`.</param> + /// <param name="b">The divisor. The output is on the range [0, <paramref name="b"/>).</param> /// <returns>The resulting output.</returns> public static real_t PosMod(real_t a, real_t b) { @@ -477,11 +477,11 @@ namespace Godot } /// <summary> - /// Returns the result of `x` raised to the power of `y`. + /// Returns the result of <paramref name="x"/> raised to the power of <paramref name="y"/>. /// </summary> /// <param name="x">The base.</param> /// <param name="y">The exponent.</param> - /// <returns>`x` raised to the power of `y`.</returns> + /// <returns><paramref name="x"/> raised to the power of <paramref name="y"/>.</returns> public static real_t Pow(real_t x, real_t y) { return (real_t)Math.Pow(x, y); @@ -494,11 +494,11 @@ namespace Godot /// <returns>The same angle expressed in degrees.</returns> public static real_t Rad2Deg(real_t rad) { - return rad * Rad2DegConst; + return rad * _rad2DegConst; } /// <summary> - /// Rounds `s` to the nearest whole number, + /// Rounds <paramref name="s"/> to the nearest whole number, /// with halfway cases rounded towards the nearest multiple of two. /// </summary> /// <param name="s">The number to round.</param> @@ -509,29 +509,33 @@ namespace Godot } /// <summary> - /// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`. + /// Returns the sign of <paramref name="s"/>: <c>-1</c> or <c>1</c>. + /// Returns <c>0</c> if <paramref name="s"/> is <c>0</c>. /// </summary> /// <param name="s">The input number.</param> - /// <returns>One of three possible values: `1`, `-1`, or `0`.</returns> + /// <returns>One of three possible values: <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public static int Sign(int s) { - if (s == 0) return 0; + if (s == 0) + return 0; return s < 0 ? -1 : 1; } /// <summary> - /// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`. + /// Returns the sign of <paramref name="s"/>: <c>-1</c> or <c>1</c>. + /// Returns <c>0</c> if <paramref name="s"/> is <c>0</c>. /// </summary> /// <param name="s">The input number.</param> - /// <returns>One of three possible values: `1`, `-1`, or `0`.</returns> + /// <returns>One of three possible values: <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public static int Sign(real_t s) { - if (s == 0) return 0; + if (s == 0) + return 0; return s < 0 ? -1 : 1; } /// <summary> - /// Returns the sine of angle `s` in radians. + /// Returns the sine of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The sine of that angle.</returns> @@ -541,7 +545,7 @@ namespace Godot } /// <summary> - /// Returns the hyperbolic sine of angle `s` in radians. + /// Returns the hyperbolic sine of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The hyperbolic sine of that angle.</returns> @@ -551,8 +555,8 @@ namespace Godot } /// <summary> - /// Returns a number smoothly interpolated between `from` and `to`, - /// based on the `weight`. Similar to <see cref="Lerp(real_t, real_t, real_t)"/>, + /// Returns a number smoothly interpolated between <paramref name="from"/> and <paramref name="to"/>, + /// based on the <paramref name="weight"/>. Similar to <see cref="Lerp(real_t, real_t, real_t)"/>, /// but interpolates faster at the beginning and slower at the end. /// </summary> /// <param name="from">The start value for interpolation.</param> @@ -566,16 +570,16 @@ namespace Godot return from; } real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0); - return x * x * (3 - 2 * x); + return x * x * (3 - (2 * x)); } /// <summary> - /// Returns the square root of `s`, where `s` is a non-negative number. + /// Returns the square root of <paramref name="s"/>, where <paramref name="s"/> is a non-negative number. /// - /// If you need negative inputs, use `System.Numerics.Complex`. + /// If you need negative inputs, use <see cref="System.Numerics.Complex"/>. /// </summary> /// <param name="s">The input number. Must not be negative.</param> - /// <returns>The square root of `s`.</returns> + /// <returns>The square root of <paramref name="s"/>.</returns> public static real_t Sqrt(real_t s) { return (real_t)Math.Sqrt(s); @@ -590,7 +594,8 @@ namespace Godot /// <returns>The position of the first non-zero digit.</returns> public static int StepDecimals(real_t step) { - double[] sd = new double[] { + double[] sd = new double[] + { 0.9999, 0.09999, 0.009999, @@ -601,7 +606,7 @@ namespace Godot 0.00000009999, 0.000000009999, }; - double abs = Mathf.Abs(step); + double abs = Abs(step); double decs = abs - (int)abs; // Strip away integer part for (int i = 0; i < sd.Length; i++) { @@ -614,9 +619,8 @@ namespace Godot } /// <summary> - /// Snaps float value `s` to a given `step`. - /// This can also be used to round a floating point - /// number to an arbitrary number of decimals. + /// Snaps float value <paramref name="s"/> to a given <paramref name="step"/>. + /// This can also be used to round a floating point number to an arbitrary number of decimals. /// </summary> /// <param name="s">The value to snap.</param> /// <param name="step">The step size to snap to.</param> @@ -625,14 +629,14 @@ namespace Godot { if (step != 0f) { - return Floor(s / step + 0.5f) * step; + return Floor((s / step) + 0.5f) * step; } return s; } /// <summary> - /// Returns the tangent of angle `s` in radians. + /// Returns the tangent of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The tangent of that angle.</returns> @@ -642,7 +646,7 @@ namespace Godot } /// <summary> - /// Returns the hyperbolic tangent of angle `s` in radians. + /// Returns the hyperbolic tangent of angle <paramref name="s"/> in radians. /// </summary> /// <param name="s">The angle in radians.</param> /// <returns>The hyperbolic tangent of that angle.</returns> @@ -652,8 +656,9 @@ namespace Godot } /// <summary> - /// Wraps `value` between `min` and `max`. Usable for creating loop-alike - /// behavior or infinite surfaces. If `min` is `0`, this is equivalent + /// Wraps <paramref name="value"/> between <paramref name="min"/> and <paramref name="max"/>. + /// Usable for creating loop-alike behavior or infinite surfaces. + /// If <paramref name="min"/> is <c>0</c>, this is equivalent /// to <see cref="PosMod(int, int)"/>, so prefer using that instead. /// </summary> /// <param name="value">The value to wrap.</param> @@ -663,12 +668,16 @@ namespace Godot public static int Wrap(int value, int min, int max) { int range = max - min; - return range == 0 ? min : min + ((value - min) % range + range) % range; + if (range == 0) + return min; + + return min + ((((value - min) % range) + range) % range); } /// <summary> - /// Wraps `value` between `min` and `max`. Usable for creating loop-alike - /// behavior or infinite surfaces. If `min` is `0`, this is equivalent + /// Wraps <paramref name="value"/> between <paramref name="min"/> and <paramref name="max"/>. + /// Usable for creating loop-alike behavior or infinite surfaces. + /// If <paramref name="min"/> is <c>0</c>, this is equivalent /// to <see cref="PosMod(real_t, real_t)"/>, so prefer using that instead. /// </summary> /// <param name="value">The value to wrap.</param> @@ -678,7 +687,11 @@ namespace Godot public static real_t Wrap(real_t value, real_t min, real_t max) { real_t range = max - min; - return IsZeroApprox(range) ? min : min + ((value - min) % range + range) % range; + if (IsZeroApprox(range)) + { + return min; + } + return min + ((((value - min) % range) + range) % range); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs index c2f4701b5f..9bb73ce7dd 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 { @@ -13,18 +12,18 @@ namespace Godot // Define constants with Decimal precision and cast down to double or float. /// <summary> - /// The natural number `e`. + /// The natural number <c>e</c>. /// </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. - /// 1e-06 with single-precision floats, but 1e-14 if `REAL_T_IS_DOUBLE`. + /// 1e-06 with single-precision floats, but 1e-14 if <c>REAL_T_IS_DOUBLE</c>. /// </summary> #if REAL_T_IS_DOUBLE public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used. @@ -45,7 +44,7 @@ namespace Godot /// <summary> /// Returns the amount of digits after the decimal place. /// </summary> - /// <param name="s">The input <see cref="System.Decimal"/> value.</param> + /// <param name="s">The input <see cref="decimal"/> value.</param> /// <returns>The amount of digits.</returns> public static int DecimalCount(decimal s) { @@ -53,48 +52,51 @@ namespace Godot } /// <summary> - /// Rounds `s` upward (towards positive infinity). + /// Rounds <paramref name="s"/> upward (towards positive infinity). /// - /// This is the same as <see cref="Ceil(real_t)"/>, but returns an `int`. + /// This is the same as <see cref="Ceil(real_t)"/>, but returns an <c>int</c>. /// </summary> /// <param name="s">The number to ceil.</param> - /// <returns>The smallest whole number that is not less than `s`.</returns> + /// <returns>The smallest whole number that is not less than <paramref name="s"/>.</returns> public static int CeilToInt(real_t s) { return (int)Math.Ceiling(s); } /// <summary> - /// Rounds `s` downward (towards negative infinity). + /// Rounds <paramref name="s"/> downward (towards negative infinity). /// - /// This is the same as <see cref="Floor(real_t)"/>, but returns an `int`. + /// This is the same as <see cref="Floor(real_t)"/>, but returns an <c>int</c>. /// </summary> /// <param name="s">The number to floor.</param> - /// <returns>The largest whole number that is not more than `s`.</returns> + /// <returns>The largest whole number that is not more than <paramref name="s"/>.</returns> public static int FloorToInt(real_t s) { return (int)Math.Floor(s); } /// <summary> + /// Rounds <paramref name="s"/> to the nearest whole number. /// + /// This is the same as <see cref="Round(real_t)"/>, but returns an <c>int</c>. /// </summary> - /// <param name="s"></param> - /// <returns></returns> + /// <param name="s">The number to round.</param> + /// <returns>The rounded number.</returns> public static int RoundToInt(real_t s) { return (int)Math.Round(s); } /// <summary> - /// Returns true if `a` and `b` are approximately equal to each other. + /// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately + /// equal to each other. /// The comparison is done using the provided tolerance value. /// If you want the tolerance to be calculated for you, use <see cref="IsEqualApprox(real_t, real_t)"/>. /// </summary> /// <param name="a">One of the values.</param> /// <param name="b">The other value.</param> /// <param name="tolerance">The pre-calculated tolerance value.</param> - /// <returns>A bool for whether or not the two values are equal.</returns> + /// <returns>A <see langword="bool"/> for whether or not the two values are equal.</returns> public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance) { // Check for exact equality first, required to handle "infinity" values. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs index 4ecc55f94e..f53b5dc904 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs @@ -3,9 +3,45 @@ using System.Runtime.CompilerServices; namespace Godot { + /// <summary> + /// A pre-parsed relative or absolute path in a scene tree, + /// for use with <see cref="Node.GetNode(NodePath)"/> and similar functions. + /// It can reference a node, a resource within a node, or a property + /// of a node or resource. + /// For instance, <c>"Path2D/PathFollow2D/Sprite2D:texture:size"</c> + /// would refer to the <c>size</c> property of the <c>texture</c> + /// resource on the node named <c>"Sprite2D"</c> which is a child of + /// the other named nodes in the path. + /// You will usually just pass a string to <see cref="Node.GetNode(NodePath)"/> + /// and it will be automatically converted, but you may occasionally + /// want to parse a path ahead of time with NodePath. + /// Exporting a NodePath variable will give you a node selection widget + /// in the properties panel of the editor, which can often be useful. + /// A NodePath is composed of a list of slash-separated node names + /// (like a filesystem path) and an optional colon-separated list of + /// "subnames" which can be resources or properties. + /// + /// Note: In the editor, NodePath properties are automatically updated when moving, + /// renaming or deleting a node in the scene tree, but they are never updated at runtime. + /// </summary> + /// <example> + /// Some examples of NodePaths include the following: + /// <code> + /// // No leading slash means it is relative to the current node. + /// new NodePath("A"); // Immediate child A. + /// new NodePath("A/B"); // A's child B. + /// new NodePath("."); // The current node. + /// new NodePath(".."); // The parent node. + /// new NodePath("../C"); // A sibling node C. + /// // A leading slash means it is absolute from the SceneTree. + /// new NodePath("/root"); // Equivalent to GetTree().Root + /// new NodePath("/root/Main"); // If your main scene's root node were named "Main". + /// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene. + /// </code> + /// </example> public sealed partial class NodePath : IDisposable { - private bool disposed = false; + private bool _disposed = false; private IntPtr ptr; @@ -14,7 +50,7 @@ namespace Godot if (instance == null) throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null."); - if (instance.disposed) + if (instance._disposed) throw new ObjectDisposedException(instance.GetType().FullName); return instance.ptr; @@ -25,6 +61,9 @@ namespace Godot Dispose(false); } + /// <summary> + /// Disposes of this <see cref="NodePath"/>. + /// </summary> public void Dispose() { Dispose(true); @@ -33,7 +72,7 @@ namespace Godot private void Dispose(bool disposing) { - if (disposed) + if (_disposed) return; if (ptr != IntPtr.Zero) @@ -42,7 +81,7 @@ namespace Godot ptr = IntPtr.Zero; } - disposed = true; + _disposed = true; } internal NodePath(IntPtr ptr) @@ -50,57 +89,168 @@ namespace Godot this.ptr = ptr; } - public NodePath() : this(string.Empty) {} - + /// <summary> + /// Constructs an empty <see cref="NodePath"/>. + /// </summary> + public NodePath() : this(string.Empty) { } + + /// <summary> + /// Constructs a <see cref="NodePath"/> from a string <paramref name="path"/>, + /// e.g.: <c>"Path2D/PathFollow2D/Sprite2D:texture:size"</c>. + /// A path is absolute if it starts with a slash. Absolute paths + /// are only valid in the global scene tree, not within individual + /// scenes. In a relative path, <c>"."</c> and <c>".."</c> indicate + /// the current node and its parent. + /// The "subnames" optionally included after the path to the target + /// node can point to resources or properties, and can also be nested. + /// </summary> + /// <example> + /// Examples of valid NodePaths (assuming that those nodes exist and + /// have the referenced resources or properties): + /// <code> + /// // Points to the Sprite2D node. + /// "Path2D/PathFollow2D/Sprite2D" + /// // Points to the Sprite2D node and its "texture" resource. + /// // GetNode() would retrieve "Sprite2D", while GetNodeAndResource() + /// // would retrieve both the Sprite2D node and the "texture" resource. + /// "Path2D/PathFollow2D/Sprite2D:texture" + /// // Points to the Sprite2D node and its "position" property. + /// "Path2D/PathFollow2D/Sprite2D:position" + /// // Points to the Sprite2D node and the "x" component of its "position" property. + /// "Path2D/PathFollow2D/Sprite2D:position:x" + /// // Absolute path (from "root") + /// "/root/Level/Path2D" + /// </code> + /// </example> + /// <param name="path"></param> public NodePath(string path) { ptr = godot_icall_NodePath_Ctor(path); } + /// <summary> + /// Converts a string to a <see cref="NodePath"/>. + /// </summary> + /// <param name="from">The string to convert.</param> public static implicit operator NodePath(string from) => new NodePath(from); + /// <summary> + /// Converts this <see cref="NodePath"/> to a string. + /// </summary> + /// <param name="from">The <see cref="NodePath"/> to convert.</param> public static implicit operator string(NodePath from) => from.ToString(); + /// <summary> + /// Converts this <see cref="NodePath"/> to a string. + /// </summary> + /// <returns>A string representation of this <see cref="NodePath"/>.</returns> public override string ToString() { return godot_icall_NodePath_operator_String(GetPtr(this)); } + /// <summary> + /// Returns a node path with a colon character (<c>:</c>) prepended, + /// transforming it to a pure property path with no node name (defaults + /// to resolving from the current node). + /// </summary> + /// <example> + /// <code> + /// // This will be parsed as a node path to the "x" property in the "position" node. + /// var nodePath = new NodePath("position:x"); + /// // This will be parsed as a node path to the "x" component of the "position" property in the current node. + /// NodePath propertyPath = nodePath.GetAsPropertyPath(); + /// GD.Print(propertyPath); // :position:x + /// </code> + /// </example> + /// <returns>The <see cref="NodePath"/> as a pure property path.</returns> public NodePath GetAsPropertyPath() { return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this))); } + /// <summary> + /// Returns all subnames concatenated with a colon character (<c>:</c>) + /// as separator, i.e. the right side of the first colon in a node path. + /// </summary> + /// <example> + /// <code> + /// var nodepath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path"); + /// GD.Print(nodepath.GetConcatenatedSubnames()); // texture:load_path + /// </code> + /// </example> + /// <returns>The subnames concatenated with <c>:</c>.</returns> public string GetConcatenatedSubnames() { return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this)); } + /// <summary> + /// Gets the node name indicated by <paramref name="idx"/> (0 to <see cref="GetNameCount"/>). + /// </summary> + /// <example> + /// <code> + /// var nodePath = new NodePath("Path2D/PathFollow2D/Sprite2D"); + /// GD.Print(nodePath.GetName(0)); // Path2D + /// GD.Print(nodePath.GetName(1)); // PathFollow2D + /// GD.Print(nodePath.GetName(2)); // Sprite + /// </code> + /// </example> + /// <param name="idx">The name index.</param> + /// <returns>The name at the given index <paramref name="idx"/>.</returns> public string GetName(int idx) { return godot_icall_NodePath_get_name(GetPtr(this), idx); } + /// <summary> + /// Gets the number of node names which make up the path. + /// Subnames (see <see cref="GetSubnameCount"/>) are not included. + /// For example, <c>"Path2D/PathFollow2D/Sprite2D"</c> has 3 names. + /// </summary> + /// <returns>The number of node names which make up the path.</returns> public int GetNameCount() { return godot_icall_NodePath_get_name_count(GetPtr(this)); } + /// <summary> + /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubnameCount"/>). + /// </summary> + /// <param name="idx">The subname index.</param> + /// <returns>The subname at the given index <paramref name="idx"/>.</returns> public string GetSubname(int idx) { return godot_icall_NodePath_get_subname(GetPtr(this), idx); } + /// <summary> + /// Gets the number of resource or property names ("subnames") in the path. + /// Each subname is listed after a colon character (<c>:</c>) in the node path. + /// For example, <c>"Path2D/PathFollow2D/Sprite2D:texture:load_path"</c> has 2 subnames. + /// </summary> + /// <returns>The number of subnames in the path.</returns> public int GetSubnameCount() { return godot_icall_NodePath_get_subname_count(GetPtr(this)); } + /// <summary> + /// Returns <see langword="true"/> if the node path is absolute (as opposed to relative), + /// which means that it starts with a slash character (<c>/</c>). Absolute node paths can + /// be used to access the root node (<c>"/root"</c>) or autoloads (e.g. <c>"/global"</c> + /// if a "global" autoload was registered). + /// </summary> + /// <returns>If the <see cref="NodePath"/> is an absolute path.</returns> public bool IsAbsolute() { return godot_icall_NodePath_is_absolute(GetPtr(this)); } + /// <summary> + /// Returns <see langword="true"/> if the node path is empty. + /// </summary> + /// <returns>If the <see cref="NodePath"/> is empty.</returns> public bool IsEmpty() { return godot_icall_NodePath_is_empty(GetPtr(this)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 48582d5ad8..8fe08e7e1d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -5,13 +5,16 @@ namespace Godot { public partial class Object : IDisposable { - private bool disposed = false; + private bool _disposed = false; private static StringName nativeName = "Object"; internal IntPtr ptr; internal bool memoryOwn; + /// <summary> + /// Constructs a new <see cref="Object"/>. + /// </summary> public Object() : this(false) { if (ptr == IntPtr.Zero) @@ -29,6 +32,9 @@ namespace Godot this.memoryOwn = memoryOwn; } + /// <summary> + /// The pointer to the native instance of this <see cref="Object"/>. + /// </summary> public IntPtr NativeInstance { get { return ptr; } @@ -39,7 +45,7 @@ namespace Godot if (instance == null) return IntPtr.Zero; - if (instance.disposed) + if (instance._disposed) throw new ObjectDisposedException(instance.GetType().FullName); return instance.ptr; @@ -50,15 +56,21 @@ namespace Godot Dispose(false); } + /// <summary> + /// Disposes of this <see cref="Object"/>. + /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + /// <summary> + /// Disposes implementation of this <see cref="Object"/>. + /// </summary> protected virtual void Dispose(bool disposing) { - if (disposed) + if (_disposed) return; if (ptr != IntPtr.Zero) @@ -66,26 +78,30 @@ namespace Godot if (memoryOwn) { memoryOwn = false; - godot_icall_Reference_Disposed(this, ptr, !disposing); + godot_icall_RefCounted_Disposed(this, ptr, !disposing); } else { godot_icall_Object_Disposed(this, ptr); } - this.ptr = IntPtr.Zero; + ptr = IntPtr.Zero; } - disposed = true; + _disposed = true; } + /// <summary> + /// Converts this <see cref="Object"/> to a string. + /// </summary> + /// <returns>A string representation of this object.</returns> public override string ToString() { return godot_icall_Object_ToString(GetPtr(this)); } /// <summary> - /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance + /// Returns a new <see cref="SignalAwaiter"/> awaiter configured to complete when the instance /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter. /// </summary> /// <param name="source"> @@ -107,13 +123,17 @@ namespace Godot /// } /// </code> /// </example> + /// <returns> + /// A <see cref="SignalAwaiter"/> that completes when + /// <paramref name="source"/> emits the <paramref name="signal"/>. + /// </returns> public SignalAwaiter ToSignal(Object source, StringName signal) { return new SignalAwaiter(source, signal, this); } /// <summary> - /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance. + /// Gets a new <see cref="DynamicGodotObject"/> associated with this instance. /// </summary> public dynamic DynamicObject => new DynamicGodotObject(this); @@ -129,7 +149,7 @@ namespace Godot internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer); + internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 2f8b5f297c..66f7b745f7 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 { @@ -21,10 +21,10 @@ namespace Godot /// <summary> /// The normal of the plane, which must be normalized. - /// In the scalar equation of the plane `ax + by + cz = d`, this is - /// the vector `(a, b, c)`, where `d` is the <see cref="D"/> property. + /// In the scalar equation of the plane <c>ax + by + cz = d</c>, this is + /// the vector <c>(a, b, c)</c>, where <c>d</c> is the <see cref="D"/> property. /// </summary> - /// <value>Equivalent to `x`, `y`, and `z`.</value> + /// <value>Equivalent to <see cref="x"/>, <see cref="y"/>, and <see cref="z"/>.</value> public Vector3 Normal { get { return _normal; } @@ -82,8 +82,8 @@ namespace Godot /// <summary> /// The distance from the origin to the plane (in the direction of /// <see cref="Normal"/>). This value is typically non-negative. - /// In the scalar equation of the plane `ax + by + cz = d`, - /// this is `d`, while the `(a, b, c)` coordinates are represented + /// In the scalar equation of the plane <c>ax + by + cz = d</c>, + /// this is <c>d</c>, while the <c>(a, b, c)</c> coordinates are represented /// by the <see cref="Normal"/> property. /// </summary> /// <value>The plane's distance from the origin.</value> @@ -92,7 +92,7 @@ namespace Godot /// <summary> /// The center of the plane, the point where the normal line intersects the plane. /// </summary> - /// <value>Equivalent to <see cref="Normal"/> multiplied by `D`.</value> + /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value> public Vector3 Center { get @@ -107,7 +107,7 @@ namespace Godot } /// <summary> - /// Returns the shortest distance from this plane to the position `point`. + /// Returns the shortest distance from this plane to the position <paramref name="point"/>. /// </summary> /// <param name="point">The position to use for the calculation.</param> /// <returns>The shortest distance.</returns> @@ -117,12 +117,12 @@ namespace Godot } /// <summary> - /// Returns true if point is inside the plane. + /// Returns <see langword="true"/> if point is inside the plane. /// Comparison uses a custom minimum epsilon threshold. /// </summary> /// <param name="point">The point to check.</param> /// <param name="epsilon">The tolerance threshold.</param> - /// <returns>A bool for whether or not the plane has the point.</returns> + /// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns> public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) { real_t dist = _normal.Dot(point) - D; @@ -130,12 +130,12 @@ namespace Godot } /// <summary> - /// Returns the intersection point of the three planes: `b`, `c`, - /// and this plane. If no intersection is found, `null` is returned. + /// Returns the intersection point of the three planes: <paramref name="b"/>, <paramref name="c"/>, + /// and this plane. If no intersection is found, <see langword="null"/> is returned. /// </summary> /// <param name="b">One of the three planes to use in the calculation.</param> /// <param name="c">One of the three planes to use in the calculation.</param> - /// <returns>The intersection, or `null` if none is found.</returns> + /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> public Vector3? Intersect3(Plane b, Plane c) { real_t denom = _normal.Cross(b._normal).Dot(c._normal); @@ -145,21 +145,21 @@ namespace Godot return null; } - Vector3 result = b._normal.Cross(c._normal) * D + - c._normal.Cross(_normal) * b.D + - _normal.Cross(b._normal) * c.D; + Vector3 result = (b._normal.Cross(c._normal) * D) + + (c._normal.Cross(_normal) * b.D) + + (_normal.Cross(b._normal) * c.D); return result / denom; } /// <summary> - /// Returns the intersection point of a ray consisting of the - /// position `from` and the direction normal `dir` with this plane. - /// If no intersection is found, `null` is returned. + /// Returns the intersection point of a ray consisting of the position <paramref name="from"/> + /// and the direction normal <paramref name="dir"/> with this plane. + /// If no intersection is found, <see langword="null"/> is returned. /// </summary> /// <param name="from">The start of the ray.</param> /// <param name="dir">The direction of the ray, normalized.</param> - /// <returns>The intersection, or `null` if none is found.</returns> + /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> public Vector3? IntersectRay(Vector3 from, Vector3 dir) { real_t den = _normal.Dot(dir); @@ -177,17 +177,17 @@ namespace Godot return null; } - return from + dir * -dist; + return from - (dir * dist); } /// <summary> /// Returns the intersection point of a line segment from - /// position `begin` to position `end` with this plane. - /// If no intersection is found, `null` is returned. + /// position <paramref name="begin"/> to position <paramref name="end"/> with this plane. + /// If no intersection is found, <see langword="null"/> is returned. /// </summary> /// <param name="begin">The start of the line segment.</param> /// <param name="end">The end of the line segment.</param> - /// <returns>The intersection, or `null` if none is found.</returns> + /// <returns>The intersection, or <see langword="null"/> if none is found.</returns> public Vector3? IntersectSegment(Vector3 begin, Vector3 end) { Vector3 segment = begin - end; @@ -206,14 +206,14 @@ namespace Godot return null; } - return begin + segment * -dist; + return begin - (segment * dist); } /// <summary> - /// Returns true if `point` is located above the plane. + /// Returns <see langword="true"/> if <paramref name="point"/> is located above the plane. /// </summary> /// <param name="point">The point to check.</param> - /// <returns>A bool for whether or not the point is above the plane.</returns> + /// <returns>A <see langword="bool"/> for whether or not the point is above the plane.</returns> public bool IsPointOver(Vector3 point) { return _normal.Dot(point) > D; @@ -236,13 +236,13 @@ namespace Godot } /// <summary> - /// Returns the orthogonal projection of `point` into the plane. + /// Returns the orthogonal projection of <paramref name="point"/> into the plane. /// </summary> /// <param name="point">The point to project.</param> /// <returns>The projected point.</returns> public Vector3 Project(Vector3 point) { - return point - _normal * DistanceTo(point); + return point - (_normal * DistanceTo(point)); } // Constants @@ -251,27 +251,28 @@ namespace Godot private static readonly Plane _planeXY = new Plane(0, 0, 1, 0); /// <summary> - /// A plane that extends in the Y and Z axes (normal vector points +X). + /// A <see cref="Plane"/> that extends in the Y and Z axes (normal vector points +X). /// </summary> - /// <value>Equivalent to `new Plane(1, 0, 0, 0)`.</value> + /// <value>Equivalent to <c>new Plane(1, 0, 0, 0)</c>.</value> public static Plane PlaneYZ { get { return _planeYZ; } } /// <summary> - /// A plane that extends in the X and Z axes (normal vector points +Y). + /// A <see cref="Plane"/> that extends in the X and Z axes (normal vector points +Y). /// </summary> - /// <value>Equivalent to `new Plane(0, 1, 0, 0)`.</value> + /// <value>Equivalent to <c>new Plane(0, 1, 0, 0)</c>.</value> public static Plane PlaneXZ { get { return _planeXZ; } } /// <summary> - /// A plane that extends in the X and Y axes (normal vector points +Z). + /// A <see cref="Plane"/> that extends in the X and Y axes (normal vector points +Z). /// </summary> - /// <value>Equivalent to `new Plane(0, 0, 1, 0)`.</value> + /// <value>Equivalent to <c>new Plane(0, 0, 1, 0)</c>.</value> public static Plane PlaneXY { get { return _planeXY; } } /// <summary> - /// Constructs a plane from four values. `a`, `b` and `c` become the + /// Constructs a <see cref="Plane"/> from four values. + /// <paramref name="a"/>, <paramref name="b"/> and <paramref name="c"/> become the /// components of the resulting plane's <see cref="Normal"/> vector. - /// `d` becomes the plane's distance from the origin. + /// <paramref name="d"/> becomes the plane's distance from the origin. /// </summary> /// <param name="a">The X component of the plane's normal vector.</param> /// <param name="b">The Y component of the plane's normal vector.</param> @@ -280,22 +281,23 @@ namespace Godot public Plane(real_t a, real_t b, real_t c, real_t d) { _normal = new Vector3(a, b, c); - this.D = d; + D = d; } /// <summary> - /// Constructs a plane from a normal vector and the plane's distance to the origin. + /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and + /// the plane's distance to the origin <paramref name="d"/>. /// </summary> /// <param name="normal">The normal of the plane, must be normalized.</param> /// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param> public Plane(Vector3 normal, real_t d) { - this._normal = normal; - this.D = d; + _normal = normal; + D = d; } /// <summary> - /// Constructs a plane from the three points, given in clockwise order. + /// Constructs a <see cref="Plane"/> from the three points, given in clockwise order. /// </summary> /// <param name="v1">The first point.</param> /// <param name="v2">The second point.</param> @@ -322,6 +324,11 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this plane and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the plane and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Plane) @@ -332,14 +339,19 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this plane and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other plane to compare.</param> + /// <returns>Whether or not the planes are equal.</returns> public bool Equals(Plane other) { return _normal == other._normal && D == other.D; } /// <summary> - /// Returns true if this plane and `other` are approximately equal, by running - /// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. + /// Returns <see langword="true"/> if this plane and <paramref name="other"/> are + /// approximately equal, by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. /// </summary> /// <param name="other">The other plane to compare.</param> /// <returns>Whether or not the planes are approximately equal.</returns> @@ -348,27 +360,31 @@ namespace Godot return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D); } + /// <summary> + /// Serves as the hash function for <see cref="Plane"/>. + /// </summary> + /// <returns>A hash code for this plane.</returns> public override int GetHashCode() { return _normal.GetHashCode() ^ D.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Plane"/> to a string. + /// </summary> + /// <returns>A string representation of this plane.</returns> public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - _normal.ToString(), - D.ToString() - }); + return $"{_normal}, {D}"; } + /// <summary> + /// Converts this <see cref="Plane"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this plane.</returns> 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/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index bd3bcb0c58..1694ac0320 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.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 { @@ -12,10 +12,10 @@ namespace Godot /// A unit quaternion used for representing 3D rotations. /// Quaternions need to be normalized to be used for rotation. /// - /// It is similar to Basis, which implements matrix representation of - /// rotations, and can be parametrized using both an axis-angle pair - /// or Euler angles. Basis stores rotation, scale, and shearing, - /// while Quat only stores rotation. + /// It is similar to <see cref="Basis"/>, which implements matrix + /// representation of rotations, and can be parametrized using both + /// an axis-angle pair or Euler angles. Basis stores rotation, scale, + /// and shearing, while Quaternion only stores rotation. /// /// Due to its compactness and the way it is stored in memory, certain /// operations (obtaining axis-angle and performing SLERP, in particular) @@ -23,22 +23,22 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Quat : IEquatable<Quat> + public struct Quaternion : IEquatable<Quaternion> { /// <summary> - /// X component of the quaternion (imaginary `i` axis part). + /// X component of the quaternion (imaginary <c>i</c> axis part). /// Quaternion components should usually not be manipulated directly. /// </summary> public real_t x; /// <summary> - /// Y component of the quaternion (imaginary `j` axis part). + /// Y component of the quaternion (imaginary <c>j</c> axis part). /// Quaternion components should usually not be manipulated directly. /// </summary> public real_t y; /// <summary> - /// Z component of the quaternion (imaginary `k` axis part). + /// Z component of the quaternion (imaginary <c>k</c> axis part). /// Quaternion components should usually not be manipulated directly. /// </summary> public real_t z; @@ -52,7 +52,12 @@ namespace Godot /// <summary> /// Access quaternion components using their index. /// </summary> - /// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`, `[2]` is equivalent to `.z`, `[3]` is equivalent to `.w`.</value> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>, + /// <c>[2]</c> is equivalent to <see cref="z"/>, + /// <c>[3]</c> is equivalent to <see cref="w"/>. + /// </value> public real_t this[int index] { get @@ -96,7 +101,8 @@ namespace Godot /// <summary> /// Returns the length (magnitude) of the quaternion. /// </summary> - /// <value>Equivalent to `Mathf.Sqrt(LengthSquared)`.</value> + /// <seealso cref="LengthSquared"/> + /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value> public real_t Length { get { return Mathf.Sqrt(LengthSquared); } @@ -107,26 +113,43 @@ namespace Godot /// This method runs faster than <see cref="Length"/>, so prefer it if /// you need to compare quaternions or need the squared length for some formula. /// </summary> - /// <value>Equivalent to `Dot(this)`.</value> + /// <value>Equivalent to <c>Dot(this)</c>.</value> public real_t LengthSquared { get { return Dot(this); } } /// <summary> - /// Performs a cubic spherical interpolation between quaternions `preA`, - /// this vector, `b`, and `postB`, by the given amount `t`. + /// Returns the angle between this quaternion and <paramref name="to"/>. + /// This is the magnitude of the angle you would need to rotate + /// by to get from one to the other. + /// + /// Note: This method has an abnormally high amount + /// of floating-point error, so methods such as + /// <see cref="Mathf.IsZeroApprox"/> will not work reliably. + /// </summary> + /// <param name="to">The other quaternion.</param> + /// <returns>The angle between the quaternions.</returns> + public real_t AngleTo(Quaternion to) + { + real_t dot = Dot(to); + return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1)); + } + + /// <summary> + /// Performs a cubic spherical interpolation between quaternions <paramref name="preA"/>, this quaternion, + /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>. /// </summary> /// <param name="b">The destination quaternion.</param> /// <param name="preA">A quaternion before this quaternion.</param> - /// <param name="postB">A quaternion after `b`.</param> + /// <param name="postB">A quaternion after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight) + public Quaternion CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight) { real_t t2 = (1.0f - weight) * weight * 2f; - Quat sp = Slerp(b, weight); - Quat sq = preA.Slerpni(postB, weight); + Quaternion sp = Slerp(b, weight); + Quaternion sq = preA.Slerpni(postB, weight); return sp.Slerpni(sq, t2); } @@ -135,9 +158,9 @@ namespace Godot /// </summary> /// <param name="b">The other quaternion.</param> /// <returns>The dot product.</returns> - public real_t Dot(Quat b) + public real_t Dot(Quaternion b) { - return x * b.x + y * b.y + z * b.z + w * b.w; + return (x * b.x) + (y * b.y) + (z * b.z) + (w * b.w); } /// <summary> @@ -152,7 +175,7 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var basis = new Basis(this); @@ -163,21 +186,21 @@ namespace Godot /// Returns the inverse of the quaternion. /// </summary> /// <returns>The inverse quaternion.</returns> - public Quat Inverse() + public Quaternion Inverse() { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif - return new Quat(-x, -y, -z, w); + return new Quaternion(-x, -y, -z, w); } /// <summary> /// Returns whether the quaternion is normalized or not. /// </summary> - /// <returns>A bool for whether the quaternion is normalized or not.</returns> + /// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns> public bool IsNormalized() { return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon; @@ -187,26 +210,26 @@ namespace Godot /// Returns a copy of the quaternion, normalized to unit length. /// </summary> /// <returns>The normalized quaternion.</returns> - public Quat Normalized() + public Quaternion Normalized() { return this / Length; } /// <summary> /// Returns the result of the spherical linear interpolation between - /// this quaternion and `to` by amount `weight`. + /// this quaternion and <paramref name="to"/> by amount <paramref name="weight"/>. /// /// Note: Both quaternions must be normalized. /// </summary> /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerp(Quat to, real_t weight) + public Quaternion Slerp(Quaternion to, real_t weight) { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } if (!to.IsNormalized()) { @@ -217,7 +240,7 @@ namespace Godot // Calculate cosine. real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w; - var to1 = new Quat(); + var to1 = new Quaternion(); // Adjust signs if necessary. if (cosom < 0.0) @@ -255,24 +278,24 @@ namespace Godot } // Calculate final values. - return new Quat + return new Quaternion ( - scale0 * x + scale1 * to1.x, - scale0 * y + scale1 * to1.y, - scale0 * z + scale1 * to1.z, - scale0 * w + scale1 * to1.w + (scale0 * x) + (scale1 * to1.x), + (scale0 * y) + (scale1 * to1.y), + (scale0 * z) + (scale1 * to1.z), + (scale0 * w) + (scale1 * to1.w) ); } /// <summary> /// Returns the result of the spherical linear interpolation between - /// this quaternion and `to` by amount `weight`, but without + /// this quaternion and <paramref name="to"/> by amount <paramref name="weight"/>, but without /// checking if the rotation path is not bigger than 90 degrees. /// </summary> /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerpni(Quat to, real_t weight) + public Quaternion Slerpni(Quaternion to, real_t weight) { real_t dot = Dot(to); @@ -286,12 +309,12 @@ namespace Godot real_t newFactor = Mathf.Sin(weight * theta) * sinT; real_t invFactor = Mathf.Sin((1.0f - weight) * theta) * sinT; - return new Quat + return new Quaternion ( - invFactor * x + newFactor * to.x, - invFactor * y + newFactor * to.y, - invFactor * z + newFactor * to.z, - invFactor * w + newFactor * to.w + (invFactor * x) + (newFactor * to.x), + (invFactor * y) + (newFactor * to.y), + (invFactor * z) + (newFactor * to.z), + (invFactor * w) + (newFactor * to.w) ); } @@ -305,33 +328,33 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var u = new Vector3(x, y, z); Vector3 uv = u.Cross(v); - return v + ((uv * w) + u.Cross(uv)) * 2; + return v + (((uv * w) + u.Cross(uv)) * 2); } // Constants - private static readonly Quat _identity = new Quat(0, 0, 0, 1); + private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1); /// <summary> /// The identity quaternion, representing no rotation. /// Equivalent to an identity <see cref="Basis"/> matrix. If a vector is transformed by /// an identity quaternion, it will not change. /// </summary> - /// <value>Equivalent to `new Quat(0, 0, 0, 1)`.</value> - public static Quat Identity { get { return _identity; } } + /// <value>Equivalent to <c>new Quaternion(0, 0, 0, 1)</c>.</value> + public static Quaternion Identity { get { return _identity; } } /// <summary> - /// Constructs a quaternion defined by the given values. + /// Constructs a <see cref="Quaternion"/> defined by the given values. /// </summary> - /// <param name="x">X component of the quaternion (imaginary `i` axis part).</param> - /// <param name="y">Y component of the quaternion (imaginary `j` axis part).</param> - /// <param name="z">Z component of the quaternion (imaginary `k` axis part).</param> + /// <param name="x">X component of the quaternion (imaginary <c>i</c> axis part).</param> + /// <param name="y">Y component of the quaternion (imaginary <c>j</c> axis part).</param> + /// <param name="z">Z component of the quaternion (imaginary <c>k</c> axis part).</param> /// <param name="w">W component of the quaternion (real part).</param> - public Quat(real_t x, real_t y, real_t z, real_t w) + public Quaternion(real_t x, real_t y, real_t z, real_t w) { this.x = x; this.y = y; @@ -340,60 +363,59 @@ namespace Godot } /// <summary> - /// Constructs a quaternion from the given quaternion. + /// Constructs a <see cref="Quaternion"/> from the given <see cref="Quaternion"/>. /// </summary> /// <param name="q">The existing quaternion.</param> - public Quat(Quat q) + public Quaternion(Quaternion q) { this = q; } /// <summary> - /// Constructs a quaternion from the given <see cref="Basis"/>. + /// Constructs a <see cref="Quaternion"/> from the given <see cref="Basis"/>. /// </summary> - /// <param name="basis">The basis to construct from.</param> - public Quat(Basis basis) + /// <param name="basis">The <see cref="Basis"/> to construct from.</param> + public Quaternion(Basis basis) { - this = basis.Quat(); + this = basis.Quaternion(); } /// <summary> - /// Constructs a quaternion that will perform a rotation specified by - /// Euler angles (in the YXZ convention: when decomposing, - /// first Z, then X, and Y last), + /// Constructs a <see cref="Quaternion"/> that will perform a rotation specified by + /// Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), /// given in the vector format as (X angle, Y angle, Z angle). /// </summary> - /// <param name="eulerYXZ"></param> - public Quat(Vector3 eulerYXZ) + /// <param name="eulerYXZ">Euler angles that the quaternion will be rotated by.</param> + public Quaternion(Vector3 eulerYXZ) { - real_t half_a1 = eulerYXZ.y * 0.5f; - real_t half_a2 = eulerYXZ.x * 0.5f; - real_t half_a3 = eulerYXZ.z * 0.5f; + real_t halfA1 = eulerYXZ.y * 0.5f; + real_t halfA2 = eulerYXZ.x * 0.5f; + real_t halfA3 = eulerYXZ.z * 0.5f; // R = Y(a1).X(a2).Z(a3) convention for Euler angles. // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) // a3 is the angle of the first rotation, following the notation in this reference. - real_t cos_a1 = Mathf.Cos(half_a1); - real_t sin_a1 = Mathf.Sin(half_a1); - real_t cos_a2 = Mathf.Cos(half_a2); - real_t sin_a2 = Mathf.Sin(half_a2); - real_t cos_a3 = Mathf.Cos(half_a3); - real_t sin_a3 = Mathf.Sin(half_a3); + real_t cosA1 = Mathf.Cos(halfA1); + real_t sinA1 = Mathf.Sin(halfA1); + real_t cosA2 = Mathf.Cos(halfA2); + real_t sinA2 = Mathf.Sin(halfA2); + real_t cosA3 = Mathf.Cos(halfA3); + real_t sinA3 = Mathf.Sin(halfA3); - x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3; - y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3; - z = cos_a1 * cos_a2 * sin_a3 - sin_a1 * sin_a2 * cos_a3; - w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3; + x = (sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3); + y = (sinA1 * cosA2 * cosA3) - (cosA1 * sinA2 * sinA3); + z = (cosA1 * cosA2 * sinA3) - (sinA1 * sinA2 * cosA3); + w = (sinA1 * sinA2 * sinA3) + (cosA1 * cosA2 * cosA3); } /// <summary> - /// Constructs a quaternion that will rotate around the given axis + /// Constructs a <see cref="Quaternion"/> that will rotate around the given axis /// by the specified angle. The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> - public Quat(Vector3 axis, real_t angle) + public Quaternion(Vector3 axis, real_t angle) { #if DEBUG if (!axis.IsNormalized()) @@ -424,118 +446,140 @@ namespace Godot } } - public static Quat operator *(Quat left, Quat right) + public static Quaternion operator *(Quaternion left, Quaternion right) { - return new Quat + return new Quaternion ( - left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, - left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z, - left.w * right.z + left.z * right.w + left.x * right.y - left.y * right.x, - left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z + (left.w * right.x) + (left.x * right.w) + (left.y * right.z) - (left.z * right.y), + (left.w * right.y) + (left.y * right.w) + (left.z * right.x) - (left.x * right.z), + (left.w * right.z) + (left.z * right.w) + (left.x * right.y) - (left.y * right.x), + (left.w * right.w) - (left.x * right.x) - (left.y * right.y) - (left.z * right.z) ); } - public static Quat operator +(Quat left, Quat right) + public static Quaternion operator +(Quaternion left, Quaternion right) { - return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + return new Quaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); } - public static Quat operator -(Quat left, Quat right) + public static Quaternion operator -(Quaternion left, Quaternion right) { - return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + return new Quaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); } - public static Quat operator -(Quat left) + public static Quaternion operator -(Quaternion left) { - return new Quat(-left.x, -left.y, -left.z, -left.w); + return new Quaternion(-left.x, -left.y, -left.z, -left.w); } - public static Quat operator *(Quat left, Vector3 right) + public static Quaternion operator *(Quaternion left, Vector3 right) { - return new Quat + return new Quaternion ( - left.w * right.x + left.y * right.z - left.z * right.y, - left.w * right.y + left.z * right.x - left.x * right.z, - left.w * right.z + left.x * right.y - left.y * right.x, - -left.x * right.x - left.y * right.y - left.z * right.z + (left.w * right.x) + (left.y * right.z) - (left.z * right.y), + (left.w * right.y) + (left.z * right.x) - (left.x * right.z), + (left.w * right.z) + (left.x * right.y) - (left.y * right.x), + -(left.x * right.x) - (left.y * right.y) - (left.z * right.z) ); } - public static Quat operator *(Vector3 left, Quat right) + public static Quaternion operator *(Vector3 left, Quaternion right) { - return new Quat + return new Quaternion ( - right.w * left.x + right.y * left.z - right.z * left.y, - right.w * left.y + right.z * left.x - right.x * left.z, - right.w * left.z + right.x * left.y - right.y * left.x, - -right.x * left.x - right.y * left.y - right.z * left.z + (right.w * left.x) + (right.y * left.z) - (right.z * left.y), + (right.w * left.y) + (right.z * left.x) - (right.x * left.z), + (right.w * left.z) + (right.x * left.y) - (right.y * left.x), + -(right.x * left.x) - (right.y * left.y) - (right.z * left.z) ); } - public static Quat operator *(Quat left, real_t right) + public static Quaternion operator *(Quaternion left, real_t right) { - return new Quat(left.x * right, left.y * right, left.z * right, left.w * right); + return new Quaternion(left.x * right, left.y * right, left.z * right, left.w * right); } - public static Quat operator *(real_t left, Quat right) + public static Quaternion operator *(real_t left, Quaternion right) { - return new Quat(right.x * left, right.y * left, right.z * left, right.w * left); + return new Quaternion(right.x * left, right.y * left, right.z * left, right.w * left); } - public static Quat operator /(Quat left, real_t right) + public static Quaternion operator /(Quaternion left, real_t right) { return left * (1.0f / right); } - public static bool operator ==(Quat left, Quat right) + public static bool operator ==(Quaternion left, Quaternion right) { return left.Equals(right); } - public static bool operator !=(Quat left, Quat right) + public static bool operator !=(Quaternion left, Quaternion right) { return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this quaternion and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the quaternion and the other object are equal.</returns> public override bool Equals(object obj) { - if (obj is Quat) + if (obj is Quaternion) { - return Equals((Quat)obj); + return Equals((Quaternion)obj); } return false; } - public bool Equals(Quat other) + /// <summary> + /// Returns <see langword="true"/> if this quaternion and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other quaternion to compare.</param> + /// <returns>Whether or not the quaternions are equal.</returns> + public bool Equals(Quaternion other) { return x == other.x && y == other.y && z == other.z && w == other.w; } /// <summary> - /// Returns true if this quaternion and `other` are approximately equal, by running - /// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. + /// Returns <see langword="true"/> if this quaternion and <paramref name="other"/> are approximately equal, + /// by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. /// </summary> /// <param name="other">The other quaternion to compare.</param> /// <returns>Whether or not the quaternions are approximately equal.</returns> - public bool IsEqualApprox(Quat other) + public bool IsEqualApprox(Quaternion other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } + /// <summary> + /// Serves as the hash function for <see cref="Quaternion"/>. + /// </summary> + /// <returns>A hash code for this quaternion.</returns> public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Quaternion"/> to a string. + /// </summary> + /// <returns>A string representation of this quaternion.</returns> public override string ToString() { - return String.Format("({0}, {1}, {2}, {3})", x.ToString(), y.ToString(), z.ToString(), w.ToString()); + return $"({x}, {y}, {z}, {w})"; } + /// <summary> + /// Converts this <see cref="Quaternion"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this quaternion.</returns> 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/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs index 94761531b1..1588869ec0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs @@ -3,9 +3,15 @@ using System.Runtime.CompilerServices; namespace Godot { + /// <summary> + /// The RID type is used to access the unique integer ID of a resource. + /// They are opaque, which means they do not grant access to the associated + /// resource by themselves. They are used by and with the low-level Server + /// classes such as <see cref="RenderingServer"/>. + /// </summary> public sealed partial class RID : IDisposable { - private bool disposed = false; + private bool _disposed = false; internal IntPtr ptr; @@ -14,7 +20,7 @@ namespace Godot if (instance == null) throw new NullReferenceException($"The instance of type {nameof(RID)} is null."); - if (instance.disposed) + if (instance._disposed) throw new ObjectDisposedException(instance.GetType().FullName); return instance.ptr; @@ -25,6 +31,9 @@ namespace Godot Dispose(false); } + /// <summary> + /// Disposes of this <see cref="RID"/>. + /// </summary> public void Dispose() { Dispose(true); @@ -33,7 +42,7 @@ namespace Godot private void Dispose(bool disposing) { - if (disposed) + if (_disposed) return; if (ptr != IntPtr.Zero) @@ -42,7 +51,7 @@ namespace Godot ptr = IntPtr.Zero; } - disposed = true; + _disposed = true; } internal RID(IntPtr ptr) @@ -50,6 +59,9 @@ namespace Godot this.ptr = ptr; } + /// <summary> + /// The pointer to the native instance of this <see cref="RID"/>. + /// </summary> public IntPtr NativeInstance { get { return ptr; } @@ -60,25 +72,36 @@ namespace Godot this.ptr = IntPtr.Zero; } + /// <summary> + /// Constructs a new <see cref="RID"/> for the given <see cref="Object"/> <paramref name="from"/>. + /// </summary> public RID(Object from) { this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from)); } + /// <summary> + /// Returns the ID of the referenced resource. + /// </summary> + /// <returns>The ID of the referenced resource.</returns> public int GetId() { - return godot_icall_RID_get_id(RID.GetPtr(this)); + return godot_icall_RID_get_id(GetPtr(this)); } + /// <summary> + /// Converts this <see cref="RID"/> to a string. + /// </summary> + /// <returns>A string representation of this RID.</returns> public override string ToString() => "[RID]"; [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static IntPtr godot_icall_RID_Ctor(IntPtr from); + internal static extern IntPtr godot_icall_RID_Ctor(IntPtr from); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static void godot_icall_RID_Dtor(IntPtr ptr); + internal static extern void godot_icall_RID_Dtor(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_RID_get_id(IntPtr ptr); + internal static extern int godot_icall_RID_get_id(IntPtr ptr); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index 868c3536fe..1d001fba2d 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 { @@ -20,7 +20,7 @@ namespace Godot private Vector2 _size; /// <summary> - /// Beginning corner. Typically has values lower than End. + /// Beginning corner. Typically has values lower than <see cref="End"/>. /// </summary> /// <value>Directly uses a private field.</value> public Vector2 Position @@ -30,7 +30,7 @@ namespace Godot } /// <summary> - /// Size from Position to End. Typically all components are positive. + /// Size from <see cref="Position"/> to <see cref="End"/>. Typically all components are positive. /// If the size is negative, you can use <see cref="Abs"/> to fix it. /// </summary> /// <value>Directly uses a private field.</value> @@ -41,10 +41,13 @@ namespace Godot } /// <summary> - /// Ending corner. This is calculated as <see cref="Position"/> plus - /// <see cref="Size"/>. Setting this value will change the size. + /// Ending corner. This is calculated as <see cref="Position"/> plus <see cref="Size"/>. + /// Setting this value will change the size. /// </summary> - /// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value> + /// <value> + /// Getting is equivalent to <paramref name="value"/> = <see cref="Position"/> + <see cref="Size"/>, + /// setting is equivalent to <see cref="Size"/> = <paramref name="value"/> - <see cref="Position"/> + /// </value> public Vector2 End { get { return _position + _size; } @@ -52,7 +55,7 @@ namespace Godot } /// <summary> - /// The area of this Rect2. + /// The area of this <see cref="Rect2"/>. /// </summary> /// <value>Equivalent to <see cref="GetArea()"/>.</value> public real_t Area @@ -61,10 +64,10 @@ namespace Godot } /// <summary> - /// Returns a Rect2 with equivalent position and size, modified so that + /// Returns a <see cref="Rect2"/> with equivalent position and size, modified so that /// the top-left corner is the origin and width and height are positive. /// </summary> - /// <returns>The modified Rect2.</returns> + /// <returns>The modified <see cref="Rect2"/>.</returns> public Rect2 Abs() { Vector2 end = End; @@ -73,14 +76,17 @@ namespace Godot } /// <summary> - /// Returns the intersection of this Rect2 and `b`. - /// If the rectangles do not intersect, an empty Rect2 is returned. + /// Returns the intersection of this <see cref="Rect2"/> and <paramref name="b"/>. + /// If the rectangles do not intersect, an empty <see cref="Rect2"/> is returned. /// </summary> - /// <param name="b">The other Rect2.</param> - /// <returns>The intersection of this Rect2 and `b`, or an empty Rect2 if they do not intersect.</returns> + /// <param name="b">The other <see cref="Rect2"/>.</param> + /// <returns> + /// The intersection of this <see cref="Rect2"/> and <paramref name="b"/>, + /// or an empty <see cref="Rect2"/> if they do not intersect. + /// </returns> public Rect2 Intersection(Rect2 b) { - var newRect = b; + Rect2 newRect = b; if (!Intersects(newRect)) { @@ -100,10 +106,12 @@ namespace Godot } /// <summary> - /// Returns true if this Rect2 completely encloses another one. + /// Returns <see langword="true"/> if this <see cref="Rect2"/> completely encloses another one. /// </summary> - /// <param name="b">The other Rect2 that may be enclosed.</param> - /// <returns>A bool for whether or not this Rect2 encloses `b`.</returns> + /// <param name="b">The other <see cref="Rect2"/> that may be enclosed.</param> + /// <returns> + /// A <see langword="bool"/> for whether or not this <see cref="Rect2"/> encloses <paramref name="b"/>. + /// </returns> public bool Encloses(Rect2 b) { return b._position.x >= _position.x && b._position.y >= _position.y && @@ -112,13 +120,13 @@ namespace Godot } /// <summary> - /// Returns this Rect2 expanded to include a given point. + /// Returns this <see cref="Rect2"/> expanded to include a given point. /// </summary> /// <param name="to">The point to include.</param> - /// <returns>The expanded Rect2.</returns> + /// <returns>The expanded <see cref="Rect2"/>.</returns> public Rect2 Expand(Vector2 to) { - var expanded = this; + Rect2 expanded = this; Vector2 begin = expanded._position; Vector2 end = expanded._position + expanded._size; @@ -148,7 +156,7 @@ namespace Godot } /// <summary> - /// Returns the area of the Rect2. + /// Returns the area of the <see cref="Rect2"/>. /// </summary> /// <returns>The area.</returns> public real_t GetArea() @@ -157,13 +165,16 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2 grown by the specified amount on all sides. + /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount + /// on all sides. /// </summary> + /// <seealso cref="GrowIndividual(real_t, real_t, real_t, real_t)"/> + /// <seealso cref="GrowSide(Side, real_t)"/> /// <param name="by">The amount to grow by.</param> - /// <returns>The grown Rect2.</returns> + /// <returns>The grown <see cref="Rect2"/>.</returns> public Rect2 Grow(real_t by) { - var g = this; + Rect2 g = this; g._position.x -= by; g._position.y -= by; @@ -174,16 +185,19 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2 grown by the specified amount on each side individually. + /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount + /// on each side individually. /// </summary> + /// <seealso cref="Grow(real_t)"/> + /// <seealso cref="GrowSide(Side, real_t)"/> /// <param name="left">The amount to grow by on the left side.</param> /// <param name="top">The amount to grow by on the top side.</param> /// <param name="right">The amount to grow by on the right side.</param> /// <param name="bottom">The amount to grow by on the bottom side.</param> - /// <returns>The grown Rect2.</returns> + /// <returns>The grown <see cref="Rect2"/>.</returns> public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom) { - var g = this; + Rect2 g = this; g._position.x -= left; g._position.y -= top; @@ -194,14 +208,17 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2 grown by the specified amount on the specified Side. + /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount + /// on the specified <see cref="Side"/>. /// </summary> + /// <seealso cref="Grow(real_t)"/> + /// <seealso cref="GrowIndividual(real_t, real_t, real_t, real_t)"/> /// <param name="side">The side to grow.</param> /// <param name="by">The amount to grow by.</param> - /// <returns>The grown Rect2.</returns> + /// <returns>The grown <see cref="Rect2"/>.</returns> public Rect2 GrowSide(Side side, real_t by) { - var g = this; + Rect2 g = this; g = g.GrowIndividual(Side.Left == side ? by : 0, Side.Top == side ? by : 0, @@ -212,19 +229,25 @@ namespace Godot } /// <summary> - /// Returns true if the Rect2 is flat or empty, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="Rect2"/> is flat or empty, + /// or <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool for whether or not the Rect2 has area.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> has area. + /// </returns> public bool HasNoArea() { return _size.x <= 0 || _size.y <= 0; } /// <summary> - /// Returns true if the Rect2 contains a point, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="Rect2"/> contains a point, + /// or <see langword="false"/> otherwise. /// </summary> /// <param name="point">The point to check.</param> - /// <returns>A bool for whether or not the Rect2 contains `point`.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="Rect2"/> contains <paramref name="point"/>. + /// </returns> public bool HasPoint(Vector2 point) { if (point.x < _position.x) @@ -241,15 +264,16 @@ namespace Godot } /// <summary> - /// Returns true if the Rect2 overlaps with `b` + /// Returns <see langword="true"/> if the <see cref="Rect2"/> overlaps with <paramref name="b"/> /// (i.e. they have at least one point in common). /// - /// If `includeBorders` is true, they will also be considered overlapping - /// if their borders touch, even without intersection. + /// If <paramref name="includeBorders"/> is <see langword="true"/>, + /// they will also be considered overlapping if their borders touch, + /// even without intersection. /// </summary> - /// <param name="b">The other Rect2 to check for intersections with.</param> + /// <param name="b">The other <see cref="Rect2"/> to check for intersections with.</param> /// <param name="includeBorders">Whether or not to consider borders.</param> - /// <returns>A bool for whether or not they are intersecting.</returns> + /// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns> public bool Intersects(Rect2 b, bool includeBorders = false) { if (includeBorders) @@ -295,10 +319,10 @@ namespace Godot } /// <summary> - /// Returns a larger Rect2 that contains this Rect2 and `b`. + /// Returns a larger <see cref="Rect2"/> that contains this <see cref="Rect2"/> and <paramref name="b"/>. /// </summary> - /// <param name="b">The other Rect2.</param> - /// <returns>The merged Rect2.</returns> + /// <param name="b">The other <see cref="Rect2"/>.</param> + /// <returns>The merged <see cref="Rect2"/>.</returns> public Rect2 Merge(Rect2 b) { Rect2 newRect; @@ -315,7 +339,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2 from a position and size. + /// Constructs a <see cref="Rect2"/> from a position and size. /// </summary> /// <param name="position">The position.</param> /// <param name="size">The size.</param> @@ -326,7 +350,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2 from a position, width, and height. + /// Constructs a <see cref="Rect2"/> from a position, width, and height. /// </summary> /// <param name="position">The position.</param> /// <param name="width">The width.</param> @@ -338,7 +362,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2 from x, y, and size. + /// Constructs a <see cref="Rect2"/> from x, y, and size. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -350,7 +374,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2 from x, y, width, and height. + /// Constructs a <see cref="Rect2"/> from x, y, width, and height. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -372,6 +396,11 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this rect and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the rect and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Rect2) @@ -382,43 +411,52 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this rect and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other rect to compare.</param> + /// <returns>Whether or not the rects are equal.</returns> public bool Equals(Rect2 other) { return _position.Equals(other._position) && _size.Equals(other._size); } /// <summary> - /// Returns true if this Rect2 and `other` are approximately equal, by running - /// <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component. + /// Returns <see langword="true"/> if this rect and <paramref name="other"/> are approximately equal, + /// by running <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component. /// </summary> - /// <param name="other">The other Rect2 to compare.</param> - /// <returns>Whether or not the Rect2s are approximately equal.</returns> + /// <param name="other">The other rect to compare.</param> + /// <returns>Whether or not the rects are approximately equal.</returns> public bool IsEqualApprox(Rect2 other) { return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size); } + /// <summary> + /// Serves as the hash function for <see cref="Rect2"/>. + /// </summary> + /// <returns>A hash code for this rect.</returns> public override int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Rect2"/> to a string. + /// </summary> + /// <returns>A string representation of this rect.</returns> public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } + /// <summary> + /// Converts this <see cref="Rect2"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this rect.</returns> 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..250b0d0baf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs @@ -15,7 +15,7 @@ namespace Godot private Vector2i _size; /// <summary> - /// Beginning corner. Typically has values lower than End. + /// Beginning corner. Typically has values lower than <see cref="End"/>. /// </summary> /// <value>Directly uses a private field.</value> public Vector2i Position @@ -25,7 +25,7 @@ namespace Godot } /// <summary> - /// Size from Position to End. Typically all components are positive. + /// Size from <see cref="Position"/> to <see cref="End"/>. Typically all components are positive. /// If the size is negative, you can use <see cref="Abs"/> to fix it. /// </summary> /// <value>Directly uses a private field.</value> @@ -36,10 +36,13 @@ namespace Godot } /// <summary> - /// Ending corner. This is calculated as <see cref="Position"/> plus - /// <see cref="Size"/>. Setting this value will change the size. + /// Ending corner. This is calculated as <see cref="Position"/> plus <see cref="Size"/>. + /// Setting this value will change the size. /// </summary> - /// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value> + /// <value> + /// Getting is equivalent to <paramref name="value"/> = <see cref="Position"/> + <see cref="Size"/>, + /// setting is equivalent to <see cref="Size"/> = <paramref name="value"/> - <see cref="Position"/> + /// </value> public Vector2i End { get { return _position + _size; } @@ -47,7 +50,7 @@ namespace Godot } /// <summary> - /// The area of this Rect2i. + /// The area of this <see cref="Rect2i"/>. /// </summary> /// <value>Equivalent to <see cref="GetArea()"/>.</value> public int Area @@ -56,10 +59,10 @@ namespace Godot } /// <summary> - /// Returns a Rect2i with equivalent position and size, modified so that + /// Returns a <see cref="Rect2i"/> with equivalent position and size, modified so that /// the top-left corner is the origin and width and height are positive. /// </summary> - /// <returns>The modified Rect2i.</returns> + /// <returns>The modified <see cref="Rect2i"/>.</returns> public Rect2i Abs() { Vector2i end = End; @@ -68,14 +71,17 @@ namespace Godot } /// <summary> - /// Returns the intersection of this Rect2i and `b`. - /// If the rectangles do not intersect, an empty Rect2i is returned. + /// Returns the intersection of this <see cref="Rect2i"/> and <paramref name="b"/>. + /// If the rectangles do not intersect, an empty <see cref="Rect2i"/> is returned. /// </summary> - /// <param name="b">The other Rect2i.</param> - /// <returns>The intersection of this Rect2i and `b`, or an empty Rect2i if they do not intersect.</returns> + /// <param name="b">The other <see cref="Rect2i"/>.</param> + /// <returns> + /// The intersection of this <see cref="Rect2i"/> and <paramref name="b"/>, + /// or an empty <see cref="Rect2i"/> if they do not intersect. + /// </returns> public Rect2i Intersection(Rect2i b) { - var newRect = b; + Rect2i newRect = b; if (!Intersects(newRect)) { @@ -95,10 +101,12 @@ namespace Godot } /// <summary> - /// Returns true if this Rect2i completely encloses another one. + /// Returns <see langword="true"/> if this <see cref="Rect2i"/> completely encloses another one. /// </summary> - /// <param name="b">The other Rect2i that may be enclosed.</param> - /// <returns>A bool for whether or not this Rect2i encloses `b`.</returns> + /// <param name="b">The other <see cref="Rect2i"/> that may be enclosed.</param> + /// <returns> + /// A <see langword="bool"/> for whether or not this <see cref="Rect2i"/> encloses <paramref name="b"/>. + /// </returns> public bool Encloses(Rect2i b) { return b._position.x >= _position.x && b._position.y >= _position.y && @@ -107,13 +115,13 @@ namespace Godot } /// <summary> - /// Returns this Rect2i expanded to include a given point. + /// Returns this <see cref="Rect2i"/> expanded to include a given point. /// </summary> /// <param name="to">The point to include.</param> - /// <returns>The expanded Rect2i.</returns> + /// <returns>The expanded <see cref="Rect2i"/>.</returns> public Rect2i Expand(Vector2i to) { - var expanded = this; + Rect2i expanded = this; Vector2i begin = expanded._position; Vector2i end = expanded._position + expanded._size; @@ -143,7 +151,7 @@ namespace Godot } /// <summary> - /// Returns the area of the Rect2. + /// Returns the area of the <see cref="Rect2"/>. /// </summary> /// <returns>The area.</returns> public int GetArea() @@ -152,13 +160,16 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2i grown by the specified amount on all sides. + /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount + /// on all sides. /// </summary> + /// <seealso cref="GrowIndividual(int, int, int, int)"/> + /// <seealso cref="GrowSide(Side, int)"/> /// <param name="by">The amount to grow by.</param> - /// <returns>The grown Rect2i.</returns> + /// <returns>The grown <see cref="Rect2i"/>.</returns> public Rect2i Grow(int by) { - var g = this; + Rect2i g = this; g._position.x -= by; g._position.y -= by; @@ -169,16 +180,19 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2i grown by the specified amount on each side individually. + /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount + /// on each side individually. /// </summary> + /// <seealso cref="Grow(int)"/> + /// <seealso cref="GrowSide(Side, int)"/> /// <param name="left">The amount to grow by on the left side.</param> /// <param name="top">The amount to grow by on the top side.</param> /// <param name="right">The amount to grow by on the right side.</param> /// <param name="bottom">The amount to grow by on the bottom side.</param> - /// <returns>The grown Rect2i.</returns> + /// <returns>The grown <see cref="Rect2i"/>.</returns> public Rect2i GrowIndividual(int left, int top, int right, int bottom) { - var g = this; + Rect2i g = this; g._position.x -= left; g._position.y -= top; @@ -189,14 +203,17 @@ namespace Godot } /// <summary> - /// Returns a copy of the Rect2i grown by the specified amount on the specified Side. + /// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount + /// on the specified <see cref="Side"/>. /// </summary> + /// <seealso cref="Grow(int)"/> + /// <seealso cref="GrowIndividual(int, int, int, int)"/> /// <param name="side">The side to grow.</param> /// <param name="by">The amount to grow by.</param> - /// <returns>The grown Rect2i.</returns> + /// <returns>The grown <see cref="Rect2i"/>.</returns> public Rect2i GrowSide(Side side, int by) { - var g = this; + Rect2i g = this; g = g.GrowIndividual(Side.Left == side ? by : 0, Side.Top == side ? by : 0, @@ -207,19 +224,25 @@ namespace Godot } /// <summary> - /// Returns true if the Rect2i is flat or empty, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="Rect2i"/> is flat or empty, + /// or <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool for whether or not the Rect2i has area.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> has area. + /// </returns> public bool HasNoArea() { return _size.x <= 0 || _size.y <= 0; } /// <summary> - /// Returns true if the Rect2i contains a point, or false otherwise. + /// Returns <see langword="true"/> if the <see cref="Rect2i"/> contains a point, + /// or <see langword="false"/> otherwise. /// </summary> /// <param name="point">The point to check.</param> - /// <returns>A bool for whether or not the Rect2i contains `point`.</returns> + /// <returns> + /// A <see langword="bool"/> for whether or not the <see cref="Rect2i"/> contains <paramref name="point"/>. + /// </returns> public bool HasPoint(Vector2i point) { if (point.x < _position.x) @@ -236,15 +259,16 @@ namespace Godot } /// <summary> - /// Returns true if the Rect2i overlaps with `b` + /// Returns <see langword="true"/> if the <see cref="Rect2i"/> overlaps with <paramref name="b"/> /// (i.e. they have at least one point in common). /// - /// If `includeBorders` is true, they will also be considered overlapping - /// if their borders touch, even without intersection. + /// If <paramref name="includeBorders"/> is <see langword="true"/>, + /// they will also be considered overlapping if their borders touch, + /// even without intersection. /// </summary> - /// <param name="b">The other Rect2i to check for intersections with.</param> + /// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param> /// <param name="includeBorders">Whether or not to consider borders.</param> - /// <returns>A bool for whether or not they are intersecting.</returns> + /// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns> public bool Intersects(Rect2i b, bool includeBorders = false) { if (includeBorders) @@ -274,10 +298,10 @@ namespace Godot } /// <summary> - /// Returns a larger Rect2i that contains this Rect2i and `b`. + /// Returns a larger <see cref="Rect2i"/> that contains this <see cref="Rect2i"/> and <paramref name="b"/>. /// </summary> - /// <param name="b">The other Rect2i.</param> - /// <returns>The merged Rect2i.</returns> + /// <param name="b">The other <see cref="Rect2i"/>.</param> + /// <returns>The merged <see cref="Rect2i"/>.</returns> public Rect2i Merge(Rect2i b) { Rect2i newRect; @@ -294,7 +318,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2i from a position and size. + /// Constructs a <see cref="Rect2i"/> from a position and size. /// </summary> /// <param name="position">The position.</param> /// <param name="size">The size.</param> @@ -305,7 +329,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2i from a position, width, and height. + /// Constructs a <see cref="Rect2i"/> from a position, width, and height. /// </summary> /// <param name="position">The position.</param> /// <param name="width">The width.</param> @@ -317,7 +341,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2i from x, y, and size. + /// Constructs a <see cref="Rect2i"/> from x, y, and size. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -329,7 +353,7 @@ namespace Godot } /// <summary> - /// Constructs a Rect2i from x, y, width, and height. + /// Constructs a <see cref="Rect2i"/> from x, y, width, and height. /// </summary> /// <param name="x">The position's X coordinate.</param> /// <param name="y">The position's Y coordinate.</param> @@ -351,16 +375,29 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Converts this <see cref="Rect2i"/> to a <see cref="Rect2"/>. + /// </summary> + /// <param name="value">The rect to convert.</param> public static implicit operator Rect2(Rect2i value) { return new Rect2(value._position, value._size); } + /// <summary> + /// Converts a <see cref="Rect2"/> to a <see cref="Rect2i"/>. + /// </summary> + /// <param name="value">The rect to convert.</param> public static explicit operator Rect2i(Rect2 value) { return new Rect2i((Vector2i)value.Position, (Vector2i)value.Size); } + /// <summary> + /// Returns <see langword="true"/> if this rect and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the rect and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Rect2i) @@ -371,32 +408,41 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this rect and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other rect to compare.</param> + /// <returns>Whether or not the rects are equal.</returns> public bool Equals(Rect2i other) { return _position.Equals(other._position) && _size.Equals(other._size); } + /// <summary> + /// Serves as the hash function for <see cref="Rect2i"/>. + /// </summary> + /// <returns>A hash code for this rect.</returns> public override int GetHashCode() { return _position.GetHashCode() ^ _size.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Rect2i"/> to a string. + /// </summary> + /// <returns>A string representation of this rect.</returns> public override string ToString() { - return String.Format("{0}, {1}", new object[] - { - _position.ToString(), - _size.ToString() - }); + return $"{_position}, {_size}"; } + /// <summary> + /// Converts this <see cref="Rect2i"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this rect.</returns> 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/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs index 4dc630238b..2ba0493002 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs @@ -5,9 +5,9 @@ namespace Godot { public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]> { - private bool completed; - private object[] result; - private Action action; + private bool _completed; + private object[] _result; + private Action _action; public SignalAwaiter(Object source, StringName signal, Object target) { @@ -15,24 +15,24 @@ namespace Godot } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter); + internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter); public bool IsCompleted { get { - return completed; + return _completed; } } public void OnCompleted(Action action) { - this.action = action; + this._action = action; } public object[] GetResult() { - return result; + return _result; } public IAwaiter<object[]> GetAwaiter() @@ -42,13 +42,9 @@ namespace Godot internal void SignalCallback(object[] args) { - completed = true; - result = args; - - if (action != null) - { - action(); - } + _completed = true; + _result = args; + _action?.Invoke(); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs index dc92de7a61..5680c9d55a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs @@ -1,13 +1,28 @@ namespace Godot { + /// <summary> + /// Represents a signal defined in an object. + /// </summary> public struct SignalInfo { private readonly Object _owner; private readonly StringName _signalName; + /// <summary> + /// Object that contains the signal. + /// </summary> public Object Owner => _owner; + /// <summary> + /// Name of the signal. + /// </summary> public StringName Name => _signalName; + /// <summary> + /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/> + /// in the specified <paramref name="owner"/>. + /// </summary> + /// <param name="owner">Object that contains the signal.</param> + /// <param name="name">Name of the signal.</param> public SignalInfo(Object owner, StringName name) { _owner = owner; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 98efa89ef0..6b3eb09581 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -8,6 +8,9 @@ using System.Text.RegularExpressions; namespace Godot { + /// <summary> + /// Extension methods to manipulate strings. + /// </summary> public static class StringExtensions { private static int GetSliceCount(this string instance, string splitter) @@ -61,10 +64,15 @@ 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> - public static string BaseName(this string instance) + /// <summary> + /// If the string is a path to a file, return the path to the file without the extension. + /// </summary> + /// <seealso cref="GetExtension(string)"/> + /// <seealso cref="GetBaseDir(string)"/> + /// <seealso cref="GetFile(string)"/> + /// <param name="instance">The path to a file.</param> + /// <returns>The path to the file without the extension.</returns> + public static string GetBaseName(this string instance) { int index = instance.LastIndexOf('.'); @@ -74,20 +82,26 @@ namespace Godot return instance; } - // <summary> - // Return true if the strings begins with the given string. - // </summary> + /// <summary> + /// Returns <see langword="true"/> if the strings begins + /// with the given string <paramref name="text"/>. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <param name="text">The beginning string.</param> + /// <returns>If the string begins with the given string.</returns> 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> + /// Returns the bigrams (pairs of consecutive letters) of this string. + /// </summary> + /// <param name="instance">The string that will be used.</param> + /// <returns>The bigrams of this string.</returns> public static string[] Bigrams(this string instance) { - var b = new string[instance.Length - 1]; + string[] b = new string[instance.Length - 1]; for (int i = 0; i < b.Length; i++) { @@ -99,8 +113,8 @@ namespace Godot /// <summary> /// Converts a string containing a binary number into an integer. - /// Binary strings can either be prefixed with `0b` or not, - /// and they can also start with a `-` before the optional prefix. + /// Binary strings can either be prefixed with <c>0b</c> or not, + /// and they can also start with a <c>-</c> before the optional prefix. /// </summary> /// <param name="instance">The string to convert.</param> /// <returns>The converted string.</returns> @@ -124,12 +138,18 @@ 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> + /// Returns the amount of substrings <paramref name="what"/> in the string. + /// </summary> + /// <param name="instance">The string where the substring will be searched.</param> + /// <param name="what">The substring that will be counted.</param> + /// <param name="caseSensitive">If the search is case sensitive.</param> + /// <param name="from">Index to start searching from.</param> + /// <param name="to">Index to stop searching at.</param> + /// <returns>Amount of substrings in the string.</returns> public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0) { if (what.Length == 0) @@ -187,9 +207,11 @@ namespace Godot return c; } - // <summary> - // Return a copy of the string with special characters escaped using the C language standard. - // </summary> + /// <summary> + /// Returns a copy of the string with special characters escaped using the C language standard. + /// </summary> + /// <param name="instance">The string to escape.</param> + /// <returns>The escaped string.</returns> public static string CEscape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -209,9 +231,12 @@ 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> + /// Returns a copy of the string with escaped characters replaced by their meanings + /// according to the C language standard. + /// </summary> + /// <param name="instance">The string to unescape.</param> + /// <returns>The unescaped string.</returns> public static string CUnescape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -231,13 +256,18 @@ 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> + /// Changes 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> + /// <param name="instance">The string to capitalize.</param> + /// <returns>The capitalized string.</returns> public static string Capitalize(this string instance) { string aux = instance.Replace("_", " ").ToLower(); - var cap = string.Empty; + string cap = string.Empty; for (int i = 0; i < aux.GetSliceCount(" "); i++) { @@ -254,17 +284,28 @@ 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> + /// Performs a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// </summary> + /// <seealso cref="NocasecmpTo(string, string)"/> + /// <seealso cref="CompareTo(string, string, bool)"/> + /// <param name="instance">The string to compare.</param> + /// <param name="to">The other string to compare.</param> + /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> 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> + /// Performs a comparison to another string, return -1 if less, 0 if equal and +1 if greater. + /// </summary> + /// <param name="instance">The string to compare.</param> + /// <param name="to">The other string to compare.</param> + /// <param name="caseSensitive"> + /// If <see langword="true"/>, the comparison will be case sensitive. + /// </param> + /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> public static int CompareTo(this string instance, string to, bool caseSensitive = true) { if (string.IsNullOrEmpty(instance)) @@ -316,26 +357,52 @@ namespace Godot } } - // <summary> - // Return true if the strings ends with the given string. - // </summary> + /// <summary> + /// Returns <see langword="true"/> if the strings ends + /// with the given string <paramref name="text"/>. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <param name="text">The ending string.</param> + /// <returns>If the string ends with the given string.</returns> 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> + /// <param name="instance">The string to modify.</param> + /// <param name="pos">Starting position from which to erase.</param> + /// <param name="chars">Amount of characters to erase.</param> 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> - public static string Extension(this string instance) + /// <summary> + /// Returns the extension without the leading period character (<c>.</c>) + /// if the string is a valid file name or path. If the string does not contain + /// an extension, returns an empty string instead. + /// </summary> + /// <example> + /// <code> + /// GD.Print("/path/to/file.txt".GetExtension()) // "txt" + /// GD.Print("file.txt".GetExtension()) // "txt" + /// GD.Print("file.sample.txt".GetExtension()) // "txt" + /// GD.Print(".txt".GetExtension()) // "txt" + /// GD.Print("file.txt.".GetExtension()) // "" (empty string) + /// GD.Print("file.txt..".GetExtension()) // "" (empty string) + /// GD.Print("txt".GetExtension()) // "" (empty string) + /// GD.Print("".GetExtension()) // "" (empty string) + /// </code> + /// </example> + /// <seealso cref="GetBaseName(string)"/> + /// <seealso cref="GetBaseDir(string)"/> + /// <seealso cref="GetFile(string)"/> + /// <param name="instance">The path to a file.</param> + /// <returns>The extension of the file or an empty string.</returns> + public static string GetExtension(this string instance) { int pos = instance.FindLast("."); @@ -345,14 +412,30 @@ 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> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to find.</param> + /// <param name="from">The search starting position.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> /// <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> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="FindLast(string, string, bool)"/> + /// <seealso cref="FindLast(string, string, int, bool)"/> + /// <seealso cref="FindN(string, string, int)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to find.</param> + /// <param name="from">The search starting position.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> /// <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) { @@ -362,6 +445,13 @@ namespace Godot } /// <summary>Find the last occurrence of a substring.</summary> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="Find(string, char, int, bool)"/> + /// <seealso cref="FindLast(string, string, int, bool)"/> + /// <seealso cref="FindN(string, string, int)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to find.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> /// <returns>The starting position of the substring, or -1 if not found.</returns> public static int FindLast(this string instance, string what, bool caseSensitive = true) { @@ -369,41 +459,64 @@ namespace Godot } /// <summary>Find the last occurrence of a substring specifying the search starting position.</summary> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="Find(string, char, int, bool)"/> + /// <seealso cref="FindLast(string, string, bool)"/> + /// <seealso cref="FindN(string, string, int)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to find.</param> + /// <param name="from">The search starting position.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the search is case sensitive.</param> /// <returns>The starting position of the substring, or -1 if not found.</returns> public static int FindLast(this string instance, string what, int from, bool caseSensitive = true) { 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> + /// <seealso cref="Find(string, string, int, bool)"/> + /// <seealso cref="Find(string, char, int, bool)"/> + /// <seealso cref="FindLast(string, string, bool)"/> + /// <seealso cref="FindLast(string, string, int, bool)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to find.</param> + /// <param name="from">The search starting position.</param> /// <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> + /// <seealso cref="GetBaseName(string)"/> + /// <seealso cref="GetExtension(string)"/> + /// <seealso cref="GetFile(string)"/> + /// <param name="instance">The path to a file.</param> + /// <returns>The base directory.</returns> public static string GetBaseDir(this string instance) { int basepos = instance.Find("://"); string rs; - var @base = string.Empty; + string directory = string.Empty; if (basepos != -1) { - var end = basepos + 3; + int end = basepos + 3; rs = instance.Substring(end); - @base = instance.Substring(0, end); + directory = instance.Substring(0, end); } else { if (instance.BeginsWith("/")) { rs = instance.Substring(1); - @base = "/"; + directory = "/"; } else { @@ -414,14 +527,19 @@ namespace Godot int sep = Mathf.Max(rs.FindLast("/"), rs.FindLast("\\")); if (sep == -1) - return @base; + return directory; - return @base + rs.Substr(0, sep); + return directory + 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> + /// <seealso cref="GetBaseName(string)"/> + /// <seealso cref="GetExtension(string)"/> + /// <seealso cref="GetBaseDir(string)"/> + /// <param name="instance">The path to a file.</param> + /// <returns>The file name.</returns> public static string GetFile(this string instance) { int sep = Mathf.Max(instance.FindLast("/"), instance.FindLast("\\")); @@ -461,14 +579,16 @@ 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> + /// <param name="instance">The string to hash.</param> + /// <returns>The calculated hash of the string.</returns> 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 } @@ -483,7 +603,7 @@ namespace Godot /// <returns>The hexadecimal representation of this byte.</returns> internal static string HexEncode(this byte b) { - var ret = string.Empty; + string ret = string.Empty; for (int i = 0; i < 2; i++) { @@ -513,7 +633,7 @@ namespace Godot /// <returns>The hexadecimal representation of this byte array.</returns> public static string HexEncode(this byte[] bytes) { - var ret = string.Empty; + string ret = string.Empty; foreach (byte b in bytes) { @@ -525,8 +645,8 @@ namespace Godot /// <summary> /// Converts a string containing a hexadecimal number into an integer. - /// Hexadecimal strings can either be prefixed with `0x` or not, - /// and they can also start with a `-` before the optional prefix. + /// Hexadecimal strings can either be prefixed with <c>0x</c> or not, + /// and they can also start with a <c>-</c> before the optional prefix. /// </summary> /// <param name="instance">The string to convert.</param> /// <returns>The converted string.</returns> @@ -553,18 +673,30 @@ namespace Godot return sign * int.Parse(instance, NumberStyles.HexNumber); } - // <summary> - // Insert a substring at a given position. - // </summary> + /// <summary> + /// Inserts a substring at a given position. + /// </summary> + /// <param name="instance">The string to modify.</param> + /// <param name="pos">Position at which to insert the substring.</param> + /// <param name="what">Substring to insert.</param> + /// <returns> + /// The string with <paramref name="what"/> inserted at the given + /// position <paramref name="pos"/>. + /// </returns> 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> - public static bool IsAbsPath(this string instance) + /// <summary> + /// Returns <see langword="true"/> if the string is a path to a file or + /// directory and its startign point is explicitly defined. This includes + /// <c>res://</c>, <c>user://</c>, <c>C:\</c>, <c>/</c>, etc. + /// </summary> + /// <seealso cref="IsRelativePath(string)"/> + /// <param name="instance">The string to check.</param> + /// <returns>If the string is an absolute path.</returns> + public static bool IsAbsolutePath(this string instance) { if (string.IsNullOrEmpty(instance)) return false; @@ -574,17 +706,28 @@ 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> - public static bool IsRelPath(this string instance) + /// <summary> + /// Returns <see langword="true"/> if the string is a path to a file or + /// directory and its starting point is implicitly defined within the + /// context it is being used. The starting point may refer to the current + /// directory (<c>./</c>), or the current <see cref="Node"/>. + /// </summary> + /// <seealso cref="IsAbsolutePath(string)"/> + /// <param name="instance">The string to check.</param> + /// <returns>If the string is a relative path.</returns> + public static bool IsRelativePath(this string instance) { - return !IsAbsPath(instance); + return !IsAbsolutePath(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> + /// <seealso cref="IsSubsequenceOfI(string, string)"/> + /// <param name="instance">The subsequence to search.</param> + /// <param name="text">The string that contains the subsequence.</param> + /// <param name="caseSensitive">If <see langword="true"/>, the check is case sensitive.</param> + /// <returns>If the string is a subsequence of the given string.</returns> public static bool IsSubsequenceOf(this string instance, string text, bool caseSensitive = true) { int len = instance.Length; @@ -625,34 +768,46 @@ 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> + /// <seealso cref="IsSubsequenceOf(string, string, bool)"/> + /// <param name="instance">The subsequence to search.</param> + /// <param name="text">The string that contains the subsequence.</param> + /// <returns>If the string is a subsequence of the given string.</returns> 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> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid floating point number.</returns> 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> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid HTML color.</returns> 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> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid identifier.</returns> public static bool IsValidIdentifier(this string instance) { int len = instance.Length; @@ -660,18 +815,15 @@ namespace Godot if (len == 0) return false; + if (instance[0] >= '0' && instance[0] <= '9') + return false; // Identifiers cannot start with numbers. + for (int i = 0; i < len; i++) { - if (i == 0) - { - if (instance[0] >= '0' && instance[0] <= '9') - return false; // Don't start with number plz - } - - bool validChar = instance[i] >= '0' && - instance[i] <= '9' || instance[i] >= 'a' && - instance[i] <= 'z' || instance[i] >= 'A' && - instance[i] <= 'Z' || instance[i] == '_'; + bool validChar = instance[i] == '_' || + (instance[i] >= 'a' && instance[i] <= 'z') || + (instance[i] >= 'A' && instance[i] <= 'Z') || + (instance[i] >= '0' && instance[i] <= '9'); if (!validChar) return false; @@ -680,18 +832,22 @@ namespace Godot return true; } - // <summary> - // Check whether the string contains a valid integer. - // </summary> + /// <summary> + /// Check whether the string contains a valid integer. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid integer.</returns> 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> + /// <param name="instance">The string to check.</param> + /// <returns>If the string contains a valid IP address.</returns> public static bool IsValidIPAddress(this string instance) { // TODO: Support IPv6 addresses @@ -714,9 +870,11 @@ namespace Godot return true; } - // <summary> - // Return a copy of the string with special characters escaped using the JSON standard. - // </summary> + /// <summary> + /// Returns a copy of the string with special characters escaped using the JSON standard. + /// </summary> + /// <param name="instance">The string to escape.</param> + /// <returns>The escaped string.</returns> public static string JSONEscape(this string instance) { var sb = new StringBuilder(string.Copy(instance)); @@ -733,9 +891,13 @@ namespace Godot return sb.ToString(); } - // <summary> - // Return an amount of characters from the left of the string. - // </summary> + /// <summary> + /// Returns an amount of characters from the left of the string. + /// </summary> + /// <seealso cref="Right(string, int)"/> + /// <param name="instance">The original string.</param> + /// <param name="pos">The position in the string where the left side ends.</param> + /// <returns>The left side of the string from the given position.</returns> public static string Left(this string instance, int pos) { if (pos <= 0) @@ -748,8 +910,10 @@ namespace Godot } /// <summary> - /// Return the length of the string in characters. + /// Returns the length of the string in characters. /// </summary> + /// <param name="instance">The string to check.</param> + /// <returns>The length of the string.</returns> public static int Length(this string instance) { return instance.Length; @@ -758,6 +922,7 @@ namespace Godot /// <summary> /// Returns a copy of the string with characters removed from the left. /// </summary> + /// <seealso cref="RStrip(string, string)"/> /// <param name="instance">The string to remove characters from.</param> /// <param name="chars">The characters to be removed.</param> /// <returns>A copy of the string with characters removed from the left.</returns> @@ -783,8 +948,15 @@ 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> + /// <param name="instance">The string to check.</param> + /// <param name="expr">Expression to check.</param> + /// <param name="caseSensitive"> + /// If <see langword="true"/>, the check will be case sensitive. + /// </param> + /// <returns>If the expression has any matches.</returns> private static bool ExprMatch(this string instance, string expr, bool caseSensitive) { // case '\0': @@ -798,14 +970,25 @@ 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> + /// <seealso cref="MatchN(string, string)"/> + /// <param name="instance">The string to check.</param> + /// <param name="expr">Expression to check.</param> + /// <param name="caseSensitive"> + /// If <see langword="true"/>, the check will be case sensitive. + /// </param> + /// <returns>If the expression has any matches.</returns> public static bool Match(this string instance, string expr, bool caseSensitive = true) { if (instance.Length == 0 || expr.Length == 0) @@ -815,8 +998,13 @@ 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> + /// <seealso cref="Match(string, string, bool)"/> + /// <param name="instance">The string to check.</param> + /// <param name="expr">Expression to check.</param> + /// <returns>If the expression has any matches.</returns> public static bool MatchN(this string instance, string expr) { if (instance.Length == 0 || expr.Length == 0) @@ -825,47 +1013,66 @@ namespace Godot return instance.ExprMatch(expr, caseSensitive: false); } - // <summary> - // Return the MD5 hash of the string as an array of bytes. - // </summary> + /// <summary> + /// Returns the MD5 hash of the string as an array of bytes. + /// </summary> + /// <seealso cref="MD5Text(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The MD5 hash of the string.</returns> public static byte[] MD5Buffer(this string instance) { return godot_icall_String_md5_buffer(instance); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static byte[] godot_icall_String_md5_buffer(string str); + internal static extern byte[] godot_icall_String_md5_buffer(string str); - // <summary> - // Return the MD5 hash of the string as a string. - // </summary> + /// <summary> + /// Returns the MD5 hash of the string as a string. + /// </summary> + /// <seealso cref="MD5Buffer(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The MD5 hash of the string.</returns> public static string MD5Text(this string instance) { return godot_icall_String_md5_text(instance); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_String_md5_text(string str); + internal static extern 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> + /// <seealso cref="CasecmpTo(string, string)"/> + /// <seealso cref="CompareTo(string, string, bool)"/> + /// <param name="instance">The string to compare.</param> + /// <param name="to">The other string to compare.</param> + /// <returns>-1 if less, 0 if equal and +1 if greater.</returns> 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> + /// Returns the character code at position <paramref name="at"/>. + /// </summary> + /// <param name="instance">The string to check.</param> + /// <param name="at">The position int the string for the character to check.</param> + /// <returns>The character code.</returns> 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> + /// <seealso cref="PadZeros(string, int)"/> + /// <param name="instance">The string to pad.</param> + /// <param name="digits">Amount of digits after the decimal point.</param> + /// <returns>The string padded with zeroes.</returns> public static string PadDecimals(this string instance, int digits) { int c = instance.Find("."); @@ -899,9 +1106,14 @@ 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> + /// <seealso cref="PadDecimals(string, int)"/> + /// <param name="instance">The string to pad.</param> + /// <param name="digits">Amount of digits before the decimal point.</param> + /// <returns>The string padded with zeroes.</returns> public static string PadZeros(this string instance, int digits) { string s = instance; @@ -932,9 +1144,14 @@ 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> + /// <param name="instance">The path that will be concatenated.</param> + /// <param name="file">File name to concatenate with the path.</param> + /// <returns>The concatenated path with the given file name.</returns> public static string PlusFile(this string instance, string file) { if (instance.Length > 0 && instance[instance.Length - 1] == '/') @@ -942,47 +1159,72 @@ 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> + /// <seealso cref="ReplaceN(string, string, string)"/> + /// <param name="instance">The string to modify.</param> + /// <param name="what">The substring to be replaced in the string.</param> + /// <param name="forwhat">The substring that replaces <paramref name="what"/>.</param> + /// <returns>The string with the substring occurrences replaced.</returns> 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> + /// <seealso cref="Replace(string, string, string)"/> + /// <param name="instance">The string to modify.</param> + /// <param name="what">The substring to be replaced in the string.</param> + /// <param name="forwhat">The substring that replaces <paramref name="what"/>.</param> + /// <returns>The string with the substring occurrences replaced.</returns> 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> + /// <seealso cref="RFindN(string, string, int)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to search in the string.</param> + /// <param name="from">The position at which to start searching.</param> + /// <returns>The position at which the substring was found, or -1 if not found.</returns> public static int RFind(this string instance, string what, int from = -1) { return godot_icall_String_rfind(instance, what, from); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_String_rfind(string str, string what, int from); + internal static extern 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> + /// <seealso cref="RFind(string, string, int)"/> + /// <param name="instance">The string that will be searched.</param> + /// <param name="what">The substring to search in the string.</param> + /// <param name="from">The position at which to start searching.</param> + /// <returns>The position at which the substring was found, or -1 if not found.</returns> public static int RFindN(this string instance, string what, int from = -1) { return godot_icall_String_rfindn(instance, what, from); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static int godot_icall_String_rfindn(string str, string what, int from); + internal static extern 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> + /// Returns the right side of the string from a given position. + /// </summary> + /// <seealso cref="Left(string, int)"/> + /// <param name="instance">The original string.</param> + /// <param name="pos">The position in the string from which the right side starts.</param> + /// <returns>The right side of the string from the given position.</returns> public static string Right(this string instance, int pos) { if (pos >= instance.Length) @@ -997,6 +1239,7 @@ namespace Godot /// <summary> /// Returns a copy of the string with characters removed from the right. /// </summary> + /// <seealso cref="LStrip(string, string)"/> /// <param name="instance">The string to remove characters from.</param> /// <param name="chars">The characters to be removed.</param> /// <returns>A copy of the string with characters removed from the right.</returns> @@ -1021,28 +1264,41 @@ namespace Godot return instance.Substr(0, end + 1); } + /// <summary> + /// Returns the SHA-256 hash of the string as an array of bytes. + /// </summary> + /// <seealso cref="SHA256Text(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The SHA-256 hash of the string.</returns> public static byte[] SHA256Buffer(this string instance) { return godot_icall_String_sha256_buffer(instance); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static byte[] godot_icall_String_sha256_buffer(string str); + internal static extern byte[] godot_icall_String_sha256_buffer(string str); - // <summary> - // Return the SHA-256 hash of the string as a string. - // </summary> + /// <summary> + /// Returns the SHA-256 hash of the string as a string. + /// </summary> + /// <seealso cref="SHA256Buffer(string)"/> + /// <param name="instance">The string to hash.</param> + /// <returns>The SHA-256 hash of the string.</returns> public static string SHA256Text(this string instance) { return godot_icall_String_sha256_text(instance); } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern static string godot_icall_String_sha256_text(string str); + internal static extern 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> + /// Returns the similarity index of the text compared to this string. + /// 1 means totally similar and 0 means totally dissimilar. + /// </summary> + /// <param name="instance">The string to compare.</param> + /// <param name="text">The other string to compare.</param> + /// <returns>The similarity index.</returns> public static float Similarity(this string instance, string text) { if (instance == text) @@ -1080,17 +1336,44 @@ 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> + /// Returns a simplified canonical path. + /// </summary> + public static string SimplifyPath(this string instance) + { + return godot_icall_String_simplify_path(instance); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string godot_icall_String_simplify_path(string str); + + /// <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> + /// <seealso cref="SplitFloats(string, string, bool)"/> + /// <param name="instance">The string to split.</param> + /// <param name="divisor">The divisor string that splits the string.</param> + /// <param name="allowEmpty"> + /// If <see langword="true"/>, the array may include empty strings. + /// </param> + /// <returns>The array of strings split from the string.</returns> 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> + /// <seealso cref="Split(string, string, bool)"/> + /// <param name="instance">The string to split.</param> + /// <param name="divisor">The divisor string that splits the string.</param> + /// <param name="allowEmpty"> + /// If <see langword="true"/>, the array may include empty floats. + /// </param> + /// <returns>The array of floats split from the string.</returns> public static float[] SplitFloats(this string instance, string divisor, bool allowEmpty = true) { var ret = new List<float>(); @@ -1113,7 +1396,8 @@ namespace Godot return ret.ToArray(); } - private static readonly char[] _nonPrintable = { + private static readonly char[] _nonPrintable = + { (char)00, (char)01, (char)02, (char)03, (char)04, (char)05, (char)06, (char)07, (char)08, (char)09, (char)10, (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, @@ -1122,9 +1406,14 @@ 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> + /// Returns 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> + /// <param name="instance">The string to strip.</param> + /// <param name="left">If the left side should be stripped.</param> + /// <param name="right">If the right side should be stripped.</param> + /// <returns>The string stripped of any non-printable characters.</returns> public static string StripEdges(this string instance, bool left = true, bool right = true) { if (left) @@ -1137,58 +1426,86 @@ 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> + /// Returns part of the string from the position <paramref name="from"/>, with length <paramref name="len"/>. + /// </summary> + /// <param name="instance">The string to slice.</param> + /// <param name="from">The position in the string that the part starts from.</param> + /// <param name="len">The length of the returned part.</param> + /// <returns> + /// Part of the string from the position <paramref name="from"/>, with length <paramref name="len"/>. + /// </returns> 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> + /// Converts 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> + /// <seealso cref="ToUTF8(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The string as ASCII encoded bytes.</returns> 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> + /// Converts a string, containing a decimal number, into a <see langword="float" />. + /// </summary> + /// <seealso cref="ToInt(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The number representation of the string.</returns> 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> + /// Converts a string, containing an integer number, into an <see langword="int" />. + /// </summary> + /// <seealso cref="ToFloat(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The number representation of the string.</returns> public static int ToInt(this string instance) { return int.Parse(instance); } - // <summary> - // Return the string converted to lowercase. - // </summary> + /// <summary> + /// Returns the string converted to lowercase. + /// </summary> + /// <seealso cref="ToUpper(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The string converted to lowercase.</returns> public static string ToLower(this string instance) { return instance.ToLower(); } - // <summary> - // Return the string converted to uppercase. - // </summary> + /// <summary> + /// Returns the string converted to uppercase. + /// </summary> + /// <seealso cref="ToLower(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The string converted to uppercase.</returns> 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> + /// Converts 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> + /// <seealso cref="ToAscii(string)"/> + /// <param name="instance">The string to convert.</param> + /// <returns>The string as UTF-8 encoded bytes.</returns> public static byte[] ToUTF8(this string instance) { return Encoding.UTF8.GetBytes(instance); @@ -1197,8 +1514,8 @@ namespace Godot /// <summary> /// Decodes a string in URL encoded format. This is meant to /// decode parameters in a URL when receiving an HTTP request. - /// This mostly wraps around `System.Uri.UnescapeDataString()`, - /// but also handles `+`. + /// This mostly wraps around <see cref="Uri.UnescapeDataString"/>, + /// but also handles <c>+</c>. /// See <see cref="URIEncode"/> for encoding. /// </summary> /// <param name="instance">The string to decode.</param> @@ -1211,7 +1528,7 @@ namespace Godot /// <summary> /// Encodes a string to URL friendly format. This is meant to /// encode parameters in a URL when sending an HTTP request. - /// This wraps around `System.Uri.EscapeDataString()`. + /// This wraps around <see cref="Uri.EscapeDataString"/>. /// See <see cref="URIDecode"/> for decoding. /// </summary> /// <param name="instance">The string to encode.</param> @@ -1221,17 +1538,24 @@ namespace Godot return Uri.EscapeDataString(instance); } - // <summary> - // Return a copy of the string with special characters escaped using the XML standard. - // </summary> + /// <summary> + /// Returns a copy of the string with special characters escaped using the XML standard. + /// </summary> + /// <seealso cref="XMLUnescape(string)"/> + /// <param name="instance">The string to escape.</param> + /// <returns>The escaped string.</returns> 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> + /// Returns a copy of the string with escaped characters replaced by their meanings + /// according to the XML standard. + /// </summary> + /// <seealso cref="XMLEscape(string)"/> + /// <param name="instance">The string to unescape.</param> + /// <returns>The unescaped string.</returns> public static string XMLUnescape(this string instance) { return SecurityElement.FromString(instance).Text; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs index 7700b6d4ed..b1d504410b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs @@ -3,6 +3,13 @@ using System.Runtime.CompilerServices; namespace Godot { + /// <summary> + /// StringNames are immutable strings designed for general-purpose representation of unique names. + /// StringName ensures that only one instance of a given name exists (so two StringNames with the + /// same value are the same object). + /// Comparing them is much faster than with regular strings, because only the pointers are compared, + /// not the whole strings. + /// </summary> public sealed partial class StringName : IDisposable { private IntPtr ptr; @@ -23,6 +30,9 @@ namespace Godot Dispose(false); } + /// <summary> + /// Disposes of this <see cref="StringName"/>. + /// </summary> public void Dispose() { Dispose(true); @@ -43,25 +53,48 @@ namespace Godot this.ptr = ptr; } + /// <summary> + /// Constructs an empty <see cref="StringName"/>. + /// </summary> public StringName() { ptr = IntPtr.Zero; } + /// <summary> + /// Constructs a <see cref="StringName"/> from the given <paramref name="path"/> string. + /// </summary> + /// <param name="path">String to construct the <see cref="StringName"/> from.</param> public StringName(string path) { ptr = path == null ? IntPtr.Zero : godot_icall_StringName_Ctor(path); } + /// <summary> + /// Converts a string to a <see cref="StringName"/>. + /// </summary> + /// <param name="from">The string to convert.</param> public static implicit operator StringName(string from) => new StringName(from); + /// <summary> + /// Converts a <see cref="StringName"/> to a string. + /// </summary> + /// <param name="from">The <see cref="StringName"/> to convert.</param> public static implicit operator string(StringName from) => from.ToString(); + /// <summary> + /// Converts this <see cref="StringName"/> to a string. + /// </summary> + /// <returns>A string representation of this <see cref="StringName"/>.</returns> public override string ToString() { return ptr == IntPtr.Zero ? string.Empty : godot_icall_StringName_operator_String(GetPtr(this)); } + /// <summary> + /// Check whether this <see cref="StringName"/> is empty. + /// </summary> + /// <returns>If the <see cref="StringName"/> is empty.</returns> public bool IsEmpty() { return ptr == IntPtr.Zero || godot_icall_StringName_is_empty(GetPtr(this)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index bc0f81b2a7..daea09ba72 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 { @@ -21,18 +21,18 @@ namespace Godot public struct Transform2D : IEquatable<Transform2D> { /// <summary> - /// The basis matrix's X vector (column 0). Equivalent to array index `[0]`. + /// The basis matrix's X vector (column 0). Equivalent to array index <c>[0]</c>. /// </summary> /// <value></value> public Vector2 x; /// <summary> - /// The basis matrix's Y vector (column 1). Equivalent to array index `[1]`. + /// The basis matrix's Y vector (column 1). Equivalent to array index <c>[1]</c>. /// </summary> public Vector2 y; /// <summary> - /// The origin vector (column 2, the third column). Equivalent to array index `[2]`. + /// The origin vector (column 2, the third column). Equivalent to array index <c>[2]</c>. /// The origin vector represents translation. /// </summary> public Vector2 origin; @@ -77,7 +77,8 @@ namespace Godot } /// <summary> - /// Access whole columns in the form of Vector2. The third column is the origin vector. + /// Access whole columns in the form of <see cref="Vector2"/>. + /// The third column is the <see cref="origin"/> vector. /// </summary> /// <param name="column">Which column vector.</param> public Vector2 this[int column] @@ -116,7 +117,8 @@ namespace Godot } /// <summary> - /// Access matrix elements in column-major order. The third column is the origin vector. + /// Access matrix elements in column-major order. + /// The third column is the <see cref="origin"/> vector. /// </summary> /// <param name="column">Which column, the matrix horizontal position.</param> /// <param name="row">Which row, the matrix vertical position.</param> @@ -138,6 +140,7 @@ namespace Godot /// Returns the inverse of the transform, under the assumption that /// the transformation is composed of rotation, scaling, and translation. /// </summary> + /// <seealso cref="Inverse"/> /// <returns>The inverse transformation matrix.</returns> public Transform2D AffineInverse() { @@ -146,7 +149,7 @@ namespace Godot if (det == 0) throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted."); - var inv = this; + Transform2D inv = this; real_t temp = inv[0, 0]; inv[0, 0] = inv[1, 1]; @@ -173,13 +176,14 @@ namespace Godot /// <returns>The determinant of the basis matrix.</returns> private real_t BasisDeterminant() { - return x.x * y.y - x.y * y.x; + return (x.x * y.y) - (x.y * y.x); } /// <summary> /// Returns a vector transformed (multiplied) by the basis matrix. - /// This method does not account for translation (the origin vector). + /// This method does not account for translation (the <see cref="origin"/> vector). /// </summary> + /// <seealso cref="BasisXformInv(Vector2)"/> /// <param name="v">A vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector2 BasisXform(Vector2 v) @@ -189,11 +193,12 @@ namespace Godot /// <summary> /// Returns a vector transformed (multiplied) by the inverse basis matrix. - /// This method does not account for translation (the origin vector). + /// This method does not account for translation (the <see cref="origin"/> vector). /// /// Note: This results in a multiplication by the inverse of the /// basis matrix only if it represents a rotation-reflection. /// </summary> + /// <seealso cref="BasisXform(Vector2)"/> /// <param name="v">A vector to inversely transform.</param> /// <returns>The inversely transformed vector.</returns> public Vector2 BasisXformInv(Vector2 v) @@ -202,7 +207,7 @@ namespace Godot } /// <summary> - /// Interpolates this transform to the other `transform` by `weight`. + /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>. /// </summary> /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -233,8 +238,8 @@ namespace Godot else { real_t angle = weight * Mathf.Acos(dot); - Vector2 v3 = (v2 - v1 * dot).Normalized(); - v = v1 * Mathf.Cos(angle) + v3 * Mathf.Sin(angle); + Vector2 v3 = (v2 - (v1 * dot)).Normalized(); + v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle)); } // Extract parameters @@ -258,7 +263,7 @@ namespace Godot /// <returns>The inverse matrix.</returns> public Transform2D Inverse() { - var inv = this; + Transform2D inv = this; // Swap real_t temp = inv.x.y; @@ -277,13 +282,13 @@ namespace Godot /// <returns>The orthonormalized transform.</returns> public Transform2D Orthonormalized() { - var on = this; + Transform2D on = this; Vector2 onX = on.x; Vector2 onY = on.y; onX.Normalize(); - onY = onY - onX * onX.Dot(onY); + onY = onY - (onX * onX.Dot(onY)); onY.Normalize(); on.x = onX; @@ -293,7 +298,7 @@ namespace Godot } /// <summary> - /// Rotates the transform by `phi` (in radians), using matrix multiplication. + /// Rotates the transform by <paramref name="phi"/> (in radians), using matrix multiplication. /// </summary> /// <param name="phi">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> @@ -309,7 +314,7 @@ namespace Godot /// <returns>The scaled transformation matrix.</returns> public Transform2D Scaled(Vector2 scale) { - var copy = this; + Transform2D copy = this; copy.x *= scale; copy.y *= scale; copy.origin *= scale; @@ -326,16 +331,16 @@ namespace Godot private real_t Tdotx(Vector2 with) { - return this[0, 0] * with[0] + this[1, 0] * with[1]; + return (this[0, 0] * with[0]) + (this[1, 0] * with[1]); } private real_t Tdoty(Vector2 with) { - return this[0, 1] * with[0] + this[1, 1] * with[1]; + return (this[0, 1] * with[0]) + (this[1, 1] * with[1]); } /// <summary> - /// Translates the transform by the given `offset`, + /// Translates the transform by the given <paramref name="offset"/>, /// relative to the transform's basis vectors. /// /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, @@ -345,7 +350,7 @@ namespace Godot /// <returns>The translated matrix.</returns> public Transform2D Translated(Vector2 offset) { - var copy = this; + Transform2D copy = this; copy.origin += copy.BasisXform(offset); return copy; } @@ -353,6 +358,7 @@ namespace Godot /// <summary> /// Returns a vector transformed (multiplied) by this transformation matrix. /// </summary> + /// <seealso cref="XformInv(Vector2)"/> /// <param name="v">A vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector2 Xform(Vector2 v) @@ -363,6 +369,7 @@ namespace Godot /// <summary> /// Returns a vector transformed (multiplied) by the inverse transformation matrix. /// </summary> + /// <seealso cref="Xform(Vector2)"/> /// <param name="v">A vector to inversely transform.</param> /// <returns>The inversely transformed vector.</returns> public Vector2 XformInv(Vector2 v) @@ -378,20 +385,20 @@ namespace Godot /// <summary> /// The identity transform, with no translation, rotation, or scaling applied. - /// This is used as a replacement for `Transform2D()` in GDScript. - /// Do not use `new Transform2D()` with no arguments in C#, because it sets all values to zero. + /// This is used as a replacement for <c>Transform2D()</c> in GDScript. + /// Do not use <c>new Transform2D()</c> with no arguments in C#, because it sets all values to zero. /// </summary> - /// <value>Equivalent to `new Transform2D(Vector2.Right, Vector2.Down, Vector2.Zero)`.</value> + /// <value>Equivalent to <c>new Transform2D(Vector2.Right, Vector2.Down, Vector2.Zero)</c>.</value> public static Transform2D Identity { get { return _identity; } } /// <summary> /// The transform that will flip something along the X axis. /// </summary> - /// <value>Equivalent to `new Transform2D(Vector2.Left, Vector2.Down, Vector2.Zero)`.</value> + /// <value>Equivalent to <c>new Transform2D(Vector2.Left, Vector2.Down, Vector2.Zero)</c>.</value> public static Transform2D FlipX { get { return _flipX; } } /// <summary> /// The transform that will flip something along the Y axis. /// </summary> - /// <value>Equivalent to `new Transform2D(Vector2.Right, Vector2.Up, Vector2.Zero)`.</value> + /// <value>Equivalent to <c>new Transform2D(Vector2.Right, Vector2.Up, Vector2.Zero)</c>.</value> public static Transform2D FlipY { get { return _flipY; } } /// <summary> @@ -411,12 +418,12 @@ namespace Godot /// Constructs a transformation matrix from the given components. /// Arguments are named such that xy is equal to calling x.y /// </summary> - /// <param name="xx">The X component of the X column vector, accessed via `t.x.x` or `[0][0]`</param> - /// <param name="xy">The Y component of the X column vector, accessed via `t.x.y` or `[0][1]`</param> - /// <param name="yx">The X component of the Y column vector, accessed via `t.y.x` or `[1][0]`</param> - /// <param name="yy">The Y component of the Y column vector, accessed via `t.y.y` or `[1][1]`</param> - /// <param name="ox">The X component of the origin vector, accessed via `t.origin.x` or `[2][0]`</param> - /// <param name="oy">The Y component of the origin vector, accessed via `t.origin.y` or `[2][1]`</param> + /// <param name="xx">The X component of the X column vector, accessed via <c>t.x.x</c> or <c>[0][0]</c></param> + /// <param name="xy">The Y component of the X column vector, accessed via <c>t.x.y</c> or <c>[0][1]</c></param> + /// <param name="yx">The X component of the Y column vector, accessed via <c>t.y.x</c> or <c>[1][0]</c></param> + /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.y.y</c> or <c>[1][1]</c></param> + /// <param name="ox">The X component of the origin vector, accessed via <c>t.origin.x</c> or <c>[2][0]</c></param> + /// <param name="oy">The Y component of the origin vector, accessed via <c>t.origin.y</c> or <c>[2][1]</c></param> public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { x = new Vector2(xx, xy); @@ -425,16 +432,17 @@ namespace Godot } /// <summary> - /// Constructs a transformation matrix from a rotation value and origin vector. + /// Constructs a transformation matrix from a <paramref name="rotation"/> value and + /// <paramref name="origin"/> vector. /// </summary> - /// <param name="rot">The rotation of the new transform, in radians.</param> - /// <param name="pos">The origin vector, or column index 2.</param> - public Transform2D(real_t rot, Vector2 pos) + /// <param name="rotation">The rotation of the new transform, in radians.</param> + /// <param name="origin">The origin vector, or column index 2.</param> + public Transform2D(real_t rotation, Vector2 origin) { - x.x = y.y = Mathf.Cos(rot); - x.y = y.x = Mathf.Sin(rot); + x.x = y.y = Mathf.Cos(rotation); + x.y = y.x = Mathf.Sin(rotation); y.x *= -1; - origin = pos; + this.origin = origin; } public static Transform2D operator *(Transform2D left, Transform2D right) @@ -464,19 +472,29 @@ namespace Godot return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this transform and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the transform and the other object are equal.</returns> public override bool Equals(object obj) { return obj is Transform2D transform2D && Equals(transform2D); } + /// <summary> + /// Returns <see langword="true"/> if this transform and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other transform to compare.</param> + /// <returns>Whether or not the matrices are equal.</returns> public bool Equals(Transform2D other) { return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin); } /// <summary> - /// Returns true if this transform and `other` are approximately equal, by running - /// <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component. + /// Returns <see langword="true"/> if this transform and <paramref name="other"/> are approximately equal, + /// by running <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component. /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> @@ -485,29 +503,31 @@ namespace Godot return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin); } + /// <summary> + /// Serves as the hash function for <see cref="Transform2D"/>. + /// </summary> + /// <returns>A hash code for this transform.</returns> public override int GetHashCode() { return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Transform2D"/> to a string. + /// </summary> + /// <returns>A string representation of this transform.</returns> public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(), - y.ToString(), - origin.ToString() - }); + return $"[X: {x}, Y: {y}, O: {origin}]"; } + /// <summary> + /// Converts this <see cref="Transform2D"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this transform.</returns> public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(format), - y.ToString(format), - 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/Transform.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index ac47f6029f..7176cd60dc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.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 { @@ -19,7 +19,7 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Transform : IEquatable<Transform> + public struct Transform3D : IEquatable<Transform3D> { /// <summary> /// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis @@ -28,12 +28,13 @@ namespace Godot public Basis basis; /// <summary> - /// The origin vector (column 3, the fourth column). Equivalent to array index `[3]`. + /// The origin vector (column 3, the fourth column). Equivalent to array index <c>[3]</c>. /// </summary> public Vector3 origin; /// <summary> - /// Access whole columns in the form of Vector3. The fourth column is the origin vector. + /// Access whole columns in the form of <see cref="Vector3"/>. + /// The fourth column is the <see cref="origin"/> vector. /// </summary> /// <param name="column">Which column vector.</param> public Vector3 this[int column] @@ -77,7 +78,8 @@ namespace Godot } /// <summary> - /// Access matrix elements in column-major order. The fourth column is the origin vector. + /// Access matrix elements in column-major order. + /// The fourth column is the <see cref="origin"/> vector. /// </summary> /// <param name="column">Which column, the matrix horizontal position.</param> /// <param name="row">Which row, the matrix vertical position.</param> @@ -106,33 +108,36 @@ namespace Godot /// Returns the inverse of the transform, under the assumption that /// the transformation is composed of rotation, scaling, and translation. /// </summary> + /// <seealso cref="Inverse"/> /// <returns>The inverse transformation matrix.</returns> - public Transform AffineInverse() + public Transform3D AffineInverse() { Basis basisInv = basis.Inverse(); - return new Transform(basisInv, basisInv.Xform(-origin)); + return new Transform3D(basisInv, basisInv.Xform(-origin)); } /// <summary> - /// Interpolates this transform to the other `transform` by `weight`. + /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>. /// </summary> /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform InterpolateWith(Transform transform, real_t weight) + public Transform3D InterpolateWith(Transform3D transform, real_t weight) { /* not sure if very "efficient" but good enough? */ Vector3 sourceScale = basis.Scale; - Quat sourceRotation = basis.RotationQuat(); + Quaternion sourceRotation = basis.GetRotationQuaternion(); Vector3 sourceLocation = origin; Vector3 destinationScale = transform.basis.Scale; - Quat destinationRotation = transform.basis.RotationQuat(); + Quaternion destinationRotation = transform.basis.GetRotationQuaternion(); Vector3 destinationLocation = transform.origin; - var interpolated = new Transform(); - interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight)); + var interpolated = new Transform3D(); + Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized(); + Vector3 scale = sourceScale.Lerp(destinationScale, weight); + interpolated.basis.SetQuaternionScale(quaternion, scale); interpolated.origin = sourceLocation.Lerp(destinationLocation, weight); return interpolated; @@ -144,28 +149,28 @@ namespace Godot /// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling). /// </summary> /// <returns>The inverse matrix.</returns> - public Transform Inverse() + public Transform3D Inverse() { Basis basisTr = basis.Transposed(); - return new Transform(basisTr, basisTr.Xform(-origin)); + return new Transform3D(basisTr, basisTr.Xform(-origin)); } /// <summary> /// Returns a copy of the transform rotated such that its - /// -Z axis (forward) points towards the target position. + /// -Z axis (forward) points towards the <paramref name="target"/> position. /// - /// The transform will first be rotated around the given up vector, - /// and then fully aligned to the target by a further rotation around - /// an axis perpendicular to both the target and up vectors. + /// The transform will first be rotated around the given <paramref name="up"/> vector, + /// and then fully aligned to the <paramref name="target"/> by a further rotation around + /// an axis perpendicular to both the <paramref name="target"/> and <paramref name="up"/> vectors. /// /// Operations take place in global space. /// </summary> /// <param name="target">The object to look at.</param> /// <param name="up">The relative up direction</param> /// <returns>The resulting transform.</returns> - public Transform LookingAt(Vector3 target, Vector3 up) + public Transform3D LookingAt(Vector3 target, Vector3 up) { - var t = this; + Transform3D t = this; t.SetLookAt(origin, target, up); return t; } @@ -175,21 +180,21 @@ namespace Godot /// and normalized axis vectors (scale of 1 or -1). /// </summary> /// <returns>The orthonormalized transform.</returns> - public Transform Orthonormalized() + public Transform3D Orthonormalized() { - return new Transform(basis.Orthonormalized(), origin); + return new Transform3D(basis.Orthonormalized(), origin); } /// <summary> - /// Rotates the transform around the given `axis` by `phi` (in radians), + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="phi"/> (in radians), /// using matrix multiplication. The axis must be a normalized vector. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform Rotated(Vector3 axis, real_t phi) + public Transform3D Rotated(Vector3 axis, real_t phi) { - return new Transform(new Basis(axis, phi), new Vector3()) * this; + return new Transform3D(new Basis(axis, phi), new Vector3()) * this; } /// <summary> @@ -197,9 +202,9 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform Scaled(Vector3 scale) + public Transform3D Scaled(Vector3 scale) { - return new Transform(basis.Scaled(scale), origin * scale); + return new Transform3D(basis.Scaled(scale), origin * scale); } private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) @@ -226,7 +231,7 @@ namespace Godot } /// <summary> - /// Translates the transform by the given `offset`, + /// Translates the transform by the given <paramref name="offset"/>, /// relative to the transform's basis vectors. /// /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, @@ -234,9 +239,9 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform Translated(Vector3 offset) + public Transform3D Translated(Vector3 offset) { - return new Transform(basis, new Vector3 + return new Transform3D(basis, new Vector3 ( origin[0] += basis.Row0.Dot(offset), origin[1] += basis.Row1.Dot(offset), @@ -247,6 +252,7 @@ namespace Godot /// <summary> /// Returns a vector transformed (multiplied) by this transformation matrix. /// </summary> + /// <seealso cref="XformInv(Vector3)"/> /// <param name="v">A vector to transform.</param> /// <returns>The transformed vector.</returns> public Vector3 Xform(Vector3 v) @@ -265,6 +271,7 @@ namespace Godot /// Note: This results in a multiplication by the inverse of the /// transformation matrix only if it represents a rotation-reflection. /// </summary> + /// <seealso cref="Xform(Vector3)"/> /// <param name="v">A vector to inversely transform.</param> /// <returns>The inversely transformed vector.</returns> public Vector3 XformInv(Vector3 v) @@ -273,40 +280,40 @@ namespace Godot return new Vector3 ( - basis.Row0[0] * vInv.x + basis.Row1[0] * vInv.y + basis.Row2[0] * vInv.z, - basis.Row0[1] * vInv.x + basis.Row1[1] * vInv.y + basis.Row2[1] * vInv.z, - basis.Row0[2] * vInv.x + basis.Row1[2] * vInv.y + basis.Row2[2] * vInv.z + (basis.Row0[0] * vInv.x) + (basis.Row1[0] * vInv.y) + (basis.Row2[0] * vInv.z), + (basis.Row0[1] * vInv.x) + (basis.Row1[1] * vInv.y) + (basis.Row2[1] * vInv.z), + (basis.Row0[2] * vInv.x) + (basis.Row1[2] * vInv.y) + (basis.Row2[2] * vInv.z) ); } // Constants - private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero); - private static readonly Transform _flipX = new Transform(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); + private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero); + private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipY = new Transform3D(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipZ = new Transform3D(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); /// <summary> /// The identity transform, with no translation, rotation, or scaling applied. - /// This is used as a replacement for `Transform()` in GDScript. - /// Do not use `new Transform()` with no arguments in C#, because it sets all values to zero. + /// This is used as a replacement for <c>Transform()</c> in GDScript. + /// Do not use <c>new Transform()</c> with no arguments in C#, because it sets all values to zero. /// </summary> - /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform Identity { get { return _identity; } } + /// <value>Equivalent to <c>new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)</c>.</value> + public static Transform3D Identity { get { return _identity; } } /// <summary> /// The transform that will flip something along the X axis. /// </summary> - /// <value>Equivalent to `new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipX { get { return _flipX; } } + /// <value>Equivalent to <c>new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)</c>.</value> + public static Transform3D FlipX { get { return _flipX; } } /// <summary> /// The transform that will flip something along the Y axis. /// </summary> - /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipY { get { return _flipY; } } + /// <value>Equivalent to <c>new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)</c>.</value> + public static Transform3D FlipY { get { return _flipY; } } /// <summary> /// The transform that will flip something along the Z axis. /// </summary> - /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)`.</value> - public static Transform FlipZ { get { return _flipZ; } } + /// <value>Equivalent to <c>new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)</c>.</value> + public static Transform3D FlipZ { get { return _flipZ; } } /// <summary> /// Constructs a transformation matrix from 4 vectors (matrix columns). @@ -315,98 +322,114 @@ namespace Godot /// <param name="column1">The Y vector, or column index 1.</param> /// <param name="column2">The Z vector, or column index 2.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) + public Transform3D(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) { basis = new Basis(column0, column1, column2); this.origin = origin; } /// <summary> - /// Constructs a transformation matrix from the given quaternion and origin vector. + /// Constructs a transformation matrix from the given <paramref name="quaternion"/> + /// and <paramref name="origin"/> vector. /// </summary> - /// <param name="quat">The <see cref="Godot.Quat"/> to create the basis from.</param> + /// <param name="quaternion">The <see cref="Quaternion"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Quat quat, Vector3 origin) + public Transform3D(Quaternion quaternion, Vector3 origin) { - basis = new Basis(quat); + basis = new Basis(quaternion); this.origin = origin; } /// <summary> - /// Constructs a transformation matrix from the given basis and origin vector. + /// Constructs a transformation matrix from the given <paramref name="basis"/> and + /// <paramref name="origin"/> vector. /// </summary> - /// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param> + /// <param name="basis">The <see cref="Basis"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Basis basis, Vector3 origin) + public Transform3D(Basis basis, Vector3 origin) { this.basis = basis; this.origin = origin; } - public static Transform operator *(Transform left, Transform right) + public static Transform3D operator *(Transform3D left, Transform3D right) { left.origin = left.Xform(right.origin); left.basis *= right.basis; return left; } - public static bool operator ==(Transform left, Transform right) + public static bool operator ==(Transform3D left, Transform3D right) { return left.Equals(right); } - public static bool operator !=(Transform left, Transform right) + public static bool operator !=(Transform3D left, Transform3D right) { return !left.Equals(right); } + /// <summary> + /// Returns <see langword="true"/> if this transform and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the transform and the other object are equal.</returns> public override bool Equals(object obj) { - if (obj is Transform) + if (obj is Transform3D) { - return Equals((Transform)obj); + return Equals((Transform3D)obj); } return false; } - public bool Equals(Transform other) + /// <summary> + /// Returns <see langword="true"/> if this transform and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other transform to compare.</param> + /// <returns>Whether or not the matrices are equal.</returns> + public bool Equals(Transform3D other) { return basis.Equals(other.basis) && origin.Equals(other.origin); } /// <summary> - /// Returns true if this transform and `other` are approximately equal, by running - /// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. + /// Returns <see langword="true"/> if this transform and <paramref name="other"/> are approximately equal, + /// by running <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component. /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> - public bool IsEqualApprox(Transform other) + public bool IsEqualApprox(Transform3D other) { return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin); } + /// <summary> + /// Serves as the hash function for <see cref="Transform3D"/>. + /// </summary> + /// <returns>A hash code for this transform.</returns> public override int GetHashCode() { return basis.GetHashCode() ^ origin.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Transform3D"/> to a string. + /// </summary> + /// <returns>A string representation of this transform.</returns> public override string ToString() { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(), - origin.ToString() - }); + return $"[X: {basis.x}, Y: {basis.y}, Z: {basis.z}, O: {origin}]"; } + /// <summary> + /// Converts this <see cref="Transform3D"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this transform.</returns> public string ToString(string format) { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(format), - 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/UnhandledExceptionArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs new file mode 100644 index 0000000000..eae8927ceb --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Godot +{ + /// <summary> + /// Event arguments for when unhandled exceptions occur. + /// </summary> + public class UnhandledExceptionArgs + { + /// <summary> + /// Exception object. + /// </summary> + public Exception Exception { get; private set; } + + internal UnhandledExceptionArgs(Exception exception) + { + Exception = exception; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 6279ea1ace..fe70d71cce 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 { @@ -27,23 +21,36 @@ namespace Godot /// </summary> public enum Axis { + /// <summary> + /// The vector's X axis. + /// </summary> X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> Y } /// <summary> - /// The vector's X component. Also accessible by using the index position `[0]`. + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. /// </summary> public real_t x; + /// <summary> - /// The vector's Y component. Also accessible by using the index position `[1]`. + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. /// </summary> public real_t y; /// <summary> /// Access vector components using their index. /// </summary> - /// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`.</value> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0 or 1. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>. + /// </value> public real_t this[int index] { get @@ -103,7 +110,7 @@ namespace Godot /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians. /// /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when - /// called with the vector's `y` and `x` as parameters: `Mathf.Atan2(v.y, v.x)`. + /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>. /// </summary> /// <returns>The angle of this vector, in radians.</returns> public real_t Angle() @@ -132,9 +139,9 @@ namespace Godot } /// <summary> - /// Returns the aspect ratio of this vector, the ratio of `x` to `y`. + /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>. /// </summary> - /// <returns>The `x` component divided by the `y` component.</returns> + /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns> public real_t Aspect() { return x / y; @@ -160,40 +167,39 @@ namespace Godot } /// <summary> - /// Returns the vector with a maximum length by limiting its length to `length`. + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. /// </summary> - /// <param name="length">The length to limit to.</param> - /// <returns>The vector with its length limited.</returns> - public Vector2 Clamped(real_t length) + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector2 Clamp(Vector2 min, Vector2 max) { - var v = this; - real_t l = Length(); - - if (l > 0 && length < l) - { - v /= l; - v *= length; - } - - return v; + return new Vector2 + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y) + ); } /// <summary> - /// Returns the cross product of this vector and `b`. + /// Returns the cross product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector.</param> /// <returns>The cross product value.</returns> public real_t Cross(Vector2 b) { - return x * b.y - y * b.x; + return (x * b.y) - (y * b.x); } /// <summary> - /// Performs a cubic interpolation between vectors `preA`, this vector, `b`, and `postB`, by the given amount `t`. + /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector, + /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>. /// </summary> /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> - /// <param name="postB">A vector after `b`.</param> + /// <param name="postB">A vector after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t weight) @@ -207,24 +213,26 @@ namespace Godot real_t t2 = t * t; real_t t3 = t2 * t; - return 0.5f * (p1 * 2.0f + - (-p0 + p2) * t + - (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); + return 0.5f * ( + (p1 * 2.0f) + + ((-p0 + p2) * t) + + (((2.0f * p0) - (5.0f * p1) + (4 * p2) - p3) * t2) + + ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3) + ); } /// <summary> - /// Returns the normalized vector pointing from this vector to `b`. + /// Returns the normalized vector pointing from this vector to <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to point towards.</param> - /// <returns>The direction from this vector to `b`.</returns> + /// <returns>The direction from this vector to <paramref name="b"/>.</returns> public Vector2 DirectionTo(Vector2 b) { return new Vector2(b.x - x, b.y - y).Normalized(); } /// <summary> - /// Returns the squared distance between this vector and `to`. + /// Returns the squared distance between this vector and <paramref name="to"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. /// </summary> @@ -236,7 +244,7 @@ namespace Godot } /// <summary> - /// Returns the distance between this vector and `to`. + /// Returns the distance between this vector and <paramref name="to"/>. /// </summary> /// <param name="to">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> @@ -246,13 +254,13 @@ namespace Godot } /// <summary> - /// Returns the dot product of this vector and `with`. + /// Returns the dot product of this vector and <paramref name="with"/>. /// </summary> /// <param name="with">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> public real_t Dot(Vector2 with) { - return x * with.x + y * with.y; + return (x * with.x) + (y * with.y); } /// <summary> @@ -265,7 +273,7 @@ namespace Godot } /// <summary> - /// Returns the inverse of this vector. This is the same as `new Vector2(1 / v.x, 1 / v.y)`. + /// Returns the inverse of this vector. This is the same as <c>new Vector2(1 / v.x, 1 / v.y)</c>. /// </summary> /// <returns>The inverse of this vector.</returns> public Vector2 Inverse() @@ -274,9 +282,9 @@ namespace Godot } /// <summary> - /// Returns true if the vector is normalized, and false otherwise. + /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool indicating whether or not the vector is normalized.</returns> + /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> public bool IsNormalized() { return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; @@ -285,10 +293,11 @@ namespace Godot /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> + /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> public real_t Length() { - return Mathf.Sqrt(x * x + y * y); + return Mathf.Sqrt((x * x) + (y * y)); } /// <summary> @@ -299,12 +308,12 @@ namespace Godot /// <returns>The squared length of this vector.</returns> public real_t LengthSquared() { - return x * x + y * y; + return (x * x) + (y * y); } /// <summary> /// Returns the result of the linear interpolation between - /// this vector and `to` by amount `weight`. + /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -320,10 +329,12 @@ namespace Godot /// <summary> /// Returns the result of the linear interpolation between - /// this vector and `to` by the vector amount `weight`. + /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> - /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <param name="weight"> + /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation. + /// </param> /// <returns>The resulting vector of the interpolation.</returns> public Vector2 Lerp(Vector2 to, Vector2 weight) { @@ -335,6 +346,25 @@ namespace Godot } /// <summary> + /// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>. + /// </summary> + /// <param name="length">The length to limit to.</param> + /// <returns>The vector with its length limited.</returns> + public Vector2 LimitLength(real_t length = 1.0f) + { + Vector2 v = this; + real_t l = Length(); + + if (l > 0 && length < l) + { + v /= l; + v *= length; + } + + return v; + } + + /// <summary> /// Returns the axis of the vector's largest value. See <see cref="Axis"/>. /// If both components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -355,35 +385,41 @@ namespace Godot } /// <summary> - /// Moves this vector toward `to` by the fixed `delta` amount. + /// Moves this vector toward <paramref name="to"/> by the fixed <paramref name="delta"/> amount. /// </summary> /// <param name="to">The vector to move towards.</param> /// <param name="delta">The amount to move towards by.</param> /// <returns>The resulting vector.</returns> public Vector2 MoveToward(Vector2 to, real_t delta) { - var v = this; - var vd = to - v; - var len = vd.Length(); - return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta; + Vector2 v = this; + Vector2 vd = to - v; + real_t len = vd.Length(); + if (len <= delta || len < Mathf.Epsilon) + return to; + + return v + (vd / len * delta); } /// <summary> - /// Returns the vector scaled to unit length. Equivalent to `v / v.Length()`. + /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. /// </summary> /// <returns>A normalized version of the vector.</returns> public Vector2 Normalized() { - var v = this; + Vector2 v = this; v.Normalize(); return v; } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `mod`. + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="mod"/>. /// </summary> /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `mod`.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. + /// </returns> public Vector2 PosMod(real_t mod) { Vector2 v; @@ -393,10 +429,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `modv`'s components. + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="modv"/>'s components. /// </summary> /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `modv`'s components.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. + /// </returns> public Vector2 PosMod(Vector2 modv) { Vector2 v; @@ -406,7 +445,7 @@ namespace Godot } /// <summary> - /// Returns this vector projected onto another vector `b`. + /// Returns this vector projected onto another vector <paramref name="onNormal"/>. /// </summary> /// <param name="onNormal">The vector to project onto.</param> /// <returns>The projected vector.</returns> @@ -416,7 +455,7 @@ namespace Godot } /// <summary> - /// Returns this vector reflected from a plane defined by the given `normal`. + /// Returns this vector reflected from a plane defined by the given <paramref name="normal"/>. /// </summary> /// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param> /// <returns>The reflected vector.</returns> @@ -425,14 +464,14 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif - return 2 * Dot(normal) * normal - this; + return (2 * Dot(normal) * normal) - this; } /// <summary> - /// Rotates this vector by `phi` radians. + /// Rotates this vector by <paramref name="phi"/> radians. /// </summary> /// <param name="phi">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> @@ -460,7 +499,7 @@ namespace Godot /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. /// </summary> - /// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public Vector2 Sign() { Vector2 v; @@ -471,7 +510,7 @@ namespace Godot /// <summary> /// Returns the result of the spherical linear interpolation between - /// this vector and `to` by amount `weight`. + /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// /// Note: Both vectors must be normalized. /// </summary> @@ -487,24 +526,24 @@ namespace Godot } if (!to.IsNormalized()) { - throw new InvalidOperationException("Vector2.Slerp: `to` is not normalized."); + throw new InvalidOperationException($"Vector2.Slerp: `{nameof(to)}` is not normalized."); } #endif return Rotated(AngleTo(to) * weight); } /// <summary> - /// Returns this vector slid along a plane defined by the given normal. + /// Returns this vector slid along a plane defined by the given <paramref name="normal"/>. /// </summary> /// <param name="normal">The normal vector defining the plane to slide on.</param> /// <returns>The slid vector.</returns> public Vector2 Slide(Vector2 normal) { - return this - normal * Dot(normal); + return this - (normal * Dot(normal)); } /// <summary> - /// Returns this vector with each component snapped to the nearest multiple of `step`. + /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. /// This can also be used to round to an arbitrary number of decimals. /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> @@ -519,7 +558,7 @@ namespace Godot /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2 Perpendicular() + public Vector2 Orthogonal() { return new Vector2(y, -x); } @@ -535,40 +574,40 @@ namespace Godot private static readonly Vector2 _left = new Vector2(-1, 0); /// <summary> - /// Zero vector, a vector with all components set to `0`. + /// Zero vector, a vector with all components set to <c>0</c>. /// </summary> - /// <value>Equivalent to `new Vector2(0, 0)`</value> + /// <value>Equivalent to <c>new Vector2(0, 0)</c>.</value> public static Vector2 Zero { get { return _zero; } } /// <summary> - /// One vector, a vector with all components set to `1`. + /// One vector, a vector with all components set to <c>1</c>. /// </summary> - /// <value>Equivalent to `new Vector2(1, 1)`</value> + /// <value>Equivalent to <c>new Vector2(1, 1)</c>.</value> public static Vector2 One { get { return _one; } } /// <summary> - /// Infinity vector, a vector with all components set to `Mathf.Inf`. + /// Infinity vector, a vector with all components set to <see cref="Mathf.Inf"/>. /// </summary> - /// <value>Equivalent to `new Vector2(Mathf.Inf, Mathf.Inf)`</value> + /// <value>Equivalent to <c>new Vector2(Mathf.Inf, Mathf.Inf)</c>.</value> public static Vector2 Inf { get { return _inf; } } /// <summary> /// Up unit vector. Y is down in 2D, so this vector points -Y. /// </summary> - /// <value>Equivalent to `new Vector2(0, -1)`</value> + /// <value>Equivalent to <c>new Vector2(0, -1)</c>.</value> public static Vector2 Up { get { return _up; } } /// <summary> /// Down unit vector. Y is down in 2D, so this vector points +Y. /// </summary> - /// <value>Equivalent to `new Vector2(0, 1)`</value> + /// <value>Equivalent to <c>new Vector2(0, 1)</c>.</value> public static Vector2 Down { get { return _down; } } /// <summary> /// Right unit vector. Represents the direction of right. /// </summary> - /// <value>Equivalent to `new Vector2(1, 0)`</value> + /// <value>Equivalent to <c>new Vector2(1, 0)</c>.</value> public static Vector2 Right { get { return _right; } } /// <summary> /// Left unit vector. Represents the direction of left. /// </summary> - /// <value>Equivalent to `new Vector2(-1, 0)`</value> + /// <value>Equivalent to <c>new Vector2(-1, 0)</c>.</value> public static Vector2 Left { get { return _left; } } /// <summary> @@ -592,6 +631,17 @@ namespace Godot y = v.y; } + /// <summary> + /// Creates a unit Vector2 rotated to the given angle. This is equivalent to doing + /// <c>Vector2(Mathf.Cos(angle), Mathf.Sin(angle))</c> or <c>Vector2.Right.Rotated(angle)</c>. + /// </summary> + /// <param name="angle">Angle of the vector, in radians.</param> + /// <returns>The resulting vector.</returns> + public static Vector2 FromAngle(real_t angle) + { + return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); + } + public static Vector2 operator +(Vector2 left, Vector2 right) { left.x += right.x; @@ -708,6 +758,11 @@ namespace Godot return left.x >= right.x; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the vector and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Vector2) @@ -717,14 +772,19 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other vector to compare.</param> + /// <returns>Whether or not the vectors are equal.</returns> public bool Equals(Vector2 other) { return x == other.x && y == other.y; } /// <summary> - /// Returns true if this vector and `other` are approximately equal, by running - /// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are approximately equal, + /// by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. /// </summary> /// <param name="other">The other vector to compare.</param> /// <returns>Whether or not the vectors are approximately equal.</returns> @@ -733,27 +793,31 @@ namespace Godot return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y); } + /// <summary> + /// Serves as the hash function for <see cref="Vector2"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Vector2"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - x.ToString(), - y.ToString() - }); + return $"({x}, {y})"; } + /// <summary> + /// Converts this <see cref="Vector2"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> 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 8dd9ab2f0d..ca4531d885 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 { @@ -22,23 +21,36 @@ namespace Godot /// </summary> public enum Axis { + /// <summary> + /// The vector's X axis. + /// </summary> X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> Y } /// <summary> - /// The vector's X component. Also accessible by using the index position `[0]`. + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. /// </summary> public int x; + /// <summary> - /// The vector's Y component. Also accessible by using the index position `[1]`. + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. /// </summary> public int y; /// <summary> /// Access vector components using their index. /// </summary> - /// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`.</value> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0 or 1. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>. + /// </value> public int this[int index] { get @@ -82,7 +94,7 @@ namespace Godot /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians. /// /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when - /// called with the vector's `y` and `x` as parameters: `Mathf.Atan2(v.y, v.x)`. + /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>. /// </summary> /// <returns>The angle of this vector, in radians.</returns> public real_t Angle() @@ -111,16 +123,33 @@ namespace Godot } /// <summary> - /// Returns the aspect ratio of this vector, the ratio of `x` to `y`. + /// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>. /// </summary> - /// <returns>The `x` component divided by the `y` component.</returns> + /// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns> public real_t Aspect() { return x / (real_t)y; } /// <summary> - /// Returns the cross product of this vector and `b`. + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector2i Clamp(Vector2i min, Vector2i max) + { + return new Vector2i + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y) + ); + } + + /// <summary> + /// Returns the cross product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector.</param> /// <returns>The cross product vector.</returns> @@ -130,7 +159,7 @@ namespace Godot } /// <summary> - /// Returns the squared distance between this vector and `b`. + /// Returns the squared distance between this vector and <paramref name="b"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. /// </summary> @@ -142,7 +171,7 @@ namespace Godot } /// <summary> - /// Returns the distance between this vector and `b`. + /// Returns the distance between this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> @@ -152,7 +181,7 @@ namespace Godot } /// <summary> - /// Returns the dot product of this vector and `b`. + /// Returns the dot product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> @@ -164,6 +193,7 @@ namespace Godot /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> + /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> public real_t Length() { @@ -208,10 +238,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components and `mod`. + /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components + /// and <paramref name="mod"/>. /// </summary> /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(int, int)"/> by `mod`.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. + /// </returns> public Vector2i PosMod(int mod) { Vector2i v = this; @@ -221,10 +254,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components and `modv`'s components. + /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components + /// and <paramref name="modv"/>'s components. /// </summary> /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(int, int)"/> by `modv`'s components.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. + /// </returns> public Vector2i PosMod(Vector2i modv) { Vector2i v = this; @@ -238,7 +274,7 @@ namespace Godot /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(int)"/> on each component. /// </summary> - /// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public Vector2i Sign() { Vector2i v = this; @@ -248,13 +284,13 @@ namespace Godot } /// <summary> - /// Returns a vector rotated 90 degrees counter-clockwise + /// Returns a perpendicular vector rotated 90 degrees counter-clockwise /// compared to the original, with the same length. /// </summary> /// <returns>The perpendicular vector.</returns> - public Vector2 Perpendicular() + public Vector2i Orthogonal() { - return new Vector2(y, -x); + return new Vector2i(y, -x); } // Constants @@ -267,35 +303,35 @@ namespace Godot private static readonly Vector2i _left = new Vector2i(-1, 0); /// <summary> - /// Zero vector, a vector with all components set to `0`. + /// Zero vector, a vector with all components set to <c>0</c>. /// </summary> - /// <value>Equivalent to `new Vector2i(0, 0)`</value> + /// <value>Equivalent to <c>new Vector2i(0, 0)</c>.</value> public static Vector2i Zero { get { return _zero; } } /// <summary> - /// One vector, a vector with all components set to `1`. + /// One vector, a vector with all components set to <c>1</c>. /// </summary> - /// <value>Equivalent to `new Vector2i(1, 1)`</value> + /// <value>Equivalent to <c>new Vector2i(1, 1)</c>.</value> public static Vector2i One { get { return _one; } } /// <summary> /// Up unit vector. Y is down in 2D, so this vector points -Y. /// </summary> - /// <value>Equivalent to `new Vector2i(0, -1)`</value> + /// <value>Equivalent to <c>new Vector2i(0, -1)</c>.</value> public static Vector2i Up { get { return _up; } } /// <summary> /// Down unit vector. Y is down in 2D, so this vector points +Y. /// </summary> - /// <value>Equivalent to `new Vector2i(0, 1)`</value> + /// <value>Equivalent to <c>new Vector2i(0, 1)</c>.</value> public static Vector2i Down { get { return _down; } } /// <summary> /// Right unit vector. Represents the direction of right. /// </summary> - /// <value>Equivalent to `new Vector2i(1, 0)`</value> + /// <value>Equivalent to <c>new Vector2i(1, 0)</c>.</value> public static Vector2i Right { get { return _right; } } /// <summary> /// Left unit vector. Represents the direction of left. /// </summary> - /// <value>Equivalent to `new Vector2i(-1, 0)`</value> + /// <value>Equivalent to <c>new Vector2i(-1, 0)</c>.</value> public static Vector2i Left { get { return _left; } } /// <summary> @@ -460,16 +496,29 @@ namespace Godot return left.x >= right.x; } + /// <summary> + /// Converts this <see cref="Vector2i"/> to a <see cref="Vector2"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> public static implicit operator Vector2(Vector2i value) { return new Vector2(value.x, value.y); } + /// <summary> + /// Converts a <see cref="Vector2"/> to a <see cref="Vector2i"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> public static explicit operator Vector2i(Vector2 value) { return new Vector2i(value); } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the vector and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Vector2i) @@ -480,32 +529,41 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are equal. + /// </summary> + /// <param name="other">The other vector to compare.</param> + /// <returns>Whether or not the vectors are equal.</returns> public bool Equals(Vector2i other) { return x == other.x && y == other.y; } + /// <summary> + /// Serves as the hash function for <see cref="Vector2i"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Vector2i"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> public override string ToString() { - return String.Format("({0}, {1})", new object[] - { - this.x.ToString(), - this.y.ToString() - }); + return $"({x}, {y})"; } + /// <summary> + /// Converts this <see cref="Vector2i"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> 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 3b895bbbf6..01e3a71bcb 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 { @@ -27,28 +21,46 @@ namespace Godot /// </summary> public enum Axis { + /// <summary> + /// The vector's X axis. + /// </summary> X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> Y, + /// <summary> + /// The vector's Z axis. + /// </summary> Z } /// <summary> - /// The vector's X component. Also accessible by using the index position `[0]`. + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. /// </summary> public real_t x; + /// <summary> - /// The vector's Y component. Also accessible by using the index position `[1]`. + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. /// </summary> public real_t y; + /// <summary> - /// The vector's Z component. Also accessible by using the index position `[2]`. + /// The vector's Z component. Also accessible by using the index position <c>[2]</c>. /// </summary> public real_t z; /// <summary> /// Access vector components using their index. /// </summary> - /// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`, `[2]` is equivalent to `.z`.</value> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0, 1 or 2. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>, + /// <c>[2]</c> is equivalent to <see cref="z"/>. + /// </value> public real_t this[int index] { get @@ -140,7 +152,25 @@ namespace Godot } /// <summary> - /// Returns the cross product of this vector and `b`. + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector3 Clamp(Vector3 min, Vector3 max) + { + return new Vector3 + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z) + ); + } + + /// <summary> + /// Returns the cross product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector.</param> /// <returns>The cross product vector.</returns> @@ -148,19 +178,19 @@ namespace Godot { return new Vector3 ( - y * b.z - z * b.y, - z * b.x - x * b.z, - x * b.y - y * b.x + (y * b.z) - (z * b.y), + (z * b.x) - (x * b.z), + (x * b.y) - (y * b.x) ); } /// <summary> - /// Performs a cubic interpolation between vectors `preA`, this vector, - /// `b`, and `postB`, by the given amount `t`. + /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector, + /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>. /// </summary> /// <param name="b">The destination vector.</param> /// <param name="preA">A vector before this vector.</param> - /// <param name="postB">A vector after `b`.</param> + /// <param name="postB">A vector after <paramref name="b"/>.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated vector.</returns> public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t weight) @@ -175,24 +205,24 @@ namespace Godot real_t t3 = t2 * t; return 0.5f * ( - p1 * 2.0f + (-p0 + p2) * t + - (2.0f * p0 - 5.0f * p1 + 4f * p2 - p3) * t2 + - (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3 - ); + (p1 * 2.0f) + ((-p0 + p2) * t) + + (((2.0f * p0) - (5.0f * p1) + (4f * p2) - p3) * t2) + + ((-p0 + (3.0f * p1) - (3.0f * p2) + p3) * t3) + ); } /// <summary> - /// Returns the normalized vector pointing from this vector to `b`. + /// Returns the normalized vector pointing from this vector to <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to point towards.</param> - /// <returns>The direction from this vector to `b`.</returns> + /// <returns>The direction from this vector to <paramref name="b"/>.</returns> public Vector3 DirectionTo(Vector3 b) { return new Vector3(b.x - x, b.y - y, b.z - z).Normalized(); } /// <summary> - /// Returns the squared distance between this vector and `b`. + /// Returns the squared distance between this vector and <paramref name="b"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. /// </summary> @@ -204,8 +234,9 @@ namespace Godot } /// <summary> - /// Returns the distance between this vector and `b`. + /// Returns the distance between this vector and <paramref name="b"/>. /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector3)"/> /// <param name="b">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> public real_t DistanceTo(Vector3 b) @@ -214,13 +245,13 @@ namespace Godot } /// <summary> - /// Returns the dot product of this vector and `b`. + /// Returns the dot product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> public real_t Dot(Vector3 b) { - return x * b.x + y * b.y + z * b.z; + return (x * b.x) + (y * b.y) + (z * b.z); } /// <summary> @@ -233,7 +264,7 @@ namespace Godot } /// <summary> - /// Returns the inverse of this vector. This is the same as `new Vector3(1 / v.x, 1 / v.y, 1 / v.z)`. + /// Returns the inverse of this vector. This is the same as <c>new Vector3(1 / v.x, 1 / v.y, 1 / v.z)</c>. /// </summary> /// <returns>The inverse of this vector.</returns> public Vector3 Inverse() @@ -242,9 +273,9 @@ namespace Godot } /// <summary> - /// Returns true if the vector is normalized, and false otherwise. + /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. /// </summary> - /// <returns>A bool indicating whether or not the vector is normalized.</returns> + /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> public bool IsNormalized() { return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; @@ -253,6 +284,7 @@ namespace Godot /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> + /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> public real_t Length() { @@ -280,7 +312,7 @@ namespace Godot /// <summary> /// Returns the result of the linear interpolation between - /// this vector and `to` by amount `weight`. + /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -297,7 +329,7 @@ namespace Godot /// <summary> /// Returns the result of the linear interpolation between - /// this vector and `to` by the vector amount `weight`. + /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -313,6 +345,25 @@ namespace Godot } /// <summary> + /// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>. + /// </summary> + /// <param name="length">The length to limit to.</param> + /// <returns>The vector with its length limited.</returns> + public Vector3 LimitLength(real_t length = 1.0f) + { + Vector3 v = this; + real_t l = Length(); + + if (l > 0 && length < l) + { + v /= l; + v *= length; + } + + return v; + } + + /// <summary> /// Returns the axis of the vector's largest value. See <see cref="Axis"/>. /// If all components are equal, this method returns <see cref="Axis.X"/>. /// </summary> @@ -333,32 +384,35 @@ namespace Godot } /// <summary> - /// Moves this vector toward `to` by the fixed `delta` amount. + /// Moves this vector toward <paramref name="to"/> by the fixed <paramref name="delta"/> amount. /// </summary> /// <param name="to">The vector to move towards.</param> /// <param name="delta">The amount to move towards by.</param> /// <returns>The resulting vector.</returns> public Vector3 MoveToward(Vector3 to, real_t delta) { - var v = this; - var vd = to - v; - var len = vd.Length(); - return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta; + Vector3 v = this; + Vector3 vd = to - v; + real_t len = vd.Length(); + if (len <= delta || len < Mathf.Epsilon) + return to; + + return v + (vd / len * delta); } /// <summary> - /// Returns the vector scaled to unit length. Equivalent to `v / v.Length()`. + /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. /// </summary> /// <returns>A normalized version of the vector.</returns> public Vector3 Normalized() { - var v = this; + Vector3 v = this; v.Normalize(); return v; } /// <summary> - /// Returns the outer product with `b`. + /// Returns the outer product with <paramref name="b"/>. /// </summary> /// <param name="b">The other vector.</param> /// <returns>A <see cref="Basis"/> representing the outer product matrix.</returns> @@ -372,10 +426,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `mod`. + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="mod"/>. /// </summary> /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `mod`.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. + /// </returns> public Vector3 PosMod(real_t mod) { Vector3 v; @@ -386,10 +443,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `modv`'s components. + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="modv"/>'s components. /// </summary> /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `modv`'s components.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. + /// </returns> public Vector3 PosMod(Vector3 modv) { Vector3 v; @@ -400,7 +460,7 @@ namespace Godot } /// <summary> - /// Returns this vector projected onto another vector `b`. + /// Returns this vector projected onto another vector <paramref name="onNormal"/>. /// </summary> /// <param name="onNormal">The vector to project onto.</param> /// <returns>The projected vector.</returns> @@ -410,7 +470,7 @@ namespace Godot } /// <summary> - /// Returns this vector reflected from a plane defined by the given `normal`. + /// Returns this vector reflected from a plane defined by the given <paramref name="normal"/>. /// </summary> /// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param> /// <returns>The reflected vector.</returns> @@ -419,15 +479,15 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif - return 2.0f * Dot(normal) * normal - this; + return (2.0f * Dot(normal) * normal) - this; } /// <summary> - /// Rotates this vector around a given `axis` vector by `phi` radians. - /// The `axis` vector must be a normalized vector. + /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="phi"/> radians. + /// The <paramref name="axis"/> vector must be a normalized vector. /// </summary> /// <param name="axis">The vector to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate by, in radians.</param> @@ -437,7 +497,7 @@ namespace Godot #if DEBUG if (!axis.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(axis)); + throw new ArgumentException("Argument is not normalized", nameof(axis)); } #endif return new Basis(axis, phi).Xform(this); @@ -458,7 +518,7 @@ namespace Godot /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. /// </summary> - /// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public Vector3 Sign() { Vector3 v; @@ -472,7 +532,7 @@ namespace Godot /// Returns the signed angle to the given vector, in radians. /// The sign of the angle is positive in a counter-clockwise /// direction and negative in a clockwise direction when viewed - /// from the side specified by the `axis`. + /// from the side specified by the <paramref name="axis"/>. /// </summary> /// <param name="to">The other vector to compare this vector to.</param> /// <param name="axis">The reference axis to use for the angle sign.</param> @@ -487,7 +547,7 @@ namespace Godot /// <summary> /// Returns the result of the spherical linear interpolation between - /// this vector and `to` by amount `weight`. + /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. /// /// Note: Both vectors must be normalized. /// </summary> @@ -503,7 +563,7 @@ namespace Godot } if (!to.IsNormalized()) { - throw new InvalidOperationException("Vector3.Slerp: `to` is not normalized."); + throw new InvalidOperationException($"Vector3.Slerp: `{nameof(to)}` is not normalized."); } #endif real_t theta = AngleTo(to); @@ -511,17 +571,17 @@ namespace Godot } /// <summary> - /// Returns this vector slid along a plane defined by the given normal. + /// Returns this vector slid along a plane defined by the given <paramref name="normal"/>. /// </summary> /// <param name="normal">The normal vector defining the plane to slide on.</param> /// <returns>The slid vector.</returns> public Vector3 Slide(Vector3 normal) { - return this - normal * Dot(normal); + return this - (normal * Dot(normal)); } /// <summary> - /// Returns this vector with each component snapped to the nearest multiple of `step`. + /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. /// This can also be used to round to an arbitrary number of decimals. /// </summary> /// <param name="step">A vector value representing the step size to snap to.</param> @@ -539,10 +599,10 @@ namespace Godot /// <summary> /// Returns a diagonal matrix with the vector as main diagonal. /// - /// This is equivalent to a Basis with no rotation or shearing and + /// This is equivalent to a <see cref="Basis"/> with no rotation or shearing and /// this vector's components set as the scale. /// </summary> - /// <returns>A Basis with the vector as its main diagonal.</returns> + /// <returns>A <see cref="Basis"/> with the vector as its main diagonal.</returns> public Basis ToDiagonalMatrix() { return new Basis( @@ -565,54 +625,54 @@ namespace Godot private static readonly Vector3 _back = new Vector3(0, 0, 1); /// <summary> - /// Zero vector, a vector with all components set to `0`. + /// Zero vector, a vector with all components set to <c>0</c>. /// </summary> - /// <value>Equivalent to `new Vector3(0, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3(0, 0, 0)</c>.</value> public static Vector3 Zero { get { return _zero; } } /// <summary> - /// One vector, a vector with all components set to `1`. + /// One vector, a vector with all components set to <c>1</c>. /// </summary> - /// <value>Equivalent to `new Vector3(1, 1, 1)`</value> + /// <value>Equivalent to <c>new Vector3(1, 1, 1)</c>.</value> public static Vector3 One { get { return _one; } } /// <summary> - /// Infinity vector, a vector with all components set to `Mathf.Inf`. + /// Infinity vector, a vector with all components set to <see cref="Mathf.Inf"/>. /// </summary> - /// <value>Equivalent to `new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf)`</value> + /// <value>Equivalent to <c>new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf)</c>.</value> public static Vector3 Inf { get { return _inf; } } /// <summary> /// Up unit vector. /// </summary> - /// <value>Equivalent to `new Vector3(0, 1, 0)`</value> + /// <value>Equivalent to <c>new Vector3(0, 1, 0)</c>.</value> public static Vector3 Up { get { return _up; } } /// <summary> /// Down unit vector. /// </summary> - /// <value>Equivalent to `new Vector3(0, -1, 0)`</value> + /// <value>Equivalent to <c>new Vector3(0, -1, 0)</c>.</value> public static Vector3 Down { get { return _down; } } /// <summary> /// Right unit vector. Represents the local direction of right, /// and the global direction of east. /// </summary> - /// <value>Equivalent to `new Vector3(1, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3(1, 0, 0)</c>.</value> public static Vector3 Right { get { return _right; } } /// <summary> /// Left unit vector. Represents the local direction of left, /// and the global direction of west. /// </summary> - /// <value>Equivalent to `new Vector3(-1, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3(-1, 0, 0)</c>.</value> public static Vector3 Left { get { return _left; } } /// <summary> /// Forward unit vector. Represents the local direction of forward, /// and the global direction of north. /// </summary> - /// <value>Equivalent to `new Vector3(0, 0, -1)`</value> + /// <value>Equivalent to <c>new Vector3(0, 0, -1)</c>.</value> public static Vector3 Forward { get { return _forward; } } /// <summary> /// Back unit vector. Represents the local direction of back, /// and the global direction of south. /// </summary> - /// <value>Equivalent to `new Vector3(0, 0, 1)`</value> + /// <value>Equivalent to <c>new Vector3(0, 0, 1)</c>.</value> public static Vector3 Back { get { return _back; } } /// <summary> @@ -781,6 +841,11 @@ namespace Godot return left.x > right.x; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the vector and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Vector3) @@ -791,14 +856,19 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are equal + /// </summary> + /// <param name="other">The other vector to compare.</param> + /// <returns>Whether or not the vectors are equal.</returns> public bool Equals(Vector3 other) { return x == other.x && y == other.y && z == other.z; } /// <summary> - /// Returns true if this vector and `other` are approximately equal, by running - /// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are approximately equal, + /// by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. /// </summary> /// <param name="other">The other vector to compare.</param> /// <returns>Whether or not the vectors are approximately equal.</returns> @@ -807,29 +877,31 @@ namespace Godot return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z); } + /// <summary> + /// Serves as the hash function for <see cref="Vector3"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Vector3"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(), - y.ToString(), - z.ToString() - }); + return $"({x}, {y}, {z})"; } + /// <summary> + /// Converts this <see cref="Vector3"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> 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 bf25ba9cb3..2a7771cdfc 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 { @@ -22,28 +21,46 @@ namespace Godot /// </summary> public enum Axis { + /// <summary> + /// The vector's X axis. + /// </summary> X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> Y, + /// <summary> + /// The vector's Z axis. + /// </summary> Z } /// <summary> - /// The vector's X component. Also accessible by using the index position `[0]`. + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. /// </summary> public int x; + /// <summary> - /// The vector's Y component. Also accessible by using the index position `[1]`. + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. /// </summary> public int y; + /// <summary> - /// The vector's Z component. Also accessible by using the index position `[2]`. + /// The vector's Z component. Also accessible by using the index position <c>[2]</c>. /// </summary> public int z; /// <summary> - /// Access vector components using their index. + /// Access vector components using their <paramref name="index"/>. /// </summary> - /// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`, `[2]` is equivalent to `.z`.</value> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0, 1 or 2. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>, + /// <c>[2]</c> is equivalent to <see cref="z"/>. + /// </value> public int this[int index] { get @@ -89,7 +106,25 @@ namespace Godot } /// <summary> - /// Returns the squared distance between this vector and `b`. + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector3i Clamp(Vector3i min, Vector3i max) + { + return new Vector3i + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z) + ); + } + + /// <summary> + /// Returns the squared distance between this vector and <paramref name="b"/>. /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if /// you need to compare vectors or need the squared distance for some formula. /// </summary> @@ -101,8 +136,9 @@ namespace Godot } /// <summary> - /// Returns the distance between this vector and `b`. + /// Returns the distance between this vector and <paramref name="b"/>. /// </summary> + /// <seealso cref="DistanceSquaredTo(Vector3i)"/> /// <param name="b">The other vector to use.</param> /// <returns>The distance between the two vectors.</returns> public real_t DistanceTo(Vector3i b) @@ -111,7 +147,7 @@ namespace Godot } /// <summary> - /// Returns the dot product of this vector and `b`. + /// Returns the dot product of this vector and <paramref name="b"/>. /// </summary> /// <param name="b">The other vector to use.</param> /// <returns>The dot product of the two vectors.</returns> @@ -123,6 +159,7 @@ namespace Godot /// <summary> /// Returns the length (magnitude) of this vector. /// </summary> + /// <seealso cref="LengthSquared"/> /// <returns>The length of this vector.</returns> public real_t Length() { @@ -169,10 +206,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components and `mod`. + /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components + /// and <paramref name="mod"/>. /// </summary> /// <param name="mod">A value representing the divisor of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(int, int)"/> by `mod`.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>. + /// </returns> public Vector3i PosMod(int mod) { Vector3i v = this; @@ -183,10 +223,13 @@ namespace Godot } /// <summary> - /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components and `modv`'s components. + /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components + /// and <paramref name="modv"/>'s components. /// </summary> /// <param name="modv">A vector representing the divisors of the operation.</param> - /// <returns>A vector with each component <see cref="Mathf.PosMod(int, int)"/> by `modv`'s components.</returns> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components. + /// </returns> public Vector3i PosMod(Vector3i modv) { Vector3i v = this; @@ -201,7 +244,7 @@ namespace Godot /// on the signs of this vector's components, or zero if the component is zero, /// by calling <see cref="Mathf.Sign(int)"/> on each component. /// </summary> - /// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> public Vector3i Sign() { Vector3i v = this; @@ -223,49 +266,49 @@ namespace Godot private static readonly Vector3i _back = new Vector3i(0, 0, 1); /// <summary> - /// Zero vector, a vector with all components set to `0`. + /// Zero vector, a vector with all components set to <c>0</c>. /// </summary> - /// <value>Equivalent to `new Vector3i(0, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3i(0, 0, 0)</c>.</value> public static Vector3i Zero { get { return _zero; } } /// <summary> - /// One vector, a vector with all components set to `1`. + /// One vector, a vector with all components set to <c>1</c>. /// </summary> - /// <value>Equivalent to `new Vector3i(1, 1, 1)`</value> + /// <value>Equivalent to <c>new Vector3i(1, 1, 1)</c>.</value> public static Vector3i One { get { return _one; } } /// <summary> /// Up unit vector. /// </summary> - /// <value>Equivalent to `new Vector3i(0, 1, 0)`</value> + /// <value>Equivalent to <c>new Vector3i(0, 1, 0)</c>.</value> public static Vector3i Up { get { return _up; } } /// <summary> /// Down unit vector. /// </summary> - /// <value>Equivalent to `new Vector3i(0, -1, 0)`</value> + /// <value>Equivalent to <c>new Vector3i(0, -1, 0)</c>.</value> public static Vector3i Down { get { return _down; } } /// <summary> /// Right unit vector. Represents the local direction of right, /// and the global direction of east. /// </summary> - /// <value>Equivalent to `new Vector3i(1, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3i(1, 0, 0)</c>.</value> public static Vector3i Right { get { return _right; } } /// <summary> /// Left unit vector. Represents the local direction of left, /// and the global direction of west. /// </summary> - /// <value>Equivalent to `new Vector3i(-1, 0, 0)`</value> + /// <value>Equivalent to <c>new Vector3i(-1, 0, 0)</c>.</value> public static Vector3i Left { get { return _left; } } /// <summary> /// Forward unit vector. Represents the local direction of forward, /// and the global direction of north. /// </summary> - /// <value>Equivalent to `new Vector3i(0, 0, -1)`</value> + /// <value>Equivalent to <c>new Vector3i(0, 0, -1)</c>.</value> public static Vector3i Forward { get { return _forward; } } /// <summary> /// Back unit vector. Represents the local direction of back, /// and the global direction of south. /// </summary> - /// <value>Equivalent to `new Vector3i(0, 0, 1)`</value> + /// <value>Equivalent to <c>new Vector3i(0, 0, 1)</c>.</value> public static Vector3i Back { get { return _back; } } /// <summary> @@ -462,16 +505,29 @@ namespace Godot return left.x > right.x; } + /// <summary> + /// Converts this <see cref="Vector3i"/> to a <see cref="Vector3"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> public static implicit operator Vector3(Vector3i value) { return new Vector3(value.x, value.y, value.z); } + /// <summary> + /// Converts a <see cref="Vector3"/> to a <see cref="Vector3i"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> public static explicit operator Vector3i(Vector3 value) { return new Vector3i(value); } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="obj"/> are equal. + /// </summary> + /// <param name="obj">The other object to compare.</param> + /// <returns>Whether or not the vector and the other object are equal.</returns> public override bool Equals(object obj) { if (obj is Vector3i) @@ -482,34 +538,41 @@ namespace Godot return false; } + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are equal + /// </summary> + /// <param name="other">The other vector to compare.</param> + /// <returns>Whether or not the vectors are equal.</returns> public bool Equals(Vector3i other) { return x == other.x && y == other.y && z == other.z; } + /// <summary> + /// Serves as the hash function for <see cref="Vector3i"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode(); } + /// <summary> + /// Converts this <see cref="Vector3i"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> 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})"; } + /// <summary> + /// Converts this <see cref="Vector3i"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> 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/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 7c1a23d510..1fcfe74c86 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -14,9 +14,12 @@ <ItemGroup> <Compile Include="Core\AABB.cs" /> <Compile Include="Core\Array.cs" /> + <Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" /> + <Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" /> <Compile Include="Core\Attributes\ExportAttribute.cs" /> <Compile Include="Core\Attributes\GodotMethodAttribute.cs" /> <Compile Include="Core\Attributes\RPCAttributes.cs" /> + <Compile Include="Core\Attributes\ScriptPathAttribute.cs" /> <Compile Include="Core\Attributes\SignalAttribute.cs" /> <Compile Include="Core\Attributes\ToolAttribute.cs" /> <Compile Include="Core\Basis.cs" /> @@ -37,6 +40,7 @@ <Compile Include="Core\GodotSynchronizationContext.cs" /> <Compile Include="Core\GodotTaskScheduler.cs" /> <Compile Include="Core\GodotTraceListener.cs" /> + <Compile Include="Core\GodotUnhandledExceptionEvent.cs" /> <Compile Include="Core\Interfaces\IAwaitable.cs" /> <Compile Include="Core\Interfaces\IAwaiter.cs" /> <Compile Include="Core\Interfaces\ISerializationListener.cs" /> @@ -46,7 +50,7 @@ <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> <Compile Include="Core\Plane.cs" /> - <Compile Include="Core\Quat.cs" /> + <Compile Include="Core\Quaternion.cs" /> <Compile Include="Core\Rect2.cs" /> <Compile Include="Core\Rect2i.cs" /> <Compile Include="Core\RID.cs" /> @@ -54,8 +58,9 @@ <Compile Include="Core\SignalAwaiter.cs" /> <Compile Include="Core\StringExtensions.cs" /> <Compile Include="Core\StringName.cs" /> - <Compile Include="Core\Transform.cs" /> <Compile Include="Core\Transform2D.cs" /> + <Compile Include="Core\Transform3D.cs" /> + <Compile Include="Core\UnhandledExceptionArgs.cs" /> <Compile Include="Core\Vector2.cs" /> <Compile Include="Core\Vector2i.cs" /> <Compile Include="Core\Vector3.cs" /> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 34a96eba17..6c5503a3bd 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -31,7 +31,7 @@ #ifdef MONO_GLUE_ENABLED #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/string_name.h" #include "../csharp_script.h" @@ -65,7 +65,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } - void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + void *data = CSharpLanguage::get_existing_instance_binding(p_ptr); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -78,17 +78,17 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { +void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == nullptr); - // This is only called with Reference derived classes - CRASH_COND(!Object::cast_to<Reference>(p_ptr)); + // This is only called with RefCounted derived classes + CRASH_COND(!Object::cast_to<RefCounted>(p_ptr)); #endif - Reference *ref = static_cast<Reference *>(p_ptr); + RefCounted *rc = static_cast<RefCounted *>(p_ptr); - if (ref->get_script_instance()) { - CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance()); + if (rc->get_script_instance()) { + CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { bool delete_owner; @@ -97,9 +97,9 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance); if (delete_owner) { - memdelete(ref); + memdelete(rc); } else if (remove_script_instance) { - ref->set_script_instance(nullptr); + rc->set_script_instance(nullptr); } } return; @@ -108,11 +108,11 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea // Unsafe refcount decrement. The managed instance also counts as a reference. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object) - CSharpLanguage::get_singleton()->pre_unsafe_unreference(ref); - if (ref->unreference()) { - memdelete(ref); + CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc); + if (rc->unreference()) { + memdelete(rc); } else { - void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + void *data = CSharpLanguage::get_existing_instance_binding(rc); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -145,18 +145,18 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) { } Ref<WeakRef> wref; - Reference *ref = Object::cast_to<Reference>(p_ptr); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); - if (ref) { - REF r = ref; + if (rc) { + REF r = rc; if (!r.is_valid()) { return nullptr; } - wref.instance(); + wref.instantiate(); wref->set_ref(r); } else { - wref.instance(); + wref.instantiate(); wref->set_obj(p_ptr); } @@ -175,8 +175,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++; } @@ -242,7 +242,7 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) { void godot_register_object_icalls() { GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed); + GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 191f863350..86976de244 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -230,6 +230,19 @@ int32_t godot_icall_Dictionary_Count(Dictionary *ptr) { return ptr->size(); } +int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) { + *keys = godot_icall_Dictionary_Keys(ptr); + *values = godot_icall_Dictionary_Values(ptr); + return godot_icall_Dictionary_Count(ptr); +} + +void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) { + Array *keys = godot_icall_Dictionary_Keys(ptr); + Array *values = godot_icall_Dictionary_Values(ptr); + *key = GDMonoMarshal::variant_to_mono_object(keys->get(index)); + *value = GDMonoMarshal::variant_to_mono_object(values->get(index)); +} + void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); Variant *ret = ptr->getptr(varKey); @@ -338,6 +351,8 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 3db52d7c30..eed3bd2167 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -61,7 +61,7 @@ void godot_register_glue_header_icalls() { #include "core/config/engine.h" #include "core/object/class_db.h" #include "core/object/method_bind.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/node_path.h" #include "core/string/ustring.h" #include "core/typedefs.h" diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp index 18a9221f89..bb80a836ad 100644 --- a/modules/mono/glue/string_glue.cpp +++ b/modules/mono/glue/string_glue.cpp @@ -67,6 +67,11 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) { return GDMonoMarshal::mono_string_from_godot(ret); } +MonoString *godot_icall_String_simplify_path(MonoString *p_str) { + String ret = GDMonoMarshal::mono_string_to_godot(p_str).simplify_path(); + return GDMonoMarshal::mono_string_from_godot(ret); +} + void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text); @@ -74,6 +79,7 @@ void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text); + GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path); } #endif // MONO_GLUE_ENABLED |