using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using HG; using HarmonyLib; using IL.RoR2; using Microsoft.CodeAnalysis; using Mono.Cecil.Cil; using MonoMod.Cil; using MonoMod.RuntimeDetour; using R2API.Utils; using RoR2; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("BetterLoadingScreen")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetterLoadingScreen")] [assembly: AssemblyTitle("BetterLoadingScreen")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } internal class IsExternalInit { } } namespace BetterLoadingScreen { internal static class Log { internal static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } private static string getLogPrefix(string callerPath, string callerMemberName, int callerLineNumber) { int num = callerPath.LastIndexOf("BetterLoadingScreen"); if (num >= 0) { callerPath = callerPath.Substring(num + "BetterLoadingScreen".Length + 1); } return $"{callerPath}:{callerLineNumber} ({callerMemberName}) "; } internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogError((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Error_NoCallerPrefix(object data) { _logSource.LogError(data); } internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogFatal((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Fatal_NoCallerPrefix(object data) { _logSource.LogFatal(data); } internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogInfo((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Info_NoCallerPrefix(object data) { _logSource.LogInfo(data); } internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogMessage((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Message_NoCallerPrefix(object data) { _logSource.LogMessage(data); } internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1) { _logSource.LogWarning((object)(getLogPrefix(callerPath, callerMemberName, callerLineNumber) + data)); } internal static void Warning_NoCallerPrefix(object data) { _logSource.LogWarning(data); } } [BepInPlugin("Gorakh.BetterLoadingScreen", "BetterLoadingScreen", "1.0.0")] public class Main : BaseUnityPlugin { private readonly record struct SystemInitializerCall(MethodInfo InitMethod, object Instance, object[] Arguments) { public void Invoke() { InitMethod.Invoke(Instance, Arguments); } } [CompilerGenerated] private static class <>O { public static Manipulator <0>__RoR2Application_InitializeGameRoutine_MoveNext; public static Manipulator <1>__SystemInitializerAttribute_Execute; public static Func <2>__runSystemInitializersAsync; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func <>9__8_1; public static Func <>9__8_2; public static Manipulator <>9__8_0; public static Func <>9__9_0; public static Func <>9__9_1; public static Func <>9__9_2; public static Func <>9__10_2; public static Func <>9__11_0; internal void b__8_0(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val = new ILCursor(il); while (val.TryGotoNext((MoveType)2, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)AccessTools.DeclaredPropertyGetter(typeof(ReadableProgress), "value")) })) { val.EmitDelegate>((Func)((float value) => Util.Remap(value, 0f, 1f, 0f, 0.7f))); } } internal float b__8_1(float value) { return Util.Remap(value, 0f, 1f, 0f, 0.7f); } internal bool b__8_2(Instruction x) { return ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)AccessTools.DeclaredPropertyGetter(typeof(ReadableProgress), "value")); } internal bool b__9_0(Instruction x) { return ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)SymbolExtensions.GetMethodInfo((Expression>)((MethodBase _) => _.Invoke(null, null)))); } internal object b__9_1(MethodInfo initMethod, object instance, object[] args) { _initializerCallQueue.Enqueue(new SystemInitializerCall(initMethod, instance, args)); return null; } internal bool b__9_2(Instruction x) { return ILPatternMatchingExt.MatchStsfld(x, "hasExecuted"); } internal bool b__10_2(Instruction x) { return ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)SymbolExtensions.GetMethodInfo((Expression)(() => SystemInitializerAttribute.Execute()))); } internal bool b__11_0(TMP_Text label) { return ((Object)label).name.Equals("LoadingPercentIndicator", StringComparison.Ordinal); } } public const string PluginGUID = "Gorakh.BetterLoadingScreen"; public const string PluginAuthor = "Gorakh"; public const string PluginName = "BetterLoadingScreen"; public const string PluginVersion = "1.0.0"; private static Type RoR2Application_InitializeGameRoutine_IteratorType; private static readonly Queue _initializerCallQueue = new Queue(); private const float SYSTEM_INITIALIZER_START_PERCENT = 0.7f; private void Awake() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown Stopwatch stopwatch = Stopwatch.StartNew(); Log.Init(((BaseUnityPlugin)this).Logger); Type type = findIteratorType(typeof(RoR2Application), "LoadGameContent"); if ((object)type != null) { MethodInfo methodInfo = findIteratorMoveNextMethod(type); if ((object)methodInfo != null) { object obj = <>c.<>9__8_0; if (obj == null) { Manipulator val = delegate(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ILCursor val4 = new ILCursor(il); while (val4.TryGotoNext((MoveType)2, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)AccessTools.DeclaredPropertyGetter(typeof(ReadableProgress), "value")) })) { val4.EmitDelegate>((Func)((float value) => Util.Remap(value, 0f, 1f, 0f, 0.7f))); } }; <>c.<>9__8_0 = val; obj = (object)val; } new ILHook((MethodBase)methodInfo, (Manipulator)obj); } } RoR2Application_InitializeGameRoutine_IteratorType = findIteratorType(typeof(RoR2Application), "InitializeGameRoutine"); if ((object)RoR2Application_InitializeGameRoutine_IteratorType != null) { MethodInfo methodInfo2 = findIteratorMoveNextMethod(RoR2Application_InitializeGameRoutine_IteratorType); if ((object)methodInfo2 != null) { object obj2 = <>O.<0>__RoR2Application_InitializeGameRoutine_MoveNext; if (obj2 == null) { Manipulator val2 = RoR2Application_InitializeGameRoutine_MoveNext; <>O.<0>__RoR2Application_InitializeGameRoutine_MoveNext = val2; obj2 = (object)val2; } new ILHook((MethodBase)methodInfo2, (Manipulator)obj2); object obj3 = <>O.<1>__SystemInitializerAttribute_Execute; if (obj3 == null) { Manipulator val3 = SystemInitializerAttribute_Execute; <>O.<1>__SystemInitializerAttribute_Execute = val3; obj3 = (object)val3; } SystemInitializerAttribute.Execute += (Manipulator)obj3; } } stopwatch.Stop(); Log.Info_NoCallerPrefix($"Initialized in {stopwatch.Elapsed.TotalSeconds:F2} seconds"); } private static void SystemInitializerAttribute_Execute(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (val.TryGotoNext((MoveType)0, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)SymbolExtensions.GetMethodInfo((Expression>)((MethodBase _) => _.Invoke(null, null)))) })) { val.Remove(); val.EmitDelegate>((Func)delegate(MethodInfo initMethod, object instance, object[] args) { _initializerCallQueue.Enqueue(new SystemInitializerCall(initMethod, instance, args)); return null; }); } if (val.TryGotoNext((MoveType)0, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchStsfld(x, "hasExecuted") })) { val.Emit(OpCodes.Pop); val.Emit(OpCodes.Ldc_I4_0); } } private static void RoR2Application_InitializeGameRoutine_MoveNext(ILContext il) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) FieldInfo field = RoR2Application_InitializeGameRoutine_IteratorType.GetField("<>1__state", BindingFlags.Instance | BindingFlags.NonPublic); if ((object)field == null) { Log.Error("Unable to find iterator state field", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "RoR2Application_InitializeGameRoutine_MoveNext", 114); return; } FieldInfo field2 = RoR2Application_InitializeGameRoutine_IteratorType.GetField("<>2__current", BindingFlags.Instance | BindingFlags.NonPublic); if ((object)field2 == null) { Log.Error("Unable to find iterator current field", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "RoR2Application_InitializeGameRoutine_MoveNext", 121); return; } ILCursor val = new ILCursor(il); ILLabel[] stateSwitchLabels = Array.Empty(); if (!val.TryGotoNext((MoveType)0, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchSwitch(x, ref stateSwitchLabels) })) { Log.Error("Unable to find iterator state switch", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "RoR2Application_InitializeGameRoutine_MoveNext", 130); return; } Instruction next = val.Next; if (!val.TryGotoNext((MoveType)2, new Func[1] { (Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)SymbolExtensions.GetMethodInfo((Expression)(() => SystemInitializerAttribute.Execute()))) })) { Log.Error("Unable to find SystemInitializer Execute call", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "RoR2Application_InitializeGameRoutine_MoveNext", 149); return; } ILLabel val2 = val.DefineLabel(); int num = appendState(val2); val.Emit(OpCodes.Ldarg_0); val.EmitDelegate>((Func)runSystemInitializersAsync); val.Emit(OpCodes.Stfld, field2); val.Emit(OpCodes.Ldarg_0); val.Emit(OpCodes.Ldc_I4, num); val.Emit(OpCodes.Stfld, field); val.Emit(OpCodes.Ldc_I4_1); val.Emit(OpCodes.Ret); val.MarkLabel(val2); next.Operand = stateSwitchLabels; int appendState(ILLabel targetLabel) { int num2 = stateSwitchLabels.Length; Array.Resize(ref stateSwitchLabels, stateSwitchLabels.Length + 1); stateSwitchLabels[num2] = targetLabel; return num2; } } private static IEnumerator runSystemInitializersAsync() { TMP_Text loadingPercentIndicatorLabel = (from label in Object.FindObjectsOfType() where ((Object)label).name.Equals("LoadingPercentIndicator", StringComparison.Ordinal) select label).FirstOrDefault(); Animation loadingPercentAnimation = (Object.op_Implicit((Object)(object)loadingPercentIndicatorLabel) ? ((Component)loadingPercentIndicatorLabel).GetComponentInChildren() : null); StringBuilder loadingTextStringBuilder = StringBuilderPool.RentStringBuilder(); int numCallsCompleted = 0; int totalCalls = _initializerCallQueue.Count; while (_initializerCallQueue.Count > 0) { _initializerCallQueue.Dequeue().Invoke(); numCallsCompleted++; float num = Util.Remap((float)numCallsCompleted / (float)totalCalls, 0f, 1f, 0.7f, 1f); if (Object.op_Implicit((Object)(object)loadingPercentIndicatorLabel)) { loadingTextStringBuilder.Clear(); StringBuilderExtensions.AppendInt(loadingTextStringBuilder, Mathf.FloorToInt(num * 100f), 1u, uint.MaxValue); loadingTextStringBuilder.Append("%"); loadingPercentIndicatorLabel.SetText(loadingTextStringBuilder); } if (Object.op_Implicit((Object)(object)loadingPercentAnimation)) { AnimationClip clip = loadingPercentAnimation.clip; clip.SampleAnimation(((Component)loadingPercentAnimation).gameObject, num * 0.99f * clip.length); } yield return 0; } StringBuilderPool.ReturnStringBuilder(loadingTextStringBuilder); SystemInitializerAttribute.hasExecuted = true; } private static Type findIteratorType(Type declaringType, string iteratorMethodName) { Type type = declaringType.GetNestedTypes(BindingFlags.NonPublic).FirstOrDefault((Type t) => typeof(IEnumerator).IsAssignableFrom(t) && t.Name.StartsWith("<" + iteratorMethodName + ">d__")); if ((object)type == null) { Log.Error("Unable to find " + iteratorMethodName + " iterator class", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "findIteratorType", 224); return null; } Log.Info("Found " + iteratorMethodName + " iterator class: " + type.FullName, "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "findIteratorType", 228); return type; } private static MethodInfo findIteratorMoveNextMethod(Type iteratorType) { MethodInfo method = iteratorType.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic); if ((object)method == null) { Log.Error("Unable to find " + iteratorType.FullName + " iterator MoveNext method", "X:\\Git\\RoR2\\BetterLoadingScreen\\BetterLoadingScreen\\Main.cs", "findIteratorMoveNextMethod", 237); return null; } return method; } } }