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 PortalNetwork v0.2.1
plugins/PortalNetwork.dll
Decompiled 3 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using PortalNetwork.Core; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("PortalNetwork")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.1.0")] [assembly: AssemblyInformationalVersion("0.2.1+deb90a60d854664f408151a45a03da157f40fa8c")] [assembly: AssemblyProduct("PortalNetwork")] [assembly: AssemblyTitle("PortalNetwork")] [assembly: AssemblyVersion("0.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 PortalNetwork { internal static class ChoiceWindow { private sealed class Exit { public string Label; public Vector3 Position; public Quaternion Rotation; } [CompilerGenerated] private static class <>O { public static Action<ZRpc, ZPackage> <0>__OnListReply; public static UnityAction <1>__Close; } private const float ReplyTimeoutSeconds = 3f; private const float RowHeight = 46f; private const float Width = 420f; private static ZRpc _server; private static TeleportWorld _portal; private static ZDOID _pending = ZDOID.None; private static float _pendingSince; private static GameObject _panel; private static bool _open; private static bool _blocked; private static int _closedFrame = -1; private static float _health; internal static bool Bypass; internal static bool BlocksGame { get { if (!_open) { return Time.frameCount == _closedFrame; } return true; } } internal static bool Connected { get { if (_server != null && (Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer()?.m_rpc == _server; } return false; } } internal static void RegisterServer(ZRpc rpc) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) _server = rpc; _pending = ZDOID.None; rpc.Register<ZPackage>("PortalNetwork_ListReply", (Action<ZRpc, ZPackage>)OnListReply); } internal static void RequestList(TeleportWorld portal, ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!_open && (!(_pending == id) || !(Time.time - _pendingSince < 3f))) { _portal = portal; _pending = id; _pendingSince = Time.time; ZPackage val = new ZPackage(); val.Write(id); _server.Invoke("PortalNetwork_ListRequest", new object[1] { val }); } } private static void OnListReply(ZRpc rpc, ZPackage reply) { //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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) ZDOID val = reply.ReadZDOID(); string network = reply.ReadString(); int num = reply.ReadInt(); List<Exit> list = new List<Exit>(num); for (int i = 0; i < num; i++) { Exit exit = new Exit { Label = reply.ReadString() }; reply.ReadZDOID(); exit.Position = reply.ReadVector3(); exit.Rotation = reply.ReadQuaternion(); list.Add(exit); } if (val != _pending) { return; } _pending = ZDOID.None; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_portal == (Object)null || !InReach(localPlayer)) { return; } if (list.Count == 0) { Bypass = true; try { _portal.Teleport(localPlayer); return; } finally { Bypass = false; } } Open(localPlayer, network, list); } private static bool InReach(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(((Component)player).transform.position, ((Component)_portal).transform.position) <= _portal.m_activationRange + 1f; } internal static void Update() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (_pending != ZDOID.None && Time.time - _pendingSince >= 3f) { _pending = ZDOID.None; Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "Сеть порталов не отвечает.", 0, (Sprite)null, false); } } if (!_open) { return; } Player localPlayer2 = Player.m_localPlayer; if ((Object)(object)localPlayer2 == (Object)null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)_panel == (Object)null || (Object)(object)_portal == (Object)null || GameUiOpen() || ((Character)localPlayer2).IsDead() || !InReach(localPlayer2) || ((Character)localPlayer2).GetHealth() < _health - 0.01f) { Close(); return; } _health = ((Character)localPlayer2).GetHealth(); if (ZInput.GetKeyDown((KeyCode)27, false) || ZInput.GetButtonDown("JoyButtonB")) { Close(); } } private static bool GameUiOpen() { if (!Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen()) { return StoreGui.IsVisible(); } return true; } private static void Open(Player player, string network, List<Exit> exits) { if (!GameUiOpen() && !((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { if ((Object)(object)_panel != (Object)null) { Object.Destroy((Object)(object)_panel); } Build(network, exits); _health = ((Character)player).GetHealth(); _open = true; if (!_blocked) { GUIManager.BlockInput(true); _blocked = true; } } } private static void Build(string network, List<Exit> exits) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown GUIManager instance = GUIManager.Instance; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0.5f, 1f); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 0f); float num = 170f + (float)exits.Count * 46f; _panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, val, val, Vector2.zero, 420f, num, true); ((Object)_panel).name = "SansaraPortalNetworkWindow"; Text component = instance.CreateText("Портал «" + network + "»", _panel.transform, val2, val2, new Vector2(0f, -40f), instance.AveriaSerifBold, 30, instance.ValheimOrange, true, Color.black, 380f, 50f, false).GetComponent<Text>(); component.alignment = (TextAnchor)4; component.resizeTextForBestFit = true; component.resizeTextMinSize = 16; component.resizeTextMaxSize = 30; for (int i = 0; i < exits.Count; i++) { Exit exit = exits[i]; ((UnityEvent)instance.CreateButton(exit.Label, _panel.transform, val2, val2, new Vector2(0f, -95f - (float)i * 46f), 340f, 40f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate { Go(exit); }); } ButtonClickedEvent onClick = instance.CreateButton("Закрыть (Esc)", _panel.transform, val3, val3, new Vector2(0f, 40f), 220f, 40f).GetComponent<Button>().onClick; object obj = <>O.<1>__Close; if (obj == null) { UnityAction val4 = Close; <>O.<1>__Close = val4; obj = (object)val4; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } private static void Go(Exit exit) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0081: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_portal == (Object)null) { Close(); return; } if (!((Humanoid)localPlayer).IsTeleportable(_portal.m_allowAllItems)) { ((Character)localPlayer).Message((MessageType)2, "$msg_noteleport", 0, (Sprite)null, false); Close(); return; } Vector3 val = exit.Position + exit.Rotation * Vector3.forward * _portal.m_exitDistance + Vector3.up; if (!((Character)localPlayer).TeleportTo(val, exit.Rotation, true)) { ((Character)localPlayer).Message((MessageType)2, "Портал ещё не готов, подождите секунду.", 0, (Sprite)null, false); return; } Game.instance.IncrementPlayerStat((PlayerStatType)15, 1f, false); Close(); } private static void Close() { _open = false; _closedFrame = Time.frameCount; if ((Object)(object)_panel != (Object)null) { _panel.SetActive(false); } if (_blocked) { GUIManager.BlockInput(false); _blocked = false; } } } [HarmonyPatch(typeof(TextInput), "RequestText")] internal static class PortalNameLimitPatch { private static void Prefix(TextReceiver sign, ref int charLimit) { if (sign is TeleportWorld) { charLimit = Math.Max(charLimit, Plugin.MaxNameLength.Value); } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] internal static class TeleportPatch { private static bool Prefix(TeleportWorld __instance, Player player, ZNetView ___m_nview) { //IL_0050: 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_006e: Unknown result type (might be due to invalid IL or missing references) try { if (ChoiceWindow.Bypass || !Plugin.Enabled.Value || !ChoiceWindow.Connected || (Object)(object)___m_nview == (Object)null) { return true; } ZDO zDO = ___m_nview.GetZDO(); if (zDO != null && PortalTag.Parse(zDO.GetString(ZDOVars.s_tag, "")).Kind == PortalTagKind.Parent) { ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)1); if (!((ZDOID)(ref connectionZDOID)).IsNone() && !Refused(__instance, player)) { ChoiceWindow.RequestList(__instance, zDO.m_uid); return false; } } return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Сеть порталов: вход в портал: " + ex)); return true; } } private static bool Refused(TeleportWorld portal, Player player) { if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)32)) { return true; } float num = default(float); if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)33) && (RandEventSystem.instance.GetBossEvent() != null || (ZoneSystem.instance.GetGlobalKey((GlobalKeys)47, ref num) && num > 0f))) { return true; } return !((Humanoid)player).IsTeleportable(portal.m_allowAllItems); } } [HarmonyPatch(typeof(PlayerController), "TakeInput")] internal static class ControllerInputPatch { private static void Postfix(ref bool __result) { if (ChoiceWindow.BlocksGame) { __result = false; } } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class PlayerInputPatch { private static void Postfix(ref bool __result) { if (ChoiceWindow.BlocksGame) { __result = false; } } } [HarmonyPatch(typeof(Menu), "Update")] internal static class MenuPatch { private static bool Prefix() { return !ChoiceWindow.BlocksGame; } } internal static class Net { public const string ListRequest = "PortalNetwork_ListRequest"; public const string ListReply = "PortalNetwork_ListReply"; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class NewConnectionPatch { private static void Postfix(ZNet __instance, ZNetPeer peer) { try { if (peer?.m_rpc != null) { if (__instance.IsServer()) { peer.m_rpc.Register<ZPackage>("PortalNetwork_ListRequest", (Action<ZRpc, ZPackage>)ServerLinks.OnListRequest); } else { ChoiceWindow.RegisterServer(peer.m_rpc); } } } catch (Exception ex) { Plugin.Log.LogError((object)("Сеть порталов: OnNewConnection: " + ex)); } } } [BepInPlugin("sansara.PortalNetwork", "Portal Network", "0.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "sansara.PortalNetwork"; public const string Name = "Portal Network"; public const string Version = "0.2.1"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> MaxChildren; internal static ConfigEntry<int> MaxNameLength; internal static ConfigEntry<string> SelfTestMode; private void Awake() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Сеть порталов: «(сеть)» ведёт в окно выбора, «(сеть)имя» — в «(сеть)». false — все порталы как в обычной игре."); MaxChildren = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxChildren", 10, new ConfigDescription("Сервер: сколько выходов может быть у одного центрального портала. Лишние работают как обычные порталы.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); MaxNameLength = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxNameLength", 20, new ConfigDescription("Клиент: сколько символов можно ввести в имя портала (в игре 10). Работает и при выключенной сети.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 40), Array.Empty<object>())); SelfTestMode = ((BaseUnityPlugin)this).Config.Bind<string>("Debug", "SelfTest", "Off", "Только для тестовой копии. Run — создать три служебных портала «(st)» и записать в журнал их связи; Cleanup — удалить их по одному, проверяя связи; Off — выключено."); new Harmony("sansara.PortalNetwork").PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)string.Format("{0} {1} loaded: Enabled={2}, MaxChildren={3}, SelfTest={4}", "Portal Network", "0.2.1", Enabled.Value, MaxChildren.Value, SelfTestMode.Value)); } private void Update() { try { if (Application.isBatchMode) { SelfTest.Tick(); } else { ChoiceWindow.Update(); } } catch (Exception ex) { Log.LogError((object)("Сеть порталов: Update: " + ex)); } } } internal static class SelfTest { private const string Parent = "(st)"; private const string Child1 = "(st)1"; private const string Child2 = "(st)2"; private static readonly Vector3 Origin = new Vector3(9000f, 500f, 3000f); private const float CycleSeconds = 5f; private const float AfterLoadSeconds = 20f; private static int _cycle; private static float _nextAt = -1f; private static int _vanillaCalls; internal static void CountVanillaCall() { _vanillaCalls++; } internal static void Tick() { string value = Plugin.SelfTestMode.Value; if (value == "Off" || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || (Object)(object)Game.instance == (Object)null || ZDOMan.instance == null || ZDOMan.instance.NrOfObjects() == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (_nextAt < 0f) { _nextAt = realtimeSinceStartup + 20f; } else if (!(realtimeSinceStartup < _nextAt) && _cycle < ((value == "Run") ? 6 : 7)) { _nextAt = realtimeSinceStartup + 5f; _cycle++; Plugin.Log.LogInfo((object)$"Самопроверка сети порталов: timeScale {Time.timeScale}, вызовов ConnectPortals всего {_vanillaCalls}."); if (value == "Run") { Run(_cycle); } else if (value == "Cleanup") { Cleanup(_cycle); } Game.instance.ConnectPortals(); } } private static void Run(int cycle) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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) if (cycle <= 6) { Report($"цикл {cycle}"); switch (cycle) { case 1: Create("(st)", 0); Create("(st)1", 1); Create("(st)2", 2); break; case 6: { ZDO val = Find("(st)"); ZDO val2 = Find("(st)1"); ZDO val3 = Find("(st)2"); bool flag = val != null && val2 != null && val3 != null && Link(val2) == val.m_uid && Link(val3) == val.m_uid && Link(val) == val2.m_uid; Plugin.Log.LogInfo((object)("Самопроверка сети порталов: " + (flag ? "ПРОЙДЕНА" : "НЕ ПРОЙДЕНА") + " — связи пережили циклы ConnectPortals.")); break; } } } } private static void Cleanup(int cycle) { //IL_009b: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (cycle > 7) { return; } Report($"очистка, цикл {cycle}"); switch (cycle) { case 1: Destroy("(st)1"); break; case 3: { ZDO val3 = Find("(st)"); ZDO val4 = Find("(st)2"); Verdict("центральный перешёл на оставшийся выход", val3 != null && val4 != null && Link(val3) == val4.m_uid); Destroy("(st)2"); break; } case 5: { ZDO val = Find("(st)"); int ok; if (val != null) { ZDOID val2 = Link(val); ok = (((ZDOID)(ref val2)).IsNone() ? 1 : 0); } else { ok = 0; } Verdict("без выходов центральный стал обычным порталом без связи", (byte)ok != 0); Destroy("(st)"); break; } case 2: case 4: break; } } private static void Verdict(string what, bool ok) { Plugin.Log.LogInfo((object)("Самопроверка сети порталов: " + (ok ? "ПРОЙДЕНА" : "НЕ ПРОЙДЕНА") + " — " + what + ".")); } private static void Report(string when) { string text = string.Join("; ", new string[3] { "(st)", "(st)1", "(st)2" }.Select(delegate(string tag) { //IL_001c: 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_0036: Unknown result type (might be due to invalid IL or missing references) ZDO val = Find(tag); if (val == null) { return tag + " нет"; } ZDO zDO = ZDOMan.instance.GetZDO(Link(val)); object obj; if (zDO == null) { ZDOID val2 = Link(val); obj = (((ZDOID)(ref val2)).IsNone() ? "нет связи" : "неизвестный"); } else { obj = zDO.GetString(ZDOVars.s_tag, ""); } return tag + " → " + (string?)obj; })); Plugin.Log.LogInfo((object)("Самопроверка сети порталов (" + when + "): " + text)); } private static ZDOID Link(ZDO zdo) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return zdo.GetConnectionZDOID((ConnectionType)1); } private static ZDO Find(string tag) { return ((IEnumerable<ZDO>)ZDOMan.instance.GetPortalList()).FirstOrDefault((Func<ZDO, bool>)((ZDO z) => z.GetString(ZDOVars.s_tag, "") == tag)); } private static void Create(string tag, int index) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) if (Find(tag) == null) { GameObject prefab = ZNetScene.instance.GetPrefab("portal_wood"); ZNetView component = prefab.GetComponent<ZNetView>(); int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); ZDO val = ZDOMan.instance.CreateNewZDO(Origin + Vector3.right * ((float)index * 10f), stableHashCode); val.Persistent = component.m_persistent; val.Type = component.m_type; val.Distant = component.m_distant; val.SetPrefab(stableHashCode); val.Set(ZDOVars.s_tag, tag); Plugin.Log.LogInfo((object)$"Самопроверка сети порталов: создан {tag} {val.m_uid}."); } } private static void Destroy(string tag) { ZDO val = Find(tag); if (val != null) { val.SetOwner(ZDOMan.GetSessionID()); ZDOMan.instance.DestroyZDO(val); Plugin.Log.LogInfo((object)("Самопроверка сети порталов: удалён " + tag + ".")); } } } internal static class ServerLinks { internal static bool Hiding; private static NetworkPlan<ZDOID> _plan; private static string _lastSummary = ""; internal static NetworkPlan<ZDOID> BuildPlan() { return NetworkPlan<ZDOID>.Build(from z in ZDOMan.instance.GetPortalList() select new KeyValuePair<ZDOID, string>(z.m_uid, z.GetString(ZDOVars.s_tag, "")), Plugin.MaxChildren.Value); } internal static NetworkPlan<ZDOID> BuildPlanForHiding() { return _plan; } internal static void Reconcile() { //IL_002a: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) _plan = BuildPlan(); foreach (ZDO portal in ZDOMan.instance.GetPortalList()) { if (_plan.TryGetTarget(portal.m_uid, out var target) && portal.GetConnectionZDOID((ConnectionType)1) != target) { SetConnection(portal, target); } } LogChanges(); } private static void SetConnection(ZDO portal, ZDOID target) { //IL_002c: 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_0057: 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) long owner = portal.GetOwner(); if (owner == 0L || owner == ZDOMan.GetSessionID() || ZNet.instance.GetPeer(owner) == null) { portal.SetOwner(ZDOMan.GetSessionID()); portal.SetConnection((ConnectionType)1, target); ZDOMan.instance.ForceSendZDO(portal.m_uid); } else { ZRoutedRpc.instance.InvokeRoutedRPC(owner, "RPC_SetConnection", new object[2] { portal.m_uid, target }); } } private static void LogChanges() { string text = string.Join("; ", _plan.Networks.Select((Network<ZDOID> n) => "(" + n.Name + "): " + string.Join(", ", n.Children.Select((NetworkChild<ZDOID> c) => c.Label)) + ((n.Overflow > 0) ? $" и ещё {n.Overflow} сверх лимита" : "")).OrderBy<string, string>((string s) => s, StringComparer.Ordinal).Concat(from a in _plan.AmbiguousNetworks.OrderBy<string, string>((string s) => s, StringComparer.Ordinal) select "(" + a + "): несколько центральных порталов, сеть не работает")); if (text != _lastSummary) { _lastSummary = text; Plugin.Log.LogInfo((object)("Сети порталов: " + ((text.Length > 0) ? text : "нет"))); } } internal static void OnListRequest(ZRpc rpc, ZPackage request) { //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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0029: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) try { ZDOID val = request.ReadZDOID(); Network<ZDOID> network = (Plugin.Enabled.Value ? BuildPlan().FindByParent(val) : null); ZPackage val2 = new ZPackage(); val2.Write(val); val2.Write(network?.Name ?? ""); val2.Write(network?.Children.Count ?? 0); if (network != null) { foreach (NetworkChild<ZDOID> child in network.Children) { ZDO zDO = ZDOMan.instance.GetZDO(child.Id); val2.Write(child.Label); val2.Write(child.Id); val2.Write(zDO.GetPosition()); val2.Write(zDO.GetRotation()); } } rpc.Invoke("PortalNetwork_ListReply", new object[1] { val2 }); Plugin.Log.LogInfo((object)$"Сеть порталов: запрос списка {val}: выходов {network?.Children.Count ?? 0}."); } catch (Exception ex) { Plugin.Log.LogError((object)("Сеть порталов: запрос списка: " + ex)); } } } [HarmonyPatch(typeof(Game), "ConnectPortals")] internal static class ConnectPortalsPatch { private static void Prefix() { if (!Plugin.Enabled.Value || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } try { SelfTest.CountVanillaCall(); ServerLinks.Reconcile(); ServerLinks.Hiding = true; } catch (Exception ex) { Plugin.Log.LogError((object)("Сеть порталов: связи: " + ex)); } } private static void Finalizer() { ServerLinks.Hiding = false; } } [HarmonyPatch(typeof(ZDOMan), "GetPortalList")] internal static class PortalListPatch { private static void Postfix(List<ZDO> __result) { if (ServerLinks.Hiding) { NetworkPlan<ZDOID> plan = ServerLinks.BuildPlanForHiding(); __result.RemoveAll((ZDO z) => plan.IsManaged(z.m_uid)); } } } } namespace PortalNetwork.Core { public sealed class NetworkChild<TId> { public TId Id { get; } public string Label { get; } public NetworkChild(TId id, string label) { Id = id; Label = label; } } public sealed class Network<TId> { public string Name { get; } public TId ParentId { get; } public IReadOnlyList<NetworkChild<TId>> Children { get; } public int Overflow { get; } public Network(string name, TId parentId, IReadOnlyList<NetworkChild<TId>> children, int overflow) { Name = name; ParentId = parentId; Children = children; Overflow = overflow; } } public sealed class NetworkPlan<TId> { private sealed class LabelOrder : IComparer<string> { public static readonly LabelOrder Instance = new LabelOrder(); public int Compare(string a, string b) { long result; bool flag = long.TryParse(a, NumberStyles.None, CultureInfo.InvariantCulture, out result); long result2; bool flag2 = long.TryParse(b, NumberStyles.None, CultureInfo.InvariantCulture, out result2); if (flag && flag2) { return result.CompareTo(result2); } if (flag != flag2) { if (!flag) { return 1; } return -1; } return string.CompareOrdinal(a, b); } } private readonly Dictionary<TId, TId> _targets = new Dictionary<TId, TId>(); private readonly Dictionary<TId, Network<TId>> _byParent = new Dictionary<TId, Network<TId>>(); public IReadOnlyCollection<Network<TId>> Networks => _byParent.Values; public IReadOnlyList<string> AmbiguousNetworks { get; } private NetworkPlan(List<string> ambiguous) { AmbiguousNetworks = ambiguous; } public bool IsManaged(TId id) { return _targets.ContainsKey(id); } public bool TryGetTarget(TId id, out TId target) { return _targets.TryGetValue(id, out target); } public Network<TId> FindByParent(TId id) { if (!_byParent.TryGetValue(id, out var value)) { return null; } return value; } public static NetworkPlan<TId> Build(IEnumerable<KeyValuePair<TId, string>> portals, int maxChildren) { Dictionary<string, List<TId>> dictionary = new Dictionary<string, List<TId>>(StringComparer.Ordinal); Dictionary<string, List<NetworkChild<TId>>> dictionary2 = new Dictionary<string, List<NetworkChild<TId>>>(StringComparer.Ordinal); foreach (KeyValuePair<TId, string> portal in portals) { PortalTag portalTag = PortalTag.Parse(portal.Value); if (portalTag.Kind == PortalTagKind.Parent) { Bucket(dictionary, portalTag.Network).Add(portal.Key); } else if (portalTag.Kind == PortalTagKind.Child) { Bucket(dictionary2, portalTag.Network).Add(new NetworkChild<TId>(portal.Key, portalTag.Label)); } } List<string> list = new List<string>(); NetworkPlan<TId> networkPlan = new NetworkPlan<TId>(list); int count = Math.Max(1, maxChildren); foreach (KeyValuePair<string, List<NetworkChild<TId>>> item in dictionary2) { if (!dictionary.TryGetValue(item.Key, out var value)) { continue; } if (value.Count > 1) { list.Add(item.Key); continue; } List<NetworkChild<TId>> list2 = item.Value.OrderBy((NetworkChild<TId> c) => c.Label, LabelOrder.Instance).ToList(); List<NetworkChild<TId>> list3 = list2.Take(count).ToList(); TId val = value[0]; networkPlan._byParent[val] = new Network<TId>(item.Key, val, list3, list2.Count - list3.Count); networkPlan._targets[val] = list3[0].Id; foreach (NetworkChild<TId> item2 in list3) { networkPlan._targets[item2.Id] = val; } } return networkPlan; } private static List<T> Bucket<T>(Dictionary<string, List<T>> map, string key) { if (!map.TryGetValue(key, out var value)) { value = (map[key] = new List<T>()); } return value; } } public enum PortalTagKind { None, Parent, Child } public sealed class PortalTag { private static readonly PortalTag NoneTag = new PortalTag(PortalTagKind.None, "", ""); public PortalTagKind Kind { get; } public string Network { get; } public string Label { get; } private PortalTag(PortalTagKind kind, string network, string label) { Kind = kind; Network = network; Label = label; } public static PortalTag Parse(string text) { string text2 = (text ?? "").Trim(); if (text2.Length == 0 || text2[0] != '(') { return NoneTag; } int num = text2.IndexOf(')'); if (num < 0) { return NoneTag; } string text3 = text2.Substring(1, num - 1).Trim(); if (text3.Length == 0) { return NoneTag; } string text4 = text2.Substring(num + 1).Trim(); return new PortalTag((text4.Length == 0) ? PortalTagKind.Parent : PortalTagKind.Child, text3, text4); } } }