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 ServerSideMap PoV v1.0.2
plugins/ServerSideMap_PoV.dll
Decompiled 3 minutes agousing System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Splatform; using TMPro; using UnityEngine; [assembly: AssemblyTitle("ServerSideMap")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ServerSideMap")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("38A5EB8E-7BF4-43B7-9806-9C0DD82AB865")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.0.0")] namespace ServerSideMap; public static class CommandsPinUpsync { [HarmonyPatch(typeof(Chat), "InputText")] private class ChatPatchInputText { private static bool Prefix(Chat __instance, TMP_InputField ___m_input) { string text = ___m_input.text; if (text.ToLower().Equals("/convertpins ignorelocaldupes")) { UtilityPin.UploadAllPins(removeDupes: true); return false; } if (text.ToLower().Equals("/convertpins")) { UtilityPin.UploadAllPins(); return false; } if (text.ToLower().Equals("/deletealllocalpins")) { UtilityPin.DeleteLocalPins(); return false; } if (text.ToLower().Equals("/deleteallsharedpins confirm")) { UtilityPin.DeleteAllSharedPins(); return false; } if (text.ToLower().Equals("/deleteallsharedpins")) { Utility.Message("This deletes EVERY shared pin for everyone. Type /deleteallsharedpins confirm"); return false; } if (text.ToLower().Equals("/downloadpins")) { UtilityPin.DownloadPins(); return false; } return true; } } } public static class ExplorationDatabase { [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] private class MinimapPatchExploreInterval { private static void Postfix(Minimap __instance) { if (_dirty) { object value = Traverse.Create((object)__instance).Field("m_fogTexture").GetValue(); Texture2D val = (Texture2D)((value is Texture2D) ? value : null); val.Apply(); _dirty = false; } } } private static bool _dirty; public static bool[] Explored; public const int MapSize = 2048; public const int MapSizeSquared = 4194304; private static List<PinData> ServerPins = new List<PinData>(); public static List<PinData> ClientPins = new List<PinData>(); public static ZPackage Default() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(4); val.Write(2048); for (int i = 0; i < 4194304; i++) { val.Write(false); } val.Write(0); val.SetPos(0); return val; } public static ZPackage PackPins(List<PinData> pins) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0034: 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_004a: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(pins.Count); foreach (PinData pin in pins) { val.Write(pin.Name); val.Write(pin.Pos); val.Write((int)pin.Type); val.Write(pin.Checked); val.Write(pin.Icon ?? ""); } val.SetPos(0); Utility.Log("Packing pins: " + pins.Count); return val; } public static List<PinData> UnpackPins(ZPackage z) { //IL_002b: 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) //IL_003d: Unknown result type (might be due to invalid IL or missing references) List<PinData> list = new List<PinData>(); int num = z.ReadInt(); for (int i = 0; i < num; i++) { PinData pinData = new PinData(); pinData.Name = z.ReadString(); pinData.Pos = z.ReadVector3(); pinData.Type = (PinType)z.ReadInt(); pinData.Checked = z.ReadBool(); pinData.Icon = z.ReadString(); PinData item = pinData; list.Add(item); } return list; } public static ZPackage PackPin(PinData pin, bool skipSetPos = false) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0014: 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_002a: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(pin.Name); val.Write(pin.Pos); val.Write((int)pin.Type); val.Write(pin.Checked); val.Write(pin.Icon ?? ""); if (!skipSetPos) { val.SetPos(0); } return val; } public static PinData UnpackPin(ZPackage z) { //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_0025: Unknown result type (might be due to invalid IL or missing references) PinData pinData = new PinData(); pinData.Name = z.ReadString(); pinData.Pos = z.ReadVector3(); pinData.Type = (PinType)z.ReadInt(); pinData.Checked = z.ReadBool(); pinData.Icon = z.ReadString(); return pinData; } public static List<PinData> GetPins() { return ServerPins; } public static void AddPin(PinData pin) { ServerPins.Add(pin); } public static void RemovePinEqual(PinData needle) { foreach (PinData item in ServerPins.ToList()) { if (UtilityPin.ArePinsEqual(item, needle)) { ServerPins.Remove(item); } } } public static void SetPinState(PinData needle, bool state) { foreach (PinData item in ServerPins.ToList()) { if (UtilityPin.ArePinsEqual(item, needle)) { item.Checked = state; } } } public static void SetMapData(ZPackage mapData) { //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_0077: Unknown result type (might be due to invalid IL or missing references) ServerPins.Clear(); int num = mapData.ReadInt(); int num2 = mapData.ReadInt(); bool[] array = new bool[num2 * num2]; for (int i = 0; i < num2 * num2; i++) { array[i] = mapData.ReadBool(); } int num3 = mapData.ReadInt(); for (int j = 0; j < num3; j++) { PinData pinData = new PinData(); pinData.Name = mapData.ReadString(); pinData.Pos = mapData.ReadVector3(); pinData.Type = (PinType)mapData.ReadInt(); pinData.Checked = mapData.ReadBool(); PinData pinData2 = pinData; if (num >= 4) { pinData2.Icon = mapData.ReadString(); } ServerPins.Add(pinData2); } Explored = array; } public static ZPackage GetMapData() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected I4, but got Unknown ZPackage val = new ZPackage(); val.Write(4); val.Write(2048); bool[] explored = Explored; foreach (bool flag in explored) { val.Write(flag); } val.Write(ServerPins.Count); Utility.Log("Map saved. Pin Count: " + ServerPins.Count); foreach (PinData serverPin in ServerPins) { val.Write(serverPin.Name); val.Write(serverPin.Pos); val.Write((int)serverPin.Type); val.Write(serverPin.Checked); val.Write(serverPin.Icon ?? ""); } return val; } public static void SetExplored(int x, int y) { Explored[y * 2048 + x] = true; } public static bool GetExplored(int x, int y) { return Explored[y * 2048 + x]; } public static bool GetExplored(int idx) { return Explored[idx]; } public static bool[] GetExplorationArray() { return Explored; } public static void MergeExplorationArray(bool[] arr, int startIndex, int size) { for (int i = 0; i < size; i++) { Explored[startIndex + i] = arr[i] || Explored[startIndex + i]; } } public static ZPackage PackBoolArray(bool[] arr, int chunkId, int startIndex, int size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(chunkId); byte b = 0; int num = 0; for (int i = startIndex; i < startIndex + size; i++) { if (arr[i]) { byte b2 = (byte)(1 << num); b |= b2; } num++; if (num >= 8) { val.Write(b); b = 0; num = 0; } } if (num > 0) { val.Write(b); } return val; } public static bool[] UnpackBoolArray(ZPackage z, int length) { bool[] array = new bool[length]; for (int i = 0; i < length; i += 8) { byte b = z.ReadByte(); array[i] = (b & 1) != 0; array[i + 1] = (b & 2) != 0; array[i + 2] = (b & 4) != 0; array[i + 3] = (b & 8) != 0; array[i + 4] = (b & 0x10) != 0; array[i + 5] = (b & 0x20) != 0; array[i + 6] = (b & 0x40) != 0; array[i + 7] = (b & 0x80) != 0; } return array; } public static void OnReceiveMapData(ZRpc client, ZPackage mapData) { mapData.SetPos(0); int x = mapData.ReadInt(); int y = mapData.ReadInt(); object value = Traverse.Create(typeof(Minimap)).Field("s_instance").GetValue(); Minimap instance = (Minimap)((value is Minimap) ? value : null); _dirty = _Minimap.Explore(instance, x, y) || _dirty; } } public class PinData { public string Name; public PinType Type; public Vector3 Pos; public bool Checked; public string Icon = ""; } public static class ExplorationMapSync { [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] private class MinimapPatchExplore { private static void Postfix(int x, int y, bool __result) { if (__result && !_blockExplore && Store.IsSharingMap()) { if (_ZNet.IsServer(_ZNet._instance)) { OnClientExplore(null, x, y); return; } object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet instance = (ZNet)((value is ZNet) ? value : null); ZRpc serverRPC = _ZNet.GetServerRPC(instance); serverRPC.Invoke("SSMPoV_OnClientExplore", new object[2] { x, y }); } } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] private class MinimapPatchSetMapData { private static void Prefix() { _blockExplore = true; } private static void Postfix(Minimap __instance) { _blockExplore = false; } } private static bool _blockExplore = false; public static void OnClientExplore(ZRpc client, int x, int y) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown if (!Store.IsSharingMap()) { return; } ExplorationDatabase.SetExplored(x, y); object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet val = (ZNet)((value is ZNet) ? value : null); List<ZNetPeer> list = Traverse.Create((object)val).Field("m_peers").GetValue() as List<ZNetPeer>; foreach (ZNetPeer item in list) { if (item.IsReady() && item.m_rpc != client) { ZPackage val2 = new ZPackage(); val2.Write(x); val2.Write(y); item.m_rpc.Invoke("SSMPoV_OnReceiveMapData", new object[1] { val2 }); } } ZPackage val3 = new ZPackage(); val3.Write(x); val3.Write(y); ExplorationDatabase.OnReceiveMapData(null, val3); } } public static class Hotkeys { [HarmonyPatch(typeof(Player), "Update")] private class PlayerInputPatch { private static void Postfix(Player __instance) { //IL_000a: 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) if (Store.HasKeyConvertAll() && Input.GetKeyDown(Store.GetKeyConvertAll())) { Utility.Log("Hotkey: GetKeyConvertAll"); UtilityPin.UploadAllPins(); } if (Store.HasKeyConvertIgnoreDupes() && Input.GetKeyDown(Store.GetKeyConvertIgnoreDupes())) { Utility.Log("Hotkey: GetKeyConvertIgnoreDupes"); UtilityPin.UploadAllPins(removeDupes: true); } } } } public class InitialMapSync { [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class ZnetPatchRPC_PeerInfo { private static void Postfix(ZRpc rpc, ZNet __instance) { if (Store.IsSharingMap() && __instance.IsServer()) { SendChunkToClient(rpc, 0); } } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] private class MinimapPatchSetMapData { private static void Postfix(Minimap __instance) { if (Store.IsSharingMap() && _ZNet.IsServer(_ZNet._instance)) { SendChunkToClient(null, 0); } } } private static int CHUNKS = 64; public static void OnReceiveMapDataInitial(ZRpc client, ZPackage mapData) { if (!Store.IsSharingMap()) { return; } mapData.SetPos(0); int num = mapData.ReadInt(); bool[] array = ExplorationDatabase.UnpackBoolArray(mapData, 4194304 / CHUNKS); int num2 = num * (4194304 / CHUNKS); for (int i = 0; i < array.Length; i++) { if (array[i]) { _Minimap.Explore(_Minimap._instance, (num2 + i) % 2048, (num2 + i) / 2048); } } object value = Traverse.Create((object)_Minimap._instance).Field("m_fogTexture").GetValue(); Texture2D val = (Texture2D)((value is Texture2D) ? value : null); val.Apply(); ((MonoBehaviour)_ZNet._instance).StartCoroutine(SendChunkToServer(client, num)); } public static void OnClientInitialData(ZRpc client, ZPackage mapData) { if (Store.IsSharingMap()) { mapData.SetPos(0); int num = mapData.ReadInt(); int startIndex = num * (4194304 / CHUNKS); int num2 = 4194304 / CHUNKS; ExplorationDatabase.MergeExplorationArray(ExplorationDatabase.UnpackBoolArray(mapData, num2), startIndex, num2); SendChunkToClient(client, num + 1); } } private static void SendChunkToClient(ZRpc client, int chunk) { if (chunk < CHUNKS) { int size = 4194304 / CHUNKS; int startIndex = chunk * (4194304 / CHUNKS); ZPackage val = ExplorationDatabase.PackBoolArray(ExplorationDatabase.GetExplorationArray(), chunk, startIndex, size); if (client == null) { OnReceiveMapDataInitial(null, val); return; } client.Invoke("SSMPoV_OnReceiveMapDataInitial", new object[1] { val }); } } private static IEnumerator SendChunkToServer(ZRpc client, int chunk) { if (chunk >= CHUNKS) { yield break; } int size = 4194304 / CHUNKS; int startIndex = chunk * (4194304 / CHUNKS); BitArray explored = Traverse.Create((object)_Minimap._instance).Field("m_explored").GetValue() as BitArray; bool[] legacy_bool_array = new bool[explored.Length]; explored.CopyTo(legacy_bool_array, 0); ZPackage z = ExplorationDatabase.PackBoolArray(legacy_bool_array, chunk, startIndex, size); if (client == null) { OnClientInitialData(null, z); yield break; } yield return (object)new WaitUntil((Func<bool>)(() => _ZNet.GetServerRPC(_ZNet._instance) != null)); ZRpc server = _ZNet.GetServerRPC(_ZNet._instance); server.Invoke("SSMPoV_OnClientInitialData", new object[1] { z }); } } public class InitialPinSync { [HarmonyPatch(typeof(Minimap), "ClearPins")] private class MinimapPatchClearPins { private static void Postfix(Minimap __instance) { ClientAppendPins(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ZNetPatchShutdown { private static void Postfix(ZNet __instance) { ExplorationDatabase.ClientPins.Clear(); } } [HarmonyPatch(typeof(Minimap), "SetMapData", new Type[] { typeof(byte[]) })] private class MinimapPatchSetMapData { private static void Postfix(Minimap __instance) { if (_ZNet.IsServer(_ZNet._instance)) { SendPinsToClient(null); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class ZnetPatchRPC_PeerInfo { private static void Postfix(ZRpc rpc, ZNet __instance) { if (__instance.IsServer()) { SendPinsToClient(rpc); } } } public static void OnReceiveInitialDataPin(ZRpc client, ZPackage pinData) { Store.ServerPinShare = true; if (Store.IsSharingPin()) { List<PinData> list = ExplorationDatabase.UnpackPins(pinData); Utility.Log("Client received initial pin data by server. Pins: " + list.Count); ExplorationDatabase.ClientPins = list; ClientAppendPins(); } } private static void ClientAppendPins() { if (!Store.IsSharingPin()) { return; } Utility.Log("ClientAppendPins " + ExplorationDatabase.ClientPins.Count); foreach (PinData clientPin in ExplorationDatabase.ClientPins) { PinData mapPin = UtilityPin.GetMapPin(clientPin); if (mapPin != null) { _Minimap.RemovePin(_Minimap._instance, mapPin); } UtilityPin.AddSharedMapPin(clientPin); } } public static void OnClientInitialDataPin(ZRpc client, ZPackage pinData) { Utility.Log("Server received initial pin data by client"); } private static void SendPinsToClient(ZRpc client) { if (Store.IsSharingPin()) { ZPackage val = ExplorationDatabase.PackPins(ExplorationDatabase.GetPins()); if (client == null) { OnReceiveInitialDataPin(null, val); return; } client.Invoke("SSMPoV_OnReceiveInitialDataPin", new object[1] { val }); } } private static void SendPinsToServer(ZRpc client) { List<PinData> list = Traverse.Create((object)_Minimap._instance).Field("m_pins").GetValue() as List<PinData>; List<PinData> list2 = new List<PinData>(); foreach (PinData item in list) { if (item.m_save) { list2.Add(UtilityPin.ConvertPin(item)); } } ZPackage val = ExplorationDatabase.PackPins(list2); if (client == null) { OnClientInitialDataPin(null, val); return; } object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet instance = (ZNet)((value is ZNet) ? value : null); ZRpc serverRPC = _ZNet.GetServerRPC(instance); serverRPC.Invoke("SSMPoV_OnClientInitialDataPin", new object[1] { val }); } } public class PinSync { [HarmonyPatch(typeof(Minimap), "OnMapLeftClick")] private class MinimapPatchOnMapLeftClick { private static void Postfix(Minimap __instance) { if (LatestClosestPin != null) { PinData clientPin = UtilityPin.GetClientPin(LatestClosestPin); if (clientPin != null) { clientPin.Checked = LatestClosestPin.m_checked; CheckPinOnServer(clientPin, clientPin.Checked); } } } } [HarmonyPatch(typeof(Minimap), "RemovePinUnderPointer")] private class MinimapPatchOnMapRightClick { private static void Postfix(Minimap __instance) { if (LatestClosestPin != null) { PinData clientPin = UtilityPin.GetClientPin(LatestClosestPin); if (clientPin != null) { RemovePinFromServer(clientPin); } } } } [HarmonyPatch(typeof(Minimap), "GetClosestPin", new Type[] { typeof(Vector3), typeof(float), typeof(bool) })] private class MinimapPatchGetClosestPin { private static void Postfix(Minimap __instance, ref PinData __result, Vector3 pos, float radius, bool mustBeVisible = true) { //IL_0032: 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_00a0: 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) if (!Store.IsSharingPin()) { return; } LatestClosestPin = __result; PinData pinData = null; float num = 999999f; foreach (PinData clientPin in ExplorationDatabase.ClientPins) { float num2 = Utils.DistanceXZ(pos, clientPin.Pos); if ((double)num2 < (double)radius && ((double)num2 < (double)num || pinData == null)) { pinData = clientPin; num = num2; } } if (pinData == null) { return; } PinData mapPin = UtilityPin.GetMapPin(pinData); if (__result == null) { __result = mapPin; LatestClosestPin = mapPin; return; } float num3 = Utils.DistanceXZ(pos, __result.m_pos); if (num3 > num) { __result = mapPin; LatestClosestPin = mapPin; } } } [HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })] private class MinimapPatchRemovePin { private static void Postfix(Minimap __instance, PinData pin) { } } [HarmonyPatch(typeof(Minimap), "OnPinTextEntered")] private class MinimapPatchOnPinTextEntered { private static void Prefix(Minimap __instance, out PinData __state, PinData ___m_namePin) { __state = null; if (___m_namePin != null) { __state = ___m_namePin; } } private static void Postfix(Minimap __instance, PinData __state) { if (__state != null) { SendPinToServer(__state); } } } private static PinData CurrentPin = null; private static PinData LatestClosestPin = null; public static void OnClientAddPin(ZRpc client, ZPackage pinData) { if (!Store.IsSharingPin()) { return; } pinData.SetPos(0); object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet val = (ZNet)((value is ZNet) ? value : null); List<ZNetPeer> list = Traverse.Create((object)val).Field("m_peers").GetValue() as List<ZNetPeer>; PinData pin = ExplorationDatabase.UnpackPin(pinData); ExplorationDatabase.AddPin(pin); Utility.Log("Server received pin by client"); foreach (ZNetPeer item in list) { if (item.IsReady() && item.m_rpc != client) { item.m_rpc.Invoke("SSMPoV_OnServerAddPin", new object[1] { ExplorationDatabase.PackPin(pin) }); } } if (client != null) { OnServerAddPin(null, ExplorationDatabase.PackPin(pin)); } } public static void OnServerAddPin(ZRpc client, ZPackage pinData) { if (Store.IsSharingPin()) { pinData.SetPos(0); PinData pinData2 = ExplorationDatabase.UnpackPin(pinData); ExplorationDatabase.ClientPins.Add(pinData2); UtilityPin.AddSharedMapPin(pinData2); Utility.Log("Client received pin by server"); } } public static void OnClientRemovePin(ZRpc client, ZPackage pinData) { if (!Store.IsSharingPin()) { return; } pinData.SetPos(0); object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet val = (ZNet)((value is ZNet) ? value : null); List<ZNetPeer> list = Traverse.Create((object)val).Field("m_peers").GetValue() as List<ZNetPeer>; PinData pinData2 = ExplorationDatabase.UnpackPin(pinData); ExplorationDatabase.RemovePinEqual(pinData2); Utility.Log("Server deleted pin by client"); foreach (ZNetPeer item in list) { if (item.IsReady() && item.m_rpc != client) { item.m_rpc.Invoke("SSMPoV_OnServerRemovePin", new object[1] { ExplorationDatabase.PackPin(pinData2) }); } } if (client != null) { OnServerRemovePin(null, ExplorationDatabase.PackPin(pinData2)); } } public static void OnServerRemovePin(ZRpc _, ZPackage pinData) { if (!Store.IsSharingPin()) { return; } pinData.SetPos(0); Utility.Log("Client deleted pin by server"); PinData pinData2 = ExplorationDatabase.UnpackPin(pinData); foreach (PinData item in ExplorationDatabase.ClientPins.ToList()) { if (UtilityPin.ArePinsEqual(item, pinData2)) { ExplorationDatabase.ClientPins.Remove(item); } } PinData mapPin = UtilityPin.GetMapPin(pinData2); if (mapPin != null) { _Minimap.RemovePin(_Minimap._instance, mapPin); } } public static void OnClientCheckPin(ZRpc client, ZPackage data) { if (!Store.IsSharingPin()) { return; } data.SetPos(0); Utility.Log("Server checked pin by client"); PinData pinData = ExplorationDatabase.UnpackPin(data); bool flag = data.ReadBool(); ExplorationDatabase.SetPinState(pinData, flag); object value = Traverse.Create(typeof(ZNet)).Field("m_instance").GetValue(); ZNet val = (ZNet)((value is ZNet) ? value : null); List<ZNetPeer> list = Traverse.Create((object)val).Field("m_peers").GetValue() as List<ZNetPeer>; foreach (ZNetPeer item in list) { if (item.IsReady() && item.m_rpc != client) { ZPackage val2 = ExplorationDatabase.PackPin(pinData, skipSetPos: true); val2.Write(flag); item.m_rpc.Invoke("SSMPoV_OnServerCheckPin", new object[1] { val2 }); } } if (client != null) { ZPackage val3 = ExplorationDatabase.PackPin(pinData, skipSetPos: true); val3.Write(flag); OnServerCheckPin(null, val3); } } public static void OnServerCheckPin(ZRpc client, ZPackage data) { if (!Store.IsSharingPin()) { return; } data.SetPos(0); Utility.Log("Client checked pin by server"); PinData pin = ExplorationDatabase.UnpackPin(data); bool flag = data.ReadBool(); foreach (PinData item in ExplorationDatabase.ClientPins.ToList()) { if (UtilityPin.ArePinsEqual(item, pin)) { item.Checked = flag; PinData mapPin = UtilityPin.GetMapPin(item); if (mapPin != null) { mapPin.m_checked = flag; } } } } public static void SendPinToServer(PinData pin, bool deletePin = true) { if (Store.IsSharingPin() && UtilityPin.IsShareable(pin)) { PinData pinData = UtilityPin.ConvertPin(pin); ZPackage val = ExplorationDatabase.PackPin(pinData); pin.m_save = !deletePin && pin.m_save; ExplorationDatabase.ClientPins.Add(pinData); if (!_ZNet.IsServer(_ZNet._instance)) { _ZNet.GetServerRPC(_ZNet._instance).Invoke("SSMPoV_OnClientAddPin", new object[1] { val }); } else { OnClientAddPin(null, val); } } } public static void RemovePinFromServer(PinData pin) { if (Store.IsSharingPin()) { ZPackage val = ExplorationDatabase.PackPin(pin); ExplorationDatabase.ClientPins.Remove(pin); if (!_ZNet.IsServer(_ZNet._instance)) { _ZNet.GetServerRPC(_ZNet._instance).Invoke("SSMPoV_OnClientRemovePin", new object[1] { val }); } else { OnClientRemovePin(null, val); } } } public static void CheckPinOnServer(PinData pin, bool state) { if (Store.IsSharingPin()) { ZPackage val = ExplorationDatabase.PackPin(pin, skipSetPos: true); val.Write(state); val.SetPos(0); if (!_ZNet.IsServer(_ZNet._instance)) { _ZNet.GetServerRPC(_ZNet._instance).Invoke("SSMPoV_OnClientCheckPin", new object[1] { val }); } else { OnClientCheckPin(null, val); } } } } public static class PovBridge { [HarmonyPatch(typeof(Minimap), "AddPin", new Type[] { typeof(Vector3), typeof(PinType), typeof(string), typeof(bool), typeof(bool), typeof(long), typeof(PlatformUserID) })] private class MinimapPatchAddPin { private static void Postfix(PinData __result) { if (InQuickMark && __result != null && __result.m_save && Store.IsSharingPin() && !string.IsNullOrEmpty(LocalIcon(__result))) { PinSync.SendPinToServer(__result); } } } [HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })] private class MinimapPatchRemovePinQuickMark { private static void Postfix(PinData pin) { if (InQuickMark && pin != null) { PinData clientPin = UtilityPin.GetClientPin(pin); if (clientPin != null) { PinSync.RemovePinFromServer(clientPin); } } } } public static Harmony HarmonyInstance; private static bool initialised; private static MethodInfo iconAt; private static MethodInfo dress; [ThreadStatic] private static bool bypass; public static bool InQuickMark; public static void Init() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Expected O, but got Unknown if (initialised) { return; } initialised = true; try { Type type = AccessTools.TypeByName("PassiveTree.QuickMark"); if (type == null) { Utility.Log("Path of Valheiman not found - sharing pins without custom icons."); return; } iconAt = AccessTools.Method(type, "IconAt", new Type[1] { typeof(PinData) }, (Type[])null); if (iconAt != null) { Harmony harmonyInstance = HarmonyInstance; MethodInfo methodInfo = iconAt; HarmonyMethod val = new HarmonyMethod(typeof(PovBridge), "IconAtPostfix", (Type[])null); harmonyInstance.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Utility.Log("PassiveTree.QuickMark.IconAt not found - custom icons disabled."); } Type type2 = AccessTools.TypeByName("PassiveTree.UI.MapIcons"); dress = ((!(type2 == null)) ? AccessTools.Method(type2, "Dress", new Type[2] { typeof(Minimap), typeof(PinData) }, (Type[])null) : null); if (dress == null) { Utility.Log("PassiveTree.UI.MapIcons.Dress not found - shared pins will not be redrawn."); } Type type3 = AccessTools.Inner(type, "Player_Update"); MethodInfo methodInfo2 = ((!(type3 == null)) ? AccessTools.Method(type3, "Postfix", (Type[])null, (Type[])null) : null); if (methodInfo2 != null) { Harmony harmonyInstance2 = HarmonyInstance; MethodInfo methodInfo = methodInfo2; HarmonyMethod val = new HarmonyMethod(typeof(PovBridge), "QuickMarkPrefix", (Type[])null); HarmonyMethod val2 = new HarmonyMethod(typeof(PovBridge), "QuickMarkFinalizer", (Type[])null); harmonyInstance2.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); } else { Utility.Log("Quick Mark handler not found - new Quick Marks will not auto-share."); } Utility.Log("Path of Valheiman icon bridge active."); } catch (Exception ex) { Utility.Log("Path of Valheiman icon bridge failed: " + ex); } } public static string LocalIcon(PinData pin) { if (iconAt == null || pin == null) { return ""; } bypass = true; try { return (iconAt.Invoke(null, new object[1] { pin }) as string) ?? ""; } catch { return ""; } finally { bypass = false; } } public static void Dress(PinData pin) { if (dress == null || pin == null || (Object)(object)_Minimap._instance == (Object)null) { return; } try { dress.Invoke(null, new object[2] { _Minimap._instance, pin }); } catch (Exception ex) { Utility.Log("Dress failed: " + ex.Message); } } private static void IconAtPostfix(PinData __0, ref string __result) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 if (!bypass && __result == null && __0 != null && (int)__0.m_type == 3) { PinData clientPin = UtilityPin.GetClientPin(__0); if (clientPin != null && !string.IsNullOrEmpty(clientPin.Icon)) { __result = clientPin.Icon; } } } private static void QuickMarkPrefix() { InQuickMark = true; } private static Exception QuickMarkFinalizer(Exception __exception) { InQuickMark = false; return __exception; } } public class SaveWorld { [HarmonyPatch(typeof(ZNet), "ServerLoadWorld")] private class ZnetPatchLoadMap { private static void Postfix(ZNet __instance) { //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown object value = Traverse.Create(typeof(ZNet)).Field("m_world").GetValue(); World val = (World)((value is World) ? value : null); string text = Path.ChangeExtension(val.GetDBPath(), null); Utility.Log("World .explored save path: " + text); string text2 = text + ".mod.serversidemap_pov.explored"; string text3 = text2 + ".beforehs"; if (File.Exists(text2) && !File.Exists(text3)) { File.Copy(text2, text3); } string text4 = text + ".mod.serversidemap.explored"; string path = text2; if (!File.Exists(text2) && File.Exists(text4)) { Utility.Log("Migrating pins and exploration from original ServerSideMap file"); path = text4; } FileStream input; try { input = File.OpenRead(path); } catch { GenerateDefaultExploredFile(__instance); return; } BinaryReader binaryReader = new BinaryReader(input); byte[] array = binaryReader.ReadAllBytes(); binaryReader.Dispose(); if (array.Length == 0) { Utility.Log("Existing explored file is 0 bytes. Generating new one."); GenerateDefaultExploredFile(__instance); } else { ZPackage mapData = new ZPackage(array); ExplorationDatabase.SetMapData(mapData); Utility.Log("loaded from existing explore file"); } } } [HarmonyPatch(typeof(ZNet), "SaveWorldThread")] private class ZnetPatchSaveWorldThread { private static void Postfix() { byte[] array = ExplorationDatabase.GetMapData().GetArray(); if (array.Length == 0) { Utility.Log("Explored data is zero bytes. Refusing to save."); return; } object value = Traverse.Create(typeof(ZNet)).Field("m_world").GetValue(); World val = (World)((value is World) ? value : null); string text = Path.ChangeExtension(val.GetDBPath(), null); string path = text + ".mod.serversidemap_pov.explored"; Utility.Log("World .explored save path: " + text); FileStream fileStream = File.Create(path); BinaryWriter binaryWriter = new BinaryWriter(fileStream); binaryWriter.Write(array); binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); fileStream.Close(); fileStream.Dispose(); } } public static void GenerateDefaultExploredFile(ZNet __instance) { ExplorationDatabase.SetMapData(ExplorationDatabase.Default()); Utility.Log("new explore file generated"); __instance.Save(true, false, false); } } [BepInPlugin("OGTristonMcPherson.ServerSideMapPoV", "ServerSideMap_PoV", "1.0.2")] public class ServerSideMap : BaseUnityPlugin { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private class ZnetPatchOnNewConnection { private static void Postfix(ZNetPeer peer, ZNet __instance) { if (__instance.IsServer()) { Utility.Log("Registered Server Events"); if (Store.IsSharingMap()) { peer.m_rpc.Register<int, int>("SSMPoV_OnClientExplore", (Action<ZRpc, int, int>)ExplorationMapSync.OnClientExplore); peer.m_rpc.Register<ZPackage>("SSMPoV_OnClientInitialData", (Action<ZRpc, ZPackage>)InitialMapSync.OnClientInitialData); } peer.m_rpc.Register<ZPackage>("SSMPoV_OnClientInitialDataPin", (Action<ZRpc, ZPackage>)InitialPinSync.OnClientInitialDataPin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnClientAddPin", (Action<ZRpc, ZPackage>)PinSync.OnClientAddPin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnClientRemovePin", (Action<ZRpc, ZPackage>)PinSync.OnClientRemovePin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnClientCheckPin", (Action<ZRpc, ZPackage>)PinSync.OnClientCheckPin); } else { Utility.Log("Registered Client Events"); if (Store.IsSharingMap()) { peer.m_rpc.Register<ZPackage>("SSMPoV_OnReceiveMapData", (Action<ZRpc, ZPackage>)ExplorationDatabase.OnReceiveMapData); peer.m_rpc.Register<ZPackage>("SSMPoV_OnReceiveMapDataInitial", (Action<ZRpc, ZPackage>)InitialMapSync.OnReceiveMapDataInitial); } peer.m_rpc.Register<ZPackage>("SSMPoV_OnReceiveInitialDataPin", (Action<ZRpc, ZPackage>)InitialPinSync.OnReceiveInitialDataPin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnServerAddPin", (Action<ZRpc, ZPackage>)PinSync.OnServerAddPin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnServerRemovePin", (Action<ZRpc, ZPackage>)PinSync.OnServerRemovePin); peer.m_rpc.Register<ZPackage>("SSMPoV_OnServerCheckPin", (Action<ZRpc, ZPackage>)PinSync.OnServerCheckPin); } } } private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown PovBridge.HarmonyInstance = new Harmony("OGTristonMcPherson.ServerSideMapPoV.pov"); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); Store.EnableMapShare = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMapShare", true, "Client: Whether or not to participate in sharing the map. Server: Whether or not to allow map sharing"); Store.EnablePinShare = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMarkerShare", true, "Client: Whether or not to participate in sharing markers. Server: Whether or not to allow marker sharing"); Store.DuplicatePinRadius = ((BaseUnityPlugin)this).Config.Bind<float>("PinShare", "DuplicatePinRadius", 15f, "A local pin will not be uploaded if a pin exists in the given radius on the server (when using /convertpins ignorelocaldupes)"); Store.sKeyConvertAll = ((BaseUnityPlugin)this).Config.Bind<string>("Hotkeys", "KeyConvertAll", "", "Hotkey to run /convertpins"); Store.sKeyConvertIgnoreDupes = ((BaseUnityPlugin)this).Config.Bind<string>("Hotkeys", "KeyConvertIgnoreDupes", "", "Hotkey to run /convertpins ignorelocaldupes"); Store.InitHotkeys(); Utility.Log("Store1: " + Store.HasKeyConvertAll()); Utility.Log("Store2: " + Store.HasKeyConvertIgnoreDupes()); } } public static class Store { public static ConfigEntry<bool> EnableMapShare; public static ConfigEntry<bool> EnablePinShare; public static ConfigEntry<float> DuplicatePinRadius; public static ConfigEntry<string> sKeyConvertAll; private static bool hasKeyConvertAll; private static KeyCode KeyConvertAll; public static ConfigEntry<string> sKeyConvertIgnoreDupes; private static bool hasKeyConvertIgnoreDupes; private static KeyCode KeyConvertIgnoreDupes; public static bool ServerPinShare = false; public static bool IsSharingMap() { return EnableMapShare.Value; } public static bool IsSharingPin() { return (ServerPinShare || _ZNet.IsServer(_ZNet._instance)) && EnablePinShare.Value; } public static float GetDuplicatePinRadius() { return DuplicatePinRadius.Value; } public static void InitHotkeys() { hasKeyConvertAll = Enum.TryParse<KeyCode>(sKeyConvertAll.Value, out KeyConvertAll); hasKeyConvertIgnoreDupes = Enum.TryParse<KeyCode>(sKeyConvertIgnoreDupes.Value, out KeyConvertIgnoreDupes); } public static bool HasKeyConvertAll() { return hasKeyConvertAll; } public static KeyCode GetKeyConvertAll() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return KeyConvertAll; } public static bool HasKeyConvertIgnoreDupes() { return hasKeyConvertIgnoreDupes; } public static KeyCode GetKeyConvertIgnoreDupes() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return KeyConvertIgnoreDupes; } } public static class Utility { private static ManualLogSource _logInstance = Logger.CreateLogSource("ServerSideMap"); public static void Log(object data) { _logInstance.Log((LogLevel)16, data); } public static void Message(string text) { Log(text); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } public static byte[] ReadAllBytes(this BinaryReader reader) { using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[4096]; int count; while ((count = reader.Read(array, 0, array.Length)) != 0) { memoryStream.Write(array, 0, count); } return memoryStream.ToArray(); } } public class UtilityPin { public static bool ArePinsEqual(PinData pin1, PinData pin2) { //IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references) return pin1.Name == pin2.m_name && pin1.Type == pin2.m_type && ((Vector3)(ref pin1.Pos)).Equals(pin2.m_pos); } public static bool ArePinsEqual(PinData pin1, PinData pin2) { //IL_0017: 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_002e: Unknown result type (might be due to invalid IL or missing references) return pin1.Name == pin2.Name && pin1.Type == pin2.Type && ((Vector3)(ref pin1.Pos)).Equals(pin2.Pos); } public static bool ArePinsDupes(PinData pin1, PinData pin2, float radius) { //IL_0001: 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) return Utils.DistanceXZ(pin1.m_pos, pin2.Pos) < radius; } public static PinData AddSharedMapPin(PinData pin) { //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_0025: Unknown result type (might be due to invalid IL or missing references) PinData val = _Minimap.AddPin(_Minimap._instance, pin.Pos, pin.Type, pin.Name, save: false, pin.Checked, 0L, new PlatformUserID("")); PovBridge.Dress(val); return val; } public static PinData FindServerDupe(PinData pin) { foreach (PinData clientPin in ExplorationDatabase.ClientPins) { if (ArePinsDupes(pin, clientPin, Store.GetDuplicatePinRadius())) { return clientPin; } } return null; } private static bool HasSharedCopy(PinData pin, string icon) { //IL_0019: 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_002f: 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) foreach (PinData clientPin in ExplorationDatabase.ClientPins) { if (clientPin.Type != pin.m_type || Utils.DistanceXZ(pin.m_pos, clientPin.Pos) > 2f || (!string.IsNullOrEmpty(icon) && !(clientPin.Icon == icon))) { continue; } return true; } return false; } public static bool LocalPinIsDupe(PinData pin) { foreach (PinData clientPin in ExplorationDatabase.ClientPins) { if (ArePinsDupes(pin, clientPin, Store.GetDuplicatePinRadius())) { return true; } } return false; } public static PinData GetMapPin(PinData needle) { List<PinData> list = Traverse.Create((object)_Minimap._instance).Field("m_pins").GetValue() as List<PinData>; foreach (PinData item in list) { if (ArePinsEqual(needle, item)) { return item; } } return null; } public static PinData GetClientPin(PinData needle) { foreach (PinData clientPin in ExplorationDatabase.ClientPins) { if (ArePinsEqual(clientPin, needle)) { return clientPin; } } return null; } public static bool IsShareable(PinData pin) { //IL_0001: 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_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_0037: Expected I4, but got Unknown PinType type = pin.m_type; switch (type - 4) { case 0: case 1: case 3: case 4: case 6: case 7: case 8: case 9: return false; default: return true; } } public static PinData ConvertPin(PinData pin) { //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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) PinData pinData = new PinData(); pinData.Name = pin.m_name; pinData.Pos = pin.m_pos; pinData.Type = pin.m_type; pinData.Checked = pin.m_checked; pinData.Icon = PovBridge.LocalIcon(pin); return pinData; } public static void UploadAllPins(bool removeDupes = false) { List<PinData> source = Traverse.Create((object)_Minimap._instance).Field("m_pins").GetValue() as List<PinData>; foreach (PinData item in source.ToList()) { if (!item.m_save || !IsShareable(item)) { continue; } if (removeDupes) { PinData pinData = FindServerDupe(item); if (pinData != null) { if (!string.IsNullOrEmpty(pinData.Icon) || string.IsNullOrEmpty(PovBridge.LocalIcon(item))) { continue; } PinData mapPin = GetMapPin(pinData); PinSync.RemovePinFromServer(pinData); if (mapPin != null) { _Minimap.RemovePin(_Minimap._instance, mapPin); } } } PinData pinData2 = ConvertPin(item); PinSync.SendPinToServer(item, deletePin: false); ExplorationDatabase.ClientPins.Add(pinData2); AddSharedMapPin(pinData2); } } public static void DeleteLocalPins() { List<PinData> source = Traverse.Create((object)_Minimap._instance).Field("m_pins").GetValue() as List<PinData>; int num = 0; foreach (PinData item in source.ToList()) { if (item.m_save && IsShareable(item)) { _Minimap.RemovePin(_Minimap._instance, item); num++; } } Utility.Message("Removed " + num + " local pins"); } public static void DeleteAllSharedPins() { List<PinData> list = ExplorationDatabase.ClientPins.ToList(); foreach (PinData item in list) { PinData mapPin = GetMapPin(item); PinSync.RemovePinFromServer(item); if (mapPin != null) { _Minimap.RemovePin(_Minimap._instance, mapPin); } } Utility.Message("Deleted " + list.Count + " shared pins for everyone"); } public static void DownloadPins() { List<PinData> list = ExplorationDatabase.ClientPins.ToList(); foreach (PinData item in list) { PinData mapPin = GetMapPin(item); mapPin.m_save = true; } } } [HarmonyPatch] public class _Minimap { [HarmonyPatch(typeof(Minimap), "Awake")] public static class Awake { private static void Postfix(Minimap __instance) { _instance = __instance; PovBridge.Init(); ManualLogSource val = Logger.CreateLogSource("ServerSideMap"); val.LogInfo((object)"Minimap awake"); } } public static Minimap _instance; [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(int), typeof(int) })] public static bool Explore(Minimap instance, int x, int y) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "AddPin", new Type[] { typeof(Vector3), typeof(PinType), typeof(string), typeof(bool), typeof(bool), typeof(long), typeof(PlatformUserID) })] public static PinData AddPin(Minimap instance, Vector3 pos, PinType type, string name, bool save, bool isChecked, long owner, PlatformUserID author) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(Minimap), "RemovePin", new Type[] { typeof(PinData) })] public static void RemovePin(Minimap instance, PinData pin) { throw new NotImplementedException(); } } [HarmonyPatch] public class _ZNet { [HarmonyPatch(typeof(ZNet), "Awake")] public static class Awake { private static void Postfix(ZNet __instance) { _instance = __instance; ManualLogSource val = Logger.CreateLogSource("ServerSideMap"); val.LogInfo((object)"ZNet awake"); Store.ServerPinShare = false; } } public static ZNet _instance; [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "GetServerRPC")] public static ZRpc GetServerRPC(ZNet instance) { throw new NotImplementedException(); } [HarmonyReversePatch(/*Could not decode attribute arguments.*/)] [HarmonyPatch(typeof(ZNet), "IsServer")] public static bool IsServer(ZNet instance) { throw new NotImplementedException(); } }