Extensions.cs
using System;
using System.Numerics;
using System.Text.Json.Nodes;
namespace PlanetMeat;
public static partial class Extensions
{
public static T FindNearestUpwards<T>( this Component comp )
{
return comp.Components.Get<T>( FindMode.Enabled | FindMode.InSelf | FindMode.InAncestors );
}
public static T FindNearestUpwards<T>( this GameObject go )
{
return go.Components.Get<T>( FindMode.Enabled | FindMode.InSelf | FindMode.InAncestors );
}
public static T AddCapped<T>( this T a, T b, T cap ) where T : IComparable<T>, IAdditionOperators<T, T, T>, ISubtractionOperators<T, T, T>
{
if ( b.CompareTo( cap - a ) >= 0 )
return cap;
return a + b;
}
public static T AddCapped<T>( this T a, T b ) where T : IMinMaxValue<T>, IComparable<T>, IAdditionOperators<T, T, T>, ISubtractionOperators<T, T, T>
{
return AddCapped( a, b, T.MaxValue );
}
private static T MultiplyCappedPositive<T>( T a, T b, T cap ) where T : IComparable<T>, IMultiplyOperators<T, T, T>, IDivisionOperators<T, T, T>
{
if ( b.CompareTo( cap / a ) >= 0 )
return cap;
return a * b;
}
public static T MultiplyCapped<T>( this T a, T b, T cap ) where T : IComparable<T>, IMultiplyOperators<T, T, T>, IDivisionOperators<T, T, T>, IUnaryNegationOperators<T, T>
{
var aToDefault = a.CompareTo( default );
var bToDefault = b.CompareTo( default );
if ( aToDefault == 0 || bToDefault == 0 )
return default;
if ( aToDefault == bToDefault )
return MultiplyCappedPositive( a, b, cap );
return -MultiplyCappedPositive( -a, b, cap );
}
public static T MultiplyCapped<T>( this T a, T b ) where T : IMinMaxValue<T>, IComparable<T>, IMultiplyOperators<T, T, T>, IDivisionOperators<T, T, T>, IUnaryNegationOperators<T, T>
{
return MultiplyCapped( a, b, T.MaxValue );
}
public static double MultiplyCapped( this double a, double b )
{
if ( a.IsNearlyZero() || b.IsNearlyZero() )
return 0.0;
return MultiplyCapped( a, b, double.MaxValue );
}
public static float MultiplyCapped( this float a, float b )
{
if ( a.AlmostEqual( 0.0f, 0.001f ) || b.AlmostEqual( 0.0f, 0.001f ) )
return 0.0f;
return MultiplyCapped( a, b, float.MaxValue );
}
public static float ToPercentage( this float f ) => 100.0f * f;
public static double ToPercentage( this double d ) => 100.0 * d;
public static int ToWholePercentage( this float f ) => (int)ToPercentage( f );
public static int ToWholePercentage( this double d ) => (int)ToPercentage( d );
public static int CountDecimalPlaces( this float f )
{
var d = Math.Abs( (decimal)f );
d -= (int)d;
var places = 0;
while ( d > 0 )
{
places++;
d *= 10;
d -= (int)d;
}
return places;
}
public static string ToNString( this float f, int decimals = 2 ) => f.ToString( "N" + decimals );
public static string ToAutoDecimalString( this float f, int maxPlaces = 2 ) => f.ToNString( Math.Min( maxPlaces, f.CountDecimalPlaces() ) );
public static bool IsNearlyZero( this double d, double e = 0.001 ) => d < e && d > -e;
public static Vector3? IntersectRay( this Sandbox.Plane p, Ray r, float epsilon = 0.001f )
{
var denom = p.Normal.Dot( r.Forward );
if ( !denom.AlmostEqual( 0.0f, epsilon ) )
{
var dist = (p.Position - r.Position).Dot( p.Normal ) / denom;
if ( dist >= 0 )
return r.Project( dist );
}
return null;
}
public static T Lowest<T, C>( this IEnumerable<T> items, Func<T, C> calculate ) where C : IComparable<C>
{
T bestCandidate = items.First();
C bestVal = calculate.Invoke( bestCandidate );
foreach ( var i in items )
{
var iVal = calculate.Invoke( i );
if ( iVal.CompareTo( bestVal ) < 0 )
{
bestCandidate = i;
bestVal = iVal;
}
}
return bestCandidate;
}
public static int HashContents<T>( this IEnumerable<T> items )
{
var hash = new HashCode();
foreach ( var item in items )
hash.Add( item );
return hash.ToHashCode();
}
public static bool IsSubsetOf<T>( this IEnumerable<T> a, IEnumerable<T> b ) => !a.Except( b ).Any();
public static bool SameContentsAs<T>( this IEnumerable<T> a, IEnumerable<T> b ) => a.IsSubsetOf( b ) && b.IsSubsetOf( a );
public static bool IsSingle<T>( this IEnumerable<T> col ) => col.Take( 2 ).Count() == 1;
public static void Shuffle<T>( this IList<T> list, Random rng )
{
for ( var i = list.Count - 1; i > 0; i-- )
{
var j = rng.Next( i + 1 );
(list[i], list[j]) = (list[j], list[i]);
}
}
public static bool TryGetTypedProperty<T>( this JsonObject json, string key, out T value )
{
if ( json.TryGetPropertyValue( key, out var p ) )
{
value = p.GetValue<T>();
return true;
}
value = default;
return false;
}
public static bool TryGetPropertyNode<T>( this JsonObject json, string key, out T value ) where T : JsonNode
{
if ( json.TryGetPropertyValue( key, out var node ) && node is T tn )
{
value = tn;
return true;
}
value = default;
return false;
}
}