Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValPerfPatcher v1.0.5
plugins/ValPerfPatcher.dll
Decompiled 2 hours agousing System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HearthBelow.Digging; using HearthBelow.VoxelMagic; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ValPerfPatcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.5.0")] [assembly: AssemblyInformationalVersion("1.0.5+004fd5406df17584e42a27c774cb856107e63cf4")] [assembly: AssemblyProduct("ValPerfPatcher")] [assembly: AssemblyTitle("ValPerfPatcher")] [assembly: AssemblyVersion("1.0.5.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 ValPerfPatcher { internal static class AdventureBackpacksProxyFix { public const string TargetGuid = "vapok.mods.adventurebackpacks"; private const string Outer = "AdventureBackpacks.Patches.ContainerPatches"; private const string ProxyName = "AB_BackpackProxy"; private static readonly string[] Patches = new string[4] { "ZNetViewIsOwnerPatch", "ZNetViewInvokeRpcPatch", "ZNetViewInvokeRpcWithTargetPatch", "ZNetViewAwakePatch" }; private static readonly Dictionary<int, bool> Cache = new Dictionary<int, bool>(); private static int _replaced; public static string Apply(Harmony harmony) { //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown Type type = AccessTools.TypeByName("AdventureBackpacks.Patches.ContainerPatches"); if (type == null) { return "Adventure Backpacks' container patches were not found"; } int num = 0; int num2 = 0; string[] patches = Patches; foreach (string text in patches) { Type type2 = AccessTools.Inner(type, text); MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "Prefix", (Type[])null, (Type[])null)); if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(bool))) { num2++; int replaced = _replaced; harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AdventureBackpacksProxyFix), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); if (_replaced == replaced + 1) { num++; } else { harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)3, harmony.Id); } } } if (num == 0) { return "Adventure Backpacks' backpack check has changed since this fix was written"; } harmony.Patch((MethodBase)AccessTools.Method(typeof(Game), "Shutdown", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AdventureBackpacksProxyFix), "Clear", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (num != num2) { return $"only {num} of {num2} checks matched; the rest are left as they were"; } return null; } public static bool IsProxy(GameObject go) { int instanceID = ((Object)go).GetInstanceID(); if (!Cache.TryGetValue(instanceID, out var value)) { if (Cache.Count > 200000) { Cache.Clear(); } value = ((Object)go).name.StartsWith("AB_BackpackProxy", StringComparison.Ordinal); Cache[instanceID] = value; } return value; } private static void Clear() { Cache.Clear(); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo objB = AccessTools.PropertyGetter(typeof(Object), "name"); MethodInfo objB2 = AccessTools.Method(typeof(string), "StartsWith", new Type[1] { typeof(string) }, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(AdventureBackpacksProxyFix), "IsProxy", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = -1; int num2 = 0; for (int i = 0; i + 2 < list.Count; i++) { if ((list[i].opcode == OpCodes.Callvirt || list[i].opcode == OpCodes.Call) && object.Equals(list[i].operand, objB) && list[i + 1].opcode == OpCodes.Ldstr && (string)list[i + 1].operand == "AB_BackpackProxy" && (list[i + 2].opcode == OpCodes.Callvirt || list[i + 2].opcode == OpCodes.Call) && object.Equals(list[i + 2].operand, objB2)) { num = i; num2++; } } if (num2 != 1 || list[num + 1].labels.Count > 0 || list[num + 2].labels.Count > 0) { return list; } list[num].opcode = OpCodes.Call; list[num].operand = operand; list.RemoveRange(num + 1, 2); _replaced++; return list; } } internal static class AzuEpiBackpackFix { public const string TargetGuid = "Azumatt.AzuExtendedPlayerInventory"; private const string TypeName = "AzuEPI.Game.Compatibility.AdvBackpacks.AdvBackpacksCompat"; private static readonly Dictionary<SharedData, bool> Cache = new Dictionary<SharedData, bool>(); private const string BackpackData = "AdventureBackpacks#AdventureBackpacks.Components.BackpackComponent"; private const string OldBackpackData = "JotunnBackpacks#JotunnBackpacks.BackpackComponent"; public static string Apply(Harmony harmony) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_0091: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown Type type = AccessTools.TypeByName("AzuEPI.Game.Compatibility.AdvBackpacks.AdvBackpacksCompat"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "IsBackpackItem", new Type[1] { typeof(ItemData) }, (Type[])null)); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { return "AzuExtendedPlayerInventory's backpack check has changed since this fix was written"; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AzuEpiBackpackFix), "Prefix", (Type[])null), new HarmonyMethod(typeof(AzuEpiBackpackFix), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Game), "Shutdown", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AzuEpiBackpackFix), "Clear", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Prefix(ItemData item, ref bool __result, out bool __state) { __state = false; SharedData val = item?.m_shared; if (val == null) { return true; } if (Cache.TryGetValue(val, out var value)) { if (!value && HasBackpackData(item)) { return true; } __result = value; return false; } __state = !HasBackpackData(item); return true; } private static bool HasBackpackData(ItemData item) { Dictionary<string, string> customData = item.m_customData; if (customData != null && customData.Count > 0) { if (!customData.ContainsKey("AdventureBackpacks#AdventureBackpacks.Components.BackpackComponent")) { return customData.ContainsKey("JotunnBackpacks#JotunnBackpacks.BackpackComponent"); } return true; } return false; } private static void Postfix(ItemData item, bool __result, bool __state) { if (__state && !((Object)(object)Player.m_localPlayer == (Object)null)) { if (Cache.Count > 4096) { Cache.Clear(); } Cache[item.m_shared] = __result; } } private static void Clear() { Cache.Clear(); } } internal static class BetterMapLocationPinsFix { public const string TargetGuid = "xtav1m.BetterMap"; private const float GameInterval = 5f; private static FieldRef<Minimap, float> _timer; public static string Apply(Harmony harmony) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown Type type = AccessTools.TypeByName("BetterMap.Scripts.Pins.NamedPinPatches"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, "Minimap_UpdateLocationPins_Postfix", Type.EmptyTypes, (Type[])null)); Type type2 = AccessTools.TypeByName("BetterMap.Scripts.Pins.NamedPins"); FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(Minimap), "m_updateLocationsTimer"); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(Minimap), "UpdateLocationPins", new Type[1] { typeof(float) }, (Type[])null); if (methodInfo == null || !methodInfo.IsStatic || methodInfo.ReturnType != typeof(void) || type2 == null || AccessTools.DeclaredMethod(type2, "NameLocationPins", Type.EmptyTypes, (Type[])null) == null) { return "BetterMap's trader pin naming has changed since this fix was written"; } if (fieldInfo == null || fieldInfo.FieldType != typeof(float) || methodInfo2 == null) { return "the game's location pin update has changed since this fix was written"; } if (!HasTimerReset(methodInfo2)) { return "the game's location pin update no longer resets its timer to 5 seconds"; } _timer = AccessTools.FieldRefAccess<Minimap, float>(fieldInfo); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BetterMapLocationPinsFix), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool HasTimerReset(MethodInfo update) { List<CodeInstruction> originalInstructions; try { originalInstructions = PatchProcessor.GetOriginalInstructions((MethodBase)update, (ILGenerator)null); } catch { return false; } for (int i = 0; i + 1 < originalInstructions.Count; i++) { if (originalInstructions[i].opcode == OpCodes.Ldc_R4 && originalInstructions[i].operand is float num && num == 5f && originalInstructions[i + 1].opcode == OpCodes.Stfld && originalInstructions[i + 1].operand is FieldInfo { Name: "m_updateLocationsTimer" }) { return true; } } return false; } private static bool Prefix() { Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return true; } return _timer.Invoke(instance) >= 5f; } } internal static class BundleCacheFix { private sealed class FileKey { public long Length; public DateTime Written; public string Key; } private const long MinBundleBytes = 262144L; private const int TailBytes = 1048576; private const string Extension = ".lz4bundle"; private static string _dir; private static ManualLogSource _log; private static readonly HashSet<string> Converting = new HashSet<string>(); private static readonly Dictionary<string, FileKey> FileKeys = new Dictionary<string, FileKey>(StringComparer.OrdinalIgnoreCase); internal static int LoadedFromCopy; internal static int Queued; internal static int Converted; internal static int Failed; internal static double SourceMegabytes; public static string Apply(Harmony harmony, ManualLogSource log) { //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Expected O, but got Unknown _log = log; _dir = Path.Combine(Path.Combine(Paths.CachePath, "ValPerfPatcher"), "bundles"); Directory.CreateDirectory(_dir); CleanUp(); Type typeFromHandle = typeof(AssetBundle); (string, Type[], string)[] obj = new(string, Type[], string)[16] { ("LoadFromStream", new Type[1] { typeof(Stream) }, "Stream1"), ("LoadFromStream", new Type[2] { typeof(Stream), typeof(uint) }, "Stream2"), ("LoadFromStream", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }, "Stream2"), ("LoadFromStreamAsync", new Type[1] { typeof(Stream) }, "StreamAsync1"), ("LoadFromStreamAsync", new Type[2] { typeof(Stream), typeof(uint) }, "StreamAsync2"), ("LoadFromStreamAsync", new Type[3] { typeof(Stream), typeof(uint), typeof(uint) }, "StreamAsync2"), ("LoadFromMemory", new Type[1] { typeof(byte[]) }, "Memory1"), ("LoadFromMemory", new Type[2] { typeof(byte[]), typeof(uint) }, "Memory2"), ("LoadFromMemoryAsync", new Type[1] { typeof(byte[]) }, "MemoryAsync1"), ("LoadFromMemoryAsync", new Type[2] { typeof(byte[]), typeof(uint) }, "MemoryAsync2"), ("LoadFromFile", new Type[1] { typeof(string) }, "File1"), ("LoadFromFile", new Type[2] { typeof(string), typeof(uint) }, "File2"), ("LoadFromFile", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }, "File3"), ("LoadFromFileAsync", new Type[1] { typeof(string) }, "File1"), ("LoadFromFileAsync", new Type[2] { typeof(string), typeof(uint) }, "File2"), ("LoadFromFileAsync", new Type[3] { typeof(string), typeof(uint), typeof(ulong) }, "File3") }; MethodInfo methodInfo = AccessTools.DeclaredMethod(typeFromHandle, "RecompressAssetBundleAsync", (Type[])null, (Type[])null); List<(MethodInfo, string)> list = new List<(MethodInfo, string)>(); (string, Type[], string)[] array = obj; for (int i = 0; i < array.Length; i++) { (string, Type[], string) tuple = array[i]; string item = tuple.Item1; Type[] item2 = tuple.Item2; string item3 = tuple.Item3; MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeFromHandle, item, item2, (Type[])null); if (methodInfo2 == null || methodInfo == null) { return "Unity's asset bundle loading has changed since this fix was written"; } list.Add((methodInfo2, item3)); } foreach (var (methodInfo3, text) in list) { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(BundleCacheFix), text, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } return null; } private static bool Stream1(Stream stream, ref AssetBundle __result) { return Replace(CopyFor(stream), ref __result); } private static bool Stream2(Stream stream, uint crc, ref AssetBundle __result) { if (crc == 0) { return Replace(CopyFor(stream), ref __result); } return true; } private static bool StreamAsync1(Stream stream, ref AssetBundleCreateRequest __result) { return ReplaceAsync(CopyFor(stream), ref __result); } private static bool StreamAsync2(Stream stream, uint crc, ref AssetBundleCreateRequest __result) { if (crc == 0) { return ReplaceAsync(CopyFor(stream), ref __result); } return true; } private static bool Memory1(byte[] binary, ref AssetBundle __result) { return Replace(CopyFor(binary), ref __result); } private static bool Memory2(byte[] binary, uint crc, ref AssetBundle __result) { if (crc == 0) { return Replace(CopyFor(binary), ref __result); } return true; } private static bool MemoryAsync1(byte[] binary, ref AssetBundleCreateRequest __result) { return ReplaceAsync(CopyFor(binary), ref __result); } private static bool MemoryAsync2(byte[] binary, uint crc, ref AssetBundleCreateRequest __result) { if (crc == 0) { return ReplaceAsync(CopyFor(binary), ref __result); } return true; } private static void File1(ref string path) { Redirect(ref path); } private static void File2(ref string path, uint crc) { if (crc == 0) { Redirect(ref path); } } private static void File3(ref string path, uint crc, ulong offset) { if (crc == 0 && offset == 0L) { Redirect(ref path); } } private static bool Replace(string copy, ref AssetBundle __result) { if (copy == null) { return true; } AssetBundle val = AssetBundle.LoadFromFile(copy); if ((Object)(object)val == (Object)null) { _log.LogWarning((object)("Asset bundle copy " + Path.GetFileName(copy) + " didn't load; using the mod's own bundle.")); return true; } LoadedFromCopy++; __result = val; return false; } private static bool ReplaceAsync(string copy, ref AssetBundleCreateRequest __result) { if (copy == null) { return true; } AssetBundleCreateRequest val = AssetBundle.LoadFromFileAsync(copy); if (val == null) { return true; } LoadedFromCopy++; __result = val; return false; } private static void Redirect(ref string path) { string text = CopyFor(path); if (text != null) { LoadedFromCopy++; path = text; } } private static string CopyFor(byte[] binary) { if (binary == null || (long)binary.Length < 262144L) { return null; } using MemoryStream stream = new MemoryStream(binary, writable: false); return CopyFor(stream); } private static string CopyFor(Stream stream) { try { if (stream == null || !stream.CanRead || !stream.CanSeek) { return null; } long position = stream.Position; long num = stream.Length - position; if (num < 262144) { return null; } string text; try { text = SolidLzmaKey(stream, position, num); } finally { stream.Position = position; } if (text == null) { return null; } string text2 = Ready(text); if (text2 == null && Converting.Add(text)) { string text3 = Path.Combine(_dir, text + ".src"); try { using FileStream destination = File.Create(text3); stream.CopyTo(destination); } finally { stream.Position = position; } StartConversion(text, text3, deleteSource: true); } return text2; } catch (Exception ex) { _log.LogWarning((object)("Asset bundle cache: " + ex.GetType().Name + ": " + ex.Message + "; using the usual load.")); return null; } } private static string CopyFor(string path) { try { if (string.IsNullOrEmpty(path) || path.StartsWith(_dir, StringComparison.OrdinalIgnoreCase)) { return null; } FileInfo fileInfo = new FileInfo(path); if (!fileInfo.Exists || fileInfo.Length < 262144) { return null; } if (!FileKeys.TryGetValue(path, out var value) || value.Length != fileInfo.Length || value.Written != fileInfo.LastWriteTimeUtc) { value = new FileKey { Length = fileInfo.Length, Written = fileInfo.LastWriteTimeUtc }; using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { value.Key = SolidLzmaKey(stream, 0L, fileInfo.Length); } FileKeys[path] = value; } if (value.Key == null) { return null; } string text = Ready(value.Key); if (text == null && Converting.Add(value.Key)) { StartConversion(value.Key, path, deleteSource: false); } return text; } catch (Exception ex) { _log.LogWarning((object)("Asset bundle cache: " + ex.GetType().Name + ": " + ex.Message + "; using the usual load.")); return null; } } private static string Ready(string key) { string text = Path.Combine(_dir, key + ".lz4bundle"); if (!File.Exists(text)) { return null; } try { File.SetLastWriteTimeUtc(text, DateTime.UtcNow); } catch { } return text; } private static void StartConversion(string key, string source, bool deleteSource) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) string temp = Path.Combine(_dir, key + ".tmp"); string copy = Path.Combine(_dir, key + ".lz4bundle"); SourceMegabytes += (double)new FileInfo(source).Length / 1000000.0; AssetBundleRecompressOperation op = AssetBundle.RecompressAssetBundleAsync(source, temp, BuildCompression.LZ4Runtime, 0u, (ThreadPriority)0); if (op == null) { if (deleteSource) { TryDelete(source); } Failed++; return; } Queued++; ((AsyncOperation)op).completed += delegate { try { if (op.success && File.Exists(temp)) { File.Move(temp, copy); Converted++; _log.LogInfo((object)$"Asset bundle {Path.GetFileName(source)}: fast-loading copy ready ({(double)new FileInfo(copy).Length / 1000000.0:F1} MB), used from the next load."); } else { Failed++; _log.LogWarning((object)("Asset bundle " + Path.GetFileName(source) + ": conversion failed (" + op.humanReadableResult + "); it keeps loading the usual way.")); } } catch (Exception ex) { _log.LogWarning((object)("Asset bundle " + key + ": " + ex.Message)); } finally { if (deleteSource) { TryDelete(source); } TryDelete(temp); } }; } private static string SolidLzmaKey(Stream stream, long start, long length) { byte[] array = new byte[(int)Math.Min(length, 65536L)]; ReadFully(stream, array, array.Length); if (!IsLzmaBundle(stream, start, length, array)) { return null; } byte[] bytes = Encoding.UTF8.GetBytes(Application.unityVersion); ulong hash = Fnv(14695981039346656037uL, bytes, bytes.Length); hash = Fnv(hash, array, Math.Min(array.Length, 4096)); int num = (int)Math.Min(length, 1048576L); byte[] array2 = new byte[num]; stream.Position = start + length - num; ReadFully(stream, array2, num); hash = Fnv(hash, array2, num); return $"{length:x}-{hash:x16}"; } private static bool IsLzmaBundle(Stream stream, long start, long length, byte[] head) { int i = 0; if (head.Length < 64 || ReadCString(head, ref i) != "UnityFS") { return false; } uint num = ReadU32(head, ref i); ReadCString(head, ref i); ReadCString(head, ref i); i += 8; int num2 = (int)ReadU32(head, ref i); int num3 = (int)ReadU32(head, ref i); uint num4 = ReadU32(head, ref i); if (num >= 7) { i = (i + 15) / 16 * 16; } if (num2 <= 0 || num3 <= 0 || num2 > length || num3 > 67108864) { return false; } byte[] array = new byte[num2]; if ((num4 & 0x80) != 0) { stream.Position = start + length - num2; ReadFully(stream, array, num2); } else if (i + num2 <= head.Length) { Buffer.BlockCopy(head, i, array, 0, num2); } else { stream.Position = start + i; ReadFully(stream, array, num2); } switch (num4 & 0x3F) { case 2u: case 3u: array = Lz4Block(array, num3); break; default: return false; case 0u: break; } int num5 = 16; int num6 = ReadI32BE(array, num5); num5 += 4; if (num6 <= 0 || 20 + num6 * 10 > array.Length) { return false; } int num7 = 0; while (num7 < num6) { if ((((array[num5 + 8] << 8) | array[num5 + 9]) & 0x3F) == 1) { return true; } num7++; num5 += 10; } return false; } private static byte[] Lz4Block(byte[] src, int size) { byte[] array = new byte[size]; int num = 0; int num2 = 0; while (num < src.Length && num2 < size) { int num3 = src[num++]; int num4 = num3 >> 4; if (num4 == 15) { int num5; do { num5 = src[num++]; num4 += num5; } while (num5 == 255); } Buffer.BlockCopy(src, num, array, num2, num4); num += num4; num2 += num4; if (num >= src.Length || num2 >= size) { break; } int num6 = src[num] | (src[num + 1] << 8); num += 2; int num7 = num3 & 0xF; if (num7 == 15) { int num8; do { num8 = src[num++]; num7 += num8; } while (num8 == 255); } num7 += 4; int num9 = 0; while (num9 < num7) { array[num2] = array[num2 - num6]; num9++; num2++; } } return array; } private static ulong Fnv(ulong hash, byte[] data, int count) { for (int i = 0; i < count; i++) { hash = (hash ^ data[i]) * 1099511628211L; } return hash; } private static string ReadCString(byte[] b, ref int i) { int num = i; while (i < b.Length && b[i] != 0) { i++; } string result = Encoding.ASCII.GetString(b, num, i - num); i++; return result; } private static uint ReadU32(byte[] b, ref int i) { int result = (b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]; i += 4; return (uint)result; } private static int ReadI32BE(byte[] b, int i) { return (b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]; } private static void ReadFully(Stream s, byte[] buffer, int count) { int num; for (int i = 0; i < count; i += num) { num = s.Read(buffer, i, count - i); if (num <= 0) { throw new EndOfStreamException(); } } } private static void CleanUp() { string[] files = Directory.GetFiles(_dir); foreach (string text in files) { if (text.EndsWith(".src") || text.EndsWith(".tmp")) { TryDelete(text); } else if (text.EndsWith(".lz4bundle") && File.GetLastWriteTimeUtc(text) < DateTime.UtcNow.AddDays(-30.0)) { TryDelete(text); } } } private static void TryDelete(string path) { try { if (File.Exists(path)) { File.Delete(path); } } catch { } } } internal static class ChebyshevDistanceFix { internal const string VcpGuid = "MidnightsFX.ValheimCommunityPatch"; public static string Apply(Harmony harmony) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Utils), "ChebyshevDistance", new Type[2] { typeof(Vector3), typeof(Vector3) }, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(float)) { return "Utils.ChebyshevDistance has changed since this fix was written"; } if (!PatchProcessor.GetOriginalInstructions((MethodBase)methodInfo, (ILGenerator)null).Any((CodeInstruction i) => i.opcode == OpCodes.Newarr)) { return "Utils.ChebyshevDistance no longer allocates; nothing to fix"; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo != null && patchInfo.Transpilers.Any((Patch p) => p.owner == "MidnightsFX.ValheimCommunityPatch")) { return "already done by Valheim Community Patch"; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ChebyshevDistanceFix), "Prefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Prefix(Vector3 a, Vector3 b, ref float __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Abs(a.x - b.x); float num2 = Mathf.Abs(a.y - b.y); float num3 = Mathf.Abs(a.z - b.z); if (num2 > num) { num = num2; } if (num3 > num) { num = num3; } __result = num; return false; } } internal static class ComfortTweaksConfigFix { public const string TargetGuid = "xyz.alcan.comfortcalc"; private static ConfigFile _config; public static string Apply(Harmony harmony) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_00d6: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("xyz.alcan.comfortcalc", out var value) || (Object)(object)value.Instance == (Object)null) { return "Comfort Tweaks isn't loaded"; } Type nestedType = ((object)value.Instance).GetType().GetNestedType("FetchPieces", AccessTools.all); MethodInfo methodInfo = ((nestedType == null) ? null : AccessTools.DeclaredMethod(nestedType, "Postfix", new Type[1] { typeof(ZNetScene) }, (Type[])null)); if (methodInfo == null || !methodInfo.IsStatic) { return "Comfort Tweaks' piece setup has changed since this fix was written"; } _config = value.Instance.Config; if (_config == null) { return "Comfort Tweaks has no config file"; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ComfortTweaksConfigFix), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ComfortTweaksConfigFix), "Finalizer", (Type[])null), (HarmonyMethod)null); return null; } private static void Prefix(out int __state) { __state = -1; if (_config.SaveOnConfigSet) { __state = _config.Count; _config.SaveOnConfigSet = false; } } private static Exception Finalizer(Exception __exception, int __state) { if (__state >= 0) { _config.SaveOnConfigSet = true; if (_config.Count != __state) { _config.Save(); } } return __exception; } } internal static class CreatureLevelSectorTextFix { public const string TargetGuid = "org.bepinex.plugins.creaturelevelcontrol"; public static float IntervalSeconds = 0.25f; private static FieldInfo _text; private static object _lastText; private static float _next; public static string Apply(Harmony harmony) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown Type type = AccessTools.TypeByName("CreatureLevelControl.CreatureSector"); Type type2 = ((type == null) ? null : AccessTools.Inner(type, "PatchMinimapSectorUpdate")); MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "Postfix", Type.EmptyTypes, (Type[])null)); _text = ((type == null) ? null : AccessTools.Field(type, "minimapSectorText")); if (methodInfo == null || methodInfo.ReturnType != typeof(void) || _text == null || !_text.IsStatic) { return "Creature Level & Loot Control's minimap level code has changed since this fix was written"; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CreatureLevelSectorTextFix), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Prefix() { if (IntervalSeconds <= 0f) { return true; } object value = _text.GetValue(null); float unscaledTime = Time.unscaledTime; if (value != null && value == _lastText && unscaledTime < _next) { return false; } _lastText = value; _next = unscaledTime + IntervalSeconds; return true; } } internal static class CreatureManagerSpawnFix { private sealed class Copy { public FieldInfo LastField; public SpawnSystemList List; public HashSet<SpawnData> Entries; public bool Dirty = true; } private static readonly Dictionary<Type, Copy> Copies = new Dictionary<Type, Copy>(); public static string Apply(Harmony harmony, ManualLogSource log) { //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_01c9: Expected O, but got Unknown int num = 0; int num2 = 0; HashSet<Assembly> hashSet = new HashSet<Assembly>(); foreach (PluginInfo value in Chainloader.PluginInfos.Values) { BaseUnityPlugin instance = value.Instance; if ((Object)(object)instance == (Object)null || !hashSet.Add(((object)instance).GetType().Assembly)) { continue; } Type type; try { type = ((object)instance).GetType().Assembly.GetType("CreatureManager.Creature", throwOnError: false); } catch { continue; } if (type == null) { continue; } MethodInfo methodInfo = AccessTools.DeclaredMethod(type, "AddToSpawnSystem", new Type[1] { typeof(SpawnSystem) }, (Type[])null); FieldInfo fieldInfo = AccessTools.DeclaredField(type, "lastRegisteredSpawns"); if (methodInfo == null || !methodInfo.IsStatic || methodInfo.ReturnType != typeof(void) || fieldInfo == null || !fieldInfo.IsStatic || fieldInfo.FieldType != typeof(List<SpawnData>)) { num2++; log.LogInfo((object)("Creature spawn lists: " + value.Metadata.Name + "'s CreatureManager looks different; left alone.")); continue; } Copy copy = new Copy { LastField = fieldInfo }; Copies[type] = copy; instance.Config.SettingChanged += delegate { copy.Dirty = true; }; instance.Config.ConfigReloaded += delegate { copy.Dirty = true; }; harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CreatureManagerSpawnFix), "Prefix", (Type[])null), new HarmonyMethod(typeof(CreatureManagerSpawnFix), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; log.LogInfo((object)("Creature spawn lists: " + value.Metadata.Name + " reuses its spawn entries.")); } if (num == 0) { if (num2 != 0) { return "the CreatureManager copies have changed since this fix was written"; } return "no mod with CreatureManager is installed"; } harmony.Patch((MethodBase)AccessTools.Method(typeof(Game), "Shutdown", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(CreatureManagerSpawnFix), "Clear", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Prefix(SpawnSystem __0, MethodBase __originalMethod, out bool __state) { __state = true; if (__originalMethod == null || !Copies.TryGetValue(__originalMethod.DeclaringType, out var value) || value.Dirty || (Object)(object)value.List == (Object)null) { return true; } if ((Object)(object)__0 == (Object)null || __0.m_spawnLists == null || __0.m_spawnLists.Count == 0) { return true; } SpawnSystemList val = __0.m_spawnLists[0]; if ((Object)(object)val != (Object)(object)value.List || val.m_spawners == null) { return true; } if (!(value.LastField.GetValue(null) is List<SpawnData> list) || list.Count != value.Entries.Count) { return true; } int num = 0; foreach (SpawnData spawner in val.m_spawners) { if (spawner != null && value.Entries.Contains(spawner)) { num++; } } if (num != value.Entries.Count) { return true; } __state = false; return false; } private static void Postfix(SpawnSystem __0, MethodBase __originalMethod, bool __state) { if (__state && !(__originalMethod == null) && Copies.TryGetValue(__originalMethod.DeclaringType, out var value)) { List<SpawnData> list = value.LastField.GetValue(null) as List<SpawnData>; if ((Object)(object)__0 == (Object)null || __0.m_spawnLists == null || __0.m_spawnLists.Count == 0 || list == null) { value.Dirty = true; return; } value.List = __0.m_spawnLists[0]; value.Entries = new HashSet<SpawnData>(list); value.Dirty = false; } } private static void Clear() { foreach (Copy value in Copies.Values) { value.Dirty = true; value.List = null; } } } internal static class DevcommandsPermissionFix { public const string TargetGuid = "server_devcommands"; private static readonly Dictionary<string, string> Lower = new Dictionary<string, string>(); private static int _replaced; public static string Apply(Harmony harmony) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown Type type = AccessTools.TypeByName("ServerDevcommands.PermissionManager"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "GetFeaturePermissionByHash", new Type[2] { typeof(string), typeof(int) }, (Type[])null)); if (methodInfo == null) { return "Server Devcommands' permission check has changed since this fix was written"; } _replaced = 0; harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DevcommandsPermissionFix), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); if (_replaced != 1) { return "Server Devcommands' permission check has changed since this fix was written"; } return null; } public static string LowerCached(string s) { if (s == null) { return null; } if (!Lower.TryGetValue(s, out var value)) { value = s.ToLower(); Lower[s] = value; } return value; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo toLower = AccessTools.Method(typeof(string), "ToLower", new Type[0], (Type[])null); MethodInfo cached = AccessTools.Method(typeof(DevcommandsPermissionFix), "LowerCached", (Type[])null, (Type[])null); bool done = false; foreach (CodeInstruction instruction in instructions) { if (!done && (instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Call) && object.Equals(instruction.operand, toLower)) { instruction.opcode = OpCodes.Call; instruction.operand = cached; done = true; _replaced++; } yield return instruction; } } } [BepInPlugin("__valheimmods.ValPerfPatcher.Early", "ValPerfPatcher (early start)", "1.0.5")] public sealed class EarlyPlugin : BaseUnityPlugin { public const string Guid = "__valheimmods.ValPerfPatcher.Early"; public const string Name = "ValPerfPatcher (early start)"; public const string VanillaFix = "Base game: read the translation table once"; public const string LocalizerFix = "LocalizationManager mods: reuse loaded text"; public const string BundleFix = "Mod asset bundles: keep a fast-loading copy"; internal static string VanillaResult = "not started"; internal static string LocalizerResult = "not started"; internal static string BundleResult = "not started"; private void Awake() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown Harmony harmony = new Harmony("__valheimmods.ValPerfPatcher.Early"); ConfigFile config = ReadOnlyMainConfig(); VanillaResult = Run(config, "Base game: read the translation table once", () => TranslationLoadFix.ApplyVanilla(harmony)); LocalizerResult = Run(config, "LocalizationManager mods: reuse loaded text", () => TranslationLoadFix.ApplyLocalizationManagers(harmony, ((BaseUnityPlugin)this).Logger)); BundleResult = Run(config, "Mod asset bundles: keep a fast-loading copy", () => BundleCacheFix.Apply(harmony, ((BaseUnityPlugin)this).Logger)); } private string Run(ConfigFile config, string name, Func<string> apply) { if (!config.Bind<bool>("Fixes", name, true, (ConfigDescription)null).Value) { return "off in config"; } try { return apply(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(name + ": " + ex.GetType().Name + ": " + ex.Message)); return ex.GetType().Name + ": " + ex.Message; } } private static ConfigFile ReadOnlyMainConfig() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown return new ConfigFile(Path.Combine(Paths.ConfigPath, "valheimmods.ValPerfPatcher.cfg"), false) { SaveOnConfigSet = false }; } } internal static class HearthBelowDigPreviewFix { private sealed class Entry { public Vector3 Center; public Vector3 Normal; public Vector3 Right; public float Scale; public float Probe; public float Radius; public float Time; public bool Result; public readonly Vector3[] Ring = (Vector3[])(object)new Vector3[48]; public readonly bool[] Valid = new bool[48]; } public const string TargetGuid = "Azumatt.HearthBelow"; private const float MaxAge = 0.2f; private const float SameDistance = 0.01f; private const float SameDirectionDot = 0.99995f; private static FieldRef<DigProjector, Vector3[]> _ring; private static FieldRef<DigProjector, bool[]> _valid; private static readonly Dictionary<(int, float), Entry> Cache = new Dictionary<(int, float), Entry>(); public static string Apply(Harmony harmony) { //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_017b: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(DigProjector), "ConformRing", new Type[6] { typeof(Vector3), typeof(Vector3), typeof(Vector3), typeof(Vector3), typeof(float), typeof(float) }, (Type[])null); if (methodInfo == null || methodInfo.ReturnType != typeof(bool)) { return "HearthBelow's dig preview has changed since this fix was written"; } if (AccessTools.Field(typeof(DigProjector), "_ring")?.FieldType != typeof(Vector3[]) || AccessTools.Field(typeof(DigProjector), "_valid")?.FieldType != typeof(bool[]) || AccessTools.Field(typeof(DigProjector), "Radius")?.FieldType != typeof(float)) { return "HearthBelow's dig preview fields have changed since this fix was written"; } _ring = AccessTools.FieldRefAccess<DigProjector, Vector3[]>("_ring"); _valid = AccessTools.FieldRefAccess<DigProjector, bool[]>("_valid"); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HearthBelowDigPreviewFix), "Prefix", (Type[])null), new HarmonyMethod(typeof(HearthBelowDigPreviewFix), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Same(Entry e, Vector3 center, Vector3 normal, Vector3 right, float scale, float probe, float radius) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime - e.Time <= 0.2f && e.Scale == scale && e.Probe == probe && e.Radius == radius) { Vector3 val = e.Center - center; if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f && Vector3.Dot(e.Normal, normal) >= 0.99995f) { return Vector3.Dot(e.Right, right) >= 0.99995f; } } return false; } private static bool Prefix(DigProjector __instance, Vector3 center, Vector3 normal, Vector3 right, float scale, float probe, ref bool __result, out bool __state) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) __state = false; Vector3[] array = _ring.Invoke(__instance); bool[] array2 = _valid.Invoke(__instance); if (array == null || array2 == null || array.Length != 48 || array2.Length != 48) { return true; } if (!Cache.TryGetValue((((Object)__instance).GetInstanceID(), scale), out var value) || !Same(value, center, normal, right, scale, probe, __instance.Radius)) { return true; } Array.Copy(value.Ring, array, 48); Array.Copy(value.Valid, array2, 48); __result = value.Result; __state = true; return false; } private static void Postfix(DigProjector __instance, Vector3 center, Vector3 normal, Vector3 right, float scale, float probe, bool __result, bool __state) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (__state) { return; } Vector3[] array = _ring.Invoke(__instance); bool[] array2 = _valid.Invoke(__instance); if (array == null || array2 == null || array.Length != 48 || array2.Length != 48) { return; } (int, float) key = (((Object)__instance).GetInstanceID(), scale); if (!Cache.TryGetValue(key, out var value)) { if (Cache.Count > 32) { Cache.Clear(); } value = (Cache[key] = new Entry()); } value.Center = center; value.Normal = normal; value.Right = right; value.Scale = scale; value.Probe = probe; value.Radius = __instance.Radius; value.Time = Time.unscaledTime; value.Result = __result; Array.Copy(array, value.Ring, 48); Array.Copy(array2, value.Valid, 48); } } internal static class HearthBelowFix { public const string TargetGuid = "Azumatt.HearthBelow"; private static Dictionary<Heightmap, VoxelZone> _zones; private static FieldRef<VoxelZone, HashSet<Vector3Int>> _dirty; private static FieldRef<VoxelZone, bool> _swapPending; private static Action _syncOverworldVisibility; public static string Apply(Harmony harmony) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(VoxelWorld), "PumpAllZones", (Type[])null, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(VoxelWorld), "Zones"); MethodInfo methodInfo2 = AccessTools.Method(typeof(VoxelWorld), "SyncOverworldVisibility", (Type[])null, (Type[])null); if (methodInfo == null || fieldInfo == null || methodInfo2 == null) { return "HearthBelow's code has changed since this fix was written"; } if (AccessTools.Field(typeof(VoxelZone), "_dirty")?.FieldType != typeof(HashSet<Vector3Int>) || AccessTools.Field(typeof(VoxelZone), "_swapPending")?.FieldType != typeof(bool)) { return "HearthBelow's zone fields have changed since this fix was written"; } _zones = (Dictionary<Heightmap, VoxelZone>)fieldInfo.GetValue(null); _dirty = AccessTools.FieldRefAccess<VoxelZone, HashSet<Vector3Int>>("_dirty"); _swapPending = AccessTools.FieldRefAccess<VoxelZone, bool>("_swapPending"); _syncOverworldVisibility = AccessTools.MethodDelegate<Action>(methodInfo2, (object)null, true); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HearthBelowFix), "Prefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool Prefix() { if (_zones == null || _zones.Count == 0) { return true; } foreach (VoxelZone value in _zones.Values) { if (value != null) { if (_swapPending.Invoke(value)) { return true; } HashSet<Vector3Int> hashSet = _dirty.Invoke(value); if (hashSet != null && hashSet.Count > 0) { return true; } } } DistantLod.Tick(); _syncOverworldVisibility(); return false; } } internal static class JotunnInputFix { public const string TargetGuid = "com.jotunn.jotunn"; private static readonly string[] Methods = new string[3] { "ZInput_GetButtonDown", "ZInput_GetButton", "ZInput_GetButtonUp" }; private static readonly Dictionary<string, string> JoyNames = new Dictionary<string, string>(); private static int _replaced; public static string Apply(Harmony harmony) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown Type type = AccessTools.TypeByName("Jotunn.Managers.InputManager"); if (type == null) { return "Jotunn's InputManager was not found"; } _replaced = 0; int num = 0; string[] methods = Methods; foreach (string text in methods) { MethodInfo methodInfo = AccessTools.Method(type, text, new Type[1] { typeof(string) }, (Type[])null); if (!(methodInfo == null) && !methodInfo.IsStatic) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(JotunnInputFix), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); num++; } } if (num == 0 || _replaced == 0) { return "Jotunn's input code has changed since this fix was written"; } return null; } public static string JoyName(string name) { if (name == null) { return "Joy!"; } if (!JoyNames.TryGetValue(name, out var value)) { value = "Joy!" + name; JoyNames[name] = value; } return value; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo objB = AccessTools.Method(typeof(string), "Concat", new Type[2] { typeof(string), typeof(string) }, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(JotunnInputFix), "JoyName", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); for (int i = 0; i + 2 < list.Count; i++) { if (list[i].opcode == OpCodes.Ldstr && (string)list[i].operand == "Joy!" && list[i + 1].opcode == OpCodes.Ldarg_1 && list[i + 2].opcode == OpCodes.Call && object.Equals(list[i + 2].operand, objB)) { list[i].opcode = OpCodes.Ldarg_1; list[i].operand = null; list[i + 1].opcode = OpCodes.Call; list[i + 1].operand = operand; list.RemoveAt(i + 2); _replaced++; } } return list; } } [BepInPlugin("valheimmods.ValPerfPatcher", "ValPerfPatcher", "1.0.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "valheimmods.ValPerfPatcher"; public const string Name = "ValPerfPatcher"; public const string Version = "1.0.5"; private Harmony _harmony; internal const string AlreadyDone = "already done by "; private void Awake() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0019: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown Harmony val = new Harmony("valheimmods.ValPerfPatcher"); Harmony val2 = val; _harmony = val; Harmony harmony = val2; Apply("HearthBelow: skip idle zone sorting", "Azumatt.HearthBelow", "HearthBelow sorts all of its terrain zones every frame, even when none has work queued (~1 KB of garbage per frame). Skip the sort and the empty zone loop on those frames; its distant-terrain and visibility updates still run every frame.", () => HearthBelowFix.Apply(harmony)); Apply("AzuExtendedPlayerInventory: cache backpack check", "Azumatt.AzuExtendedPlayerInventory", "AzuEPI's Adventure Backpacks compatibility asks 'is this item a backpack?' several times per frame, and each answer allocates (~2.5 KB of garbage per frame). Remember the answer per item type.", () => AzuEpiBackpackFix.Apply(harmony)); Apply("Jotunn: reuse gamepad button names", "com.jotunn.jotunn", "Jotunn builds the string \"Joy!\" + button name on every input check (~80 per frame, ~2.4 KB of garbage per frame). Reuse one cached string per button.", () => JotunnInputFix.Apply(harmony)); Apply("HearthBelow: reuse dig preview fit", "Azumatt.HearthBelow", "While a digging tool is held, HearthBelow's dig preview fits its rings to the ground every frame (up to 240 raycasts). While the aim stays put, reuse the last fit for up to 0.2 s. The preview looks and works the same; its settings are untouched.", () => HearthBelowDigPreviewFix.Apply(harmony)); Apply("Server Devcommands: reuse permission section name", "server_devcommands", "Every permission check (several per frame) lowercases the same section name into a new string. Lowercase it once and reuse it.", () => DevcommandsPermissionFix.Apply(harmony)); Apply("Adventure Backpacks: backpack check without garbage", "vapok.mods.adventurebackpacks", "Adventure Backpacks checks every object's name on every ownership check (hundreds per frame), making garbage each time. This remembers the answer per object instead.", () => AdventureBackpacksProxyFix.Apply(harmony)); ConfigEntry<float> sectorText = ((BaseUnityPlugin)this).Config.Bind<float>("Creature Level & Loot Control", "Minimap level refresh seconds", 0.25f, new ConfigDescription("How often the minimap's area level text is rebuilt (the mod does it every frame). 0 = every frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); CreatureLevelSectorTextFix.IntervalSeconds = sectorText.Value; sectorText.SettingChanged += delegate { CreatureLevelSectorTextFix.IntervalSeconds = sectorText.Value; }; Apply("Creature Level & Loot Control: minimap level text a few times per second", "org.bepinex.plugins.creaturelevelcontrol", "The mod rebuilds the minimap's area level text every frame, making garbage each time. This rebuilds it at most every 'Minimap level refresh seconds'.", () => CreatureLevelSectorTextFix.Apply(harmony)); Apply("BetterMap: name trader pins only when the map updates them", "xtav1m.BetterMap", "BetterMap looks up every location on the map on every frame to name the trader pins, although the game only adds or removes those pins every 5 seconds (~0.1 ms and ~0.8 KB of garbage per frame). Do it only on the frames where the game updated them.", () => BetterMapLocationPinsFix.Apply(harmony)); Report("Base game: read the translation table once", "Startup creates many English translation objects, and each one re-reads all 13 of the game's translation files (every language). Keep the words each file gives per language after the first read and add those instead. Mods' own translation hooks still run.", EarlyPlugin.VanillaResult); Report("LocalizationManager mods: reuse loaded text", "Mods that bundle LocalizationManager (Warfare, Monstrum, Wizardry, HearthBelow, AzuEPI, Comfort Tweaks and others) search the whole BepInEx folder and re-read their translation files every time any translation object is set up (some once per game translation file). Reuse each mod's already loaded text after the first time.", EarlyPlugin.LocalizerResult); Report("Mod asset bundles: keep a fast-loading copy", "Many mods ship LZMA-compressed asset bundles that Unity unpacks completely every time they load (RtD Ocean, More World Locations, Bestiary, Valheim Armory, OdinShip: about 8 s at every startup; More World Locations' location files whenever those locations load). For any mod, the first load converts a copy to LZ4 in the background (in BepInEx\\cache\\ValPerfPatcher, a few hundred MB); later loads use that copy, which is much faster. Same assets. Copies unused for 30 days are deleted.", EarlyPlugin.BundleResult); Apply("Base game: distance check without garbage", null, "The game's 'is this near the player?' distance check builds a small throwaway array on every call (about 50 bytes), and it runs thousands of times: about 600 KB every 2 seconds in the object ownership pass alone, plus building pieces, rocks, spawners and object loading. Same result, no array.", () => ChebyshevDistanceFix.Apply(harmony)); ConfigEntry<float> interval = ((BaseUnityPlugin)this).Config.Bind<float>("Base game", "Static object ground check interval", 2f, new ConfigDescription("Valheim re-checks every rock, stump and similar object for ground underneath about every 0.3 s, forever. After a check that leaves an object where it is, wait this many seconds (with a little jitter) before checking it again. An object can take up to this long to start falling after the ground under it is dug away. 0 = game default.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); StaticPhysicsThrottle.IntervalSeconds = interval.Value; interval.SettingChanged += delegate { StaticPhysicsThrottle.IntervalSeconds = interval.Value; }; Apply("Base game: throttle static object ground checks", null, "Fewer ground checks for objects that are already resting on the ground; see 'Static object ground check interval' under Base game.", () => StaticPhysicsThrottle.Apply(harmony)); } private void Start() { Apply("CreatureManager mods: reuse spawn entries", null, "Mods that bundle CreatureManager (Bestiary, Air Animals, Land Animals and others) rebuild all their creature spawn entries from config every time an area loads (reflection per creature, about 0.35 ms per area with Bestiary). Build them once and reuse them until one of that mod's settings changes.", () => CreatureManagerSpawnFix.Apply(_harmony, ((BaseUnityPlugin)this).Logger)); Apply("Vegetation: no stacked copies in new areas", null, "Some vegetation asks for groups of plants but gives them no spread, so the extra plants of a group land exactly on the first one: invisible copies that cost as much as real ones and stay in the world (RtD Ocean's seaweed, ocean bushes, ocean rocks and land plants: about half of them). In newly generated areas, place one per group instead. Areas already generated are not changed.", () => StackedVegetationFix.Apply(_harmony, ((BaseUnityPlugin)this).Logger)); Apply("Riverheim: start building the world early", "dev.gurebu.riverheim.stable", "Riverheim builds its whole world map (about 7 s) only after the game has paused and loaded the scene. Start the same build in the background as soon as a world is started from the menu, so it runs during that wait. Same world; joining someone else's server is unchanged.", () => RiverheimLoadFix.ApplyHeadStart(_harmony, ((BaseUnityPlugin)this).Logger)); Apply("Riverheim: biome map on all CPU cores", "dev.gurebu.riverheim.stable", "Every world load the game looks up the biome and height of 4 million map points one by one (about 5 s with Riverheim). Riverheim's lookups are safe to run side by side, so split them across CPU cores. Same map. Only for Riverheim worlds, and only while no other mod hooks those lookups.", () => RiverheimLoadFix.ApplyParallelBiomes(_harmony, ((BaseUnityPlugin)this).Logger)); Apply("Comfort Tweaks: save its settings once", "xyz.alcan.comfortcalc", "On the first world load Comfort Tweaks adds a setting for every comfort piece and fire (about 260), and BepInEx rewrites its whole config file after each one (about 1.5 s). Hold those saves and write the file once at the end. Same file.", () => ComfortTweaksConfigFix.Apply(_harmony)); } private void Report(string name, string description, string result) { ((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", name, true, description); if (result == null) { if (name == "LocalizationManager mods: reuse loaded text") { TranslationLoadFix.PatchNewCopies(); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"{name}: applied ({TranslationLoadFix.CopiesPatched} copies so far" + ((TranslationLoadFix.CopiesSkipped > 0) ? $", {TranslationLoadFix.CopiesSkipped} look different and were left alone" : "") + ").")); } else if (name == "Mod asset bundles: keep a fast-loading copy") { ((BaseUnityPlugin)this).Logger.LogInfo((object)($"{name}: applied ({BundleCacheFix.LoadedFromCopy} loaded from the fast copy so far" + ((BundleCacheFix.Queued > 0) ? $", {BundleCacheFix.Queued} being converted for the next launch ({BundleCacheFix.SourceMegabytes:F0} MB)" : "") + ").")); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": applied.")); } } else if (result == "off in config") { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": off in config.")); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)(name + ": not applied - " + result)); } } private void Apply(string name, string targetGuid, string description, Func<string> apply) { if (!((BaseUnityPlugin)this).Config.Bind<bool>("Fixes", name, true, description).Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": off in config.")); return; } if (targetGuid != null && !Chainloader.PluginInfos.ContainsKey(targetGuid)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": " + targetGuid + " not installed, nothing to do.")); return; } try { string text = apply(); if (text == null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": applied.")); } else if (text.StartsWith("already done by ")) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(name + ": " + text + ", nothing to do.")); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)(name + ": not applied - " + text)); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(name + ": not applied - " + ex.GetType().Name + ": " + ex.Message)); } } } internal static class RiverheimLoadFix { private sealed class Pending { public World World; public int Seed; public object Settings; public object Pipeline; public Task Task; } private delegate Biome BiomeAt(float wx, float wy); private delegate float HeightAt(float wx, float wy, out Color mask); public const string TargetGuid = "dev.gurebu.riverheim.stable"; private const string MonitorPrefix = "valheimmods.ValPerfMonitor"; private static ManualLogSource _log; private static Func<WorldGenerator, object> _getRenderer; private static Func<World, object> _getSettings; private static Func<World, bool> _isCustom; private static Func<object, object> _getConfig; private static Func<object> _buildPipeline; private static MethodInfo _compute; private static FieldInfo _cacheField; private static Assembly _riverheim; private static Pending _pending; private static World _generating; private static MethodInfo _getBiome; private static MethodInfo _getBiomeHeight; private static MethodInfo _generatePoints; private static MethodInfo _rendererBiome; private static MethodInfo _rendererHeight; private static FieldRef<AltBiomeWorldData, World> _dataWorld; private static bool _reportedStandDown; private static bool Resolve() { if (_riverheim != null) { return _getRenderer != null; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "Riverheim") { _riverheim = assembly; break; } } if (_riverheim == null) { return false; } try { Type type = _riverheim.GetType("Riverheim.Plugin.WorldGeneratorExtensions", throwOnError: false); Type type2 = _riverheim.GetType("Riverheim.Plugin.WorldExtensions", throwOnError: false); MethodInfo getRenderer = type?.GetMethod("GetRenderer", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(WorldGenerator) }, null); MethodInfo getSettings = type2?.GetMethod("GetSettings", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(World) }, null); MethodInfo methodInfo = type2?.GetMethod("IsCustomWorldgen", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(World) }, null); if (getRenderer == null || getSettings == null || methodInfo == null || methodInfo.ReturnType != typeof(bool)) { return false; } _getRenderer = (WorldGenerator g) => getRenderer.Invoke(null, new object[1] { g }); _getSettings = (World w) => getSettings.Invoke(null, new object[1] { w }); _isCustom = (Func<World, bool>)Delegate.CreateDelegate(typeof(Func<World, bool>), methodInfo); MethodInfo getConfig = _riverheim.GetType("Riverheim.Configuration.ConfigManager", throwOnError: false)?.GetMethod("GetConfig", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { getSettings.ReturnType }, null); Type type3 = _riverheim.GetType("Riverheim.Pipeline.GeneratorPipeline", throwOnError: false); Type type4 = _riverheim.GetType("Riverheim.Plugin.RiverheimPlugin+WorldGeneratorPatch", throwOnError: false); MethodInfo build = ((type4 == null) ? null : AccessTools.DeclaredMethod(type4, "BuildPipeline", Type.EmptyTypes, (Type[])null)); MethodInfo methodInfo2 = ((type3 == null) ? null : AccessTools.DeclaredMethod(type3, "Compute", new Type[2] { typeof(int), typeof(object) }, (Type[])null)); FieldInfo fieldInfo = ((type3 == null) ? null : AccessTools.Field(type3, "cache")); if (getConfig != null && build != null && build.IsStatic && build.ReturnType == type3 && methodInfo2 != null && fieldInfo != null && fieldInfo.FieldType.Name == "PipelineCache") { _getConfig = (object s) => getConfig.Invoke(null, new object[1] { s }); _buildPipeline = () => build.Invoke(null, null); _compute = methodInfo2; _cacheField = fieldInfo; } return true; } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("Riverheim: lookup failed: " + ex.Message)); } _getRenderer = null; return false; } } public static string ApplyHeadStart(Harmony harmony, ManualLogSource log) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_012b: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown _log = log; if (!Resolve()) { return "Riverheim's code has changed since this fix was written"; } if (_buildPipeline == null) { return "Riverheim's world builder has changed since this fix was written"; } MethodInfo methodInfo = AccessTools.Method(typeof(ZNet), "SetServer", new Type[6] { typeof(bool), typeof(bool), typeof(bool), typeof(string), typeof(string), typeof(World) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(WorldGenerator), "Pregenerate", Type.EmptyTypes, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return "the game's world start code has changed since this fix was written"; } if (!HasRiverheimPrefix(methodInfo2)) { return "Riverheim no longer builds its world in WorldGenerator.Pregenerate"; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(RiverheimLoadFix), "SetServerPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(RiverheimLoadFix), "PregeneratePrefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(RiverheimLoadFix), "PregenerateFinalizer", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)_compute, new HarmonyMethod(typeof(RiverheimLoadFix), "ComputePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static bool HasRiverheimPrefix(MethodBase method) { Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo == null) { return false; } foreach (Patch prefix in patchInfo.Prefixes) { if (prefix.owner == "dev.gurebu.riverheim.stable") { return true; } } return false; } private static void SetServerPostfix(bool server, World world) { try { _pending = null; if (!server || world == null || world.m_menu || world.m_seed == 0 || !_isCustom(world)) { return; } object obj = _getSettings(world); if (obj == null) { return; } object config = _getConfig(obj); object pipeline = _buildPipeline(); if (config == null || pipeline == null) { return; } int seed = world.m_seed; Task task = Task.Run(delegate { try { _compute.Invoke(pipeline, new object[2] { seed, config }); } catch (TargetInvocationException ex2) when (ex2.InnerException != null) { throw ex2.InnerException; } }); _pending = new Pending { World = world, Seed = seed, Settings = obj, Pipeline = pipeline, Task = task }; _log.LogInfo((object)("Riverheim: started building world '" + world.m_name + "' early, while the game loads.")); } catch (Exception ex) { _pending = null; _log.LogWarning((object)("Riverheim: early world build not started (" + ex.GetType().Name + ": " + ex.Message + "); Riverheim builds it at the usual time.")); } } private static void PregeneratePrefix(WorldGenerator __instance) { _generating = __instance.m_world; } private static Exception PregenerateFinalizer(Exception __exception) { _generating = null; _pending = null; return __exception; } private static bool ComputePrefix(object __instance, int seed) { Pending pending = _pending; World generating = _generating; if (pending == null || generating == null || __instance == pending.Pipeline) { return true; } _pending = null; try { if (pending.World != generating || pending.Seed != generating.m_seed || seed != pending.Seed) { _log.LogInfo((object)"Riverheim: the early build was for another world; building normally."); return true; } object obj = _getSettings(generating); if (obj != pending.Settings && !object.Equals(obj, pending.Settings)) { _log.LogInfo((object)"Riverheim: world settings changed after the early build started; building normally."); return true; } Stopwatch stopwatch = Stopwatch.StartNew(); try { pending.Task.Wait(); } catch (AggregateException ex) { Exception ex2 = ex.InnerException ?? ex; _log.LogWarning((object)("Riverheim: early build failed (" + ex2.GetType().Name + ": " + ex2.Message + "); building normally.")); return true; } _cacheField.SetValue(__instance, _cacheField.GetValue(pending.Pipeline)); _log.LogInfo((object)$"Riverheim: early build used (waited {stopwatch.Elapsed.TotalSeconds:0.0} s for the rest)."); return false; } catch (Exception ex3) { _log.LogWarning((object)("Riverheim: early build not used (" + ex3.GetType().Name + ": " + ex3.Message + "); building normally.")); return true; } } public static string ApplyParallelBiomes(Harmony harmony, ManualLogSource log) { //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown _log = log; if (!Resolve()) { return "Riverheim's code has changed since this fix was written"; } _generatePoints = AccessTools.DeclaredMethod(typeof(AltBiomeWorldData), "GenerateBiomePoints", new Type[1] { typeof(World) }, (Type[])null); _getBiome = AccessTools.DeclaredMethod(typeof(WorldGenerator), "GetBiome", new Type[4] { typeof(float), typeof(float), typeof(float), typeof(bool) }, (Type[])null); _getBiomeHeight = AccessTools.DeclaredMethod(typeof(WorldGenerator), "GetBiomeHeight", new Type[6] { typeof(Biome), typeof(float), typeof(float), typeof(Color).MakeByRefType(), typeof(bool), typeof(bool) }, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(AltBiomeWorldData), "m_world"); int num = _generatePoints?.GetMethodBody()?.GetILAsByteArray()?.Length ?? (-1); if (_generatePoints == null || _getBiome == null || _getBiomeHeight == null || fieldInfo?.FieldType != typeof(World) || num != 294) { return $"the game's biome map code has changed since this fix was written (size {num})"; } Type type = _riverheim.GetType("Riverheim.Plugin.Rendering.ValheimWorldRenderer", throwOnError: false); _rendererBiome = type?.GetMethod("GetBiome", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(float), typeof(float) }, null); _rendererHeight = type?.GetMethod("GetHeight", BindingFlags.Instance | BindingFlags.Public, null, new Type[3] { typeof(float), typeof(float), typeof(Color).MakeByRefType() }, null); if (_rendererBiome?.ReturnType != typeof(Biome) || _rendererHeight?.ReturnType != typeof(float)) { return "Riverheim's map lookups have changed since this fix was written"; } _dataWorld = AccessTools.FieldRefAccess<AltBiomeWorldData, World>("m_world"); harmony.Patch((MethodBase)_generatePoints, new HarmonyMethod(typeof(RiverheimLoadFix), "GeneratePointsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static string ParallelBlocker(WorldGenerator gen) { if (gen == null) { return "no world generator"; } if (_getRenderer(gen) == null) { return "the world isn't a Riverheim world"; } string text = OtherHooks(_getBiome, selfTarget: false) ?? OtherHooks(_getBiomeHeight, selfTarget: false) ?? OtherHooks(_generatePoints, selfTarget: true); if (text != null) { return text + " also hooks the biome lookups"; } return null; } private static string OtherHooks(MethodBase method, bool selfTarget) { Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo == null) { return null; } foreach (Patch prefix in patchInfo.Prefixes) { if (!Expected(prefix.owner, selfTarget, prefix: true)) { return prefix.owner; } } ReadOnlyCollection<Patch>[] array = new ReadOnlyCollection<Patch>[2] { patchInfo.Postfixes, patchInfo.Finalizers }; for (int i = 0; i < array.Length; i++) { foreach (Patch item in array[i]) { if (!Expected(item.owner, selfTarget, prefix: false)) { return item.owner; } } } if (selfTarget) { foreach (Patch transpiler in patchInfo.Transpilers) { if (!Expected(transpiler.owner, selfTarget: true, prefix: false)) { return transpiler.owner; } } } return null; } private static bool Expected(string owner, bool selfTarget, bool prefix) { if (owner != null && owner.StartsWith("valheimmods.ValPerfMonitor", StringComparison.Ordinal)) { return true; } if (selfTarget) { return owner == "valheimmods.ValPerfPatcher"; } if (prefix) { return owner == "dev.gurebu.riverheim.stable"; } return false; } private static bool GeneratePointsPrefix(World world) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) WorldGenerator instance = WorldGenerator.instance; string text; try { text = ParallelBlocker(instance); } catch (Exception ex) { text = ex.GetType().Name + ": " + ex.Message; } if (text != null) { if (!_reportedStandDown) { _log.LogInfo((object)("Biome map: filled the usual way (" + text + ").")); } _reportedStandDown = true; return true; } _reportedStandDown = false; BiomeAt biomeAt; HeightAt heightAt; try { object firstArgument = _getRenderer(instance); biomeAt = (BiomeAt)Delegate.CreateDelegate(typeof(BiomeAt), firstArgument, _rendererBiome); heightAt = (HeightAt)Delegate.CreateDelegate(typeof(HeightAt), firstArgument, _rendererHeight); } catch (Exception ex2) { _log.LogInfo((object)("Biome map: filled the usual way (Riverheim's map lookups: " + ex2.GetType().Name + ": " + ex2.Message + ").")); return true; } Stopwatch stopwatch = Stopwatch.StartNew(); AltBiomeWorldData val = new AltBiomeWorldData(2048); val.dt = DateTime.Now; BiomeIndex[,] biomes = val.PointBiomes; float[,] heights = val.PointHeights; BiomeIndex ocean = BiomeHelpers.ToBiomeIndex((Biome)256); try { Parallel.For(0, 2048, delegate(int i) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) float y = AltBiomeWorldData.MapSpaceToWorldSpace((float)i); for (int j = 0; j < 2048; j++) { Vector2 val2 = new Vector2 { x = AltBiomeWorldData.MapSpaceToWorldSpace((float)j), y = y }; if (((Vector2)(ref val2)).sqrMagnitude > 110250000f) { biomes[j, i] = ocean; heights[j, i] = -1000f; } else { biomes[j, i] = BiomeHelpers.ToBiomeIndex(biomeAt(val2.x, val2.y)); heights[j, i] = heightAt(val2.x, val2.y, out var _); } } }); } catch (Exception ex3) { Exception ex4 = (ex3 as AggregateException)?.InnerException ?? ex3; _log.LogWarning((object)("Biome map: parallel fill failed (" + ex4.GetType().Name + ": " + ex4.Message + "); filling it the usual way.")); return true; } val.PointsGenerated = true; world.m_biomeData = val; _dataWorld.Invoke(val) = world; _log.LogInfo((object)$"Biome map: filled on {Environment.ProcessorCount} threads in {stopwatch.Elapsed.TotalSeconds:0.00} s."); return false; } } internal static class StackedVegetationFix { private static ManualLogSource _log; private static ZoneSystem _checked; private static int _checkedCount = -1; public static string Apply(Harmony harmony, ManualLogSource log) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown _log = log; MethodInfo methodInfo = AccessTools.Method(typeof(ZoneSystem), "PlaceVegetation", (Type[])null, (Type[])null); if (methodInfo == null || AccessTools.Field(typeof(ZoneSystem), "m_vegetation") == null || AccessTools.Field(typeof(ZoneVegetation), "m_groupRadius") == null) { return "ZoneSystem's vegetation code has changed since this fix was written"; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(StackedVegetationFix), "Prefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static void Prefix(ZoneSystem __instance) { List<ZoneVegetation> vegetation = __instance.m_vegetation; if (vegetation == null || ((Object)(object)__instance == (Object)(object)_checked && vegetation.Count == _checkedCount)) { return; } _checked = __instance; _checkedCount = vegetation.Count; HashSet<ZoneVegetation> hashSet = GameVegetation(); List<string> list = new List<string>(); foreach (ZoneVegetation item in vegetation) { if (item != null && item.m_groupSizeMax > 1 && !(item.m_groupRadius > 0f) && !hashSet.Contains(item)) { item.m_groupSizeMax = 1; if (item.m_groupSizeMin > 1) { item.m_groupSizeMin = 1; } list.Add(((Object)(object)item.m_prefab != (Object)null) ? ((Object)item.m_prefab).name : item.m_name); } } if (list.Count > 0) { _log.LogInfo((object)string.Format("Vegetation: {0} mod entries placed groups on one spot; now one per group: {1}", list.Count, string.Join(", ", list))); } } private static HashSet<ZoneVegetation> GameVegetation() { HashSet<ZoneVegetation> hashSet = new HashSet<ZoneVegetation>(); foreach (LocationList allLocationList in LocationList.GetAllLocationLists()) { if ((Object)(object)allLocationList != (Object)null && allLocationList.m_vegetation != null) { hashSet.UnionWith(allLocationList.m_vegetation); } } foreach (AltBiome altBiome in AltBiomeList.m_altBiomes) { if (altBiome != null && altBiome.m_addVegetation != null) { hashSet.UnionWith(altBiome.m_addVegetation); } } return hashSet; } } internal static class StaticPhysicsThrottle { internal static float IntervalSeconds = 2f; private static readonly Random Jitter = new Random(); private static FieldRef<StaticPhysics, float> _updateTime; private static FieldRef<StaticPhysics, bool> _falling; public static string Apply(Harmony harmony) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_010a: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(StaticPhysics), "SUpdate", new Type[2] { typeof(float), typeof(Vector2s) }, (Type[])null); if (methodInfo == null) { return "StaticPhysics.SUpdate has changed since this fix was written"; } if (AccessTools.Field(typeof(StaticPhysics), "m_updateTime")?.FieldType != typeof(float) || AccessTools.Field(typeof(StaticPhysics), "m_falling")?.FieldType != typeof(bool)) { return "StaticPhysics' fields have changed since this fix was written"; } _updateTime = AccessTools.FieldRefAccess<StaticPhysics, float>("m_updateTime"); _falling = AccessTools.FieldRefAccess<StaticPhysics, bool>("m_falling"); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(StaticPhysicsThrottle), "Prefix", (Type[])null) { priority = 800 }, new HarmonyMethod(typeof(StaticPhysicsThrottle), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return null; } private static void Prefix(StaticPhysics __instance, float time, out bool __state) { __state = !_falling.Invoke(__instance) && time > _updateTime.Invoke(__instance); } private static void Postfix(StaticPhysics __instance, float time, bool __state) { if (__state && !_falling.Invoke(__instance) && !(IntervalSeconds <= 0f)) { _updateTime.Invoke(__instance) = time + IntervalSeconds * (0.75f + 0.5f * (float)Jitter.NextDouble()); } } } internal static class TranslationLoadFix { private sealed class Copy { public FieldInfo LoadedTexts; public FieldInfo Language; public FieldInfo Objects; public Action<Localization, string> UpdatePlaceholderText; public bool Broken; } private static ManualLogSource _log; private static Harmony _harmony; private static FieldRef<Localization, Dictionary<string, string>> _translations; private static MethodInfo _loadCsv; private static readonly Dictionary<KeyValuePair<int, string>, Dictionary<string, string>> FileWords = new Dictionary<KeyValuePair<int, string>, Dictionary<string, string>>(); private static readonly Dictionary<Type, Copy> Copies = new Dictionary<Type, Copy>(); private static readonly HashSet<MethodBase> Seen = new HashSet<MethodBase>(); private static MethodInfo _setup; public static int CopiesPatched; public static int CopiesSkipped; public static string ApplyVanilla(Harmony harmony) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_014e: Expected O, but got Unknown //IL_014e: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Localization), "LoadCSV", new Type[2] { typeof(TextAsset), typeof(string) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Localization), "AddWord", new Type[2] { typeof(string), typeof(string) }, (Type[])null); FieldInfo fieldInfo = AccessTools.Field(typeof(Localization), "m_translations"); if (methodInfo == null || methodInfo.ReturnType != typeof(bool) || methodInfo2 == null || fieldInfo?.FieldType != typeof(Dictionary<string, string>)) { return "Localization.LoadCSV has changed since this fix was written"; } if (Harmony.GetPatchInfo((MethodBase)methodInfo2) != null) { return "another mod hooks Localization.AddWord, so the words must keep going through it"; } _translations = AccessTools.FieldRefAccess<Localization, Dictionary<string, string>>("m_translations"); _loadCsv = methodInfo; harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(TranslationLoadFix), "CsvPrefix", (Type[])null) { priority = 800 }, new HarmonyMethod(typeof(TranslationLoadFix), "CsvPostfix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, new HarmonyMethod(typeof(TranslationLoadFix), "CsvFinalizer", (Type[])null), (HarmonyMethod)null); return null; } private static bool CsvPrefix(Localization __instance, TextAsset file, string language, ref bool __result, out Dictionary<string, string> __state) { __state = null; if (__instance == null || (Object)(object)file == (Object)null || language == null) { return true; } Dictionary<string, string> dictionary = _translations.Invoke(__instance); if (dictionary == null) { return true; } if (FileWords.TryGetValue(new KeyValuePair<int, string>(((Object)file).GetInstanceID(), language), out var value)) { foreach (KeyValuePair<string, string> item in value) { dictionary[item.Key] = item.Value; } __result = true; return false; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)_loadCsv); if (patchInfo != null && patchInfo.Prefixes.Count > 1) { return true; } __state = dictionary; _translations.Invoke(__instance) = new Dictionary<string, string>(); return true; } private static void CsvPostfix(Localization __instance, TextAsset file, string language, bool __result, Dictionary<string, string> __state) { if (__state != null) { Dictionary<string, string> dictionary = Restore(__instance, __state); if (__result && dictionary != null) { FileWords[new KeyValuePair<int, string>(((Object)file).GetInstanceID(), language)] = dictionary; } } } private static void CsvFinalizer(Localization __instance, Exception __exception, Dictionary<string, string> __state) { if (__exception != null && __state != null && __instance != null && _translations.Invoke(__instance) != __state) { Restore(__instance, __state); } } private static Dictionary<string, string> Restore(Localization localization, Dictionary<string, string> own) { Dictionary<string, string> dictionary = _translations.Invoke(localization); _translations.Invoke(localization) = own; if (dictionary == null || dictionary == own) { return null; } foreach (KeyValuePair<string, string> item in dictionary) { own[item.Key] = item.Value; } return dictionary; } public static string ApplyLocalizationManagers(Harmony harmony, ManualLogSource log) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown _log = log; _harmony = harmony; _setup = AccessTools.Method(typeof(Localization), "SetupLanguage", new Type[1] { typeof(string) }, (Type[])null); if (_setup == null || _setup.ReturnType != typeof(bool)) { return "Localization.SetupLanguage has changed since this fix was written"; } if (_loadCsv == null) { _loadCsv = AccessTools.Method(typeof(Localization), "LoadCSV", new Type[2] { typeof(TextAsset), typeof(string) }, (Type[])null); } harmony.Patch((MethodBase)_setup, new HarmonyMethod(typeof(TranslationLoadFix), "SetupPrefix", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); PatchNewCopies(); return null; } private static void SetupPrefix() { PatchNewCopies(); } public static void PatchNewCopies() { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown MethodInfo[] array = new MethodInfo[2] { _setup, _loadCsv }; foreach (MethodInfo methodInfo in array) { if (methodInfo == null) { continue; } Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo); if (patchInfo == null) { continue; } foreach (Patch postfix in patchInfo.Postfixes) { MethodInfo patchMethod = postfix.PatchMethod; if (patchMethod == null || !Seen.Add(patchMethod)) { continue; } Type declaringType = patchMethod.DeclaringType; if (declaringType == null || declaringType.FullName != "LocalizationManager.Localizer" || patchMethod.Name != "LoadLocalization") { continue; } ParameterInfo[] parameters = patchMethod.GetParameters(); if (parameters.Length != 2 || parameters[0].ParameterType != typeof(Localization) || parameters[1].ParameterType != typeof(string)) { CopiesSkipped++; continue; } Copy copy = Inspect(declaringType); if (copy == null) { CopiesSkipped++; continue; } try { _harmony.Patch((MethodBase)patchMethod, new HarmonyMethod(typeof(TranslationLoadFix), "LocalizerPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Copies[declaringType] = copy; CopiesPatched++; } catch (Exception ex) { CopiesSkipped++; ManualLogSource log = _log; if (log != null) { log.LogDebug((object)("LocalizationManager in " + declaringType.Assembly.GetName().Name + " not patched: " + ex.Message)); } } } } } private static Copy Inspect(Type t) { FieldInfo field = t.GetField("loadedTexts", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = t.GetField("localizationLanguage", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field3 = t.GetField("localizationObjects", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = t.GetMethod("UpdatePlaceholderText", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Localization), typeof(string) }, null); if (field?.FieldType != typeof(Dictionary<string, Dictionary<string, string>>) || field2?.FieldType != typeof(ConditionalWeakTable<Localization, string>) || field3?.FieldType != typeof(List<WeakReference<Localization>>) || method == null || method.ReturnType != typeof(void)) { return null; } try { return new Copy { LoadedTexts = field, Language = field2, Objects = field3, UpdatePlaceholderText = (Action<Localization, string>)Delegate.CreateDelegate(typeof(Action<Localization, string>), method) }; } catch { return null; } } private static bool LocalizerPrefix(MethodBase __originalMethod, Localization __0, string __1) { if (__0 == null || __1 == null) { return true; } if (!Copies.TryGetValue(__originalMethod.DeclaringType, out var value) || value.Broken) { return true; } try { Dictionary<string, Dictionary<string, string>> dictionary = (Dictionary<string, Dictionary<string, string>>)value.LoadedTexts.GetValue(null); if (dictionary == null || !dictionary.TryGetValue(__1, out var value2) || value2 == null) { return true; } ConditionalWeakTable<Localization, string> conditionalWeakTable = (ConditionalWeakTable<Localization, string>)value.Language.GetValue(null); List<WeakReference<Localization>> list = (List<WeakReference<Localization>>)value.Objects.GetValue(null); if (conditionalWeakTable == null || list == null) { return true; } if (!conditionalWeakTable.Remove(__0)) { list.Add(new WeakReference<Localization>(__0)); } conditionalWeakTable.Add(__0, __1); foreach (string item in value2.Keys.ToList()) { value.UpdatePlaceholderText(__0, item); } return false; } catch (Exception ex) { value.Broken = true; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Translations: a LocalizationManager copy (" + __originalMethod.DeclaringType.Assembly.GetName().Name + ") behaved unexpectedly, left alone from now on: " + ex.Message)); } return true; } } } }