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 ValheimCommunityPatch v0.22.1
plugins/ValheimCommunityPatch.dll
Decompiled 3 hours ago
The result has been truncated due to the large size, download it to view full contents!
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.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using SoftReferenceableAssets; using Unity.Collections; using UnityEngine; using UnityEngine.Rendering; using ValheimCommunityPatch.Patches.Correctness; using ValheimCommunityPatch.Patches.Performance; using ValheimCommunityPatch.Patches.Terrain; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimCommunityPatch")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimCommunityPatch")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.22.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.22.1.0")] namespace ValheimCommunityPatch { internal static class HeightmapSampling { internal static bool TryGetHeight(Heightmap hmap, Vector3 position, out float height) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) Vector3 normal; return Sample(hmap, ((Component)hmap).transform.position, position, out height, out normal, wantNormal: false); } internal static bool TryGetHeight(Heightmap hmap, Vector3 origin, Vector3 position, out float height) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Vector3 normal; return Sample(hmap, origin, position, out height, out normal, wantNormal: false); } internal static bool TryGetSurface(Heightmap hmap, Vector3 position, out float height, out Vector3 normal) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Sample(hmap, ((Component)hmap).transform.position, position, out height, out normal, wantNormal: true); } internal static bool TryGetSurface(Heightmap hmap, Vector3 origin, Vector3 position, out float height, out Vector3 normal) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) return Sample(hmap, origin, position, out height, out normal, wantNormal: true); } private static bool Sample(Heightmap hmap, Vector3 origin, Vector3 position, out float height, out Vector3 normal, bool wantNormal) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) normal = Vector3.up; int width = hmap.m_width; float scale = hmap.m_scale; float num = (position.x - origin.x) / scale + (float)width * 0.5f; float num2 = (position.z - origin.z) / scale + (float)width * 0.5f; if (num < 0f || num > (float)width || num2 < 0f || num2 > (float)width) { height = 0f; return false; } int num3 = Mathf.Min((int)num, width - 1); int num4 = Mathf.Min((int)num2, width - 1); float num5 = num - (float)num3; float num6 = num2 - (float)num4; float height2 = hmap.GetHeight(num3, num4); float height3 = hmap.GetHeight(num3 + 1, num4); float height4 = hmap.GetHeight(num3, num4 + 1); float height5 = hmap.GetHeight(num3 + 1, num4 + 1); Vector3 val; if (num5 + num6 <= 1f) { height = height2 + (height3 - height2) * num5 + (height4 - height2) * num6 + origin.y; if (wantNormal) { val = new Vector3(height2 - height3, scale, height2 - height4); normal = ((Vector3)(ref val)).normalized; } } else { height = height5 + (height4 - height5) * (1f - num5) + (height3 - height5) * (1f - num6) + origin.y; if (wantNormal) { val = new Vector3(height4 - height5, scale, height3 - height5); normal = ((Vector3)(ref val)).normalized; } } return true; } } internal static class Logger { private static bool _debug; internal static bool DebugEnabled => _debug; internal static void SetDebug(bool enabled) { _debug = enabled; } internal static void LogDebug(string message) { if (_debug) { ValheimCommunityPatch.Log.LogInfo((object)("[DEBUG]" + message)); } } internal static void LogInfo(string message) { ValheimCommunityPatch.Log.LogInfo((object)message); } internal static void LogWarning(string message) { ValheimCommunityPatch.Log.LogWarning((object)message); } internal static void LogError(string message) { ValheimCommunityPatch.Log.LogError((object)message); } internal static void DebugSink(object message) { if (_debug) { LogDebug(message?.ToString() ?? string.Empty); } } } internal static class PatchHelper { internal const int AnyCount = -1; internal static List<CodeInstruction> Copy(IEnumerable<CodeInstruction> instructions) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown List<CodeInstruction> list = ((instructions is ICollection<CodeInstruction> collection) ? new List<CodeInstruction>(collection.Count) : new List<CodeInstruction>()); foreach (CodeInstruction instruction in instructions) { list.Add(new CodeInstruction(instruction)); } return list; } internal static IEnumerable<CodeInstruction> ReplaceCalls(IEnumerable<CodeInstruction> instructions, MethodInfo original, MethodInfo replacement, string site, int expected = -1) { if (original == null || replacement == null) { Logger.LogWarning(site + ": a method this fix needs could not be resolved, so it is inactive here."); return instructions; } List<CodeInstruction> list = Copy(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], original)) { list[i].opcode = OpCodes.Call; list[i].operand = replacement; num++; } } if ((expected == -1) ? (num > 0) : (num == expected)) { return list; } string text = ((expected == -1) ? "at least 1" : expected.ToString()); Logger.LogWarning(site + ": expected " + text + " call(s) to " + original.DeclaringType?.Name + "." + original.Name + ", " + $"found {num}, so this fix is inactive here. Another mod has most likely already " + "rewritten the method - if so, nothing is wrong."); return instructions; } internal static bool HasHook(MethodBase target, Type hookClass) { Patches val = ((target == null) ? null : Harmony.GetPatchInfo(target)); if (val == null) { return false; } if (!DeclaredBy(val.Prefixes, hookClass)) { return DeclaredBy(val.Postfixes, hookClass); } return true; } private static bool DeclaredBy(IReadOnlyList<Patch> patches, Type hookClass) { foreach (Patch patch in patches) { if (!(patch.owner != "MidnightsFX.ValheimCommunityPatch") && patch.PatchMethod?.DeclaringType == hookClass) { return true; } } return false; } } internal sealed class HookHealth { private readonly string _fixName; private readonly Func<bool> _allAttached; private bool _checked; private bool _healthy; internal bool Healthy { get { if (_checked) { return _healthy; } _checked = true; _healthy = _allAttached(); if (!_healthy) { Logger.LogError(_fixName + ": a maintenance hook is not attached, so this fix stands down to vanilla for this session. A Valheim update has most likely changed one of the patched methods - look for the patch failure logged at startup."); } return _healthy; } } internal HookHealth(string fixName, Func<bool> allAttached) { _fixName = fixName; _allAttached = allAttached; } } internal enum Side { Client, Server, Both } [AttributeUsage(AttributeTargets.Class, Inherited = false)] internal sealed class PatchSideAttribute : Attribute { internal Side Side { get; } internal PatchSideAttribute(Side side) { Side = side; } internal static Side Of(Type type) { Type type2 = type; while (type2 != null) { object[] customAttributes = type2.GetCustomAttributes(typeof(PatchSideAttribute), inherit: false); if (customAttributes.Length != 0) { return ((PatchSideAttribute)customAttributes[0]).Side; } type2 = type2.DeclaringType; } return Side.Both; } internal static string Tag(Side side) { return side switch { Side.Client => "(client)", Side.Server => "(server)", _ => "(both)", }; } } internal static class RunMode { private static readonly bool _headless = (int)SystemInfo.graphicsDeviceType == 4; private static ZNet _resolvedFor; private static bool _isServer; private static bool _isDedicated; internal static bool IsHeadless => _headless; internal static bool IsServer { get { Resolve(); return _isServer; } } internal static bool IsDedicated { get { Resolve(); return _isDedicated; } } private static void Resolve() { ZNet instance = ZNet.instance; if (instance != _resolvedFor) { if (instance == null) { _resolvedFor = null; _isServer = false; _isDedicated = false; } else { _isServer = instance.IsServer(); _isDedicated = instance.IsDedicated(); _resolvedFor = instance; } } } } [PatchSide(Side.Both)] internal static class TeardownHooks { [HarmonyPatch(typeof(ZNetView))] internal static class ViewHook { [HarmonyPostfix] [HarmonyPatch("OnDestroy")] private static void OnDestroyPostfix(ZNetView __instance) { if (_statsOn) { _viewDestroys++; } if (__instance.m_ghost) { if (_statsOn) { _ghostDestroys++; } } else { SectorInstanceIndexPatch.OnViewDestroyed(__instance); } } } [HarmonyPatch(typeof(WearNTear))] internal static class PieceHook { [HarmonyPostfix] [HarmonyPatch("OnDestroy")] private static void OnDestroyPostfix(WearNTear __instance) { int instanceID = ((Object)__instance).GetInstanceID(); SupportSleepPatch.OnPieceDestroyed(__instance, instanceID); WearSupportLookupPatch.OnPieceDestroyed(instanceID); WearCacheEventPatch.OnPieceDestroyed(__instance, instanceID); } } [HarmonyPatch(typeof(ZNetScene))] internal static class FrameHook { [HarmonyPrefix] [HarmonyPatch("Update")] private static void UpdatePrefix() { if (LogStormStats == null || !LogStormStats.Value) { if (_statsOn) { LogSummary("final"); Clear(); _statsOn = false; } return; } if (!_statsOn) { _statsOn = true; Clear(); _statsSince = Time.unscaledTime; Logger.LogInfo("Destroy storm stats: on. Bucketing frames by teardown count; a summary follows every 30 s."); return; } RecordFrame(_viewDestroys, Time.unscaledDeltaTime * 1000f); _viewDestroys = 0; if (Time.unscaledTime - _statsSince >= 30f) { LogSummary("periodic"); Clear(); _statsSince = Time.unscaledTime; } } } internal static ConfigEntry<bool> LogStormStats; private static bool _statsOn; private static float _statsSince; private static int _viewDestroys; private static int _ghostDestroys; private static int _unloadPasses; private static int _unloadObjects; private static int _unloadWorstObjects; private static double _unloadMs; private static double _unloadWorstMs; private static int _unloadWorstBacklog; private static int _unloadDeferredPasses; private static readonly int[] BucketFloor = new int[5] { 0, 1, 25, 100, 500 }; private static readonly string[] BucketName = new string[5] { "0", "1-24", "25-99", "100-499", "500+" }; private static readonly long[] BucketFrames = new long[5]; private static readonly double[] BucketMs = new double[5]; private static readonly double[] BucketWorstMs = new double[5]; private const float ReportIntervalSeconds = 30f; internal static bool StatsOn => _statsOn; internal static void BindConfig() { LogStormStats = ValConfig.BindServerConfig("Debug", "Log Destroy Storm Stats", value: false, "Diagnostic. Buckets every frame by how many networked objects were torn down in it and reports the frame time each bucket ran at, so a teardown burst can be told apart from a steady drain. Also reports the unload pass's own object count and wall-clock. Costs a counter increment per destroyed object; leave it off unless you are measuring.", null, advanced: true); } internal static void NoteUnloadPass(int processed, int backlog, double milliseconds) { if (_statsOn) { _unloadPasses++; _unloadObjects += processed; _unloadMs += milliseconds; if (processed > _unloadWorstObjects) { _unloadWorstObjects = processed; } if (milliseconds > _unloadWorstMs) { _unloadWorstMs = milliseconds; } if (backlog > _unloadWorstBacklog) { _unloadWorstBacklog = backlog; } if (backlog > processed) { _unloadDeferredPasses++; } } } private static void RecordFrame(int destroys, float frameMs) { int num = 0; for (int num2 = BucketFloor.Length - 1; num2 >= 0; num2--) { if (destroys >= BucketFloor[num2]) { num = num2; break; } } BucketFrames[num]++; BucketMs[num] += frameMs; if ((double)frameMs > BucketWorstMs[num]) { BucketWorstMs[num] = frameMs; } } private static void Clear() { _viewDestroys = 0; _ghostDestroys = 0; _unloadPasses = 0; _unloadObjects = 0; _unloadWorstObjects = 0; _unloadMs = 0.0; _unloadWorstMs = 0.0; _unloadWorstBacklog = 0; _unloadDeferredPasses = 0; for (int i = 0; i < BucketFrames.Length; i++) { BucketFrames[i] = 0L; BucketMs[i] = 0.0; BucketWorstMs[i] = 0.0; } } private static void LogSummary(string kind) { long num = 0L; for (int i = 0; i < BucketFrames.Length; i++) { num += BucketFrames[i]; } if (num == 0L) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"Destroy storm stats ({kind}), {num} frame(s) over ").Append($"{Time.unscaledTime - _statsSince:F0} s:"); for (int j = 0; j < BucketFrames.Length; j++) { if (BucketFrames[j] != 0L) { stringBuilder.Append($" | {BucketName[j]} destroys: {BucketFrames[j]} frame(s), ").Append($"mean {BucketMs[j] / (double)BucketFrames[j]:F1} ms, worst {BucketWorstMs[j]:F0} ms"); } } stringBuilder.Append($" || ghost destroys {_ghostDestroys}"); if (_unloadPasses > 0) { stringBuilder.Append($" || unload pass: {_unloadPasses} pass(es), {_unloadObjects} object(s), ").Append($"{_unloadMs:F0} ms managed, worst pass {_unloadWorstObjects} object(s) / ").Append($"{_unloadWorstMs:F1} ms") .Append($", worst backlog {_unloadWorstBacklog}, {_unloadDeferredPasses} pass(es) capped"); } Logger.LogInfo(stringBuilder.ToString()); } } internal static class ValConfig { public static ConfigFile cfg; public static ConfigEntry<bool> EnableDebugMode; public static ConfigEntry<bool> PatchEverySide; public const string SectionPerformance = "Fixes - Performance"; public const string SectionCorrectness = "Fixes - Correctness"; public const string SectionTerrain = "Fixes - Terrain"; public const string SectionDebug = "Debug"; internal static void Bind(ConfigFile file) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown cfg = file; cfg.SaveOnConfigSet = false; EnableDebugMode = cfg.Bind<bool>("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdvanced = true } })); Logger.SetDebug(EnableDebugMode.Value); EnableDebugMode.SettingChanged += delegate { Logger.SetDebug(EnableDebugMode.Value); }; PatchEverySide = cfg.Bind<bool>("Client config", "Patch Every Side", false, new ConfigDescription("Applies every fix regardless of which side it is for. Normally the client-only fixes are not applied on a dedicated server, because nothing there could ever reach them. Turn this on only if this machine has a display but was detected as headless. Requires a game restart.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdvanced = true } })); BindFixConfig(); cfg.SaveOnConfigSet = true; cfg.Save(); } private static void BindFixConfig() { TeardownHooks.BindConfig(); OrphanZdoIndexPatch.BindConfig(); ZdoPrefabIndexPatch.BindConfig(); HeightmapLookupPatch.BindConfig(); StaticPhysicsCachePatch.BindConfig(); ClutterRebuildCapPatch.BindConfig(); HeightmapBuilderThroughputPatch.BindConfig(); ZoneGenPacingPatch.BindConfig(); TerrainLodSpreadPatch.BindConfig(); WearSupportLookupPatch.BindConfig(); SceneIdleSkipPatch.BindConfig(); LightCostPatch.BindConfig(); RemoveSweepPacingPatch.BindConfig(); SpawnQueueCachePatch.BindConfig(); SectorInstanceIndexPatch.BindConfig(); SupportSleepPatch.BindConfig(); ZoneDiffRemovalPatch.BindConfig(); ReflectionSlicePatch.BindConfig(); PhysicsCatchupPatch.BindConfig(); SpawnEventQueuePatch.BindConfig(); RecipeGetAmountNrePatch.BindConfig(); ProjectileZeroVelocityPatch.BindConfig(); SpawnAreaNullPrefabPatch.BindConfig(); ZdoLoadDuplicatePatch.BindConfig(); RemoveObjectsNrePatch.BindConfig(); EffectAreaPatch.BindConfig(); FuelLossPatch.BindConfig(); BossKeySharePatch.BindConfig(); ItemIconVariantPatch.BindConfig(); SendFailureLogSpamPatch.BindConfig(); ContainerLogSpamPatch.BindConfig(); NegativeStaminaPatch.BindConfig(); DungeonZoneLoadPinPatch.BindConfig(); SeamlessNormalsPatch.BindConfig(); PaintSeamReconcilePatch.BindConfig(); TerrainOpPaintFanoutPatch.BindConfig(); PaintMaskStridePatch.BindConfig(); TerrainCompNullHmapPatch.BindConfig(); } public static ConfigEntry<bool> BindFixToggle(Type patchClass, string category, string key, bool value, string description, bool advanced = false) { return BindServerConfig(category, key, value, PatchSideAttribute.Tag(PatchSideAttribute.Of(patchClass)) + " " + description, null, advanced); } public static ConfigEntry<bool> BindServerConfig(string category, string key, bool value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown return cfg.Bind<bool>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<int> BindServerConfig(string category, string key, int value, string description, bool advanced = false, int valMin = 0, int valMax = 150) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0034: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown return cfg.Bind<int>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<float> BindServerConfig(string category, string key, float value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_0034: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown return cfg.Bind<float>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } } [BepInPlugin("MidnightsFX.ValheimCommunityPatch", "ValheimCommunityPatch", "0.22.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class ValheimCommunityPatch : BaseUnityPlugin { public const string PluginGUID = "MidnightsFX.ValheimCommunityPatch"; public const string PluginName = "ValheimCommunityPatch"; public const string PluginVersion = "0.22.1"; internal static ManualLogSource Log; private readonly Harmony harmony = new Harmony("MidnightsFX.ValheimCommunityPatch"); public void Awake() { Log = ((BaseUnityPlugin)this).Logger; ValConfig.Bind(((BaseUnityPlugin)this).Config); CollisionCallbackReusePatch.Apply(); ApplyPatches(); } private void ApplyPatches() { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; bool flag = ValConfig.PatchEverySide != null && ValConfig.PatchEverySide.Value; Type[] types = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in types) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length == 0) { continue; } Side side = PatchSideAttribute.Of(type); bool flag2 = type.DeclaringType == null; if (side == Side.Client && RunMode.IsHeadless && !flag) { if (flag2) { num3++; } Log.LogDebug((object)("Skipped " + type.Name + ": client-only, and this process is headless.")); continue; } try { harmony.CreateClassProcessor(type).Patch(); if (flag2) { num++; switch (side) { case Side.Client: num4++; break; case Side.Server: num5++; break; default: num6++; break; } } Log.LogDebug((object)("Applied " + type.Name + " " + PatchSideAttribute.Tag(side) + ".")); } catch (Exception arg) { num2++; Log.LogError((object)$"Could not apply {type.Name}: {arg}"); } } Log.LogInfo((object)$"{num} fix(es) applied: {num5} server, {num6} both, {num4} client."); if (num3 > 0) { Log.LogInfo((object)($"{num3} client-only fix(es) not applied: this process has no graphics device, " + "so it is a dedicated server and nothing would ever reach them. If that is wrong, set 'Patch Every Side' in the config.")); } if (num2 > 0) { Log.LogWarning((object)($"{num2} fix(es) failed. The failures above are usually caused by a Valheim " + "update changing a patched method; the remaining fixes are unaffected.")); } } public void OnDestroy() { ZsfxIdleDormancyPatch.RestoreAll(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } } namespace ValheimCommunityPatch.Patches.Terrain { [PatchSide(Side.Client)] [HarmonyPatch] internal static class PaintMaskStridePatch { internal static ConfigEntry<bool> Enabled; internal static void BindConfig() { Enabled = ValConfig.BindFixToggle(typeof(PaintMaskStridePatch), "Fixes - Terrain", "Fix Terrain Paint Mask Indexing", value: true, "Corrects the array stride and bounds used when reading and writing terrain paint. Vanilla indexes a 33-wide paint array with a stride of 32, which skews the paint diagonally, and refuses to write the row and column each zone shares with its neighbour."); } [HarmonyPrefix] [HarmonyPatch(typeof(Heightmap), "SetPaintMask")] private static bool SetPaintMaskPrefix(Heightmap __instance, int x, int y, Color paint) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null || !Enabled.Value) { return true; } int num = __instance.m_width + 1; if (x < 0 || y < 0 || x >= num || y >= num) { return false; } __instance.m_paintMask.SetPixel(x, y, paint); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(TerrainComp), "UpdatePaintMask")] private static bool UpdatePaintMaskPrefix(TerrainComp __instance, Heightmap hmap) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null || !Enabled.Value) { return true; } if (!__instance.m_initialized) { return false; } int num = __instance.m_width + 1; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { int num2 = i * num + j; if (__instance.m_modifiedPaint[num2]) { Color val = __instance.m_paintMask[num2]; val.a = hmap.GetPaintMask(j, i).a; __instance.m_paintMask[num2] = val; } } } __instance.Save(false); hmap.Poke(0, false); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(Heightmap), "UpdateTerrainAlpha", new Type[] { typeof(Heightmap) })] private static bool UpdateTerrainAlphaPrefix(Heightmap hmap, ref bool __result) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_0077: 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_0091: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null || !Enabled.Value) { return true; } HMBuildData val = HeightmapBuilder.instance.RequestTerrainSync(((Component)hmap).transform.position, hmap.m_width, hmap.m_scale, hmap.IsDistantLod, WorldGenerator.instance); int num = hmap.m_width + 1; int num2 = 0; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { float a = val.m_baseMask[i * num + j].a; Color paintMask = hmap.GetPaintMask(j, i); if (a != paintMask.a) { paintMask.a = a; hmap.SetPaintMask(j, i, paintMask); num2++; } } } if (num2 > 0) { hmap.GetAndCreateTerrainCompiler().UpdatePaintMask(hmap); Logger.LogInfo($"Corrected {num2} terrain alpha pixel(s) at {((Component)hmap).transform.position}."); } __result = num2 > 0; return false; } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(Heightmap))] internal static class PaintSeamReconcilePatch { private enum Edge { East, West, North, South } private struct Corner { internal Heightmap Map; internal int X; internal int Y; internal Color Boundary; internal Color Inward; } internal static ConfigEntry<bool> Enabled; private static readonly List<Heightmap> DirtyNeighbours = new List<Heightmap>(); private static readonly Corner[] CornerBuffer = new Corner[4]; internal static void BindConfig() { Enabled = ValConfig.BindFixToggle(typeof(PaintSeamReconcilePatch), "Fixes - Terrain", "Fix Terrain Paint Seams", value: true, "Makes terrain paint agree along zone boundaries. Vanilla can end up with dirt painted on only one side of a 64m zone border, which draws a hard straight line across the ground. Paint that the ground next to the border already carries is carried across the boundary; a lone stripe sitting on the border with nothing behind it on either side is removed."); } [HarmonyPostfix] [HarmonyPatch("ApplyModifiers")] private static void ApplyModifiersPostfix(Heightmap __instance) { if (Enabled == null || !Enabled.Value || RunMode.IsDedicated || __instance.IsDistantLod || (Object)(object)__instance.m_paintMask == (Object)null) { return; } int width = __instance.m_width; if (width >= 2) { float num = (float)width * __instance.m_scale; DirtyNeighbours.Clear(); if ((0u | (ReconcileEdge(__instance, FindNeighbour(__instance, num, 0f), Edge.East, width) ? 1u : 0u) | (ReconcileEdge(__instance, FindNeighbour(__instance, 0f - num, 0f), Edge.West, width) ? 1u : 0u) | (ReconcileEdge(__instance, FindNeighbour(__instance, 0f, num), Edge.North, width) ? 1u : 0u) | (ReconcileEdge(__instance, FindNeighbour(__instance, 0f, 0f - num), Edge.South, width) ? 1u : 0u) | (ReconcileCorner(__instance, num, highX: true, highZ: true, width) ? 1u : 0u) | (ReconcileCorner(__instance, num, highX: true, highZ: false, width) ? 1u : 0u) | (ReconcileCorner(__instance, num, highX: false, highZ: true, width) ? 1u : 0u) | (ReconcileCorner(__instance, num, highX: false, highZ: false, width) ? 1u : 0u)) != 0) { __instance.m_paintMask.Apply(); } for (int i = 0; i < DirtyNeighbours.Count; i++) { DirtyNeighbours[i].m_paintMask.Apply(); } DirtyNeighbours.Clear(); } } private static bool ReconcileEdge(Heightmap ours, Heightmap theirs, Edge edge, int width) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)theirs == (Object)null || (Object)(object)theirs.m_paintMask == (Object)null) { return false; } bool result = false; bool flag = false; for (int i = 1; i < width; i++) { int num; int num2; int num3; int num4; int num5; int num6; int num7; int num8; switch (edge) { case Edge.East: num = width; num2 = i; num3 = width - 1; num4 = i; num5 = 0; num6 = i; num7 = 1; num8 = i; break; case Edge.West: num = 0; num2 = i; num3 = 1; num4 = i; num5 = width; num6 = i; num7 = width - 1; num8 = i; break; case Edge.North: num = i; num2 = width; num3 = i; num4 = width - 1; num5 = i; num6 = 0; num7 = i; num8 = 1; break; default: num = i; num2 = 0; num3 = i; num4 = 1; num5 = i; num6 = width; num7 = i; num8 = width - 1; break; } Color pixel = ours.m_paintMask.GetPixel(num, num2); Color pixel2 = theirs.m_paintMask.GetPixel(num5, num6); if (!SamePaint(pixel, pixel2)) { Color val = Merge(pixel, pixel2, ours.m_paintMask.GetPixel(num3, num4), theirs.m_paintMask.GetPixel(num7, num8)); if (!SamePaint(val, pixel)) { ours.m_paintMask.SetPixel(num, num2, new Color(val.r, val.g, val.b, pixel.a)); result = true; } if (!SamePaint(val, pixel2)) { theirs.m_paintMask.SetPixel(num5, num6, new Color(val.r, val.g, val.b, pixel2.a)); flag = true; } } } if (flag) { MarkDirty(theirs); } return result; } private static bool ReconcileCorner(Heightmap ours, float zoneSize, bool highX, bool highZ, int width) { //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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) float dx = (highX ? zoneSize : (0f - zoneSize)); float dz = (highZ ? zoneSize : (0f - zoneSize)); int count = 0; count = AddCorner(count, ours, width, highX, highZ); count = AddCorner(count, FindNeighbour(ours, dx, 0f), width, !highX, highZ); count = AddCorner(count, FindNeighbour(ours, 0f, dz), width, highX, !highZ); count = AddCorner(count, FindNeighbour(ours, dx, dz), width, !highX, !highZ); if (count < 2) { return false; } Color boundary = CornerBuffer[0].Boundary; Color boundary2 = CornerBuffer[0].Boundary; Color inward = CornerBuffer[0].Inward; for (int i = 1; i < count; i++) { Color boundary3 = CornerBuffer[i].Boundary; Color inward2 = CornerBuffer[i].Inward; ((Color)(ref boundary))..ctor(Mathf.Min(boundary.r, boundary3.r), Mathf.Min(boundary.g, boundary3.g), Mathf.Min(boundary.b, boundary3.b)); ((Color)(ref boundary2))..ctor(Mathf.Max(boundary2.r, boundary3.r), Mathf.Max(boundary2.g, boundary3.g), Mathf.Max(boundary2.b, boundary3.b)); ((Color)(ref inward))..ctor(Mathf.Max(inward.r, inward2.r), Mathf.Max(inward.g, inward2.g), Mathf.Max(inward.b, inward2.b)); } Color val = default(Color); ((Color)(ref val))..ctor(Mathf.Clamp(inward.r, boundary.r, boundary2.r), Mathf.Clamp(inward.g, boundary.g, boundary2.g), Mathf.Clamp(inward.b, boundary.b, boundary2.b)); bool result = false; for (int j = 0; j < count; j++) { Corner corner = CornerBuffer[j]; if (!SamePaint(val, corner.Boundary)) { corner.Map.m_paintMask.SetPixel(corner.X, corner.Y, new Color(val.r, val.g, val.b, corner.Boundary.a)); if ((Object)(object)corner.Map == (Object)(object)ours) { result = true; } else { MarkDirty(corner.Map); } } } return result; } private static int AddCorner(int count, Heightmap hmap, int width, bool highX, bool highZ) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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) if ((Object)(object)hmap == (Object)null || (Object)(object)hmap.m_paintMask == (Object)null) { return count; } int num = (highX ? width : 0); int num2 = (highZ ? width : 0); int num3 = ((!highX) ? 1 : (width - 1)); int num4 = ((!highZ) ? 1 : (width - 1)); CornerBuffer[count] = new Corner { Map = hmap, X = num, Y = num2, Boundary = hmap.m_paintMask.GetPixel(num, num2), Inward = hmap.m_paintMask.GetPixel(num3, num4) }; return count + 1; } private static Color Merge(Color a, Color b, Color supportA, Color supportB) { //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_000c: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) return new Color(MergeChannel(a.r, b.r, supportA.r, supportB.r), MergeChannel(a.g, b.g, supportA.g, supportB.g), MergeChannel(a.b, b.b, supportA.b, supportB.b)); } private static float MergeChannel(float a, float b, float supportA, float supportB) { return Mathf.Clamp(Mathf.Max(supportA, supportB), Mathf.Min(a, b), Mathf.Max(a, b)); } private static bool SamePaint(Color merged, Color current) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (merged.r == current.r && merged.g == current.g) { return merged.b == current.b; } return false; } private static void MarkDirty(Heightmap hmap) { if (!DirtyNeighbours.Contains(hmap)) { DirtyNeighbours.Add(hmap); } } private static Heightmap FindNeighbour(Heightmap hmap, float dx, float dz) { //IL_0006: 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_0017: Unknown result type (might be due to invalid IL or missing references) Heightmap val = Heightmap.FindHeightmap(((Component)hmap).transform.position + new Vector3(dx, 0f, dz)); if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)hmap || val.IsDistantLod) { return null; } if (val.m_width != hmap.m_width || val.m_scale != hmap.m_scale) { return null; } return val; } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(Heightmap))] internal static class SeamlessNormalsPatch { [HarmonyPatch(typeof(MonoUpdaters), "LateUpdate")] internal static class ProcessDirtyHook { [HarmonyPostfix] private static void Postfix() { if (Dirty.Count == 0) { return; } if (Enabled == null || !Enabled.Value || RunMode.IsDedicated) { foreach (Heightmap item in Dirty) { if ((Object)(object)item != (Object)null && (Object)(object)item.m_renderMesh != (Object)null) { item.m_renderMesh.RecalculateTangents(); } } Dirty.Clear(); return; } RebuiltScratch.Clear(); AffectedScratch.Clear(); foreach (Heightmap item2 in Dirty) { if (!((Object)(object)item2 == (Object)null)) { RebuiltScratch.Add(item2); AffectedScratch.Add(item2); float num = (float)item2.m_width * item2.m_scale; AddNeighbour(item2, 0f - num, 0f); AddNeighbour(item2, num, 0f); AddNeighbour(item2, 0f, 0f - num); AddNeighbour(item2, 0f, num); } } Dirty.Clear(); foreach (Heightmap item3 in AffectedScratch) { if (!ApplyNormals(item3) && RebuiltScratch.Contains(item3)) { ApplyFallbackTangents(item3); } } RebuiltScratch.Clear(); AffectedScratch.Clear(); } private static void AddNeighbour(Heightmap origin, float dx, float dz) { Heightmap val = FindNeighbour(origin, dx, dz); if ((Object)(object)val != (Object)null) { AffectedScratch.Add(val); } } } [HarmonyPatch(typeof(Heightmap), "OnDestroy")] internal static class OnDestroyHook { [HarmonyPostfix] private static void Postfix(Heightmap __instance) { Dirty.Remove(__instance); } } internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> VerifyTangents; private static readonly List<Vector3> NormalBuffer = new List<Vector3>(); private static readonly List<Vector4> TangentBuffer = new List<Vector4>(); private static readonly List<Vector4> VerifyBuffer = new List<Vector4>(); private static readonly HashSet<Heightmap> Dirty = new HashSet<Heightmap>(); private static readonly HashSet<Heightmap> RebuiltScratch = new HashSet<Heightmap>(); private static readonly HashSet<Heightmap> AffectedScratch = new HashSet<Heightmap>(); private static readonly MethodInfo RecalculateTangentsMethod = AccessTools.Method(typeof(Mesh), "RecalculateTangents", new Type[0], (Type[])null); private static readonly MethodInfo TangentsOrDeferMethod = AccessTools.Method(typeof(SeamlessNormalsPatch), "TangentsOrDefer", (Type[])null, (Type[])null); internal static void BindConfig() { Enabled = ValConfig.BindFixToggle(typeof(SeamlessNormalsPatch), "Fixes - Terrain", "Fix Terrain Seams", value: true, "Computes terrain lighting normals across zone boundaries instead of per zone. Vanilla shades the same ground differently on each side of a 64m zone border, which shows up as a hard crease running through flat terrain - most noticeable in the Plains and Meadows."); VerifyTangents = ValConfig.BindServerConfig("Debug", "Verify Terrain Tangents", value: false, "Diagnostic. Uses Unity's tangent recalculation instead of the analytic tangents the seam fix normally computes, compares the two on a sample of vertices, and logs any disagreement. Costs the mesh pass the analytic version exists to avoid, so leave it off unless terrain lighting looks wrong.", null, advanced: true); } [HarmonyTranspiler] [HarmonyPriority(0)] [HarmonyPatch("RebuildRenderMesh")] private static IEnumerable<CodeInstruction> RebuildRenderMeshTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List<CodeInstruction> list = PatchHelper.Copy(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if (CodeInstructionExtensions.Calls(list[i], RecalculateTangentsMethod)) { list[i].opcode = OpCodes.Ldarg_0; list[i].operand = null; list.Insert(i + 1, new CodeInstruction(OpCodes.Call, (object)TangentsOrDeferMethod)); num++; i++; } } if (num != 1) { Logger.LogWarning($"Heightmap.RebuildRenderMesh: expected 1 RecalculateTangents call, found {num}, " + "so the tangent half of the terrain seam fix is inactive. Another mod has most likely already rewritten the method - if so, nothing is wrong."); return instructions; } return list; } private static void TangentsOrDefer(Mesh mesh, Heightmap hmap) { if (!WillProcess(hmap)) { mesh.RecalculateTangents(); } } private static bool WillProcess(Heightmap hmap) { if (Enabled != null && Enabled.Value && !RunMode.IsDedicated && !hmap.IsDistantLod) { return (Object)(object)MonoUpdaters.s_instance != (Object)null; } return false; } [HarmonyPostfix] [HarmonyPatch("RebuildRenderMesh")] private static void RebuildRenderMeshPostfix(Heightmap __instance) { if (WillProcess(__instance)) { Dirty.Add(__instance); } } private static Vector4 AnalyticTangent(Vector3 normal) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) float num = 1f - normal.x * normal.x; float num2 = (0f - normal.x) * normal.y; float num3 = (0f - normal.x) * normal.z; float num4 = 1f / Mathf.Sqrt(num * num + num2 * num2 + num3 * num3); return new Vector4(num * num4, num2 * num4, num3 * num4, -1f); } private static bool ApplyNormals(Heightmap hmap) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) Mesh renderMesh = hmap.m_renderMesh; if ((Object)(object)renderMesh == (Object)null) { return false; } int width = hmap.m_width; int num = width + 1; if (renderMesh.vertexCount != num * num) { return false; } float num2 = (float)width * hmap.m_scale; Heightmap val = FindNeighbour(hmap, 0f - num2, 0f); Heightmap val2 = FindNeighbour(hmap, num2, 0f); Heightmap val3 = FindNeighbour(hmap, 0f, 0f - num2); Heightmap val4 = FindNeighbour(hmap, 0f, num2); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { return false; } float y = ((Component)hmap).transform.position.y; float y2 = ((Component)val).transform.position.y; float y3 = ((Component)val2).transform.position.y; float y4 = ((Component)val3).transform.position.y; float y5 = ((Component)val4).transform.position.y; float num3 = 1f / (2f * hmap.m_scale); bool flag = VerifyTangents == null || !VerifyTangents.Value; NormalBuffer.Clear(); TangentBuffer.Clear(); Vector3 val5 = default(Vector3); for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { float num4 = (Sample(hmap, j + 1, i, val, val2, val3, val4, y, y2, y3, y4, y5) - Sample(hmap, j - 1, i, val, val2, val3, val4, y, y2, y3, y4, y5)) * num3; float num5 = (Sample(hmap, j, i + 1, val, val2, val3, val4, y, y2, y3, y4, y5) - Sample(hmap, j, i - 1, val, val2, val3, val4, y, y2, y3, y4, y5)) * num3; float num6 = 1f / Mathf.Sqrt(num4 * num4 + 1f + num5 * num5); ((Vector3)(ref val5))..ctor((0f - num4) * num6, num6, (0f - num5) * num6); NormalBuffer.Add(val5); if (flag) { TangentBuffer.Add(AnalyticTangent(val5)); } } } renderMesh.SetNormals(NormalBuffer); if (flag) { renderMesh.SetTangents(TangentBuffer); } else { renderMesh.RecalculateTangents(); CompareTangents(renderMesh); } return true; } private static void ApplyFallbackTangents(Heightmap hmap) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) Mesh renderMesh = hmap.m_renderMesh; if ((Object)(object)renderMesh == (Object)null) { return; } if (VerifyTangents != null && VerifyTangents.Value) { renderMesh.RecalculateTangents(); return; } NormalBuffer.Clear(); renderMesh.GetNormals(NormalBuffer); TangentBuffer.Clear(); for (int i = 0; i < NormalBuffer.Count; i++) { TangentBuffer.Add(AnalyticTangent(NormalBuffer[i])); } renderMesh.SetTangents(TangentBuffer); } private static void CompareTangents(Mesh mesh) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) VerifyBuffer.Clear(); mesh.GetTangents(VerifyBuffer); if (VerifyBuffer.Count != NormalBuffer.Count) { return; } int num = 0; float num2 = 1f; for (int i = 0; i < VerifyBuffer.Count; i += 173) { Vector4 val = AnalyticTangent(NormalBuffer[i]); Vector4 val2 = VerifyBuffer[i]; float num3 = val.x * val2.x + val.y * val2.y + val.z * val2.z; if (num3 < num2) { num2 = num3; } if (num3 < 0.99f || val2.w > 0f) { num++; } } if (num == 0) { Logger.LogDebug($"Tangent verify: agreed (worst dot {num2:F4})."); } else { Logger.LogWarning($"Tangent verify: {num} sampled vertex(es) diverged (worst dot {num2:F4}). " + "Unity's tangents were used. Please report this."); } } private static float Sample(Heightmap hmap, int x, int y, Heightmap west, Heightmap east, Heightmap south, Heightmap north, float selfY, float westY, float eastY, float southY, float northY) { int width = hmap.m_width; if (x < 0) { return west.GetHeight(width - 1, y) + westY; } if (x > width) { return east.GetHeight(1, y) + eastY; } if (y < 0) { return south.GetHeight(x, width - 1) + southY; } if (y > width) { return north.GetHeight(x, 1) + northY; } return hmap.GetHeight(x, y) + selfY; } private static Heightmap FindNeighbour(Heightmap hmap, float dx, float dz) { //IL_0006: 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_0017: Unknown result type (might be due to invalid IL or missing references) Heightmap val = Heightmap.FindHeightmap(((Component)hmap).transform.position + new Vector3(dx, 0f, dz)); if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)hmap || val.IsDistantLod) { return null; } if (val.m_width != hmap.m_width || val.m_scale != hmap.m_scale) { return null; } return val; } } [PatchSide(Side.Both)] [HarmonyPatch(typeof(TerrainComp))] internal static class TerrainCompNullHmapPatch { internal static ConfigEntry<bool> Enabled; private static readonly HashSet<TerrainComp> RecoveryFailed = new HashSet<TerrainComp>(); internal static void BindConfig() { Enabled = ValConfig.BindFixToggle(typeof(TerrainCompNullHmapPatch), "Fixes - Terrain", "Fix Terrain Compiler Init Race", value: true, "Recovers a terrain compiler that loaded before its zone's heightmap existed. In vanilla it throws a NullReferenceException every frame from then on and that zone stops accepting terrain edits entirely."); } [HarmonyPrefix] [HarmonyPatch("Update")] private static bool UpdatePrefix(TerrainComp __instance) { if (Enabled == null || !Enabled.Value) { return true; } if ((Object)(object)__instance.m_hmap != (Object)null && __instance.m_initialized) { return true; } if (RecoveryFailed.Count > 0 && RecoveryFailed.Contains(__instance)) { return false; } TryRecover(__instance); return false; } private static bool TryRecover(TerrainComp comp) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) Heightmap val = (((Object)(object)comp.m_hmap != (Object)null) ? comp.m_hmap : Heightmap.FindHeightmap(((Component)comp).transform.position)); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)comp.m_nview == (Object)null || !comp.m_nview.IsValid()) { return false; } comp.m_hmap = val; try { if (!comp.m_initialized) { TerrainComp val2 = TerrainComp.FindTerrainCompiler(((Component)comp).transform.position); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)comp && (Object)(object)ZNetScene.instance != (Object)null) { Logger.LogWarning($"Found another terrain compiler at {((Component)comp).transform.position}, removing it. " + "Two compilers in one zone means one of their saved terrain edits would be discarded at random, so this resolves it the way TerrainComp.Awake does."); ZNetScene.instance.Destroy(((Component)val2).gameObject); } if (!TerrainComp.s_instances.Contains(comp)) { TerrainComp.s_instances.Add(comp); } comp.m_nview.Register<ZPackage>("ApplyOperation", (Action<long, ZPackage>)comp.RPC_ApplyOperation); comp.Initialize(); } else if (!TerrainComp.s_instances.Contains(comp)) { TerrainComp.s_instances.Add(comp); } comp.CheckLoad(); } catch (Exception arg) { RecoveryFailed.RemoveWhere((TerrainComp failed) => (Object)(object)failed == (Object)null); RecoveryFailed.Add(comp); Logger.LogError($"Failed to recover terrain compiler at {((Component)comp).transform.position}, and it will not " + $"be retried: {arg}"); return false; } Logger.LogInfo($"Recovered terrain compiler at {((Component)comp).transform.position} after its heightmap loaded."); return true; } } [PatchSide(Side.Both)] [HarmonyPatch(typeof(TerrainOp))] internal static class TerrainOpPaintFanoutPatch { internal static ConfigEntry<bool> Enabled; private static readonly List<Heightmap> Reached = new List<Heightmap>(); private static readonly List<Heightmap> PaintReached = new List<Heightmap>(); internal static void BindConfig() { Enabled = ValConfig.BindFixToggle(typeof(TerrainOpPaintFanoutPatch), "Fixes - Terrain", "Fix Terrain Paint Zone Fanout", value: true, "Sends terrain paint to every zone the paint actually covers. Vanilla measures which zones an edit touches from its radius, but the paint itself reaches about a metre further west and south, so the neighbouring zone never records paint applied to ground it shares - which is what leaves dirt stopping dead along a 64m zone border."); } [HarmonyPostfix] [HarmonyPatch("Awake")] private static void AwakePostfix(TerrainOp __instance, bool __runOriginal) { //IL_0161: 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) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) if (!__runOriginal || Enabled == null || !Enabled.Value || TerrainOp.m_forceDisableTerrainOps) { return; } Settings settings = __instance.m_settings; if (settings == null || !settings.m_paintCleared || settings.m_paintRadius <= 0f) { return; } Vector3 position = ((Component)__instance).transform.position; Heightmap val = Heightmap.FindHeightmap(position); float num = (((Object)(object)val != (Object)null) ? val.m_scale : 1f); float radius = settings.GetRadius(); float num2 = settings.m_paintRadius + num; if (num2 <= radius) { return; } Reached.Clear(); PaintReached.Clear(); try { Heightmap.FindHeightmap(position, radius, Reached); Heightmap.FindHeightmap(position, num2, PaintReached); bool level = settings.m_level; bool raise = settings.m_raise; bool smooth = settings.m_smooth; settings.m_level = false; settings.m_raise = false; settings.m_smooth = false; try { for (int i = 0; i < PaintReached.Count; i++) { Heightmap val2 = PaintReached[i]; if (!((Object)(object)val2 == (Object)null) && !val2.IsDistantLod && !Reached.Contains(val2) && IsBehindOperation(val2, position)) { val2.GetAndCreateTerrainCompiler().ApplyOperation(__instance); } } } finally { settings.m_level = level; settings.m_raise = raise; settings.m_smooth = smooth; } } catch (Exception arg) { Logger.LogWarning($"Could not extend terrain paint past {position} into neighbouring zones: {arg}"); } finally { Reached.Clear(); PaintReached.Clear(); } } private static bool IsBehindOperation(Heightmap hmap, Vector3 pos) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0039: Unknown result type (might be due to invalid IL or missing references) float num = (float)hmap.m_width * hmap.m_scale * 0.5f; Vector3 position = ((Component)hmap).transform.position; if (!(position.x + num <= pos.x)) { return position.z + num <= pos.z; } return true; } } } namespace ValheimCommunityPatch.Patches.Performance { [PatchSide(Side.Client)] [HarmonyPatch(typeof(Heightmap))] internal static class AsyncColliderBakePatch { private sealed class PendingBake { public Heightmap m_hmap; public MeshCollider m_collider; public Mesh m_mesh; public int m_meshId; public MeshColliderCookingOptions m_options; public volatile bool m_done; } [HarmonyPatch(typeof(ZoneSystem), "SpawnZone")] internal static class SpawnZoneContextHook { [HarmonyPrefix] private static void Prefix(Vector2s zoneID, SpawnMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) _deferContext = (int)mode == 1 && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZNet.instance != (Object)null && zoneID != ZoneSystem.GetZone(ZNet.instance.GetReferencePosition()); } [HarmonyFinalizer] private static void Finalizer() { _deferContext = false; } } [HarmonyPatch(typeof(Heightmap), "CustomLateUpdate")] internal static class LateUpdateContextHook { [HarmonyPrefix] private static void Prefix() { _lateUpdateContext = (Object)(object)Player.m_localPlayer != (Object)null; } [HarmonyFinalizer] private static void Finalizer() { _lateUpdateContext = false; } } [HarmonyPatch(typeof(MonoUpdaters), "LateUpdate")] internal static class AssignBakedHook { [HarmonyPostfix] private static void Postfix() { for (int num = Pending.Count - 1; num >= 0; num--) { PendingBake pendingBake = Pending[num]; if (pendingBake.m_done) { Pending.RemoveAt(num); if (!((Object)(object)pendingBake.m_hmap == (Object)null) && !((Object)(object)pendingBake.m_collider == (Object)null)) { pendingBake.m_collider.sharedMesh = pendingBake.m_mesh; } } } } } [HarmonyPatch(typeof(Heightmap), "OnDestroy")] internal static class DestroyGuardHook { [HarmonyPrefix] private static void Prefix(Heightmap __instance) { PendingBake pendingBake = FindPending(__instance); if (pendingBake != null) { WaitOut(pendingBake); Pending.Remove(pendingBake); } } } private static readonly List<PendingBake> Pending = new List<PendingBake>(); private static bool _deferContext; private static bool _lateUpdateContext; private static PendingBake FindPending(Heightmap hmap) { for (int i = 0; i < Pending.Count; i++) { if (Pending[i].m_hmap == hmap) { return Pending[i]; } } return null; } private static void WaitOut(PendingBake bake) { while (!bake.m_done) { Thread.Sleep(0); } } [HarmonyPrefix] [HarmonyPatch("RebuildCollisionMesh")] private static void RebuildCollisionMeshPrefix(Heightmap __instance, out MeshCollider __state) { __state = null; PendingBake pendingBake = FindPending(__instance); if (pendingBake != null) { WaitOut(pendingBake); Pending.Remove(pendingBake); } if ((_deferContext || _lateUpdateContext) && !((Object)(object)__instance.m_collider == (Object)null)) { __state = __instance.m_collider; __instance.m_collider = null; } } [HarmonyPostfix] [HarmonyPatch("RebuildCollisionMesh")] private static void RebuildCollisionMeshPostfix(Heightmap __instance, MeshCollider __state) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__state == (Object)null) { return; } __instance.m_collider = __state; Mesh collisionMesh = __instance.m_collisionMesh; if ((Object)(object)collisionMesh == (Object)null) { return; } PendingBake bake = new PendingBake { m_hmap = __instance, m_collider = __state, m_mesh = collisionMesh, m_meshId = ((Object)collisionMesh).GetInstanceID(), m_options = __state.cookingOptions }; Pending.Add(bake); ThreadPool.QueueUserWorkItem(delegate { //IL_0012: Unknown result type (might be due to invalid IL or missing references) try { Physics.BakeMesh(bake.m_meshId, false, bake.m_options); } finally { bake.m_done = true; } }); } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(ClutterSystem))] internal static class ClutterGroundDataPatch { [HarmonyPrefix] [HarmonyPatch("GetGroundInfo")] private static bool GetGroundInfoPrefix(Vector3 p, out Vector3 point, out Vector3 normal, out Heightmap hmap, out Biome biome, ref bool __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected I4, but got Unknown if (!HeightmapLookupPatch.TryGetCached(p, out var hmap2, out var origin)) { hmap2 = Heightmap.FindHeightmap(p); origin = (((Object)(object)hmap2 != (Object)null) ? ((Component)hmap2).transform.position : Vector3.zero); } float height = 0f; Vector3 normal2 = Vector3.up; if ((Object)(object)hmap2 != (Object)null && HeightmapSampling.TryGetSurface(hmap2, origin, p, out height, out normal2) && height <= p.y + 500f && height >= p.y - 500f) { point = new Vector3(p.x, height, p.z); normal = normal2; hmap = hmap2; biome = (Biome)(int)hmap2.GetBiome(point, 0.02f, false); __result = true; return false; } point = p; normal = Vector3.up; hmap = null; biome = (Biome)1; __result = false; return false; } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(ClutterSystem))] internal static class ClutterRebuildCapPatch { internal static ConfigEntry<int> Budget; internal static void BindConfig() { Budget = ValConfig.BindServerConfig("Fixes - Performance", "Grass Rebuild Budget", 8, "How many grass patches a full rebuild may regenerate per frame. Higher finishes the rebuild sooner but hitches more; 64 is effectively vanilla.", advanced: true, 1, 64); } [HarmonyPrefix] [HarmonyPatch("GeneratePatches")] private static bool GeneratePatchesPrefix(ClutterSystem __instance, bool rebuildAll, Vector3 center) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!rebuildAll) { return true; } int num = ((Budget != null) ? Budget.Value : 8); bool flag = false; for (int i = 0; i < num; i++) { bool generated = false; RunRing(__instance, center, ref generated); flag = generated; if (!generated) { break; } } if (flag) { __instance.m_forceRebuild = true; } return false; } private static void RunRing(ClutterSystem clutter, Vector3 center, ref bool generated) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) Vector2Int vegPatch = clutter.GetVegPatch(center); clutter.GeneratePatch(center, vegPatch, ref generated, false); int num = Mathf.CeilToInt((clutter.m_distance - clutter.m_grassPatchSize / 2f) / clutter.m_grassPatchSize); for (int i = 1; i <= num; i++) { for (int j = ((Vector2Int)(ref vegPatch)).x - i; j <= ((Vector2Int)(ref vegPatch)).x + i; j++) { clutter.GeneratePatch(center, new Vector2Int(j, ((Vector2Int)(ref vegPatch)).y - i), ref generated, false); clutter.GeneratePatch(center, new Vector2Int(j, ((Vector2Int)(ref vegPatch)).y + i), ref generated, false); } for (int k = ((Vector2Int)(ref vegPatch)).y - i + 1; k <= ((Vector2Int)(ref vegPatch)).y + i - 1; k++) { clutter.GeneratePatch(center, new Vector2Int(((Vector2Int)(ref vegPatch)).x - i, k), ref generated, false); clutter.GeneratePatch(center, new Vector2Int(((Vector2Int)(ref vegPatch)).x + i, k), ref generated, false); } } } } [PatchSide(Side.Both)] internal static class CollisionCallbackReusePatch { internal static void Apply() { if (Physics.reuseCollisionCallbacks) { Logger.LogInfo("Collision callback reuse was already enabled by the game, so 'Fix Collision Callback Allocation' changes nothing on this build."); } else { Physics.reuseCollisionCallbacks = true; } } } [PatchSide(Side.Both)] [HarmonyPatch] internal static class CollisionContactsAllocPatch { private const int MaxCachedContacts = 64; private static readonly ContactPoint[][] Buffers = new ContactPoint[65][]; private static readonly ContactPoint[] Empty = (ContactPoint[])(object)new ContactPoint[0]; private static readonly MethodInfo ContactsGetter = AccessTools.PropertyGetter(typeof(Collision), "contacts"); private static readonly MethodInfo ReusedContactsMethod = AccessTools.Method(typeof(CollisionContactsAllocPatch), "ReusedContacts", (Type[])null, (Type[])null); private static ContactPoint[] ReusedContacts(Collision collision) { if (collision == null) { return Empty; } int contactCount = collision.contactCount; if (contactCount <= 0) { return Empty; } if (contactCount > 64) { return collision.contacts; } ContactPoint[] array = Buffers[contactCount]; if (array == null) { array = (ContactPoint[])(object)new ContactPoint[contactCount]; Buffers[contactCount] = array; } collision.GetContacts(array); return array; } [HarmonyTranspiler] [HarmonyPriority(0)] [HarmonyPatch(typeof(Character), "OnCollisionStay")] private static IEnumerable<CodeInstruction> CharacterOnCollisionStayTranspiler(IEnumerable<CodeInstruction> instructions) { return PatchHelper.ReplaceCalls(instructions, ContactsGetter, ReusedContactsMethod, "Character.OnCollisionStay", 1); } [HarmonyTranspiler] [HarmonyPriority(0)] [HarmonyPatch(typeof(ImpactEffect), "OnCollisionEnter")] private static IEnumerable<CodeInstruction> ImpactEffectOnCollisionEnterTranspiler(IEnumerable<CodeInstruction> instructions) { return PatchHelper.ReplaceCalls(instructions, ContactsGetter, ReusedContactsMethod, "ImpactEffect.OnCollisionEnter", 2); } [HarmonyTranspiler] [HarmonyPriority(0)] [HarmonyPatch(typeof(FloatingTerrain), "OnCollisionStay")] private static IEnumerable<CodeInstruction> FloatingTerrainOnCollisionStayTranspiler(IEnumerable<CodeInstruction> instructions) { return PatchHelper.ReplaceCalls(instructions, ContactsGetter, ReusedContactsMethod, "FloatingTerrain.OnCollisionStay", 1); } } [PatchSide(Side.Both)] [HarmonyPatch(typeof(CookingStation))] internal static class CookingSlotKeyPatch { private static int[] SlotKeys = new int[0]; private static int[] StatusKeys = new int[0]; private static void EnsureKeys(int count) { if (SlotKeys.Length < count) { int[] array = new int[count]; int[] array2 = new int[count]; for (int i = 0; i < count; i++) { array[i] = StringExtensionMethods.GetStableHashCode("slot" + i); array2[i] = StringExtensionMethods.GetStableHashCode("slotstatus" + i); } SlotKeys = array; StatusKeys = array2; } } private static bool TryPrepare(CookingStation station, int slot) { if (slot < 0) { return false; } Transform[] slots = station.m_slots; EnsureKeys(Mathf.Max(slot + 1, (slots != null) ? slots.Length : 0)); return true; } [HarmonyPrefix] [HarmonyPatch("GetSlot")] private static bool GetSlotPrefix(CookingStation __instance, int slot, ref string itemName, ref float cookedTime, ref Status status, ref bool cheated) { if (!TryPrepare(__instance, slot)) { return true; } if (!__instance.m_nview.IsValid()) { itemName = ""; status = (Status)0; cookedTime = 0f; cheated = false; return false; } ZDO zDO = __instance.m_nview.GetZDO(); itemName = zDO.GetString(SlotKeys[slot], ""); cookedTime = zDO.GetFloat(SlotKeys[slot], 0f); status = (Status)zDO.GetInt(StatusKeys[slot], 0); cheated = zDO.GetBool(ZDOVars.s_cheatedQueued + slot, false); return false; } [HarmonyPrefix] [HarmonyPatch("SetSlot")] private static bool SetSlotPrefix(CookingStation __instance, int slot, string itemName, float cookedTime, Status status, bool cheated) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown if (!TryPrepare(__instance, slot)) { return true; } if (!__instance.m_nview.IsValid()) { return false; } ZDO zDO = __instance.m_nview.GetZDO(); zDO.Set(SlotKeys[slot], itemName); zDO.Set(SlotKeys[slot], cookedTime); zDO.Set(StatusKeys[slot], (int)status, false); zDO.Set(ZDOVars.s_cheatedQueued + slot, cheated); return false; } } [PatchSide(Side.Both)] [HarmonyPatch(typeof(HeightmapBuilder))] internal static class HeightmapBuilderThroughputPatch { internal static ConfigEntry<int> ReadyCap; internal static void BindConfig() { ReadyCap = ValConfig.BindServerConfig("Fixes - Performance", "Terrain Builder Ready Cap", 32, "How many finished terrain results the build thread may hold before discarding the oldest. Each is roughly 100 KB. Vanilla holds 16, which the distant-terrain ring alone nearly fills.", advanced: true, 16, 128); } [HarmonyPrepare] private static bool Prepare() { if (HeightmapBuilder.m_instance != null) { Logger.LogWarning("The terrain build thread was already running before this patch applied, so 'Fix Terrain Builder Throughput' is inert this session."); } return true; } [HarmonyPrefix] [HarmonyPatch("BuildThread")] private static bool BuildThreadPrefix(HeightmapBuilder __instance) { ZLog.Log((object)"Builder started"); bool flag = false; while (!flag) { bool flag2; lock (__instance.m_lock) { flag2 = __instance.m_toBuild.Count > 0; } if (flag2) { HMBuildData val; lock (__instance.m_lock) { val = __instance.m_toBuild[0]; } __instance.Build(val); lock (__instance.m_lock) { __instance.m_toBuild.Remove(val); __instance.m_ready.Add(val); int num = ((ReadyCap != null) ? ReadyCap.Value : 16); while (__instance.m_ready.Count > num) { __instance.m_ready.RemoveAt(0); } } } if (!flag2) { Thread.Sleep(10); } lock (__instance.m_lock) { flag = __instance.m_stop; } } return false; } } [PatchSide(Side.Both)] [HarmonyPatch(typeof(Heightmap))] internal static class HeightmapLookupPatch { private struct Entry { public Heightmap m_hmap; public float m_cx; public float m_cy; public float m_cz; public float m_half; } [HarmonyPatch(typeof(Heightmap), "Awake")] internal static class AwakeHook { [HarmonyPostfix] private static void Postfix(Heightmap __instance) { if (!__instance.m_isDistantLod) { Entry entry = MakeEntry(__instance); Registered.Add(entry); FileByZone(entry); } } } [HarmonyPatch(typeof(Heightmap), "OnDestroy")] internal static class DestroyHook { [HarmonyPostfix] private static void Postfix(Heightmap __instance) { for (int i = 0; i < Registered.Count; i++) { if (Registered[i].m_hmap == __instance) { Unfile(__instance, Registered[i].m_cx, Registered[i].m_cz); Registered.RemoveAt(i); break; } } } } [HarmonyPatch(typeof(Heightmap), "Regenerate")] internal static class RegenerateHook { [HarmonyPrefix] private static void Prefix(Heightmap __instance) { if (__instance.m_isDistantLod) { return; } for (int i = 0; i < Registered.Count; i++) { if (Registered[i].m_hmap == __instance) { Entry entry = Registered[i]; Entry entry2 = MakeEntry(__instance); if (entry2.m_cx != entry.m_cx || entry2.m_cy != entry.m_cy || entry2.m_cz != entry.m_cz || entry2.m_half != entry.m_half) { Unfile(__instance, entry.m_cx, entry.m_cz); Registered[i] = entry2; FileByZone(entry2); } break; } } } } internal static ConfigEntry<bool> Verify; private static readonly List<Entry> Registered = new List<Entry>(); private static readonly Dictionary<Vector2s, Entry> ByZone = new Dictionary<Vector2s, Entry>(); private static readonly HookHealth Hooks = new HookHealth("Heightmap registry", () => PatchHelper.HasHook(AccessTools.DeclaredMethod(typeof(Heightmap), "Awake", (Type[])null, (Type[])null), typeof(AwakeHook)) && PatchHelper.HasHook(AccessTools.DeclaredMethod(typeof(Heightmap), "OnDestroy", (Type[])null, (Type[])null), typeof(DestroyHook)) && PatchHelper.HasHook(AccessTools.DeclaredMethod(typeof(Heightmap), "Regenerate", (Type[])null, (Type[])null), typeof(RegenerateHook))); internal static void BindConfig() { Verify = ValConfig.BindServerConfig("Debug", "Verify Heightmap Registry", value: false, "Diagnostic. Runs both the zone-keyed lookup and vanilla's scan on every terrain tile lookup, acts on vanilla's result, and logs any real disagreement. Costs the scan this fix exists to avoid, so leave it off unless you are validating the registry.", null, advanced: true); } private static Entry MakeEntry(Heightmap hmap) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) Vector3 position = ((Component)hmap).transform.position; return new Entry { m_hmap = hmap, m_cx = position.x, m_cy = position.y, m_cz = position.z, m_half = (float)hmap.m_width * hmap.m_scale * 0.5f }; } internal static bool TryGetCached(Vector3 point, out Heightmap hmap, out Vector3 origin) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) hmap = null; origin = default(Vector3); if (!Hooks.Healthy) { return false; } if (ByZone.TryGetValue(ZoneSystem.GetZone(point), out var value) && Contains(in value, point)) { hmap = value.m_hmap; origin = new Vector3(value.m_cx, value.m_cy, value.m_cz); return true; } for (int i = 0; i < Registered.Count; i++) { if (Contains(Registered[i], point)) { hmap = Registered[i].m_hmap; origin = new Vector3(Registered[i].m_cx, Registered[i].m_cy, Registered[i].m_cz); return true; } } return true; } private static void FileByZone(Entry entry) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(new Vector3(entry.m_cx, 0f, entry.m_cz)); if (ByZone.TryGetValue(zone, out var value) && value.m_hmap != entry.m_hmap) { Logger.LogDebug($"Two heightmaps registered for zone {zone}; keeping the newest."); } ByZone[zone] = entry; } private static void Unfile(Heightmap hmap, float cx, float cz) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(new Vector3(cx, 0f, cz)); if (ByZone.TryGetValue(zone, out var value) && value.m_hmap == hmap) { ByZone.Remove(zone); } } private static bool Contains(in Entry entry, Vector3 point) { //IL_0000: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (point.x >= entry.m_cx - entry.m_half && point.x <= entry.m_cx + entry.m_half && point.z >= entry.m_cz - entry.m_half) { return point.z <= entry.m_cz + entry.m_half; } return false; } private static Heightmap FastFind(Vector3 point) { //IL_0005: 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_0016: 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) if (ByZone.TryGetValue(ZoneSystem.GetZone(point), out var value) && Contains(in value, point)) { return value.m_hmap; } for (int i = 0; i < Registered.Count; i++) { if (Contains(Registered[i], point)) { return Registered[i].m_hmap; } } return null; } [HarmonyPrefix] [HarmonyPatch("FindHeightmap", new Type[] { typeof(Vector3) })] private static bool FindHeightmapPrefix(Vector3 point, ref Heightmap __result) { //IL_000e: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (!Hooks.Healthy) { return true; } Heightmap val = FastFind(point); if (Verify != null && Verify.Value) { Heightmap val2 = VanillaFind(point); if (val != val2) { if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null && val.IsPointInside(point, 0f) && val2.IsPointInside(point, 0f)) { Logger.LogDebug($"Heightmap registry verify: shared-edge tie at {point}."); } else { Logger.LogError($"Heightmap registry verify: DIVERGED at {point} (fast: " + (((Object)(object)val == (Object)null) ? "null" : ((object)((Component)val).transform.position/*cast due to .constrained prefix*/).ToString()) + ", vanilla: " + (((Object)(object)val2 == (Object)null) ? "null" : ((object)((Component)val2).transform.position/*cast due to .constrained prefix*/).ToString()) + "). Vanilla's result was used. Please report this - leave 'Verify Heightmap Registry' on until it is understood, since the verify pass acts on vanilla's answer."); } } __result = val2; return false; } __result = val; return false; } private static Heightmap VanillaFind(Vector3 point) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) foreach (Heightmap s_heightmap in Heightmap.s_heightmaps) { if (s_heightmap.IsPointInside(point, 0f)) { return s_heightmap; } } return null; } [HarmonyPrefix] [HarmonyPatch("HaveQueuedRebuild", new Type[] { typeof(Vector3), typeof(float) })] private static bool HaveQueuedRebuildPrefix(Vector3 point, float radius, ref bool __result) { //IL_0021: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!Hooks.Healthy) { return true; } __result = false; for (int i = 0; i < Registered.Count; i++) { Entry entry = Registered[i]; if (point.x + radius >= entry.m_cx - entry.m_half && point.x - radius <= entry.m_cx + entry.m_half && point.z + radius >= entry.m_cz - entry.m_half && point.z - radius <= entry.m_cz + entry.m_half && entry.m_hmap.HaveQueuedRebuild()) { __result = true; break; } } return false; } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(LightFlicker))] internal static class LightCostPatch { private struct Anchor { public int m_frame; public bool m_skip; } [HarmonyPatch(typeof(LightFlicker), "OnDisable")] internal static class DisableHook { [HarmonyPostfix] private static void Postfix(LightFlicker __instance) { Anchors.Remove(((Object)__instance).GetInstanceID()); } } internal static ConfigEntry<float> FlickerDistance; internal static ConfigEntry<int> PointLightLimit; private const int AnchorRefreshFrames = 10; private static readonly Dictionary<int, Anchor> Anchors = new Dictionary<int, Anchor>(); private static int _playerPosFrame = -1; private static Vector3 _playerPos; internal static void BindConfig() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0079: 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_008b: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown FlickerDistance = ValConfig.cfg.Bind<float>("Client config", "Light Flicker Distance", 45f, new ConfigDescription("Metres beyond which torch flicker stops updating. The game's own light LOD fades the light itself out at 40, so flicker past that is invisible anyway.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdvanced = true } })); PointLightLimit = ValConfig.cfg.Bind<int>("Client config", "Point Light Limit", -1, new ConfigDescription("Caps how many of the nearest point lights are enabled at once, using the game's own dormant light-priority system with its smooth fade. -1 (default) is exactly vanilla: no cap. Try 30-50 in torch-heavy bases.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 200), new object[1] { (object)new ConfigurationManagerAttributes { IsAdvanced = true } })); ApplyLightLimit(); PointLightLimit.SettingChanged += delegate { ApplyLightLimit(); }; } private static void ApplyLightLimit() { LightLod.m_lightLimit = PointLightLimit.Value; } [HarmonyPrefix] [HarmonyPatch("CustomUpdate")] private static bool CustomUpdatePrefix(LightFlicker __instance) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (__instance.m_ttl > 0f) { return true; } Player localPlayer = Player.m_localPlayer; if (localPlayer == null) { return true; } int frameCount = Time.frameCount; if (frameCount != _playerPosFrame) { _playerPosFrame = frameCount; _playerPos = ((Component)localPlayer).transform.position; } int instanceID = ((Object)__instance).GetInstanceID(); if (!Anchors.TryGetValue(instanceID, out var value) || frameCount - value.m_frame >= 10) { Vector3 position = ((Component)__instance).transform.position; float num = position.x - _playerPos.x; float num2 = position.z - _playerPos.z; float num3 = ((FlickerDistance != null) ? FlickerDistance.Value : 45f); value = new Anchor { m_frame = frameCount, m_skip = (num * num + num2 * num2 > num3 * num3) }; Anchors[instanceID] = value; } return !value.m_skip; } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(LightFlicker))] internal static class LightSettingsEventPatch { [HarmonyPatch(typeof(GraphicsSettingsManager))] internal static class SettingsHook { [HarmonyPostfix] [HarmonyPatch("ApplyGraphicsSettingsToCurrentSession")] private static void Postfix() { foreach (LightFlicker value in Subscribed.Values) { value.ApplySettings(); } } } [HarmonyPatch(typeof(ZNetScene), "Shutdown")] internal static class ShutdownHook { [HarmonyPostfix] private static void Postfix() { Subscribed.Clear(); } } private static readonly Dictionary<int, LightFlicker> Subscribed = new Dictionary<int, LightFlicker>(); private static readonly HookHealth Hooks = new HookHealth("Light settings subscription", () => PatchHelper.HasHook(AccessTools.DeclaredMethod(typeof(LightFlicker), "OnDisable", (Type[])null, (Type[])null), typeof(LightSettingsEventPatch)) && PatchHelper.HasHook(AccessTools.DeclaredMethod(typeof(GraphicsSettingsManager), "ApplyGraphicsSettingsToCurrentSession", (Type[])null, (Type[])null), typeof(SettingsHook))); [HarmonyPrefix] [HarmonyPatch("OnEnable")] private static bool OnEnablePrefix(LightFlicker __instance) { if (!Hooks.Healthy) { return true; } __instance.m_time = 0f; if ((Object)(object)__instance.m_light == (Object)null) { return false; } Subscribed[((Object)__instance).GetInstanceID()] = __instance; __instance.ApplySettings(); return false; } [HarmonyPostfix] [HarmonyPatch("OnDisable")] private static void OnDisablePostfix(LightFlicker __instance) { Subscribed.Remove(((Object)__instance).GetInstanceID()); } } [PatchSide(Side.Client)] [HarmonyPatch(typeof(LiquidVolume))] internal static class LiquidVolumeLeakPatch { private static readonly MethodInfo SafeDisposeMethod = AccessTools.Method(typeof(LiquidVolumeLeakPatch), "SafeDispose", (Type[])null, (Type[])null); private static void SafeDispose<T>(ref NativeArray<T> array) where T : struct { if (array.IsCreated) { array.Dispose(); } } private static bool IsNativeArrayOf(Type type) { if (type != null && type.IsGenericType) { return type.GetGenericTypeDefinition() == typeof(NativeArray<>); } return false; } [HarmonyTranspiler] [HarmonyPriority(0)] [HarmonyPatch("OnDestroy")] private static IEnumerable<CodeInstruction> OnDestroyTranspiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = PatchHelper.Copy(instructions); int num = 0; for (int i = 0; i < list.Count; i++) { if ((!(list[i].opcode != OpCodes.Call) || !(list[i].opcode != OpCodes.Callvirt)) && list[i].operand is MethodInfo methodInfo && !(methodInfo.Name != "Dispose") && IsNativeArrayOf(methodInfo.DeclaringType)) { Type type = methodInfo.DeclaringType.GetGenericArguments()[0]; list[i].opcode = OpCodes.Call; list[i].operand = SafeDisposeMethod.MakeGenericMethod(type); num++; } } if (num == 0) { Logger.LogWarning("LiquidVolume.OnDestroy: found no NativeArray.Dispose calls to guard, so this fix is inactiv