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 + "'");
}
}
}
}