Decompiled source of TimeoutLimit v0.2.0

TimeoutLimit.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("TimeoutLimit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TimeoutLimit")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("FE8B42E3-7082-4DFF-A5CC-6B62B0315ACA")]
[assembly: AssemblyFileVersion("0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
namespace TimeoutLimit;

public static class CodeMatcherExtensions
{
	public static CodeMatcher GetPosition(this CodeMatcher codeMatcher, out int position)
	{
		position = codeMatcher.Pos;
		return codeMatcher;
	}

	public static CodeMatcher AddLabel(this CodeMatcher codeMatcher, out Label label)
	{
		label = default(Label);
		codeMatcher.AddLabels((IEnumerable<Label>)new Label[1] { label });
		return codeMatcher;
	}

	public static CodeMatcher GetLabels(this CodeMatcher codeMatcher, out List<Label> label)
	{
		label = codeMatcher.Labels;
		return codeMatcher;
	}

	public static CodeMatcher GetOperand(this CodeMatcher codeMatcher, out object operand)
	{
		operand = codeMatcher.Operand;
		return codeMatcher;
	}

	internal static CodeMatcher Print(this CodeMatcher codeMatcher, string message)
	{
		Debug.Log((object)message);
		return codeMatcher;
	}

	internal static CodeMatcher Print(this CodeMatcher codeMatcher, int before, int after)
	{
		for (int i = -before; i <= after; i++)
		{
			int num = i;
			int num2 = codeMatcher.Pos + num;
			if (num2 > 0)
			{
				if (num2 >= codeMatcher.Length)
				{
					break;
				}
				try
				{
					CodeInstruction val = codeMatcher.InstructionAt(num);
					Debug.Log((object)($"[{num}] " + ((object)val).ToString()));
				}
				catch (Exception ex)
				{
					Debug.Log((object)ex.Message);
				}
			}
		}
		return codeMatcher;
	}

	public static bool IsVirtCall(this CodeInstruction i, string declaringType, string name)
	{
		return i.opcode == OpCodes.Callvirt && i.operand is MethodInfo methodInfo && methodInfo.DeclaringType?.Name == declaringType && methodInfo.Name == name;
	}
}
[BepInPlugin("com.maxsch.valheim.TimeoutLimit", "TimeoutLimit", "0.2.0")]
[HarmonyPatch]
public class Plugin : BaseUnityPlugin
{
	public const string ModName = "TimeoutLimit";

	public const string ModGuid = "com.maxsch.valheim.TimeoutLimit";

	public const string ModVersion = "0.2.0";

	public static Harmony harmony;

	public static HashSet<Assembly> patchedAssemblies = new HashSet<Assembly>();

	public static CodeInstruction[] loadTimeout = (CodeInstruction[])(object)new CodeInstruction[2]
	{
		new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(Plugin), "Timeout")),
		new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.PropertyGetter(typeof(ConfigEntry<float>), "Value"))
	};

	public static MethodInfo getTime = AccessTools.PropertyGetter(typeof(Time), "time");

	public static ConfigEntry<float> Timeout { get; set; }

	public void Awake()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Expected O, but got Unknown
		Timeout = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Timeout", 90f, "Timeout in seconds");
		Timeout.SettingChanged += delegate
		{
			if (Chainloader.PluginInfos.TryGetValue("com.jotunn.jotunn", out var value))
			{
				SetJotunnTimeout(value);
			}
		};
		harmony = new Harmony("com.maxsch.valheim.TimeoutLimit");
		harmony.PatchAll();
	}

	public void Start()
	{
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_0473: Expected O, but got Unknown
		//IL_0439: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Expected O, but got Unknown
		foreach (PluginInfo value in Chainloader.PluginInfos.Values)
		{
			if (value == null || !Object.op_Implicit((Object)(object)value.Instance) || value.Metadata.GUID == "com.maxsch.valheim.TimeoutLimit")
			{
				continue;
			}
			if (value.Metadata.GUID == "com.jotunn.jotunn")
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Patching " + value.Metadata.Name + " [" + value.Metadata.GUID + "]"));
				SetJotunnTimeout(value);
				continue;
			}
			Assembly assembly = ((object)value.Instance).GetType().Assembly;
			if (!patchedAssemblies.Add(assembly))
			{
				continue;
			}
			List<Type> source = (from t in assembly.GetTypes()
				where t.IsClass && (t.Name == "ConfigSync" || t.Name == "ServerSync")
				select t).ToList();
			List<Type> list = (from t in source.SelectMany((Type t) => t.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic)).SelectMany((Type t) => t.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic))
				where t.IsClass && t.Name.Contains("waitForQueue")
				select t).ToList();
			bool flag = false;
			if (value.Metadata.GUID == "Azumatt.AzuAntiCheat" && list.Count == 0)
			{
				list = (from m in assembly.GetTypes().SelectMany((Type t) => t.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic)).SelectMany((Type t) => t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
					where m.Name.Contains("waitForQueue")
					select m).SelectMany((MethodInfo m) => m.DeclaringType?.GetNestedTypes(BindingFlags.Instance | BindingFlags.NonPublic)).ToList();
				flag = list.Count == 1;
			}
			List<MethodInfo> list2 = (from m in list.SelectMany((Type t) => t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
				where m.Name == "MoveNext"
				select m).ToList();
			if (list2.Count > 0)
			{
				if (value.Metadata.GUID == "Azumatt.AzuAntiCheat")
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Patching " + value.Metadata.Name + " [" + value.Metadata.GUID + "] (special case: " + (flag ? "yes" : "no") + ")"));
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Patching " + value.Metadata.Name + " [" + value.Metadata.GUID + "]"));
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Skipping " + value.Metadata.Name + " [" + value.Metadata.GUID + "]"));
			}
			foreach (MethodInfo item in list2)
			{
				try
				{
					if (flag)
					{
						harmony.Patch((MethodBase)item, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin).GetMethod("AzuAntiCheatTranspiler")), (HarmonyMethod)null, (HarmonyMethod)null);
					}
					else
					{
						harmony.Patch((MethodBase)item, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin).GetMethod("ServerSyncTranspiler")), (HarmonyMethod)null, (HarmonyMethod)null);
					}
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to patch {item?.DeclaringType?.FullName}.{item?.Name}: {arg}");
				}
			}
		}
	}

	public void SetJotunnTimeout(PluginInfo plugin)
	{
		if (plugin != null && (Object)(object)plugin.Instance != (Object)null && plugin.Metadata.GUID == "com.jotunn.jotunn" && plugin.Metadata.Version >= new Version("2.24.0"))
		{
			Type type = AccessTools.TypeByName("Jotunn.Entities.CustomRPC, Jotunn");
			AccessTools.Field(type, "Timeout").SetValue(null, Timeout.Value);
		}
	}

	[HarmonyPatch(typeof(ZRpc), "SetLongTimeout")]
	[HarmonyTranspiler]
	public static IEnumerable<CodeInstruction> SetLongTimeoutTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[2]
		{
			new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Stsfld, (object)null, (string)null)
		};
		List<Label> label;
		return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, array).RemoveInstructions(1).InsertAndAdvance(loadTimeout)
			.MatchForward(false, array)
			.GetLabels(out label)
			.RemoveInstructions(1)
			.Insert(loadTimeout)
			.AddLabels((IEnumerable<Label>)label)
			.InstructionEnumeration();
	}

	[HarmonyPatch(typeof(Debug), "Log", new Type[] { typeof(object) })]
	[HarmonyPrefix]
	public static bool DebugContext(object message)
	{
		if (message is string text && text.Contains("seconds config sending timeout") && !text.StartsWith("["))
		{
			Assembly assembly;
			try
			{
				assembly = (new StackTrace().GetFrames() ?? Array.Empty<StackFrame>()).First((StackFrame x) => x.GetMethod().ReflectedType?.Assembly != typeof(Plugin).Assembly && x.GetMethod().ReflectedType?.Assembly != typeof(Debug).Assembly).GetMethod().ReflectedType?.Assembly;
			}
			catch (Exception)
			{
				return true;
			}
			if (assembly != null)
			{
				Debug.Log((object)$"[{assembly.GetName().Name}] {message}");
				return false;
			}
		}
		return true;
	}

	public static IEnumerable<CodeInstruction> ServerSyncTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Expected O, but got Unknown
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Expected O, but got Unknown
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Expected O, but got Unknown
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Expected O, but got Unknown
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Expected O, but got Unknown
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Expected O, but got Unknown
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Expected O, but got Unknown
		return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[3]
		{
			new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, getTime)), (string)null),
			new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Add, (object)null, (string)null)
		}).ThrowIfNotMatch("Failed to match timeout calculation", Array.Empty<CodeMatch>()).Advance(1)
			.RemoveInstructions(1)
			.InsertAndAdvance(loadTimeout)
			.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"Disconnecting {0} after 30 seconds config sending timeout", (string)null)
			})
			.ThrowIfNotMatch("Failed to match disconnect message", Array.Empty<CodeMatch>())
			.RemoveInstructions(1)
			.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Ldstr, (object)"Disconnecting {0} after {1} seconds config sending timeout")
			})
			.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Call && i.operand is MethodInfo methodInfo && methodInfo.Name == "Format"), (string)null)
			})
			.ThrowIfNotMatch("Failed to match string.Format", Array.Empty<CodeMatch>())
			.RemoveInstructions(1)
			.InsertAndAdvance(loadTimeout)
			.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Box, (object)typeof(float))
			})
			.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(string), "Format", new Type[3]
				{
					typeof(string),
					typeof(object),
					typeof(object)
				}, (Type[])null))
			})
			.InstructionEnumeration();
	}

	public static IEnumerable<CodeInstruction> AzuAntiCheatTranspiler(IEnumerable<CodeInstruction> instructions)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Expected O, but got Unknown
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Expected O, but got Unknown
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: Expected O, but got Unknown
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Expected O, but got Unknown
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Expected O, but got Unknown
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Expected O, but got Unknown
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Expected O, but got Unknown
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Expected O, but got Unknown
		return new CodeMatcher(instructions, (ILGenerator)null).Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[3]
		{
			new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => CodeInstructionExtensions.Calls(i, getTime)), (string)null),
			new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)null, (string)null),
			new CodeMatch((OpCode?)OpCodes.Add, (object)null, (string)null)
		}).ThrowIfNotMatch("Failed to match timeout calculation", Array.Empty<CodeMatch>())
			.Advance(1)
			.RemoveInstructions(1)
			.InsertAndAdvance(loadTimeout)
			.Start()
			.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Call && i.operand is MethodInfo methodInfo && methodInfo.Name == "Format"), (string)null)
			})
			.ThrowIfNotMatch("Failed to match string.Format", Array.Empty<CodeMatch>())
			.Advance(1)
			.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[6]
			{
				new CodeInstruction(OpCodes.Pop, (object)null),
				new CodeInstruction(OpCodes.Ldstr, (object)"Disconnecting peer after {0} seconds config sending timeout"),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(Plugin), "Timeout")),
				new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.PropertyGetter(typeof(ConfigEntry<float>), "Value")),
				new CodeInstruction(OpCodes.Box, (object)typeof(float)),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(string), "Format", new Type[2]
				{
					typeof(string),
					typeof(object)
				}, (Type[])null))
			})
			.InstructionEnumeration();
	}
}