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.InteropServices;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Daydream.NetworkBehaviourEvents")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Daydream.NetworkBehaviourEvents")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8D6B7A3E-C51F-4A44-8D6F-59A3565273B8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Daydream.NetworkBehaviourEvents;
public class Test
{
public virtual void OnTest()
{
}
}
public class Tester : Test
{
public override void OnTest()
{
base.OnTest();
}
}
public static class Preloader
{
private const string NetworkBehaviourFullName = "Unity.Netcode.NetworkBehaviour";
private static ManualLogSource Logger { get; set; }
private static TypeReference NetworkBehaviourRef { get; set; }
private static MethodReference[] NetworkBehaviourEvents { get; set; }
public static IEnumerable<string> TargetDLLs { get; } = new string[1] { "Assembly-CSharp.dll" };
public static void Patch(AssemblyDefinition assemblyDefinition)
{
Logger.LogInfo((object)"Patching NetworkBehaviour's sub-classes to always contain implementations of virtual methods..");
NetworkBehaviourRef = assemblyDefinition.MainModule.GetTypeReferences().FirstOrDefault((Func<TypeReference, bool>)((TypeReference typeRef) => ((MemberReference)typeRef).FullName == "Unity.Netcode.NetworkBehaviour"));
if (NetworkBehaviourRef == null)
{
Logger.LogError((object)"The game doesn't contain a reference to Unity.Netcode.NetworkBehaviour");
return;
}
NetworkBehaviourEvents = (from methodDef in (IEnumerable<MethodDefinition>)NetworkBehaviourRef.Resolve().Methods
where methodDef.IsVirtual && !((MethodReference)methodDef).HasGenericParameters && ((MemberReference)methodDef).Name.StartsWith("On")
select assemblyDefinition.MainModule.ImportReference((MethodReference)(object)methodDef)).ToArray();
CollectionExtensions.Do<TypeDefinition>(from typeDef in assemblyDefinition.MainModule.GetTypes()
where typeDef.IsSubclassOf("Unity.Netcode.NetworkBehaviour")
select typeDef, (Action<TypeDefinition>)delegate(TypeDefinition typeDef)
{
foreach (MethodReference item in NetworkBehaviourEvents.Where((MethodReference methodRef) => ((IEnumerable<MethodDefinition>)typeDef.Methods).All((MethodDefinition methodDef) => ((MemberReference)methodDef).Name != ((MemberReference)methodRef).Name)))
{
CreateEventMethod(assemblyDefinition, item, typeDef);
}
});
assemblyDefinition.Write(Path.Combine(Paths.CachePath, "Assembly-CSharp.dll"));
}
private static void CreateEventMethod(AssemblyDefinition assemblyDefinition, MethodReference methodReference, TypeDefinition typeDef)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
MethodDefinition val = new MethodDefinition(((MemberReference)methodReference).Name, (MethodAttributes)198, assemblyDefinition.MainModule.TypeSystem.Void);
typeDef.Methods.Add(val);
val.Body.InitLocals = true;
Enumerator<ParameterDefinition> enumerator = methodReference.Parameters.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
ParameterDefinition current = enumerator.Current;
((MethodReference)val).Parameters.Add(((ParameterReference)current).Resolve());
}
}
finally
{
((IDisposable)enumerator).Dispose();
}
ILProcessor iLProcessor = val.Body.GetILProcessor();
iLProcessor.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < methodReference.Parameters.Count; i++)
{
iLProcessor.Emit(OpCodes.Ldarg, i + 1);
}
iLProcessor.Emit(OpCodes.Call, methodReference);
iLProcessor.Emit(OpCodes.Ret);
}
private static void Initialize()
{
Logger = Logger.CreateLogSource("DayDream.NetworkBehaviourEvents");
}
public static void Finish()
{
Logger.LogInfo((object)("Patching complete! Verifying types contain {" + string.Join(", ", NetworkBehaviourEvents.Select((MethodReference evt) => ((MemberReference)evt).Name).ToArray()) + "}..."));
Assembly assembly2 = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly assembly) => assembly.FullName.StartsWith("Assembly-CSharp"));
if ((object)assembly2 == null)
{
Logger.LogError((object)"Couldn't find Assembly-CSharp within the AppDomain! Was it even patched?!");
}
else
{
if (NetworkBehaviourRef == null || NetworkBehaviourEvents == null)
{
return;
}
Type[] array = (from type in assembly2.GetTypes()
where type.IsSubclassOf("Unity.Netcode.NetworkBehaviour")
select type).ToArray();
int num = 0;
Type[] array2 = array;
foreach (Type allType in array2)
{
if (NetworkBehaviourEvents.Aggregate(0, (int i, MethodReference reference) => i + (((object)allType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo methodInfo) => methodInfo.Name == ((MemberReference)reference).Name) != null) ? 1 : 0)) == NetworkBehaviourEvents.Length)
{
num++;
}
}
Logger.LogInfo((object)(num + "/" + array.Length + " NetworkBehaviour Sub-Classes are now in compliance! Useless reference dll can be found in /BepInEx/cache/."));
}
}
private static bool IsSubclassOf(this Type type, string fullClassName)
{
if (type.FullName == fullClassName)
{
return false;
}
while ((object)type != null)
{
if (type.FullName == fullClassName)
{
return true;
}
type = type.BaseType;
}
return false;
}
private static bool IsSubclassOf(this TypeDefinition typeDefinition, string fullClassName)
{
if (((MemberReference)typeDefinition).FullName == fullClassName)
{
return false;
}
while (typeDefinition != null)
{
if (((MemberReference)typeDefinition).FullName == fullClassName)
{
return true;
}
TypeReference baseType = typeDefinition.BaseType;
typeDefinition = ((baseType != null) ? baseType.Resolve() : null);
}
return false;
}
}