2020-03-22 19:05:26 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
2020-03-31 13:44:18 +01:00
using System.Reflection ;
2020-03-22 19:05:26 +00:00
using System.Text.RegularExpressions ;
2020-03-24 14:36:22 +00:00
using LiteNetLib ;
2020-03-22 19:05:26 +00:00
using MessagePack ;
using Unity.Mathematics ;
using static Unity . Mathematics . math ;
using Random = Unity . Mathematics . Random ;
2020-04-11 19:18:02 +01:00
using Unity.Tiny ;
2020-03-22 19:05:26 +00:00
public static class Extensions
{
//public static IDatabaseEntry Get(this Guid entry) => Database.Get(entry);
//public static T Get<T>(this Guid entry) where T : class, IDatabaseEntry => Database.Get(entry) as T;
public static string ToJson ( this DatabaseEntry entry ) = > MessagePackSerializer . SerializeToJson ( entry ) ;
public static byte [ ] Serialize ( this DatabaseEntry entry ) = > MessagePackSerializer . Serialize ( entry ) ;
public static bool IsImplementationOf ( this Type baseType , Type interfaceType )
{
return baseType . GetInterfaces ( ) . Any ( interfaceType . Equals ) ;
}
private static readonly Dictionary < CraftedItemInstance , float > Quality = new Dictionary < CraftedItemInstance , float > ( ) ;
public static float CompoundQuality ( this CraftedItemInstance item )
{
if ( Quality . ContainsKey ( item ) ) return Quality [ item ] ;
var quality = item . Quality ;
var craftedIngredients = item . Ingredients . Where ( i = > i is CraftedItemInstance ) . ToArray ( ) ;
if ( craftedIngredients . Length > 0 )
{
quality * = craftedIngredients . Cast < CraftedItemInstance > ( ) . Average ( CompoundQuality ) ;
}
Quality [ item ] = quality ;
return Quality [ item ] ;
}
2020-03-24 14:36:22 +00:00
public static void Send < T > ( this NetPeer peer , T message , DeliveryMethod method = DeliveryMethod . ReliableOrdered ) where T : Message
{
peer . Send ( MessagePackSerializer . Serialize ( message as Message ) , method ) ;
}
2020-03-22 19:05:26 +00:00
public static float Performance ( this EquippableItemData itemData , float temperature )
{
return saturate ( itemData . HeatPerformanceCurve . Evaluate ( saturate (
( temperature - itemData . MinimumTemperature ) /
( itemData . MaximumTemperature - itemData . MinimumTemperature ) ) ) ) ;
}
public static string SplitCamelCase ( this string str )
{
return Regex . Replace (
Regex . Replace (
str ,
@"(\P{Ll})(\P{Ll}\p{Ll})" ,
"$1 $2"
) ,
@"(\p{Ll})(\P{Ll})" ,
"$1 $2"
) ;
}
private static Random ? _random ;
2020-04-23 03:31:17 +01:00
private static Random Random = > ( Random ) ( _random ? ? ( _random = new Random ( ( uint ) ( DateTime . Now . Ticks % uint . MaxValue ) ) ) ) ;
// public static T RandomElement<T>(this IEnumerable<T> enumerable) => enumerable.ElementAt(Random.NextInt(0, enumerable.Count()));
2020-05-02 01:30:33 +01:00
public static float NextUnbounded ( this ref Random random ) = > 1 / ( 1 - random . NextFloat ( ) ) - 1 ;
2020-05-03 00:36:47 +01:00
public static float NextUnbounded ( this ref Random random , float bias , float power , float ceiling ) = > 1 / ( 1 - pow ( min ( random . NextFloat ( ) , ceiling ) , 1 - pow ( clamp ( bias , 0 , . 99f ) , 1 / power ) ) ) - 1 ;
2020-03-22 19:05:26 +00:00
private static Dictionary < Type , Type [ ] > InterfaceClasses = new Dictionary < Type , Type [ ] > ( ) ;
public static Type [ ] GetAllInterfaceClasses ( this Type type )
{
if ( InterfaceClasses . ContainsKey ( type ) )
return InterfaceClasses [ type ] ;
return InterfaceClasses [ type ] = AppDomain . CurrentDomain . GetAssemblies ( )
. SelectMany ( ass = > ass . GetTypes ( ) ) . Where ( t = > t . IsClass & & t . GetInterfaces ( ) . Contains ( type ) ) . ToArray ( ) ;
}
2020-03-28 03:43:07 +00:00
private static Dictionary < Type , Type [ ] > ParentTypes = new Dictionary < Type , Type [ ] > ( ) ;
public static Type [ ] GetParentTypes ( this Type type )
{
if ( ParentTypes . ContainsKey ( type ) )
return ParentTypes [ type ] ;
return ParentTypes [ type ] = type . GetParents ( ) . ToArray ( ) ;
}
private static IEnumerable < Type > GetParents ( this Type type )
{
// is there any base type?
if ( type = = null )
{
yield break ;
}
2020-03-28 05:18:57 +00:00
yield return type ;
2020-03-28 03:43:07 +00:00
// return all implemented or inherited interfaces
foreach ( var i in type . GetInterfaces ( ) )
{
yield return i ;
}
// return all inherited types
var currentBaseType = type . BaseType ;
while ( currentBaseType ! = null )
{
yield return currentBaseType ;
currentBaseType = currentBaseType . BaseType ;
}
}
2020-03-22 19:05:26 +00:00
private static Dictionary < Type , Type [ ] > ChildClasses = new Dictionary < Type , Type [ ] > ( ) ;
public static Type [ ] GetAllChildClasses ( this Type type )
{
if ( ChildClasses . ContainsKey ( type ) )
return ChildClasses [ type ] ;
return ChildClasses [ type ] = AppDomain . CurrentDomain . GetAssemblies ( )
. SelectMany ( ass = > ass . GetTypes ( ) ) . Where ( type . IsAssignableFrom ) . ToArray ( ) ;
}
public static bool IsDefault < T > ( this T value ) where T : struct
{
bool isDefault = value . Equals ( default ( T ) ) ;
return isDefault ;
}
2020-05-11 01:17:10 +01:00
public static bool IsNull < T , TU > ( this KeyValuePair < T , TU > pair )
{
return pair . Equals ( new KeyValuePair < T , TU > ( ) ) ;
}
2020-03-22 19:05:26 +00:00
private static Dictionary < float4 [ ] , int2 > _cachedIndices = new Dictionary < float4 [ ] , int2 > ( ) ;
public static float Evaluate ( this float4 [ ] curve , float time )
{
// Clamp time
time = math . clamp ( time , curve [ 0 ] . x , curve [ curve . Length - 1 ] . x ) ;
FindSurroundingKeyframes ( time , curve ) ;
return HermiteInterpolate ( time , curve [ _cachedIndices [ curve ] . x ] , curve [ _cachedIndices [ curve ] . y ] ) ;
}
static void FindSurroundingKeyframes ( float time , float4 [ ] curve )
{
// Check that time is within cached keyframe time
if ( _cachedIndices . ContainsKey ( curve ) & &
_cachedIndices [ curve ] . x ! = _cachedIndices [ curve ] . y & &
time > = curve [ _cachedIndices [ curve ] . x ] . x & &
time < = curve [ _cachedIndices [ curve ] . y ] . x )
{
return ;
}
// Fall back to using dichotomic search.
var length = curve . Length ;
int half ;
int middle ;
int first = 0 ;
while ( length > 0 )
{
half = length > > 1 ;
middle = first + half ;
if ( time < curve [ middle ] . x )
{
length = half ;
}
else
{
first = middle + 1 ;
length = length - half - 1 ;
}
}
// If not within range, we pick the last element twice.
var indices = int2 ( first - 1 , math . min ( curve . Length - 1 , first ) ) ;
_cachedIndices [ curve ] = indices ;
}
static float HermiteInterpolate ( float time , in float4 leftKeyframe , in float4 rightKeyframe )
{
// Handle stepped curve.
if ( math . isinf ( leftKeyframe . w ) | | math . isinf ( rightKeyframe . z ) )
{
return leftKeyframe . y ;
}
float dx = rightKeyframe . x - leftKeyframe . x ;
float m0 ;
float m1 ;
float t ;
if ( dx ! = 0.0f )
{
t = ( time - leftKeyframe . x ) / dx ;
m0 = leftKeyframe . w * dx ;
m1 = rightKeyframe . z * dx ;
}
else
{
t = 0.0f ;
m0 = 0 ;
m1 = 0 ;
}
return HermiteInterpolate ( t , leftKeyframe . y , m0 , m1 , rightKeyframe . y ) ;
}
static float HermiteInterpolate ( float t , float p0 , float m0 , float m1 , float p1 )
{
// Unrolled the equations to avoid precision issue.
// (2 * t^3 -3 * t^2 +1) * p0 + (t^3 - 2 * t^2 + t) * m0 + (-2 * t^3 + 3 * t^2) * p1 + (t^3 - t^2) * m1
var a = 2.0f * p0 + m0 - 2.0f * p1 + m1 ;
var b = - 3.0f * p0 - 2.0f * m0 + 3.0f * p1 - m1 ;
var c = m0 ;
var d = p0 ;
return t * ( t * ( a * t + b ) + c ) + d ;
}
2020-04-25 00:01:13 +01:00
public static float AngleDiff ( this float2 a , float2 b )
{
2020-04-28 01:50:50 +01:00
var directionAngle = atan2 ( b . y , b . x ) ;
var currentAngle = atan2 ( a . y , a . x ) ;
2020-04-25 00:01:13 +01:00
var d1 = directionAngle - currentAngle ;
2020-04-28 01:50:50 +01:00
var d2 = directionAngle - 2 * PI - currentAngle ;
var d3 = directionAngle + 2 * PI - currentAngle ;
2020-04-25 00:01:13 +01:00
return abs ( d1 ) < abs ( d2 ) ? abs ( d1 ) < abs ( d3 ) ? d1 : d3 : abs ( d2 ) < abs ( d3 ) ? d2 : d3 ;
}
2020-03-22 19:05:26 +00:00
}
2020-03-31 13:44:18 +01:00
// https://github.com/Burtsev-Alexey/net-object-deep-copy
public static class ObjectExtensions
{
private static readonly MethodInfo CloneMethod = typeof ( Object ) . GetMethod ( "MemberwiseClone" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
public static bool IsPrimitive ( this Type type )
{
if ( type = = typeof ( String ) ) return true ;
return ( type . IsValueType & type . IsPrimitive ) ;
}
public static Object Copy ( this Object originalObject )
{
return InternalCopy ( originalObject , new Dictionary < Object , Object > ( new ReferenceEqualityComparer ( ) ) ) ;
}
private static Object InternalCopy ( Object originalObject , IDictionary < Object , Object > visited )
{
if ( originalObject = = null ) return null ;
var typeToReflect = originalObject . GetType ( ) ;
if ( IsPrimitive ( typeToReflect ) ) return originalObject ;
if ( visited . ContainsKey ( originalObject ) ) return visited [ originalObject ] ;
if ( typeof ( Delegate ) . IsAssignableFrom ( typeToReflect ) ) return null ;
var cloneObject = CloneMethod . Invoke ( originalObject , null ) ;
if ( typeToReflect . IsArray )
{
var arrayType = typeToReflect . GetElementType ( ) ;
if ( IsPrimitive ( arrayType ) = = false )
{
Array clonedArray = ( Array ) cloneObject ;
clonedArray . ForEach ( ( array , indices ) = > array . SetValue ( InternalCopy ( clonedArray . GetValue ( indices ) , visited ) , indices ) ) ;
}
}
visited . Add ( originalObject , cloneObject ) ;
CopyFields ( originalObject , visited , cloneObject , typeToReflect ) ;
RecursiveCopyBaseTypePrivateFields ( originalObject , visited , cloneObject , typeToReflect ) ;
return cloneObject ;
}
private static void RecursiveCopyBaseTypePrivateFields ( object originalObject , IDictionary < object , object > visited , object cloneObject , Type typeToReflect )
{
if ( typeToReflect . BaseType ! = null )
{
RecursiveCopyBaseTypePrivateFields ( originalObject , visited , cloneObject , typeToReflect . BaseType ) ;
CopyFields ( originalObject , visited , cloneObject , typeToReflect . BaseType , BindingFlags . Instance | BindingFlags . NonPublic , info = > info . IsPrivate ) ;
}
}
private static void CopyFields ( object originalObject , IDictionary < object , object > visited , object cloneObject , Type typeToReflect , BindingFlags bindingFlags = BindingFlags . Instance | BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . FlattenHierarchy , Func < FieldInfo , bool > filter = null )
{
foreach ( FieldInfo fieldInfo in typeToReflect . GetFields ( bindingFlags ) )
{
if ( filter ! = null & & filter ( fieldInfo ) = = false ) continue ;
if ( IsPrimitive ( fieldInfo . FieldType ) ) continue ;
var originalFieldValue = fieldInfo . GetValue ( originalObject ) ;
var clonedFieldValue = InternalCopy ( originalFieldValue , visited ) ;
fieldInfo . SetValue ( cloneObject , clonedFieldValue ) ;
}
}
public static T Copy < T > ( this T original )
{
return ( T ) Copy ( ( Object ) original ) ;
}
2020-04-11 19:18:02 +01:00
public static bool IntersectsWith ( this Rect r1 , Rect r2 )
{
return ( r2 . x + r2 . width > = r1 . x & & r2 . x < = r1 . x + r1 . width ) & &
( r2 . y + r2 . height > = r1 . y & & r2 . y < = r1 . y + r1 . height ) ;
}
2020-04-12 11:05:36 +01:00
2020-04-14 07:03:34 +01:00
// public static IEnumerable<T> FindPath<T>(this IEnumerable<Edge<T>> data, T source, T target, Func<T, T, double> costFunction, bool bestFirst = true) where T : class
// {
// List<DijkstraVertex<T>> members = new List<DijkstraVertex<T>>{new DijkstraVertex<T>{Vertex = source}};
// List<T> searched = new List<T>();
// while (true)
// {
// var v = members.Where(m=>!searched.Contains(m.Vertex)).OrderBy(m=>bestFirst?m.Heuristic:m.Cost).FirstOrDefault();
// if (v == null) return null; // No vertices left unsearched
// if (v.Vertex == target)
// {
// Stack<DijkstraVertex<T>> path = new Stack<DijkstraVertex<T>>();
// path.Push(v);
// while(path.Peek().Parent!=null)
// path.Push(path.Peek().Parent);
// return path.Select(dv => dv.Vertex).ToList();
// }
// members.AddRange(data.Where(l => l.Source == v.Vertex).Select(l => l.Target).Concat(data.Where(l => l.Target == v.Vertex).Select(l => l.Source))
// .Where(n => members.All(m => m.Vertex != n)).Select(n =>
// {
// var c = new DijkstraVertex<T> {Parent = v, Vertex = n, Cost = v.Cost + costFunction(v.Vertex,n)};
// if (bestFirst)
// c.Heuristic = c.Cost + costFunction(c.Vertex,target);
// return c;
// }));
// searched.Add(v.Vertex);
// }
// }
2020-04-12 11:05:36 +01:00
class DijkstraVertex < T >
{
public double Cost ;
public double Heuristic ;
public DijkstraVertex < T > Parent ;
public T Vertex ;
}
2020-03-31 13:44:18 +01:00
}
public class ReferenceEqualityComparer : EqualityComparer < Object >
{
public override bool Equals ( object x , object y )
{
return ReferenceEquals ( x , y ) ;
}
public override int GetHashCode ( object obj )
{
if ( obj = = null ) return 0 ;
return obj . GetHashCode ( ) ;
}
}
public static class ArrayExtensions
{
public static void ForEach ( this Array array , Action < Array , int [ ] > action )
{
if ( array . LongLength = = 0 ) return ;
ArrayTraverse walker = new ArrayTraverse ( array ) ;
do action ( array , walker . Position ) ;
while ( walker . Step ( ) ) ;
}
}
internal class ArrayTraverse
{
public int [ ] Position ;
private int [ ] maxLengths ;
public ArrayTraverse ( Array array )
{
maxLengths = new int [ array . Rank ] ;
for ( int i = 0 ; i < array . Rank ; + + i )
{
maxLengths [ i ] = array . GetLength ( i ) - 1 ;
}
Position = new int [ array . Rank ] ;
}
public bool Step ( )
{
for ( int i = 0 ; i < Position . Length ; + + i )
{
if ( Position [ i ] < maxLengths [ i ] )
{
Position [ i ] + + ;
for ( int j = 0 ; j < i ; j + + )
{
Position [ j ] = 0 ;
}
return true ;
}
}
return false ;
}
}