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();
}
}