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 DeepNorthTerrainFix v1.2.1
DeepNorthTerrainFix.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("FlorpyDorp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 FlorpyDorp")] [assembly: AssemblyDescription("Heals duplicate terrain compilers in Valheim's Deep North and prevents new ones (server + client).")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1+528090e07cc15577ec64ae9c834b9bfc56c80164")] [assembly: AssemblyProduct("DeepNorthTerrainFix")] [assembly: AssemblyTitle("DeepNorthTerrainFix")] [assembly: AssemblyVersion("1.2.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DeepNorthTerrainFix { [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class Commands { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__1_0; public static ConsoleEvent <>9__1_1; public static ConsoleEvent <>9__1_2; public static ConsoleEvent <>9__1_3; public static ConsoleEvent <>9__1_4; public static ConsoleEvent <>9__1_5; public static ConsoleEvent <>9__1_6; internal void <Postfix>b__1_0(ConsoleEventArgs args) { if (!Ready(args)) { return; } foreach (string item in SaveHealer.Report(ZDOMan.instance)) { Print(args, item); } } internal void <Postfix>b__1_1(ConsoleEventArgs args) { //IL_002c: 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_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_008c: Unknown result type (might be due to invalid IL or missing references) if (!Ready(args)) { return; } if ((Object)(object)Player.m_localPlayer == (Object)null) { Print(args, "no local player here (use dntf_scan)"); return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; Vector2s zone = ZoneSystem.GetZone(position); Print(args, $"position {position.x:0},{position.z:0} -> zone {zone.x},{zone.y}"); foreach (ZDO item in Compilers.InZone(ZDOMan.instance, zone)) { Print(args, " compiler " + Compilers.Describe(item)); } } internal void <Postfix>b__1_2(ConsoleEventArgs args) { if (!Ready(args) || !Allowed(args)) { return; } bool merge = args.Length <= 1 || !args[1].Equals("nomerge", StringComparison.OrdinalIgnoreCase); SaveHealer.Result result = SaveHealer.DedupeAll(ZDOMan.instance, merge); foreach (string line in result.Lines) { Print(args, line); } Print(args, result.Summary("dntf_fix")); Print(args, "Changes are in memory; they are written on the next world save (type 'save' to force one)."); } internal void <Postfix>b__1_3(ConsoleEventArgs args) { //IL_0146: 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_0150: Unknown result type (might be due to invalid IL or missing references) if (!Ready(args) || !Allowed(args)) { return; } string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "both"); bool flag = text == "heights" || text == "both"; bool flag2 = text == "paint" || text == "both"; if (!flag && !flag2) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); return; } Func<Vector2s, bool> zoneFilter = null; if (args.Length >= 5) { <>c__DisplayClass1_0 CS$<>8__locals12 = new <>c__DisplayClass1_0(); if (!int.TryParse(args[2], out CS$<>8__locals12.cx) || !int.TryParse(args[3], out CS$<>8__locals12.cy) || !int.TryParse(args[4], out CS$<>8__locals12.radius) || CS$<>8__locals12.radius < 0) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); return; } zoneFilter = (Vector2s z) => Math.Abs(z.x - CS$<>8__locals12.cx) <= CS$<>8__locals12.radius && Math.Abs(z.y - CS$<>8__locals12.cy) <= CS$<>8__locals12.radius; } else if (args.Length == 3) { <>c__DisplayClass1_1 CS$<>8__locals16 = new <>c__DisplayClass1_1(); if (!int.TryParse(args[2], out CS$<>8__locals16.radius) || CS$<>8__locals16.radius < 0 || (Object)(object)Player.m_localPlayer == (Object)null) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius] (dntf_zone prints your zone)"); return; } CS$<>8__locals16.c = ZoneSystem.GetZone(((Component)Player.m_localPlayer).transform.position); zoneFilter = (Vector2s z) => Math.Abs(z.x - CS$<>8__locals16.c.x) <= CS$<>8__locals16.radius && Math.Abs(z.y - CS$<>8__locals16.c.y) <= CS$<>8__locals16.radius; } else if (args.Length != 1 && args.Length != 2) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); return; } SaveHealer.Result result = SaveHealer.ReconcileSeams(ZDOMan.instance, zoneFilter, flag, flag2); foreach (string line in result.Lines) { Print(args, line); } Print(args, result.Summary("dntf_seams")); } internal void <Postfix>b__1_4(ConsoleEventArgs args) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (Ready(args) && Allowed(args)) { if (args.Length < 3 || !int.TryParse(args[1], out var result) || !int.TryParse(args[2], out var result2)) { Print(args, "usage: dntf_reset <zoneX> <zoneY> (dntf_zone prints your current zone)"); return; } int num = SaveHealer.ResetZone(ZDOMan.instance, new Vector2s(result, result2)); Print(args, (num > 0) ? $"reset {num} compiler(s) in zone {result},{result2}; terrain there returns to world generation" : $"zone {result},{result2} has no terrain compiler"); } } internal void <Postfix>b__1_5(ConsoleEventArgs args) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (!Ready(args)) { return; } if (args.Length < 3 || !int.TryParse(args[1], out var result) || !int.TryParse(args[2], out var result2)) { Print(args, "usage: dntf_zdos <zoneX> <zoneY> [radius] (dntf_zone prints your current zone)"); return; } int result3; int radius = ((args.Length > 3 && int.TryParse(args[3], out result3)) ? Math.Max(0, result3) : 0); foreach (string item in Diagnostics.ZoneCensus(ZDOMan.instance, new Vector2s(result, result2), radius)) { Print(args, item); } } internal void <Postfix>b__1_6(ConsoleEventArgs args) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!Ready(args) || !Allowed(args)) { return; } if (args.Length < 4 || !int.TryParse(args[1], out var result) || !int.TryParse(args[2], out var result2)) { Print(args, "usage: dntf_purge <zoneX> <zoneY> <prefabName|hash> [radius]"); return; } int result3; int radius = ((args.Length > 4 && int.TryParse(args[4], out result3)) ? Math.Max(0, result3) : 0); foreach (string item in Diagnostics.PurgeNonPersistent(ZDOMan.instance, new Vector2s(result, result2), radius, args[3])) { Print(args, item); } } } [CompilerGenerated] private sealed class <>c__DisplayClass1_0 { public int cx; public int radius; public int cy; internal bool <Postfix>b__7(Vector2s z) { //IL_0000: 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) if (Math.Abs(z.x - cx) <= radius) { return Math.Abs(z.y - cy) <= radius; } return false; } } [CompilerGenerated] private sealed class <>c__DisplayClass1_1 { public Vector2s c; public int radius; internal bool <Postfix>b__8(Vector2s z) { //IL_0000: 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) if (Math.Abs(z.x - c.x) <= radius) { return Math.Abs(z.y - c.y) <= radius; } return false; } } private static bool s_registered; private static void Postfix() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00ec: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_0125: 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) //IL_011b: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Expected O, but got Unknown //IL_0197: 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_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown if (s_registered) { return; } s_registered = true; object obj = <>c.<>9__1_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { if (!Ready(args)) { return; } foreach (string item in SaveHealer.Report(ZDOMan.instance)) { Print(args, item); } }; <>c.<>9__1_0 = val; obj = (object)val; } new ConsoleCommand("dntf_scan", "DeepNorthTerrainFix: list zones that have more than one terrain compiler (read-only, local view)", (ConsoleEvent)obj, false, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__1_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { //IL_002c: 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_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_008c: Unknown result type (might be due to invalid IL or missing references) if (Ready(args)) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { Vector3 position = ((Component)Player.m_localPlayer).transform.position; Vector2s zone = ZoneSystem.GetZone(position); Print(args, $"position {position.x:0},{position.z:0} -> zone {zone.x},{zone.y}"); { foreach (ZDO item2 in Compilers.InZone(ZDOMan.instance, zone)) { Print(args, " compiler " + Compilers.Describe(item2)); } return; } } Print(args, "no local player here (use dntf_scan)"); } }; <>c.<>9__1_1 = val2; obj2 = (object)val2; } new ConsoleCommand("dntf_zone", "DeepNorthTerrainFix: print your current zone coordinates and its terrain compilers", (ConsoleEvent)obj2, false, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__1_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { if (Ready(args) && Allowed(args)) { bool merge = args.Length <= 1 || !args[1].Equals("nomerge", StringComparison.OrdinalIgnoreCase); SaveHealer.Result result = SaveHealer.DedupeAll(ZDOMan.instance, merge); foreach (string line in result.Lines) { Print(args, line); } Print(args, result.Summary("dntf_fix")); Print(args, "Changes are in memory; they are written on the next world save (type 'save' to force one)."); } }; <>c.<>9__1_2 = val3; obj3 = (object)val3; } new ConsoleCommand("dntf_fix", "[nomerge] - DeepNorthTerrainFix: merge and remove duplicate terrain compilers in the whole world (runs on the server; admins only when sent from a client)", (ConsoleEvent)obj3, false, true, true, false, false, false, (ConsoleOptionsFetcher)null, false, true, false); object obj4 = <>c.<>9__1_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { //IL_0146: 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_0150: Unknown result type (might be due to invalid IL or missing references) if (Ready(args) && Allowed(args)) { string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "both"); bool flag = text == "heights" || text == "both"; bool flag2 = text == "paint" || text == "both"; if (!flag && !flag2) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); } else { Func<Vector2s, bool> zoneFilter = null; if (args.Length >= 5) { if (!int.TryParse(args[2], out var cx) || !int.TryParse(args[3], out var cy) || !int.TryParse(args[4], out var radius) || radius < 0) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); return; } zoneFilter = (Vector2s z) => Math.Abs(z.x - cx) <= radius && Math.Abs(z.y - cy) <= radius; } else if (args.Length == 3) { if (!int.TryParse(args[2], out var radius2) || radius2 < 0 || (Object)(object)Player.m_localPlayer == (Object)null) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius] (dntf_zone prints your zone)"); return; } Vector2s c = ZoneSystem.GetZone(((Component)Player.m_localPlayer).transform.position); zoneFilter = (Vector2s z) => Math.Abs(z.x - c.x) <= radius2 && Math.Abs(z.y - c.y) <= radius2; } else if (args.Length != 1 && args.Length != 2) { Print(args, "usage: dntf_seams [heights|paint|both] [zoneX zoneY radius]"); return; } SaveHealer.Result result = SaveHealer.ReconcileSeams(ZDOMan.instance, zoneFilter, flag, flag2); foreach (string line2 in result.Lines) { Print(args, line2); } Print(args, result.Summary("dntf_seams")); } } }; <>c.<>9__1_3 = val4; obj4 = (object)val4; } new ConsoleCommand("dntf_seams", "[heights|paint|both] [zoneX zoneY radius] - DeepNorthTerrainFix: make shared border vertices of adjacent zones agree; whole world unless a centre zone and radius are given (runs on the server)", (ConsoleEvent)obj4, false, true, true, false, false, false, (ConsoleOptionsFetcher)null, false, true, false); object obj5 = <>c.<>9__1_4; if (obj5 == null) { ConsoleEvent val5 = delegate(ConsoleEventArgs args) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (Ready(args) && Allowed(args)) { if (args.Length < 3 || !int.TryParse(args[1], out var result) || !int.TryParse(args[2], out var result2)) { Print(args, "usage: dntf_reset <zoneX> <zoneY> (dntf_zone prints your current zone)"); } else { int num = SaveHealer.ResetZone(ZDOMan.instance, new Vector2s(result, result2)); Print(args, (num > 0) ? $"reset {num} compiler(s) in zone {result},{result2}; terrain there returns to world generation" : $"zone {result},{result2} has no terrain compiler"); } } }; <>c.<>9__1_4 = val5; obj5 = (object)val5; } new ConsoleCommand("dntf_reset", "<zoneX> <zoneY> - DeepNorthTerrainFix: wipe all terrain modifications of one zone (buildings are kept; runs on the server)", (ConsoleEvent)obj5, false, true, true, false, false, false, (ConsoleOptionsFetcher)null, false, true, false); object obj6 = <>c.<>9__1_5; if (obj6 == null) { ConsoleEvent val6 = delegate(ConsoleEventArgs args) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) if (Ready(args)) { if (args.Length >= 3 && int.TryParse(args[1], out var result) && int.TryParse(args[2], out var result2)) { int result3; int radius = ((args.Length > 3 && int.TryParse(args[3], out result3)) ? Math.Max(0, result3) : 0); { foreach (string item3 in Diagnostics.ZoneCensus(ZDOMan.instance, new Vector2s(result, result2), radius)) { Print(args, item3); } return; } } Print(args, "usage: dntf_zdos <zoneX> <zoneY> [radius] (dntf_zone prints your current zone)"); } }; <>c.<>9__1_5 = val6; obj6 = (object)val6; } new ConsoleCommand("dntf_zdos", "<zoneX> <zoneY> [radius] - DeepNorthTerrainFix: list every object type in a zone as the running game sees it (includes non-persistent objects that never reach the save)", (ConsoleEvent)obj6, false, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj7 = <>c.<>9__1_6; if (obj7 == null) { ConsoleEvent val7 = delegate(ConsoleEventArgs args) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (Ready(args) && Allowed(args)) { if (args.Length >= 4 && int.TryParse(args[1], out var result) && int.TryParse(args[2], out var result2)) { int result3; int radius = ((args.Length > 4 && int.TryParse(args[4], out result3)) ? Math.Max(0, result3) : 0); { foreach (string item4 in Diagnostics.PurgeNonPersistent(ZDOMan.instance, new Vector2s(result, result2), radius, args[3])) { Print(args, item4); } return; } } Print(args, "usage: dntf_purge <zoneX> <zoneY> <prefabName|hash> [radius]"); } }; <>c.<>9__1_6 = val7; obj7 = (object)val7; } new ConsoleCommand("dntf_purge", "<zoneX> <zoneY> <prefabName|hash> [radius] - DeepNorthTerrainFix: remove NON-persistent objects of one prefab from a zone (never touches buildings or anything saved; runs on the server)", (ConsoleEvent)obj7, false, true, true, false, false, false, (ConsoleOptionsFetcher)null, false, true, false); Plugin.Log.LogInfo((object)"Console commands registered: dntf_scan, dntf_zone, dntf_zdos, dntf_fix, dntf_seams, dntf_reset, dntf_purge"); } private static bool Ready(ConsoleEventArgs args) { if (ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null) { Print(args, "world not loaded"); return false; } return true; } private static bool Allowed(ConsoleEventArgs args) { bool num = ZNet.instance.IsServer(); if (!num) { Print(args, "this command runs on the server; joined clients must be on the server's adminlist"); } return num; } private static void Print(ConsoleEventArgs args, string line) { ZLog.Log((object)("[DNTF] " + line)); if (args != null && (Object)(object)args.Context != (Object)null) { args.Context.AddString(line); } } } internal static class GhostOps { private static readonly Dictionary<int, bool> s_isOp = new Dictionary<int, bool>(); public static bool IsTerrainOpPrefab(int hash) { if (s_isOp.TryGetValue(hash, out var value)) { return value; } bool flag = false; try { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(hash) : null); flag = (Object)(object)val != (Object)null && (Object)(object)val.GetComponent<TerrainOp>() != (Object)null; } catch { } if ((Object)(object)ZNetScene.instance != (Object)null) { s_isOp[hash] = flag; } return flag; } public static void ResetCache() { s_isOp.Clear(); } public static int PurgeList(List<ZDO> list) { if (list == null || list.Count == 0) { return 0; } List<ZDO> list2 = null; foreach (ZDO item in list) { if (IsTerrainOpPrefab(item.GetPrefab())) { (list2 ?? (list2 = new List<ZDO>())).Add(item); } } if (list2 == null) { return 0; } foreach (ZDO item2 in list2) { Compilers.Remove(item2); } return list2.Count; } public static int PurgeAll(ZDOMan man) { List<ZDO>[] array = Compilers.SectorLists(man); if (array == null) { return 0; } int num = 0; for (int i = 0; i < array.Length; i++) { num += PurgeList(array[i]); } return num; } } internal static class Diagnostics { private sealed class Row { public int Hash; public string Name; public int Count; public int Persistent; public int NonPersistent; public int Distant; public int Unowned; public int DeadInstance; public int NoInstance; public readonly HashSet<long> Owners = new HashSet<long>(); } public static string PrefabName(int hash) { try { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(hash) : null); return ((Object)(object)val != (Object)null) ? ((Object)val).name : "?"; } catch { return "?"; } } private static IEnumerable<ZDO> ZdosIn(ZDOMan man, Vector2s center, int radius) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) List<ZDO>[] sectors = Compilers.SectorLists(man); if (sectors == null) { yield break; } for (int y = center.y - radius; y <= center.y + radius; y++) { for (int x = center.x - radius; x <= center.x + radius; x++) { SectorIndex val = ZoneSystem.SectorToIndex(new Vector2s(x, y)); if (val.Sector >= sectors.Length) { continue; } List<ZDO> list = sectors[val.Sector]; if (list == null) { continue; } foreach (ZDO item in list) { yield return item; } } } } public static List<string> ZoneCensus(ZDOMan man, Vector2s center, int radius, int maxRows = 60) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) Dictionary<int, Row> dictionary = new Dictionary<int, Row>(); int num = 0; int num2 = 0; int num3 = 0; bool flag = (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null; foreach (ZDO item in ZdosIn(man, center, radius)) { num++; int prefab = item.GetPrefab(); if (!dictionary.TryGetValue(prefab, out var value)) { Row obj = new Row { Hash = prefab, Name = PrefabName(prefab) }; value = obj; dictionary[prefab] = obj; } value.Count++; if (item.Persistent) { value.Persistent++; } else { value.NonPersistent++; num2++; } if (item.Distant) { value.Distant++; } if (!item.HasOwner()) { value.Unowned++; } else { value.Owners.Add(item.GetOwner()); } if (flag && (Object)(object)ZNetScene.instance.FindInstance(item) == (Object)null) { if (item.Created) { value.DeadInstance++; num3++; } else { value.NoInstance++; } } } List<string> list = new List<string>(); string text = ((radius > 0) ? $"zones {center.x - radius}..{center.x + radius},{center.y - radius}..{center.y + radius}" : $"zone {center.x},{center.y}"); list.Add(string.Format("{0}: {1} objects, {2} non-persistent (never saved){3}", text, num, num2, flag ? $", {num3} created-but-dead instances (block 'area ready')" : "")); List<Row> list2 = new List<Row>(dictionary.Values); list2.Sort((Row a, Row b) => b.Count.CompareTo(a.Count)); int num4 = 0; foreach (Row item2 in list2) { if (num4++ >= maxRows) { list.Add($"... {list2.Count - maxRows} more prefab types"); break; } string text2 = ""; if (item2.NonPersistent > 0) { text2 += $" nonpersistent={item2.NonPersistent}"; } if (item2.Distant > 0) { text2 += $" distant={item2.Distant}"; } if (item2.Unowned > 0) { text2 += $" unowned={item2.Unowned}"; } if (item2.Owners.Count > 0) { text2 += $" owners={item2.Owners.Count}"; } if (item2.DeadInstance > 0) { text2 += $" DEAD={item2.DeadInstance}"; } if (flag && item2.NoInstance > 0) { text2 += $" notSpawned={item2.NoInstance}"; } list.Add($" {item2.Count,6} x {item2.Name} (hash {item2.Hash}){text2}"); } return list; } public static List<string> PurgeNonPersistent(ZDOMan man, Vector2s center, int radius, string prefabNameOrHash) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); if (!int.TryParse(prefabNameOrHash, out var result)) { result = StringExtensionMethods.GetStableHashCode(prefabNameOrHash); } List<ZDO> list2 = new List<ZDO>(); int num = 0; foreach (ZDO item in ZdosIn(man, center, radius)) { if (item.GetPrefab() == result) { if (item.Persistent) { num++; } else { list2.Add(item); } } } foreach (ZDO item2 in list2) { Compilers.Remove(item2); } list.Add($"purged {list2.Count} non-persistent '{PrefabName(result)}' (hash {result}) object(s); skipped {num} persistent one(s). They disappear for everyone within a tick."); return list; } } [BepInPlugin("FlorpyDorp.DeepNorthTerrainFix", "DeepNorthTerrainFix", "1.2.1")] public class Plugin : BaseUnityPlugin { public const string GUID = "FlorpyDorp.DeepNorthTerrainFix"; public const string NAME = "DeepNorthTerrainFix"; public const string VERSION = "1.2.1"; public const string AUTHOR = "FlorpyDorp"; internal static ManualLogSource Log; internal static ConfigEntry<bool> HealOnWorldLoad; internal static ConfigEntry<bool> HealOnArrival; internal static ConfigEntry<bool> HealPeriodically; internal static ConfigEntry<float> HealIntervalSeconds; internal static ConfigEntry<bool> MergeDuplicateData; internal static ConfigEntry<bool> ClientMayHeal; internal static ConfigEntry<bool> ProtectRichestCompiler; internal static ConfigEntry<bool> FixDuplicateCompilers; internal static ConfigEntry<bool> MergeOnDedupe; internal static ConfigEntry<bool> ReuseExistingCompilerZdo; internal static ConfigEntry<bool> SkipUnownedNeighborSpread; internal static ConfigEntry<bool> FixDoubleAppliedBorderStrokes; internal static ConfigEntry<bool> CleanupNetworkedTerrainOps; internal static ConfigEntry<bool> PurgeGhostTerrainOps; internal static ConfigEntry<bool> TeleportHardTimeout; internal static ConfigEntry<float> TeleportHardTimeoutSeconds; internal static ConfigEntry<bool> PatchNetworkBudget; internal static ConfigEntry<int> SteamSendRateBytesPerSec; internal static ConfigEntry<int> ZdoInFlightBudgetBytes; internal static ConfigEntry<bool> ThrottleSnowWrites; internal static ConfigEntry<float> SnowWriteStep; private Harmony _harmony; private float _healTimer; private static readonly HashSet<long> s_pendingZoneKeys = new HashSet<long>(); private static readonly Queue<long> s_pendingZones = new Queue<long>(); private static readonly HashSet<ZDOID> s_knownCompilers = new HashSet<ZDOID>(); internal static ConfigEntry<int> ConfigVersion; private const int CurrentConfigVersion = 2; private static readonly Queue<ZDO> s_pendingGhostOps = new Queue<ZDO>(); private const int SweepSlice = 8192; private static int s_sweepCursor = -1; private static int s_sweepFound; private static int s_sweepGhosts; private void Awake() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Expected O, but got Unknown //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; HealOnWorldLoad = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "HealOnWorldLoad", true, "Server / host: right after the world is loaded, merge and remove duplicate terrain compilers in every zone. The result is saved with the next world save."); HealOnArrival = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "HealOnArrival", true, "When a terrain compiler ZDO arrives over the network for a zone that already has one, merge it into the existing one and remove it. On the server this happens the instant it arrives, before it can be forwarded to any other player."); HealPeriodically = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "HealPeriodically", true, "Server / host: scan the whole world for duplicate compilers every HealIntervalSeconds."); HealIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Heal", "HealIntervalSeconds", 120f, new ConfigDescription("Seconds between periodic scans.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 3600f), Array.Empty<object>())); MergeDuplicateData = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "MergeDuplicateData", true, "When removing a duplicate, copy any terrain vertices it modified that the survivor did not into the survivor."); ClientMayHeal = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "ClientMayHeal", true, "Allow a non-host client to run the arrival heal too (it claims ownership of the duplicate to remove it). Harmless if the server also runs this mod; useful if it does not."); ProtectRichestCompiler = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "ProtectRichestCompiler", true, "Server: refuse a client's request to destroy the terrain compiler that holds a zone's terraforming when no other compiler in that zone has as much data. An unmodded game sends exactly that request when a duplicate compiler appears on its screen while it owns the real one; vanilla then deletes every hoe and shovel stroke in the zone. The compiler is kept and re-sent to everyone instead. Keep this on."); FixDuplicateCompilers = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "FixDuplicateCompilers", true, "Client: when two terrain compiler objects exist for one zone, keep the one with the most terrain data and remove the other (claiming ownership so the removal propagates). Vanilla removes whichever was created first, which destroys real terraforming and loops create/destroy on non-owning clients."); MergeOnDedupe = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "MergeOnDedupe", true, "Client: before removing a duplicate compiler object, copy its modified vertices into the survivor."); ReuseExistingCompilerZdo = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "ReuseExistingCompilerZdo", true, "Client: before spawning a brand-new terrain compiler for a zone, look for the zone's existing compiler ZDO that just has not been instantiated yet and use that. This is where duplicates are born."); SkipUnownedNeighborSpread = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "SkipUnownedNeighborSpread", true, "Client: do not write edge-spread paint into a neighbouring zone's compiler unless this client owns it (vanilla writes it locally and silently fails to save it, so the seam differs per player until it snaps back)."); FixDoubleAppliedBorderStrokes = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "FixDoubleAppliedBorderStrokes", true, "Client: a hoe/shovel stroke that overlaps two zones is applied to both zones AND copied across the border, so the shared border column gets the stroke twice (a ridge/trench along the zone line in Deep North snow). Skip the copy when the neighbour zone receives the stroke itself."); CleanupNetworkedTerrainOps = ((BaseUnityPlugin)this).Config.Bind<bool>("Terrain", "CleanupNetworkedTerrainOps", true, "Client: if a terrain-op prefab (hoe/shovel stroke object) carries a network view, destroy it through the scene so it does not leave a dead, non-persistent ZDO behind. Such ZDOs block 'area ready' for every arriving player until their owner leaves the zone, and never appear in saves."); PurgeGhostTerrainOps = ((BaseUnityPlugin)this).Config.Bind<bool>("Heal", "PurgeGhostTerrainOps", true, "Server / host (and clients with ClientMayHeal): remove any ZDO whose prefab is a self-destructing terrain op (hoe/shovel stroke object). Such ZDOs are always garbage: the stroke was already applied, and every client that spawns the ZDO re-applies it and is left with a dead instance that blocks 'area ready'. Removed on world load, the moment one arrives over the network, and during the periodic sweep."); TeleportHardTimeout = ((BaseUnityPlugin)this).Config.Bind<bool>("Teleport", "HardTimeout", true, "Client: finish a teleport after HardTimeoutSeconds even if the destination never reports 'ready'. Vanilla waits forever if any object around the target cannot be instantiated."); TeleportHardTimeoutSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Teleport", "HardTimeoutSeconds", 25f, new ConfigDescription("Seconds after which a teleport is forced to complete.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 120f), Array.Empty<object>())); PatchNetworkBudget = ((BaseUnityPlugin)this).Config.Bind<bool>("Network", "PatchNetworkBudget", false, "Raise the Steam socket send-rate cap and the per-peer ZDO in-flight budget. Off by default since 1.2.0: on a server it pushes more data at every player, and a player with a weak upload or a congested link then sees delayed hits and rubber-banding. Only enable it if every player has plenty of bandwidth."); SteamSendRateBytesPerSec = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "SteamSendRateBytesPerSec", 512000, new ConfigDescription("Steam networking SendRateMin/Max (vanilla 153600 = 150 KB/s).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(153600, 2000000), Array.Empty<object>())); ZdoInFlightBudgetBytes = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "ZdoInFlightBudgetBytes", 30720, new ConfigDescription("ZDOMan.SendZDOs in-flight byte budget per peer (vanilla 10240). One Deep North terrain block can be 10-15 KB.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10240, 262144), Array.Empty<object>())); ThrottleSnowWrites = ((BaseUnityPlugin)this).Config.Bind<bool>("Snow", "ThrottleSnowWrites", true, "Only sync a building piece's snow-buildup value when it changed by at least SnowWriteStep. Vanilla syncs every piece about once per second while snow accumulates."); SnowWriteStep = ((BaseUnityPlugin)this).Config.Bind<float>("Snow", "SnowWriteStep", 0.05f, new ConfigDescription("Minimum change in snow buildup (0..1) before it is synced. Visuals only change at 0.25.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.25f), Array.Empty<object>())); ConfigVersion = ((BaseUnityPlugin)this).Config.Bind<int>("Internal", "ConfigVersion", 0, "Used to migrate settings when the mod updates. Do not edit."); MigrateConfig(); _harmony = new Harmony("FlorpyDorp.DeepNorthTerrainFix"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)string.Format("{0} {1} loaded ({2} methods patched).", "DeepNorthTerrainFix", "1.2.1", _harmony.GetPatchedMethods().CountItems())); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void MigrateConfig() { int value = ConfigVersion.Value; if (value < 2) { bool flag = false; if (value < 2 && PatchNetworkBudget.Value) { PatchNetworkBudget.Value = false; flag = true; Log.LogWarning((object)"Config migrated from a pre-1.2.0 file: Network.PatchNetworkBudget reset to false (it can delay hits for players with weak uploads). Set it to true in the config file if you really want it; this reset only happens once."); } ConfigVersion.Value = 2; ((BaseUnityPlugin)this).Config.Save(); if (!flag) { Log.LogInfo((object)$"Config version set to {2}."); } } } private static bool IsAuthority() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } internal static void OnSessionStart() { s_knownCompilers.Clear(); s_pendingZoneKeys.Clear(); s_pendingZones.Clear(); s_sweepCursor = -1; Compilers.ResetSession(); ZDOMan_RPC_DestroyZDO_Patch.ResetSession(); } internal static void OnWorldLoaded() { OnSessionStart(); if (ZDOMan.instance == null) { return; } if (HealOnWorldLoad.Value) { try { SaveHealer.Result result = SaveHealer.DedupeAll(ZDOMan.instance, MergeDuplicateData.Value); foreach (string line in result.Lines) { Log.LogWarning((object)("[heal on load] " + line)); } Log.LogInfo((object)result.Summary("[heal on load]")); if (result.Removed > 0) { Log.LogWarning((object)"Duplicate terrain compilers were removed; the fix is persisted with the next world save."); } } catch (Exception ex) { Log.LogError((object)("Heal on load failed: " + ex)); } } if (!PurgeGhostTerrainOps.Value) { return; } try { int num = GhostOps.PurgeAll(ZDOMan.instance); if (num > 0) { Log.LogWarning((object)$"[heal on load] removed {num} ghost terrain-op ZDO(s) from the save"); } } catch (Exception ex2) { Log.LogError((object)("Ghost terrain-op purge on load failed: " + ex2)); } } internal static void OnCompilerArrived(ZDO compiler) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!HealOnArrival.Value || compiler == null || !s_knownCompilers.Add(compiler.m_uid)) { return; } if (IsAuthority()) { if (ZDOMan.instance == null) { return; } try { foreach (string line in SaveHealer.DedupeZone(ZDOMan.instance, compiler.GetSector(), MergeDuplicateData.Value).Lines) { Log.LogWarning((object)("[heal on arrival] " + line)); } return; } catch (Exception ex) { Log.LogError((object)("Heal on arrival failed: " + ex)); return; } } long item = Compilers.ZoneKey(compiler.GetSector()); if (s_pendingZoneKeys.Add(item)) { s_pendingZones.Enqueue(item); } } internal static void EnqueueGhostOp(ZDO zdo) { if (s_pendingGhostOps.Count < 4096) { s_pendingGhostOps.Enqueue(zdo); } } private void Update() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_02f8: Unknown result type (might be due to invalid IL or missing references) if (ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null) { return; } bool flag = IsAuthority(); if (s_pendingZones.Count > 0 && (flag || ClientMayHeal.Value)) { int num = 4; while (num-- > 0 && s_pendingZones.Count > 0) { long num2 = s_pendingZones.Dequeue(); s_pendingZoneKeys.Remove(num2); Vector2s zone = Compilers.ZoneFromKey(num2); try { foreach (string line in SaveHealer.DedupeZone(ZDOMan.instance, zone, MergeDuplicateData.Value).Lines) { Log.LogWarning((object)("[heal on arrival] " + line)); } } catch (Exception ex) { Log.LogError((object)("Heal on arrival failed: " + ex)); } } } else if (s_pendingZones.Count > 0) { s_pendingZones.Clear(); s_pendingZoneKeys.Clear(); } if (s_pendingGhostOps.Count > 0) { if (flag || ClientMayHeal.Value) { int num3 = 0; while (s_pendingGhostOps.Count > 0 && num3 < 256) { ZDO val = s_pendingGhostOps.Dequeue(); if (val != null && val.IsValid()) { try { Compilers.Remove(val); num3++; } catch (Exception ex2) { Log.LogError((object)("Ghost terrain-op removal failed: " + ex2)); } } } if (num3 > 0) { Log.LogInfo((object)$"[heal on arrival] removed {num3} ghost terrain-op ZDO(s)"); } } else { s_pendingGhostOps.Clear(); } } if (!flag || !HealPeriodically.Value) { return; } if (s_sweepCursor < 0) { _healTimer += Time.deltaTime; if (_healTimer < HealIntervalSeconds.Value) { return; } _healTimer = 0f; s_sweepCursor = 0; s_sweepFound = 0; } try { List<ZDO>[] array = Compilers.SectorLists(ZDOMan.instance); if (array == null) { s_sweepCursor = -1; return; } int num4 = Math.Min(array.Length, s_sweepCursor + 8192); for (int i = s_sweepCursor; i < num4; i++) { List<ZDO> list = array[i]; if (list == null || list.Count == 0) { continue; } if (PurgeGhostTerrainOps.Value) { int num5 = GhostOps.PurgeList(list); if (num5 > 0) { s_sweepGhosts += num5; } } if (list.Count < 2) { continue; } int num6 = 0; for (int j = 0; j < list.Count; j++) { if (list[j].GetPrefab() == Compilers.PrefabHash) { num6++; } } if (num6 < 2) { continue; } SaveHealer.Result result = SaveHealer.DedupeZone(ZDOMan.instance, ZoneSystem.IndexToSector((uint)i), MergeDuplicateData.Value); foreach (string line2 in result.Lines) { Log.LogWarning((object)("[periodic heal] " + line2)); } s_sweepFound += result.ZonesWithDuplicates; } s_sweepCursor = num4; if (s_sweepCursor >= array.Length) { if (s_sweepFound > 0 || s_sweepGhosts > 0) { Log.LogInfo((object)$"[periodic heal] sweep done, {s_sweepFound} zone(s) repaired, {s_sweepGhosts} ghost terrain-op ZDO(s) removed"); } s_sweepCursor = -1; s_sweepGhosts = 0; } } catch (Exception ex3) { Log.LogError((object)("Periodic heal failed: " + ex3)); s_sweepCursor = -1; } } } internal static class EnumerableExt { public static int CountItems<T>(this IEnumerable<T> src) { int num = 0; foreach (T item in src) { _ = item; num++; } return num; } } [HarmonyPatch(typeof(ZDOMan), "LoadChunks")] internal static class ZDOMan_LoadChunks_Patch { private static void Postfix() { Plugin.OnWorldLoaded(); } } [HarmonyPatch(typeof(ZDOMan), "Load")] internal static class ZDOMan_Load_Patch { private static void Postfix() { Plugin.OnWorldLoaded(); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] internal static class ZDOMan_Ctor_Patch { private static void Postfix(ZDOMan __instance) { TerrainComp_Awake_Patch.ResetSession(); GhostOps.ResetCache(); Plugin.OnSessionStart(); __instance.m_onZDODestroyed = (Action<ZDO>)Delegate.Combine(__instance.m_onZDODestroyed, new Action<ZDO>(TerrainComp_Awake_Patch.OnZDODestroyed)); } } [HarmonyPatch(typeof(ZDO), "Deserialize")] internal static class ZDO_Deserialize_Patch { private static void Postfix(ZDO __instance) { int prefab = __instance.GetPrefab(); if (prefab == Compilers.PrefabHash) { Plugin.OnCompilerArrived(__instance); } else if (Plugin.PurgeGhostTerrainOps.Value && GhostOps.IsTerrainOpPrefab(prefab)) { Plugin.EnqueueGhostOp(__instance); } } } [HarmonyPatch] internal static class ZDOPeer_ShouldSend_Patch { private static MethodBase TargetMethod() { Type type = AccessTools.Inner(typeof(ZDOMan), "ZDOPeer"); if (!(type == null)) { return AccessTools.Method(type, "ShouldSend", new Type[1] { typeof(ZDO) }, (Type[])null); } return null; } private static bool Prefix(ZDO zdo, ref bool __result) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || Compilers.SendSuppressed.Count == 0 || !Compilers.SendSuppressed.Contains(zdo.m_uid)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ZDOMan), "RPC_DestroyZDO")] internal static class ZDOMan_RPC_DestroyZDO_Patch { private static readonly Dictionary<ZDOID, int> s_refused = new Dictionary<ZDOID, int>(); internal static void ResetSession() { s_refused.Clear(); } private static bool Prefix(ZDOMan __instance, long sender, ref ZPackage pkg) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0196: 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_019f: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.ProtectRichestCompiler.Value || !Compilers.IsServer || pkg == null) { return true; } if (sender == ZDOMan.GetSessionID()) { return true; } int pos = pkg.GetPos(); int num; try { num = pkg.ReadInt(); } catch { pkg.SetPos(pos); return true; } List<ZDOID> list = new List<ZDOID>(num); bool flag = false; for (int i = 0; i < num; i++) { ZDOID val = pkg.ReadZDOID(); ZDO zDO = __instance.GetZDO(val); if (zDO != null && zDO.GetPrefab() == Compilers.PrefabHash && Compilers.IsProtected(__instance, zDO)) { flag = true; try { zDO.SetOwner(0L); __instance.ForceSendZDO(val); } catch (Exception arg) { Plugin.Log.LogError((object)$"Protecting compiler {val} failed: {arg}"); } s_refused.TryGetValue(val, out var value); value = (s_refused[val] = value + 1); if (value <= 5 || value % 50 == 0) { Vector2s sector = zDO.GetSector(); Plugin.Log.LogWarning((object)$"[protect] refused destroy of terrain compiler {Compilers.Describe(zDO)} in zone {sector.x},{sector.y} requested by peer {sender} (x{value}); re-sent to all peers"); } } else { list.Add(val); } } if (!flag) { pkg.SetPos(pos); return true; } ZPackage val2 = new ZPackage(); val2.Write(list.Count); foreach (ZDOID item in list) { val2.Write(item); } val2.SetPos(0); pkg = val2; return true; } } [HarmonyPatch(typeof(TerrainComp), "Awake")] internal static class TerrainComp_Awake_Patch { internal static readonly FieldRef<TerrainComp, ZNetView> f_nview = AccessTools.FieldRefAccess<TerrainComp, ZNetView>("m_nview"); internal static readonly FieldRef<TerrainComp, Heightmap> f_hmap = AccessTools.FieldRefAccess<TerrainComp, Heightmap>("m_hmap"); private static readonly FieldRef<TerrainComp, bool> f_initialized = AccessTools.FieldRefAccess<TerrainComp, bool>("m_initialized"); private static readonly FieldRef<TerrainComp, int> f_operations = AccessTools.FieldRefAccess<TerrainComp, int>("m_operations"); private static readonly FieldRef<TerrainComp, bool[]> f_modifiedHeight = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedHeight"); private static readonly FieldRef<TerrainComp, float[]> f_levelDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_levelDelta"); private static readonly FieldRef<TerrainComp, float[]> f_smoothDelta = AccessTools.FieldRefAccess<TerrainComp, float[]>("m_smoothDelta"); private static readonly FieldRef<TerrainComp, bool[]> f_modifiedPaint = AccessTools.FieldRefAccess<TerrainComp, bool[]>("m_modifiedPaint"); private static readonly FieldRef<TerrainComp, Color[]> f_paintMask = AccessTools.FieldRefAccess<TerrainComp, Color[]>("m_paintMask"); private static readonly FieldInfo fi_instances = AccessTools.Field(typeof(TerrainComp), "s_instances"); private static readonly MethodInfo m_Initialize = AccessTools.Method(typeof(TerrainComp), "Initialize", (Type[])null, (Type[])null); private static readonly MethodInfo m_CheckLoad = AccessTools.Method(typeof(TerrainComp), "CheckLoad", (Type[])null, (Type[])null); private static readonly MethodInfo m_Save = AccessTools.Method(typeof(TerrainComp), "Save", new Type[1] { typeof(bool) }, (Type[])null); private static readonly MethodInfo m_Rpc = AccessTools.Method(typeof(TerrainComp), "RPC_ApplyOperation", (Type[])null, (Type[])null); private static readonly FieldRef<TerrainComp, uint> f_lastDataRevision = AccessTools.FieldRefAccess<TerrainComp, uint>("m_lastDataRevision"); private static readonly HashSet<ZDOID> s_pendingDestroy = new HashSet<ZDOID>(); internal static void ResetSession() { s_pendingDestroy.Clear(); } internal static void OnZDODestroyed(ZDO zdo) { //IL_000a: 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) if (zdo != null) { s_pendingDestroy.Remove(zdo.m_uid); Compilers.SendSuppressed.Remove(zdo.m_uid); } } private static bool Prefix(TerrainComp __instance) { //IL_006d: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.FixDuplicateCompilers.Value) { return true; } if (fi_instances == null || m_Initialize == null || m_CheckLoad == null || m_Rpc == null) { Plugin.Log.LogError((object)"TerrainComp reflection failed; falling back to vanilla Awake."); return true; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); f_nview.Invoke(__instance) = component; Heightmap val = Heightmap.FindHeightmap(((Component)__instance).transform.position); f_hmap.Invoke(__instance) = val; if ((Object)(object)val == (Object)null) { ZLog.LogWarning((object)"Terrain compiler could not find hmap"); return false; } List<TerrainComp> list = (List<TerrainComp>)fi_instances.GetValue(null); TerrainComp val2 = TerrainComp.FindTerrainCompiler(((Component)__instance).transform.position); ZDO val3 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val3 != null && s_pendingDestroy.Contains(val3.m_uid)) { RemoveDuplicate(component, ((Component)__instance).gameObject); return false; } if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)__instance) { ZNetView val4 = f_nview.Invoke(val2); ZDO val5 = (((Object)(object)val4 != (Object)null && val4.IsValid()) ? val4.GetZDO() : null); long num = Compilers.Richness(val3); long num2 = Compilers.Richness(val5); bool flag = num > num2 || (num == num2 && val3 != null && val5 != null && Compilers.CompareIds(val3, val5) < 0); Plugin.Log.LogWarning((object)string.Format("Duplicate terrain compiler at {0}: new={1} existing={2} -> keeping {3}", ((Component)__instance).transform.position, Compilers.Describe(val3), Compilers.Describe(val5), flag ? "NEW" : "EXISTING")); if (!flag) { if (Plugin.MergeOnDedupe.Value && val3 != null && f_initialized.Invoke(val2)) { m_Initialize.Invoke(__instance, null); m_CheckLoad.Invoke(__instance, null); MergeInto(val2, __instance); } RemoveDuplicate(component, ((Component)__instance).gameObject); return false; } } list.Add(__instance); if ((Object)(object)component != (Object)null) { Action<long, ZPackage> action = (Action<long, ZPackage>)Delegate.CreateDelegate(typeof(Action<long, ZPackage>), __instance, m_Rpc); component.Register<ZPackage>("RPC_ApplyOperation", action); } m_Initialize.Invoke(__instance, null); m_CheckLoad.Invoke(__instance, null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)__instance) { if (Plugin.MergeOnDedupe.Value && f_initialized.Invoke(val2)) { MergeInto(__instance, val2); } RemoveDuplicate(f_nview.Invoke(val2), ((Component)val2).gameObject); } return false; } private static void MergeInto(TerrainComp dest, TerrainComp src) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) try { bool[] array = f_modifiedHeight.Invoke(dest); bool[] array2 = f_modifiedHeight.Invoke(src); float[] array3 = f_levelDelta.Invoke(dest); float[] array4 = f_levelDelta.Invoke(src); float[] array5 = f_smoothDelta.Invoke(dest); float[] array6 = f_smoothDelta.Invoke(src); bool[] array7 = f_modifiedPaint.Invoke(dest); bool[] array8 = f_modifiedPaint.Invoke(src); Color[] array9 = f_paintMask.Invoke(dest); Color[] array10 = f_paintMask.Invoke(src); if (array == null || array2 == null || array7 == null || array8 == null) { return; } int num = 0; int num2 = Math.Min(array.Length, array2.Length); for (int i = 0; i < num2; i++) { if (array2[i] && !array[i]) { array[i] = true; array3[i] = array4[i]; array5[i] = array6[i]; num++; } } int num3 = Math.Min(array7.Length, array8.Length); for (int j = 0; j < num3; j++) { if (array8[j] && !array7[j]) { array7[j] = true; array9[j] = array10[j]; num++; } } if (num <= 0) { return; } f_operations.Invoke(dest) = Math.Max(f_operations.Invoke(dest), f_operations.Invoke(src)) + 1; ZNetView val = f_nview.Invoke(dest); if ((Object)(object)val != (Object)null && val.IsValid()) { if (!val.IsOwner()) { val.ClaimOwnership(); } m_Save?.Invoke(dest, new object[1] { false }); ZDO zDO = val.GetZDO(); if (zDO != null) { zDO.DataRevision += 1000; f_lastDataRevision.Invoke(dest) = zDO.DataRevision; } Heightmap obj = f_hmap.Invoke(dest); if (obj != null) { obj.Poke(1, false); } } Plugin.Log.LogInfo((object)$"Merged {num} vertices from duplicate compiler into survivor {((val == null) ? ((ZDOID?)null) : val.GetZDO()?.m_uid)}"); } catch (Exception arg) { Plugin.Log.LogError((object)$"MergeInto failed: {arg}"); } } private static void RemoveDuplicate(ZNetView view, GameObject go) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)view != (Object)null && view.IsValid()) { s_pendingDestroy.Add(view.GetZDO().m_uid); if (!view.IsOwner()) { view.ClaimOwnership(); } } if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(go); } else { Object.Destroy((Object)(object)go); } } catch (Exception arg) { Plugin.Log.LogError((object)$"RemoveDuplicate failed: {arg}"); } } } [HarmonyPatch(typeof(Heightmap), "GetAndCreateTerrainCompiler")] internal static class Heightmap_GetAndCreateTerrainCompiler_Patch { private static readonly MethodInfo m_CreateObject = AccessTools.Method(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null); private static bool Prefix(Heightmap __instance, ref TerrainComp __result) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_015d: 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) //IL_0172: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.ReuseExistingCompilerZdo.Value) { return true; } Vector3 position = ((Component)__instance).transform.position; TerrainComp val = TerrainComp.FindTerrainCompiler(position); if ((Object)(object)val != (Object)null) { __result = val; return false; } if (ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || m_CreateObject == null) { return true; } Vector2s zone = ZoneSystem.GetZone(position); ZDO val2 = null; long num = -1L; foreach (ZDO item in Compilers.InZone(ZDOMan.instance, zone)) { if (__instance.IsPointInside(item.GetPosition(), 0f)) { long num2 = Compilers.Richness(item); if (num2 > num) { num = num2; val2 = item; } } } if (val2 == null) { return true; } ZNetView val3 = ZNetScene.instance.FindInstance(val2); GameObject val4 = (GameObject)(((Object)(object)val3 != (Object)null) ? ((object)((Component)val3).gameObject) : ((object)(GameObject)m_CreateObject.Invoke(ZNetScene.instance, new object[1] { val2 }))); TerrainComp val5 = (((Object)(object)val4 != (Object)null) ? val4.GetComponent<TerrainComp>() : null); if ((Object)(object)val5 == (Object)null) { return true; } ZNetView component = val4.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && !component.HasOwner()) { component.ClaimOwnership(); } Plugin.Log.LogInfo((object)$"Reused existing terrain compiler ZDO {val2.m_uid} for zone {zone.x},{zone.y} instead of creating a duplicate."); __result = val5; return false; } } [HarmonyPatch(typeof(TerrainComp), "GetNeighbor")] internal static class TerrainComp_GetNeighbor_Patch { private static void Postfix(Vector3 worldPos, float radius, ref TerrainComp __result) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__result == (Object)null) { return; } if (Plugin.SkipUnownedNeighborSpread.Value && !__result.IsOwner()) { __result = null; } else if (Plugin.FixDoubleAppliedBorderStrokes.Value) { Heightmap val = TerrainComp_Awake_Patch.f_hmap.Invoke(__result); if ((Object)(object)val != (Object)null && val.IsPointInside(worldPos, radius + 0.5f)) { __result = null; } } } } internal static class NetworkedTerrainOpCleanup { private static readonly FieldRef<ZNetView, bool> f_ghost = AccessTools.FieldRefAccess<ZNetView, bool>("m_ghost"); internal static void TryCleanup(GameObject go, ZNetView view) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (Plugin.CleanupNetworkedTerrainOps.Value && !TerrainOp.m_forceDisableTerrainOps && !((Object)(object)view == (Object)null) && view.IsValid() && !f_ghost.Invoke(view) && !((Object)(object)ZNetScene.instance == (Object)null)) { ZDO zDO = view.GetZDO(); Plugin.Log.LogWarning((object)$"Terrain op '{((Object)go).name}' carries a ZNetView (zdo {zDO.m_uid}, persistent={zDO.Persistent}); destroying it through ZNetScene so no dead ZDO is left behind."); ZNetScene.instance.Destroy(go); } } } [HarmonyPatch(typeof(TerrainOp), "Awake")] internal static class TerrainOp_Awake_Patch { private static void Postfix(TerrainOp __instance) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null) { NetworkedTerrainOpCleanup.TryCleanup(((Component)__instance).gameObject, component); } } } [HarmonyPatch(typeof(ZNetView), "Awake")] internal static class ZNetView_Awake_Patch { private static void Postfix(ZNetView __instance) { if ((Object)(object)((Component)__instance).GetComponent<TerrainOp>() != (Object)null) { NetworkedTerrainOpCleanup.TryCleanup(((Component)__instance).gameObject, __instance); } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] internal static class Player_UpdateTeleport_Patch { private static readonly FieldRef<Player, bool> f_teleporting = AccessTools.FieldRefAccess<Player, bool>("m_teleporting"); private static readonly FieldRef<Player, float> f_timer = AccessTools.FieldRefAccess<Player, float>("m_teleportTimer"); private static readonly FieldRef<Player, Vector3> f_target = AccessTools.FieldRefAccess<Player, Vector3>("m_teleportTargetPos"); private static float s_lastLog; private static void Postfix(Player __instance) { //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_0095: 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_00a9: 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_0128: 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) if (!Plugin.TeleportHardTimeout.Value || !f_teleporting.Invoke(__instance)) { return; } float num = f_timer.Invoke(__instance); if (num < Plugin.TeleportHardTimeoutSeconds.Value) { if (num > 8f && Time.time - s_lastLog > 2f) { s_lastLog = Time.time; Plugin.Log.LogWarning((object)$"Teleport waiting {num:0}s: destination area not ready (ZNetScene.IsAreaReady=false). Will force after {Plugin.TeleportHardTimeoutSeconds.Value:0}s."); } return; } Vector3 val = f_target.Invoke(__instance); Vector3 val2 = val; float num2 = default(float); if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(val, ref num2)) { val2.y = num2 + 0.3f; } else if ((Object)(object)ZoneSystem.instance != (Object)null) { val2.y = ZoneSystem.instance.GetSolidHeight(val) + 0.5f; } ((Component)__instance).transform.position = val2; f_timer.Invoke(__instance) = 0f; f_teleporting.Invoke(__instance) = false; ((Character)__instance).ResetCloth(); Plugin.Log.LogWarning((object)$"Teleport forced to complete after {num:0}s at {val2}."); } } [HarmonyPatch(typeof(ZDOMan), "SendZDOs")] internal static class ZDOMan_SendZDOs_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { int budget = (Plugin.PatchNetworkBudget.Value ? Math.Max(10240, Plugin.ZdoInFlightBudgetBytes.Value) : 10240); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num && num == 10240) { instruction.operand = budget; replaced++; } yield return instruction; } Plugin.Log.LogInfo((object)$"ZDOMan.SendZDOs budget constants replaced: {replaced} -> {budget} bytes"); } } [HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")] internal static class ZSteamSocket_RegisterGlobalCallbacks_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { int rate = (Plugin.PatchNetworkBudget.Value ? Math.Max(153600, Plugin.SteamSendRateBytesPerSec.Value) : 153600); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num && num == 153600) { instruction.operand = rate; replaced++; } yield return instruction; } Plugin.Log.LogInfo((object)$"ZSteamSocket send-rate constants replaced: {replaced} -> {rate} B/s"); } } [HarmonyPatch(typeof(WearNTear), "UpdateWear")] internal static class WearNTear_UpdateWear_Patch { private static readonly ConditionalWeakTable<WearNTear, StrongBox<float>> s_last = new ConditionalWeakTable<WearNTear, StrongBox<float>>(); public static void SetSnowThrottled(ZDO zdo, int hash, float value, WearNTear self) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return; } if (!Plugin.ThrottleSnowWrites.Value) { zdo.Set(hash, value); return; } StrongBox<float> value2 = s_last.GetValue(self, (WearNTear _) => new StrongBox<float>(float.NaN)); if (float.IsNaN(value2.Value)) { value2.Value = zdo.GetFloat(hash, 0f); } float value3 = value2.Value; if (value >= 1f || value <= 0f || Mathf.Abs(value - value3) >= Plugin.SnowWriteStep.Value) { zdo.Set(hash, value); value2.Value = value; } else { ZDOExtraData.Set(zdo.m_uid, hash, value); } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); FieldInfo objB = AccessTools.Field(typeof(ZDOVars), "s_snow"); MethodInfo objB2 = AccessTools.Method(typeof(ZDO), "Set", new Type[2] { typeof(int), typeof(float) }, (Type[])null); MethodInfo methodInfo = AccessTools.Method(typeof(WearNTear_UpdateWear_Patch), "SetSnowThrottled", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { if (list[i].opcode != OpCodes.Ldsfld || !object.Equals(list[i].operand, objB)) { continue; } for (int j = i + 1; j < Math.Min(list.Count, i + 6); j++) { if ((list[j].opcode == OpCodes.Callvirt || list[j].opcode == OpCodes.Call) && object.Equals(list[j].operand, objB2)) { list[j] = CodeInstructionExtensions.WithBlocks(CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Call, (object)methodInfo), (IEnumerable<Label>)list[j].labels), (IEnumerable<ExceptionBlock>)list[j].blocks); list.Insert(j, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); num++; i = j + 1; break; } } } Plugin.Log.LogInfo((object)$"WearNTear.UpdateWear snow writes throttled at {num} call site(s)"); return list; } } internal static class SaveHealer { public sealed class Result { public int ZonesScanned; public int ZonesWithDuplicates; public int Removed; public int MergedVertices; public int SeamFixes; public int BlocksWritten; public readonly List<string> Lines = new List<string>(); public string Summary(string what) { return $"{what}: zones={ZonesScanned} duplicateZones={ZonesWithDuplicates} removed={Removed} mergedVertices={MergedVertices} seamFixes={SeamFixes} blocksWritten={BlocksWritten}"; } } private sealed class Entry { public ZDO Zdo; public TcBlock Block; public bool Dirty; } public static Result DedupeAll(ZDOMan man, bool merge) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) Dictionary<long, List<ZDO>> dictionary = Compilers.AllByZone(man); Result result = new Result { ZonesScanned = dictionary.Count }; foreach (KeyValuePair<long, List<ZDO>> item in dictionary) { if (item.Value.Count > 1) { DedupeGroup(Compilers.ZoneFromKey(item.Key), item.Value, merge, result); } } return result; } public static Result DedupeZone(ZDOMan man, Vector2s zone, bool merge) { //IL_0001: 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) List<ZDO> list = Compilers.InZone(man, zone); Result result = new Result { ZonesScanned = 1 }; if (list.Count > 1) { DedupeGroup(zone, list, merge, result); } return result; } private static void DedupeGroup(Vector2s zone, List<ZDO> list, bool merge, Result r) { //IL_00e0: 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) r.ZonesWithDuplicates++; List<ZDO> list2 = Compilers.Rank(list); ZDO zdo = list2[0]; TcBlock tcBlock = null; int num = 0; if (merge) { tcBlock = Compilers.Load(zdo); for (int i = 1; i < list2.Count; i++) { TcBlock tcBlock2 = Compilers.Load(list2[i]); if (tcBlock2 != null) { if (tcBlock == null) { tcBlock = tcBlock2; num += tcBlock2.ModifiedCount; } else { num += tcBlock.MergeFrom(tcBlock2); } } } } for (int j = 1; j < list2.Count; j++) { Compilers.Remove(list2[j]); r.Removed++; } if (merge && tcBlock != null && num > 0) { Compilers.Store(zdo, tcBlock); r.BlocksWritten++; r.MergedVertices += num; } r.Lines.Add($"zone {zone.x},{zone.y}: {list.Count} compilers -> kept {Compilers.Describe(zdo)}, removed {list2.Count - 1}, merged {num} vertices"); } public static Result ReconcileSeams(ZDOMan man, Func<Vector2s, bool> zoneFilter, bool heights, bool paint) { //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) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_0129: 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_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) Dictionary<long, List<ZDO>> dictionary = Compilers.AllByZone(man); Dictionary<long, Entry> dictionary2 = new Dictionary<long, Entry>(); foreach (KeyValuePair<long, List<ZDO>> item in dictionary) { Vector2s arg = Compilers.ZoneFromKey(item.Key); if (zoneFilter == null || zoneFilter(arg)) { ZDO zdo = Compilers.Rank(item.Value)[0]; TcBlock tcBlock = Compilers.Load(zdo); if (tcBlock != null && tcBlock.ModH.Length == tcBlock.ModP.Length) { dictionary2[item.Key] = new Entry { Zdo = zdo, Block = tcBlock }; } } } Result result = new Result { ZonesScanned = dictionary2.Count }; Dictionary<(int, int, int), List<(Entry, int)>> dictionary3 = new Dictionary<(int, int, int), List<(Entry, int)>>(); foreach (KeyValuePair<long, Entry> item2 in dictionary2) { Vector2s val = Compilers.ZoneFromKey(item2.Key); Entry value = item2.Value; int pitch = value.Block.Pitch; int num = pitch - 1; for (int i = 0; i <= num; i++) { for (int j = 0; j <= num; j++) { if (j == 0 || j == num || i == 0 || i == num) { (int, int, int) key = (pitch, val.x * num + j, val.y * num + i); if (!dictionary3.TryGetValue(key, out var value2)) { value2 = (dictionary3[key] = new List<(Entry, int)>(4)); } value2.Add((value, i * pitch + j)); } } } } foreach (List<(Entry, int)> value3 in dictionary3.Values) { if (value3.Count > 1) { ReconcileGroup(value3, heights, paint, result); } } foreach (KeyValuePair<long, Entry> item3 in dictionary2) { if (item3.Value.Dirty) { Compilers.Store(item3.Value.Zdo, item3.Value.Block); result.BlocksWritten++; Vector2s val2 = Compilers.ZoneFromKey(item3.Key); result.Lines.Add($"zone {val2.x},{val2.y}: border vertices updated"); } } return result; } private static void ReconcileGroup(List<(Entry e, int idx)> g, bool heights, bool paint, Result r) { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: 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_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) if (heights) { int num = 0; float num2 = 0f; float num3 = 0f; foreach (var (entry, num4) in g) { if (entry.Block.ModH[num4]) { num++; num2 += entry.Block.Lvl[num4]; num3 += entry.Block.Smo[num4]; } } if (num > 0) { num2 /= (float)num; num3 /= (float)num; bool flag = false; foreach (var (entry2, num5) in g) { if (!entry2.Block.ModH[num5] || !Near(entry2.Block.Lvl[num5], num2) || !Near(entry2.Block.Smo[num5], num3)) { entry2.Block.ModH[num5] = true; entry2.Block.Lvl[num5] = num2; entry2.Block.Smo[num5] = num3; entry2.Dirty = true; flag = true; } } if (flag) { r.SeamFixes++; } } } if (!paint) { return; } int num6 = 0; float num7 = 0f; float num8 = 0f; float num9 = 0f; float num10 = 0f; foreach (var (entry3, num11) in g) { if (entry3.Block.ModP[num11]) { num6++; Color val = entry3.Block.Paint[num11]; num7 += val.r; num8 += val.g; num9 += val.b; num10 += val.a; } } if (num6 <= 0) { return; } Color val2 = default(Color); ((Color)(ref val2))..ctor(num7 / (float)num6, num8 / (float)num6, num9 / (float)num6, num10 / (float)num6); bool flag2 = false; foreach (var item3 in g) { Entry item = item3.e; int item2 = item3.idx; Color val3 = item.Block.Paint[item2]; if (!item.Block.ModP[item2] || !Near(val3.r, val2.r) || !Near(val3.g, val2.g) || !Near(val3.b, val2.b) || !Near(val3.a, val2.a)) { item.Block.ModP[item2] = true; item.Block.Paint[item2] = val2; item.Dirty = true; flag2 = true; } } if (flag2) { r.SeamFixes++; } } private static bool Near(float x, float y) { return Mathf.Abs(x - y) < 0.0005f; } public static int ResetZone(ZDOMan man, Vector2s zone) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (ZDO item in Compilers.InZone(man, zone)) { TcBlock tcBlock = Compilers.Load(item); Compilers.Store(item, TcBlock.Empty((tcBlock != null) ? tcBlock.ModH.Length : 4225)); num++; } return num; } public static List<string> Report(ZDOMan man, int maxLines = 40) { //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_0095: 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) Dictionary<long, List<ZDO>> dictionary = Compilers.AllByZone(man); List<string> list = new List<string>(); int num = 0; int num2 = 0; int num3 = 0; foreach (KeyValuePair<long, List<ZDO>> item in dictionary) { num += item.Value.Count; if (item.Value.Count > 1) { num2++; num3 += item.Value.Count - 1; if (list.Count < maxLines) { Vector2s val = Compilers.ZoneFromKey(item.Key); List<ZDO> list2 = Compilers.Rank(item.Value); list.Add($"zone {val.x},{val.y}: {item.Value.Count} compilers, richest {Compilers.Describe(list2[0])}"); } } } list.Insert(0, $"terrain compilers: {num} in {dictionary.Count} zones; zones with duplicates: {num2} ({num3} extra compilers)"); return list; } } internal sealed class TcBlock { public const int DefaultVertices = 4225; public int Version = 1; public int Ops; public Vector3 LastOp; public float LastRadius; public bool[] ModH; public float[] Lvl; public float[] Smo; public bool[] ModP; public Color[] Paint; public int Pitch => (int)Math.Round(Math.Sqrt(ModH.Length)); public int ModifiedCount { get { int num = 0; for (int i = 0; i < ModH.Length; i++) { if (ModH[i]) { num++; } } for (int j = 0; j < ModP.Length; j++) { if (ModP[j]) { num++; } } return num; } } public static TcBlock Empty(int n = 4225) { return new TcBlock { ModH = new bool[n], Lvl = new float[n], Smo = new float[n], ModP = new bool[n], Paint = (Color[])(object)new Color[n] }; } public static TcBlock Parse(byte[] raw) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) if (raw == null || raw.Length == 0) { return null; } ZPackage val = new ZPackage(Utils.Decompress(raw)); TcBlock tcBlock = new TcBlock(); tcBlock.Version = val.ReadInt(); tcBlock.Ops = val.ReadInt(); tcBlock.LastOp = val.ReadVector3(); tcBlock.LastRadius = val.ReadSingle(); int num = val.ReadInt(); if (num < 0 || num > 1048576) { throw new InvalidDataException("bad height count " + num); } tcBlock.ModH = new bool[num]; tcBlock.Lvl = new float[num]; tcBlock.Smo = new float[num]; for (int i = 0; i < num; i++) { tcBlock.ModH[i] = val.ReadBool(); if (tcBlock.ModH[i]) { tcBlock.Lvl[i] = val.ReadSingle(); tcBlock.Smo[i] = val.ReadSingle(); } } int num2 = val.ReadInt(); if (num2 < 0 || num2 > 1048576) { throw new InvalidDataException("bad paint count " + num2); } tcBlock.ModP = new bool[num2]; tcBlock.Paint = (Color[])(object)new Color[num2]; Color val2 = default(Color); for (int j = 0; j < num2; j++) { tcBlock.ModP[j] = val.ReadBool(); if (tcBlock.ModP[j]) { val2.r = val.ReadSingle(); val2.g = val.ReadSingle(); val2.b = val.ReadSingle(); val2.a = val.ReadSingle(); tcBlock.Paint[j] = val2; } } int num3 = (int)Math.Round(Math.Sqrt(num)); int num4 = num3 - 1; if (num3 * num3 == num && num4 > 0 && num2 == num4 * num4) { bool[] modP = tcBlock.ModP; Color[] paint = tcBlock.Paint; tcBlock.ModP = new bool[num]; tcBlock.Paint = (Color[])(object)new Color[num]; for (int k = 0; k < num; k++) { int num5 = k / num3; int num6 = (k + 1) / num3; int num7 = k - num5; if (num5 == num4) { num7 -= num4; } if (k > 0 && (k - num5) % num4 == 0 && (k + 1 - num6) % num4 == 0) { num7--; } if (num7 >= 0 && num7 < modP.Length) { tcBlock.ModP[k] = modP[num7]; tcBlock.Paint[k] = paint[num7]; } } } return tcBlock; } public byte[] Build() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(Version); val.Write(Ops); val.Write(LastOp); val.Write(LastRadius); val.Write(ModH.Length); for (int i = 0; i < ModH.Length; i++) { val.Write(ModH[i]); if (ModH[i]) { val.Write(Lvl[i]); val.Write(Smo[i]); } } val.Write(ModP.Length); for (int j = 0; j < ModP.Length; j++) { val.Write(ModP[j]); if (ModP[j]) { val.Write(Paint[j].r); val.Write(Paint[j].g); val.Write(Paint[j].b); val.Write(Paint[j].a); } } return Utils.Compress(val.GetArray()); } public int MergeFrom(TcBlock other) { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (other == null) { return 0; } if (other.ModH.Length != ModH.Length || other.ModP.Length != ModP.Length) { Plugin.Log.LogWarning((object)$"TCData layout mismatch ({ModH.Length}/{ModP.Length} vs {other.ModH.Length}/{other.ModP.Length}); not merging"); return 0; } int num = 0; int num2 = ModH.Length; for (int i = 0; i < num2; i++) { if (other.ModH[i] && !ModH[i]) { ModH[i] = true; Lvl[i] = other.Lvl[i]; Smo[i] = other.Smo[i]; num++; } } int num3 = ModP.Length; for (int j = 0; j < num3; j++) { if (other.ModP[j] && !ModP[j]) { ModP[j] = true; Paint[j] = other.Paint[j]; num++; } } if (num > 0) { Ops = Math.Max(Ops, other.Ops) + 1; } return num; } } internal static class Compilers { public static readonly int PrefabHash = StringExtensionMethods.GetStableHashCode("_TerrainCompiler"); private static readonly FieldRef<ZDOMan, Dictionary<ZDOID, ZDO>> f_objectsByID = AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID"); private static readonly FieldRef<ZDOMan, List<ZDO>[]> f_objectsBySector = AccessTools.FieldRefAccess<ZDOMan, List<ZDO>[]>("m_objectsBySector"); public const uint RevisionJump = 1000u; public static readonly HashSet<ZDOID> SendSuppressed = new HashSet<ZDOID>(); public static bool IsServer { get { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } public static long ZoneKey(Vector2s z) { //IL_0000: 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) return ((long)z.x << 32) | (uint)z.y; } public static Vector2s ZoneFromKey(long key) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return new Vector2s((int)(key >> 32), (int)(key & 0xFFFFFFFFu)); } public static Dictionary<long, List<ZDO>> AllByZone(ZDOMan man) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) Dictionary<long, List<ZDO>> dictionary = new Dictionary<long, List<ZDO>>(); Dictionary<ZDOID, ZDO> dictionary2 = f_objectsByID.Invoke(man); if (dictionary2 == null) { return dictionary; } foreach (ZDO value2 in dictionary2.Values) { if (value2.GetPrefab() == PrefabHash) { long key = ZoneKey(value2.GetSector()); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<ZDO>(1)); } value.Add(value2); } } return dictionary; } public static List<ZDO> InZone(ZDOMan man, Vector2s zone) { //IL_0019: 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_001f: 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_0030: Unknown result type (might be due to invalid IL or missing references) List<ZDO> list = new List<ZDO>(1); List<ZDO>[] array = f_objectsBySector.Invoke(man); if (array == null) { return list; } SectorIndex val = ZoneSystem.SectorToIndex(zone); if (val.Sector >= array.Length) { return list; } List<ZDO> list2 = array[val.Sector]; if (list2 == null) { return list; } foreach (ZDO item in list2) { if (item.GetPrefab() == PrefabHash) { list.Add(item); } } return list; } public static long Richness(ZDO zdo) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return -1L; } byte[] byteArray = zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null); if (byteArray == null || byteArray.Length == 0) { return 0L; } int val = 0; try { using GZipStream gZipStream = new GZipStream(new MemoryStream(byteArray), CompressionMode.Decompress); byte[] array = new byte[8]; int i; int num; for (i = 0; i < 8; i += num) { num = gZipStream.Read(array, i, 8 - i); if (num <= 0) { break; } } if (i == 8) { val = BitConverter.ToInt32(array, 4); } } catch (Exception ex) { Plugin.Log.LogWarning((object)$"TCData header read failed for {zdo.m_uid}: {ex.Message}"); } return ((long)Math.Max(val, 0) << 32) | (uint)byteArray.Length; } public static int CompareIds(ZDO a, ZDO b) { int num = ((ZDOID)(ref a.m_uid)).UserID.CompareTo(((ZDOID)(ref b.m_uid)).UserID); if (num == 0) { return ((ZDOID)(ref a.m_uid)).ID.CompareTo(((ZDOID)(ref b.m_uid)).ID); } return num; } public static List<ZDO> Rank(List<ZDO> list) { List<ZDO> list2 = new List<ZDO>(list); list2.Sort(delegate(ZDO a, ZDO b) { long num = Richness(a); long num2 = Richness(b); return (num != num2) ? num2.CompareTo(num) : CompareIds(a, b); }); return list2; } public static TcBlock Load(ZDO zdo) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) try { return TcBlock.Parse(zdo.GetByteArray(ZDOVars.s_TCData, (byte[])null)); } catch (Exception ex) { Plugin.Log.LogWarning((object)$"TCData parse failed for {zdo.m_uid}: {ex.Message}"); return null; } } public static bool OwnedByConnectedPeer(ZDO zdo) { long owner = zdo.GetOwner(); if (owner != 0L && owner != ZDOMan.GetSessionID() && (Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.GetPeer(owner) != null; } return false; } public static void EnsureOwned(ZDO zdo) { if (!zdo.IsOwner()) { zdo.SetOwner(ZDOMan.GetSessionID()); } } public static void Store(ZDO zdo, TcBlock block) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) bool flag = OwnedByConnectedPeer(zdo); if (!IsServer) { EnsureOwned(zdo); } else if (!flag) { EnsureOwned(zdo); } zdo.Set(ZDOVars.s_TCData, block.Build()); zdo.DataRevision += 1000; if (flag) { Plugin.Log.LogInfo((object)$"{zdo.m_uid}: terrain block written while owned by connected peer {zdo.GetOwner()}; one in-flight stroke may be discarded."); } } public static void Remove(ZDO zdo) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!zdo.IsOwner()) { if (IsServer) { zdo.SetOwnerInternal(ZDOMan.GetSessionID()); } else { zdo.SetOwner(ZDOMan.GetSessionID()); } } if (IsServer) { SendSuppressed.Add(zdo.m_uid); } ZDOMan.instance.DestroyZDO(zdo); } public static void ResetSession() { SendSuppressed.Clear(); } public static bool IsProtected(ZDOMan man, ZDO zdo) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || zdo.GetPrefab() != PrefabHash) { return false; } long num = Richness(zdo); if (num <= 0) { return false; } foreach (ZDO item in InZone(man, zdo.GetSector())) { if (item != zdo && !(item.m_uid == zdo.m_uid) && Richness(item) >= num) { return false; } } return true; } public static List<ZDO>[] SectorLists(ZDOMan man) { return f_objectsBySector.Invoke(man); } public static string Describe(ZDO zdo) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return "(none)"; } long num = Richness(zdo); return $"{zdo.m_uid} ops={num >> 32} bytes={(uint)num} owner={zdo.GetOwner()}"; } } }