using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
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 Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("UnityHotReload")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+bcfa4c369b6149b8781209a4d6a848e88aad5aca")]
[assembly: AssemblyProduct("UnityHotReload")]
[assembly: AssemblyTitle("UnityHotReload")]
[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]
[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 UnityHotReloadNS
{
internal static class Log
{
private static ManualLogSource _logSource;
internal static void Init(ManualLogSource logSource)
{
_logSource = logSource;
}
internal static void Debug(object data)
{
_logSource.LogDebug(data);
}
internal static void Error(object data)
{
_logSource.LogError(data);
}
internal static void Fatal(object data)
{
_logSource.LogFatal(data);
}
internal static void Info(object data)
{
_logSource.LogInfo(data);
}
internal static void Message(object data)
{
_logSource.LogMessage(data);
}
internal static void Warning(object data)
{
_logSource.LogWarning(data);
}
}
public static class UnityHotReload
{
[CompilerGenerated]
private static class <>O
{
public static Manipulator <0>__GatherOriginalReferences;
public static Manipulator <1>__GatherInstructionsFromNewMethodAndMakeThemReferenceOriginalAssembly;
}
private const BindingFlags allFlags = (BindingFlags)(-1);
internal static int CompilationCount = 0;
private static List<ILHook> _activeILHooks = new List<ILHook>();
private static Assembly OriginalAss = null;
private static Dictionary<string, TypeReference> OriginalAssTypeRefs = new Dictionary<string, TypeReference>();
private static Dictionary<string, MethodReference> OriginalAssMethodRefs = new Dictionary<string, MethodReference>();
private static Dictionary<string, FieldReference> OriginalAssFieldRefs = new Dictionary<string, FieldReference>();
private static Dictionary<string, CallSite> OriginalAssCallSites = new Dictionary<string, CallSite>();
public static void LoadNewAssemblyVersion(Assembly originalAss, string pathOfTheNewAssembly)
{
LoadNewAssemblyVersionInternal(originalAss, pathOfTheNewAssembly);
}
private static void LoadNewAssemblyVersionInternal(Assembly originalAss, string path)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected O, but got Unknown
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Expected O, but got Unknown
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Expected O, but got Unknown
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Expected O, but got Unknown
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01c6: Expected O, but got Unknown
//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Expected O, but got Unknown
OriginalAss = originalAss;
DefaultAssemblyResolver val = new DefaultAssemblyResolver();
((BaseAssemblyResolver)val).AddSearchDirectory(Paths.ManagedPath);
((BaseAssemblyResolver)val).AddSearchDirectory(Paths.BepInExAssemblyDirectory);
Log.Debug(path);
AssemblyDefinition val2 = AssemblyDefinition.ReadAssembly(path, new ReaderParameters
{
AssemblyResolver = (IAssemblyResolver)(object)val,
ReadSymbols = true
});
try
{
((AssemblyNameReference)val2.Name).Name = $"{originalAss.GetName().Name}_HotReload_{++CompilationCount}";
Assembly assembly;
using (MemoryStream memoryStream = new MemoryStream())
{
val2.Write((Stream)memoryStream);
assembly = Assembly.Load(memoryStream.ToArray());
}
Log.Debug("originalAss: " + originalAss.GetName().Name);
Log.Debug("newAss: " + assembly.GetName().Name);
foreach (Type item in GetTypesSafe(assembly))
{
MethodInfo[] methods = item.GetMethods((BindingFlags)(-1));
foreach (MethodInfo method in methods)
{
Type type = originalAss.GetType(item.FullName);
MethodInfo methodInfo = GetMethodResolveAmbiguous(method, type);
if (methodInfo == null)
{
methodInfo = method;
}
try
{
List<ILHook> activeILHooks = _activeILHooks;
MethodInfo methodInfo2 = methodInfo;
object obj = <>O.<0>__GatherOriginalReferences;
if (obj == null)
{
Manipulator val3 = GatherOriginalReferences;
<>O.<0>__GatherOriginalReferences = val3;
obj = (object)val3;
}
activeILHooks.Add(new ILHook((MethodBase)methodInfo2, (Manipulator)obj));
List<ILHook> activeILHooks2 = _activeILHooks;
MethodInfo methodInfo3 = method;
object obj2 = <>O.<1>__GatherInstructionsFromNewMethodAndMakeThemReferenceOriginalAssembly;
if (obj2 == null)
{
Manipulator val4 = GatherInstructionsFromNewMethodAndMakeThemReferenceOriginalAssembly;
<>O.<1>__GatherInstructionsFromNewMethodAndMakeThemReferenceOriginalAssembly = val4;
obj2 = (object)val4;
}
activeILHooks2.Add(new ILHook((MethodBase)methodInfo3, (Manipulator)obj2));
if (!(methodInfo != method))
{
continue;
}
_activeILHooks.Add(new ILHook((MethodBase)methodInfo, (Manipulator)delegate(ILContext il)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
ILCursor val5 = new ILCursor(il);
for (int j = 0; j < ((MethodReference)il.Method).Parameters.Count; j++)
{
val5.Emit(OpCodes.Ldarg, j);
}
val5.Emit(OpCodes.Call, (MethodBase)method);
val5.Emit(OpCodes.Ret);
}));
}
catch (Exception arg)
{
Log.Error($"Failed to hot reload method: {item.FullName}.{method.Name}\n{arg}");
}
}
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
private static MethodInfo GetMethodResolveAmbiguous(MethodReference methodRef, Type originalType)
{
List<MethodInfo> list = (from m in originalType.GetMethods((BindingFlags)(-1))
where m.Name == ((MemberReference)methodRef).Name
select m).ToList();
if (list.Count == 1)
{
return list[0];
}
if (list.Count > 1)
{
foreach (MethodInfo item in list)
{
ParameterInfo[] parameters = item.GetParameters();
Collection<ParameterDefinition> parameters2 = methodRef.Parameters;
if (parameters.Length != parameters2.Count)
{
continue;
}
bool flag = true;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.FullName != ((MemberReference)((ParameterReference)parameters2[i]).ParameterType).FullName)
{
flag = false;
break;
}
}
if (flag)
{
Log.Debug("Resolved ambiguous method: " + originalType.FullName + "." + ((MemberReference)methodRef).Name);
return item;
}
}
}
return null;
}
private static MethodInfo GetMethodResolveAmbiguous(MethodInfo method, Type originalType)
{
List<MethodInfo> list = (from m in originalType.GetMethods((BindingFlags)(-1))
where m.Name == method.Name
select m).ToList();
if (list.Count == 1)
{
return list[0];
}
if (list.Count > 1)
{
foreach (MethodInfo item in list)
{
ParameterInfo[] parameters = item.GetParameters();
ParameterInfo[] parameters2 = method.GetParameters();
if (parameters.Length != parameters2.Length)
{
continue;
}
bool flag = true;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType.ToString() != parameters2[i].ParameterType.ToString())
{
flag = false;
break;
}
}
if (flag)
{
Log.Debug("Resolved ambiguous method: " + originalType.FullName + "." + method.Name);
return item;
}
}
}
return null;
}
private static IEnumerable<Type> GetTypesSafe(Assembly ass)
{
try
{
return ass.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("\r\n-- LoaderExceptions --");
Exception[] loaderExceptions = ex.LoaderExceptions;
foreach (Exception ex2 in loaderExceptions)
{
stringBuilder.AppendLine(ex2.ToString());
}
stringBuilder.AppendLine("\r\n-- StackTrace --");
stringBuilder.AppendLine(ex.StackTrace);
Log.Error(stringBuilder.ToString());
return ex.Types.Where((Type x) => x != null);
}
}
private static void GatherOriginalReferences(ILContext il)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
Enumerator<Instruction> enumerator = il.Instrs.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
Instruction current = enumerator.Current;
object operand = current.Operand;
TypeReference val = (TypeReference)((operand is TypeReference) ? operand : null);
if (val != null)
{
if (!OriginalAssTypeRefs.ContainsKey(((MemberReference)val).FullName))
{
OriginalAssTypeRefs.Add(((MemberReference)val).FullName, val);
}
continue;
}
object operand2 = current.Operand;
MethodReference val2 = (MethodReference)((operand2 is MethodReference) ? operand2 : null);
if (val2 != null)
{
if (!OriginalAssMethodRefs.ContainsKey(((MemberReference)val2).FullName))
{
OriginalAssMethodRefs.Add(((MemberReference)val2).FullName, val2);
}
continue;
}
object operand3 = current.Operand;
FieldReference val3 = (FieldReference)((operand3 is FieldReference) ? operand3 : null);
if (val3 != null)
{
if (!OriginalAssFieldRefs.ContainsKey(((MemberReference)val3).FullName))
{
OriginalAssFieldRefs.Add(((MemberReference)val3).FullName, val3);
}
continue;
}
object operand4 = current.Operand;
CallSite val4 = (CallSite)((operand4 is CallSite) ? operand4 : null);
if (val4 != null && !OriginalAssCallSites.ContainsKey(val4.FullName))
{
OriginalAssCallSites.Add(val4.FullName, val4);
}
}
}
finally
{
((IDisposable)enumerator).Dispose();
}
}
private static void GatherInstructionsFromNewMethodAndMakeThemReferenceOriginalAssembly(ILContext il)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
Enumerator<Instruction> enumerator = il.Instrs.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
Instruction current = enumerator.Current;
object operand = current.Operand;
object operand2 = current.Operand;
TypeReference val = (TypeReference)((operand2 is TypeReference) ? operand2 : null);
if (val != null)
{
if (!OriginalAssTypeRefs.ContainsKey(((MemberReference)val).FullName))
{
Type type = OriginalAss.GetType(((MemberReference)val).FullName);
if (type != null)
{
Log.Debug("Adding missing type ref: " + ((MemberReference)val).FullName + " / " + ((ModuleReference)((MemberReference)il.Method).Module).Name);
OriginalAssTypeRefs.Add(((MemberReference)val).FullName, il.Import(type));
}
}
if (OriginalAssTypeRefs.TryGetValue(((MemberReference)val).FullName, out var value))
{
operand = value;
}
}
else
{
object operand3 = current.Operand;
MethodReference val2 = (MethodReference)((operand3 is MethodReference) ? operand3 : null);
if (val2 != null)
{
if (!OriginalAssMethodRefs.ContainsKey(((MemberReference)val2).FullName))
{
Type type2 = OriginalAss.GetType(((MemberReference)((MemberReference)val2).DeclaringType).FullName);
if (type2 != null)
{
MethodInfo methodResolveAmbiguous = GetMethodResolveAmbiguous(val2, type2);
if (methodResolveAmbiguous != null)
{
Log.Debug("Adding missing method ref: " + ((MemberReference)val2).FullName + " / " + ((ModuleReference)((MemberReference)il.Method).Module).Name);
OriginalAssMethodRefs.Add(((MemberReference)val2).FullName, il.Import((MethodBase)methodResolveAmbiguous));
}
}
}
if (OriginalAssMethodRefs.TryGetValue(((MemberReference)val2).FullName, out var value2))
{
operand = value2;
}
}
else
{
object operand4 = current.Operand;
FieldReference val3 = (FieldReference)((operand4 is FieldReference) ? operand4 : null);
if (val3 != null)
{
if (!OriginalAssFieldRefs.ContainsKey(((MemberReference)val3).FullName))
{
FieldInfo fieldInfo = OriginalAss.GetType(((MemberReference)((MemberReference)val3).DeclaringType).FullName)?.GetField(((MemberReference)val3).Name, (BindingFlags)(-1));
if (fieldInfo != null)
{
Log.Debug("Adding missing field ref: " + ((MemberReference)val3).FullName + " / " + ((ModuleReference)((MemberReference)il.Method).Module).Name);
OriginalAssFieldRefs.Add(((MemberReference)val3).FullName, il.Import(fieldInfo));
}
}
if (OriginalAssFieldRefs.TryGetValue(((MemberReference)val3).FullName, out var value3))
{
operand = value3;
}
}
else
{
object operand5 = current.Operand;
CallSite val4 = (CallSite)((operand5 is CallSite) ? operand5 : null);
if (val4 != null && OriginalAssCallSites.TryGetValue(val4.FullName, out var value4))
{
operand = value4;
}
}
}
}
current.Operand = operand;
}
}
finally
{
((IDisposable)enumerator).Dispose();
}
}
}
[BepInPlugin("iDeathHD.UnityHotReload", "UnityHotReload", "1.0.1")]
public class UnityHotReloadPlugin : BaseUnityPlugin
{
public const string PluginGUID = "iDeathHD.UnityHotReload";
public const string PluginAuthor = "iDeathHD";
public const string PluginName = "UnityHotReload";
public const string PluginVersion = "1.0.1";
public void Awake()
{
Log.Init(((BaseUnityPlugin)this).Logger);
}
}
}