Decompiled source of OtherLoaderPatched Extras v1.0.0

Sirdoggy.OtherLoaderPatchedExtras.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Sirdoggy.OtherLoaderPatchedExtras.Common;
using Stratum;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("Sirdoggy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Utilities for assembly loading and mod hotloading")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sirdoggy.OtherLoaderPatchedExtras")]
[assembly: AssemblyTitle("OtherLoaderPatched_Extras")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace Sirdoggy.OtherLoaderPatchedExtras
{
	public static class API
	{
		public static void LoadAssemblyFromFile(FileSystemInfo handle)
		{
			Plugin.ExceptionCatcher.Run(delegate
			{
				BepInExAssemblyLoader.LoadNewAssemblyOrNullThrowing(handle);
			}, delegate(Exception e)
			{
				Plugin.Log.LogError((object)("Failed to load assembly from file: " + e.Message));
			});
		}

		public static void DiscoverAndHotLoadModAssemblies()
		{
			HotLoadingManager.PerformHotLoad();
		}

		public static bool IsHotLoadingInProgress()
		{
			return HotLoadingManager.IsHotLoadInProgress;
		}
	}
	internal static class BepInExAssemblyLoader
	{
		public static Assembly? LoadNewAssemblyOrNullThrowing(FileSystemInfo handle)
		{
			string fullPath = Path.GetFullPath(handle.FullName);
			Plugin.Log.LogMessage((object)("Loading assembly file: " + fullPath));
			if (!handle.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
			{
				throw new UnauthorizedAccessException("Assembly must be a .dll: " + fullPath);
			}
			if (new Uri(fullPath).IsUnc)
			{
				throw new UnauthorizedAccessException("Loading assembly from network path is not allowed: " + fullPath);
			}
			if (!File.Exists(fullPath))
			{
				throw new FileNotFoundException("Assembly not found: " + fullPath);
			}
			EnsureWithinBepInEx(fullPath);
			AssemblyName assemblyName = AssemblyName.GetAssemblyName(fullPath);
			string normalizedFullPath = Plugin.NormalizePath(fullPath);
			if ((object)AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(delegate(Assembly maybeLoadedAssembly)
			{
				try
				{
					if (!string.IsNullOrEmpty(maybeLoadedAssembly.Location) && Plugin.NormalizePath(maybeLoadedAssembly.Location) == normalizedFullPath)
					{
						return true;
					}
					return assemblyName != null && AssemblyName.ReferenceMatchesDefinition(assemblyName, maybeLoadedAssembly.GetName());
				}
				catch
				{
					return false;
				}
			}) != null)
			{
				Plugin.Log.LogDebug((object)("Assembly is already in CurrentDomain, skipping: " + fullPath));
				return null;
			}
			Assembly result = Assembly.LoadFrom(fullPath);
			Plugin.Log.LogDebug((object)("Successfully loaded assembly file: " + fullPath));
			return result;
		}

		private static void EnsureWithinBepInEx(string fullPath)
		{
			PathValidator.ValidatePathIsPartOfBasePath(Paths.BepInExRootPath, fullPath);
		}
	}
	internal static class BepInExPluginInitializer
	{
		public static void InitializeFromAssemblyThrowing(Assembly assembly)
		{
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			string text = assembly.GetName()?.Name ?? "<unknown>";
			Plugin.Log.LogDebug((object)("Loading types from assembly: " + text));
			Type[] array;
			try
			{
				array = assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				array = ex.Types.Where((Type type2) => (object)type2 != null).ToArray();
				if (array.Length == 0)
				{
					throw new Exception("Failed to load any types from assembly '" + text + "', exception: " + ex.Message);
				}
				ManualLogSource log = Plugin.Log;
				string[] array2 = new string[5];
				object arg = array.Length;
				Type?[] types = ex.Types;
				array2[0] = $"Loaded {arg}/{((types != null) ? types.Length : (-1))} types ";
				array2[1] = "from assembly '";
				array2[2] = text;
				array2[3] = "', exception: ";
				array2[4] = ex.Message;
				log.LogWarning((object)string.Concat(array2));
				if (ex.LoaderExceptions != null)
				{
					Exception[] loaderExceptions = ex.LoaderExceptions;
					foreach (Exception ex2 in loaderExceptions)
					{
						Plugin.Log.LogWarning((object)("- " + ex2.Message));
					}
				}
			}
			catch (Exception innerException)
			{
				throw new Exception("Unknown exception when loading types from assembly '" + text + "'", innerException);
			}
			Type[] array3 = array;
			foreach (Type type in array3)
			{
				if (!type.IsClass || !typeof(BaseUnityPlugin).IsAssignableFrom(type))
				{
					continue;
				}
				try
				{
					Plugin.Log.LogDebug((object)("Initializing BaseUnityPlugin '" + type.FullName + "'"));
					GameObject managerObject = Chainloader.ManagerObject;
					BaseUnityPlugin val = (BaseUnityPlugin)((managerObject != null) ? managerObject.AddComponent(type) : null);
					TrySaveInChainloader(((int)val != 0) ? val.Info : null);
				}
				catch (Exception ex3)
				{
					if (typeof(StratumPlugin).IsAssignableFrom(type))
					{
						Plugin.Log.LogError((object)("Exception initializing BaseUnityPlugin '" + type.FullName + "' which is also a StratumPlugin. Hotloading support for mods that depend on Stratum is very limited! Error message: " + ex3.Message));
					}
					else
					{
						Plugin.Log.LogError((object)("Exception initializing BaseUnityPlugin '" + type.FullName + "': " + ex3.Message));
					}
				}
			}
		}

		private static void TrySaveInChainloader(PluginInfo? pluginInfo)
		{
			if (pluginInfo != null)
			{
				BepInPlugin metadata = pluginInfo.Metadata;
				if (((metadata != null) ? metadata.GUID : null) != null)
				{
					Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos;
					if (pluginInfos != null)
					{
						pluginInfos[pluginInfo.Metadata.GUID] = pluginInfo;
					}
					return;
				}
			}
			Plugin.Log.LogWarning((object)"Loaded BaseUnityPlugin, but it has null PluginInfo! Can not save it in Chainloader.");
		}
	}
	internal static class HotLoadingManager
	{
		public static bool IsHotLoadInProgress;

		private static readonly HashSet<string> AlreadyLoadedPluginDirs = new HashSet<string>();

		public static void RememberLoadedPluginDirs()
		{
			string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
			foreach (string path in directories)
			{
				if (Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).Length != 0)
				{
					string item = Plugin.NormalizePath(path);
					if (!AlreadyLoadedPluginDirs.Contains(item))
					{
						AlreadyLoadedPluginDirs.Add(Plugin.NormalizePath(path));
					}
				}
			}
			Plugin.Log.LogInfo((object)(string.Format("[{0}] Saved {1} loaded plugin ", "HotLoadingManager", AlreadyLoadedPluginDirs.Count) + "directories"));
		}

		public static void PerformHotLoad()
		{
			if (IsHotLoadInProgress)
			{
				Plugin.Log.LogInfo((object)"[HotLoadingManager] Hotloading is already in progress");
				return;
			}
			IsHotLoadInProgress = true;
			Plugin.ExceptionCatcher.Run(DiscoverThrowing, delegate(Exception e)
			{
				Plugin.Log.LogError((object)("Unknown exception when loading plugins: " + e.Message));
			});
			IsHotLoadInProgress = false;
		}

		private static void DiscoverThrowing()
		{
			Plugin.Log.LogMessage((object)"[HotLoadingManager] Searching plugin directories for new assets...");
			string[] directories = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.TopDirectoryOnly);
			List<string> list = new List<string>();
			string[] array = directories;
			foreach (string text in array)
			{
				string item = Plugin.NormalizePath(text);
				if (!AlreadyLoadedPluginDirs.Contains(item))
				{
					list.Add(text);
				}
			}
			List<string> list2 = new List<string>();
			foreach (string item2 in list)
			{
				string[] files = Directory.GetFiles(item2, "*.dll", SearchOption.AllDirectories);
				list2.AddRange(files);
			}
			if (list2.Count == 0)
			{
				Plugin.Log.LogInfo((object)"[HotLoadingManager] No new plugins to load found.");
				return;
			}
			Plugin.Log.LogInfo((object)string.Format("[{0}] Found {1} potentially loadable plugins!", "HotLoadingManager", list2.Count));
			List<Assembly> list3 = new List<Assembly>();
			foreach (string item3 in list2)
			{
				try
				{
					Assembly assembly = BepInExAssemblyLoader.LoadNewAssemblyOrNullThrowing(new FileInfo(item3));
					if ((object)assembly != null)
					{
						list3.Add(assembly);
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Exception when loading assembly: " + ex.Message));
				}
			}
			if (list3.Count == 0)
			{
				Plugin.Log.LogInfo((object)"[HotLoadingManager] No assemblies were loaded, aborting.");
				return;
			}
			Plugin.Log.LogInfo((object)string.Format("[{0}] Starting loading assets from {1} new assemblies...", "HotLoadingManager", list3.Count));
			RememberLoadedPluginDirs();
			foreach (Assembly assembly2 in list3)
			{
				Plugin.ExceptionCatcher.Run(delegate
				{
					BepInExPluginInitializer.InitializeFromAssemblyThrowing(assembly2);
				}, delegate(Exception e)
				{
					Plugin.Log.LogError((object)("Failed to initialize plugin from assembly: " + e.Message));
				});
			}
		}
	}
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("Sirdoggy.OtherLoaderPatchedExtras", "OtherLoaderPatched_Extras", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ExceptionCatcher ExceptionCatcher;

		public const string Id = "Sirdoggy.OtherLoaderPatchedExtras";

		public static string Name => "OtherLoaderPatched_Extras";

		public static string Version => "1.0.0";

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			ExceptionCatcher = new ExceptionCatcher(Log);
		}

		private IEnumerator Start()
		{
			HotLoadingManager.RememberLoadedPluginDirs();
			yield break;
		}

		internal static string NormalizePath(string path)
		{
			return Path.GetFullPath(path).ToLowerInvariant();
		}
	}
}
namespace Sirdoggy.OtherLoaderPatchedExtras.Common
{
	internal class ExceptionCatcher
	{
		private readonly ManualLogSource _log;

		public ExceptionCatcher(ManualLogSource log)
		{
			_log = log;
		}

		public void Run(Action action, Action<Exception>? customHandler = null)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				if (customHandler == null)
				{
					_log.LogError((object)$"Caught unhandled exception: {ex}");
				}
				else
				{
					customHandler(ex);
				}
			}
		}
	}
	internal static class PathValidator
	{
		public static void ValidatePathIsPartOfBasePath(string basePath, string actualFullPath)
		{
			string text = Path.GetFullPath(basePath).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			string value = text + directorySeparatorChar;
			if (!Path.GetFullPath(actualFullPath).StartsWith(value, StringComparison.OrdinalIgnoreCase))
			{
				throw new UnauthorizedAccessException("Path '" + actualFullPath + "' is not allowed to access resource outside of base path '" + basePath + "'");
			}
		}
	}
}