r2mods/ilspy_dump/ror2_csproj/RoR2/SystemInitializerAttribute.cs

272 lines
7.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using HG.Reflection;
using JetBrains.Annotations;
using UnityEngine;
namespace RoR2;
[MeansImplicitUse]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class SystemInitializerAttribute : HG.Reflection.SearchableAttribute
{
private class SystemInitializationLogHandler : ILogHandler
{
public ILogHandler underlyingLogHandler;
private SystemInitializerAttribute _currentInitializer;
private string logPrefix = string.Empty;
public SystemInitializerAttribute currentInitializer
{
get
{
return _currentInitializer;
}
set
{
_currentInitializer = value;
logPrefix = "[" + currentInitializer.associatedType.FullName + "] ";
}
}
public void LogException(Exception exception, UnityEngine.Object context)
{
LogFormat(LogType.Exception, context, exception.Message, null);
}
public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
{
underlyingLogHandler.LogFormat(logType, context, logPrefix + format, args);
}
}
private class SystemTiming : IComparable
{
public string systemName;
public long systemInitDuration;
public long longestSingleIteration;
public long externalTimeDuration;
public long totalTimeSpent => externalTimeDuration + systemInitDuration;
public int CompareTo(object obj)
{
SystemTiming systemTiming = obj as SystemTiming;
return -totalTimeSpent.CompareTo(systemTiming.totalTimeSpent);
}
}
public static bool hasExecuted = false;
public Type[] dependencies = Array.Empty<Type>();
private MethodInfo methodInfo;
private Type associatedType;
private static List<Type> preInitializedTypes = new List<Type>(5);
private static Thread initThread;
private static Queue<SystemInitializerAttribute> initializerAttributes;
private static long FRAME_TIME_THRESHOLD_MS = 22L;
public SystemInitializerAttribute(params Type[] dependencies)
{
if (dependencies != null)
{
this.dependencies = dependencies;
}
}
public static void RegisterPreInitializedType(Type _type)
{
preInitializedTypes.Add(_type);
}
public static void Execute()
{
Queue<SystemInitializerAttribute> queue = new Queue<SystemInitializerAttribute>();
foreach (SystemInitializerAttribute instance in HG.Reflection.SearchableAttribute.GetInstances<SystemInitializerAttribute>())
{
MethodInfo methodInfo = instance.target as MethodInfo;
if (methodInfo != null && methodInfo.IsStatic)
{
queue.Enqueue(instance);
instance.methodInfo = methodInfo;
instance.associatedType = methodInfo.DeclaringType;
}
}
HashSet<Type> initializedTypes = new HashSet<Type>();
int num = 0;
while (queue.Count > 0)
{
SystemInitializerAttribute systemInitializerAttribute2 = queue.Dequeue();
if (!InitializerDependenciesMet(systemInitializerAttribute2))
{
queue.Enqueue(systemInitializerAttribute2);
num++;
if (num >= queue.Count)
{
break;
}
}
else
{
systemInitializerAttribute2.methodInfo.Invoke(null, Array.Empty<object>());
initializedTypes.Add(systemInitializerAttribute2.associatedType);
num = 0;
}
}
hasExecuted = true;
bool InitializerDependenciesMet(SystemInitializerAttribute initializerAttribute)
{
Type[] array = initializerAttribute.dependencies;
foreach (Type item in array)
{
if (!initializedTypes.Contains(item))
{
return false;
}
}
return true;
}
}
public static void ExecuteStatic()
{
int num = 0;
Type[] assemblyTypes = RoR2Application.AssemblyTypes;
foreach (Type type in assemblyTypes)
{
num++;
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo element in methods)
{
SystemInitializerAttribute customAttribute = CustomAttributeExtensions.GetCustomAttribute<SystemInitializerAttribute>(element);
if (customAttribute != null)
{
initializerAttributes.Enqueue(customAttribute);
customAttribute.methodInfo = element;
customAttribute.associatedType = type;
}
}
}
}
public static IEnumerator ExecuteCoroutine()
{
initializerAttributes = new Queue<SystemInitializerAttribute>();
initThread = new Thread(ExecuteStatic);
initThread.Start();
yield return null;
while (initThread.IsAlive)
{
yield return null;
}
initThread = null;
HashSet<Type> initializedTypes = new HashSet<Type>();
foreach (Type preInitializedType in preInitializedTypes)
{
initializedTypes.Add(preInitializedType);
}
preInitializedTypes.Clear();
new Stopwatch().Start();
Stopwatch multiLoopTimer = new Stopwatch();
multiLoopTimer.Start();
int yields = 0;
int num = 0;
while (initializerAttributes.Count > 0)
{
SystemInitializerAttribute initializerAttribute2 = initializerAttributes.Dequeue();
if (!InitializerDependenciesMet(initializerAttribute2))
{
initializerAttributes.Enqueue(initializerAttribute2);
num++;
if (num >= initializerAttributes.Count)
{
UnityEngine.Debug.LogFormat("SystemInitializerAttribute infinite loop detected. currentMethod={0}", initializerAttribute2.associatedType.FullName + initializerAttribute2.methodInfo.Name);
break;
}
continue;
}
IEnumerator thisStep = initializerAttribute2.methodInfo.Invoke(null, Array.Empty<object>()) as IEnumerator;
List<IEnumerator> coroutineStack = new List<IEnumerator> { thisStep };
multiLoopTimer.Stop();
long accumulatedTime = multiLoopTimer.ElapsedMilliseconds;
multiLoopTimer.Start();
if (accumulatedTime > FRAME_TIME_THRESHOLD_MS)
{
accumulatedTime = 0L;
multiLoopTimer.Stop();
multiLoopTimer.Reset();
multiLoopTimer.Start();
yields++;
yield return null;
}
while (thisStep != null)
{
while (accumulatedTime < FRAME_TIME_THRESHOLD_MS && thisStep != null)
{
if (!thisStep.MoveNext())
{
coroutineStack.RemoveAt(coroutineStack.Count - 1);
thisStep = ((coroutineStack.Count <= 0) ? null : coroutineStack[coroutineStack.Count - 1]);
}
else if (thisStep.Current != null)
{
coroutineStack.Add(thisStep.Current as IEnumerator);
thisStep = coroutineStack[coroutineStack.Count - 1];
}
multiLoopTimer.Stop();
accumulatedTime = multiLoopTimer.ElapsedMilliseconds;
multiLoopTimer.Start();
}
if (accumulatedTime > FRAME_TIME_THRESHOLD_MS)
{
accumulatedTime = 0L;
multiLoopTimer.Stop();
multiLoopTimer.Reset();
multiLoopTimer.Start();
}
if (thisStep != null)
{
yields++;
accumulatedTime = 0L;
multiLoopTimer.Stop();
multiLoopTimer.Reset();
multiLoopTimer.Start();
yield return null;
}
}
initializedTypes.Add(initializerAttribute2.associatedType);
num = 0;
}
initializerAttributes = null;
hasExecuted = true;
bool InitializerDependenciesMet(SystemInitializerAttribute initializerAttribute)
{
Type[] array = initializerAttribute.dependencies;
foreach (Type item in array)
{
initializedTypes.Contains(item);
if (!initializedTypes.Contains(item))
{
return false;
}
}
return true;
}
}
}