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 PortalLimit v0.1.4
BepInEx\config\AzuAntiCheat_Whitelist\PortalLimitClient.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace PortalLimit.Client; [BepInPlugin("keith.valheim.portallimit.client", "Portal Limit and Discovery Client", "0.1.4")] public class PortalLimitClientPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Chat), "InputText")] private static class ChatInputPatch { private static bool Prefix(Chat __instance) { string a = (((Object)(object)((Terminal)__instance).m_input != (Object)null) ? ((TMP_InputField)((Terminal)__instance).m_input).text : string.Empty); if (string.Equals(a, "/portals", StringComparison.OrdinalIgnoreCase)) { if ((Object)(object)Instance != (Object)null) { Instance.RequestCountForChat(); } if ((Object)(object)((Terminal)__instance).m_input != (Object)null) { ((TMP_InputField)((Terminal)__instance).m_input).text = string.Empty; } __instance.Hide(); return false; } if (!string.Equals(a, "/portallimit", StringComparison.OrdinalIgnoreCase)) { return true; } if ((Object)(object)Instance != (Object)null) { Instance.ToggleAdminWindow(); } if ((Object)(object)((Terminal)__instance).m_input != (Object)null) { ((TMP_InputField)((Terminal)__instance).m_input).text = string.Empty; } __instance.Hide(); return false; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class PlacePiecePatch { private static bool Prefix(Piece piece, ref bool __result) { if (!WouldExceedPortalLimit(piece)) { return true; } __result = false; Instance.ShowMessage("Portal limit reached: " + Instance.maxPortalsPerPlayer + " portal(s) per player."); Instance.RequestCount(); return false; } private static void Postfix(Piece piece, bool __result) { if (__result && (Object)(object)Instance != (Object)null && (Object)(object)piece != (Object)null && Instance.IsLimitedPortal(piece)) { Instance.ReportPortalMetadata(piece, "placed"); Instance.RequestPlacementCountSoon(); } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] private static class PieceCanBeRemovedPatch { private static void Postfix(Piece __instance, ref bool __result) { if (__result && !((Object)(object)Instance == (Object)null) && !((Object)(object)__instance == (Object)null) && Instance.IsLimitedPortal(__instance)) { long creator = __instance.GetCreator(); long localPlayerId = GetLocalPlayerId(); if (!Instance.isAdmin && creator != 0 && creator != localPlayerId) { __result = false; Instance.ShowMessage("Only the builder or an admin can remove this portal."); } } } } [HarmonyPatch(typeof(TeleportWorld), "Interact")] private static class TeleportWorldInteractPatch { private static bool Prefix(TeleportWorld __instance, Humanoid human, bool hold, ref bool __result) { if ((Object)(object)Instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)human != (Object)(object)Player.m_localPlayer) { return true; } if (Instance.replayingVanillaPortalInteract) { return true; } if (Instance.isAdmin && Instance.adminHoldEToEdit && !hold) { Instance.BeginDelayedPortalInteract(__instance); __result = false; return false; } if (hold && Instance.isAdmin && Instance.adminHoldEToEdit) { Instance.OpenAdminWindowForPortal(__instance); Instance.ResetHoldInteract(); __result = false; return false; } if (!hold && ShouldBlockPortalUse(__instance)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] private static class TeleportWorldTeleportPatch { private static bool Prefix(TeleportWorld __instance, Player player) { if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } bool flag = !ShouldBlockBlankPortalUse(__instance) && !ShouldBlockPortalUse(__instance); if (flag && (Object)(object)Instance != (Object)null) { Instance.ReportPortalMetadata(__instance, "used"); } return flag; } } [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] private static class TeleportWorldHoverTextPatch { private static void Postfix(TeleportWorld __instance, ref string __result) { if ((Object)(object)Instance == (Object)null) { return; } if (string.IsNullOrWhiteSpace(GetPortalTag(__instance)) && !string.IsNullOrEmpty(__result)) { __result = __result.Replace(" [CONNECTED]", string.Empty).Replace("[CONNECTED]", string.Empty); } if (Instance.isAdmin) { if (Instance.adminHoldEToEdit) { __result += "\n<color=yellow>Hold E: Portal Limit settings</color>"; } string portalCreatorName = GetPortalCreatorName(__instance); if (!string.IsNullOrWhiteSpace(portalCreatorName)) { __result = __result + "\n<color=#ffd27a>Built by: " + portalCreatorName + "</color>"; } } if (!Instance.discoveryEnabled || (!Instance.showDiscoveryHoverText && !Instance.isAdmin)) { return; } int discoveryRole = GetDiscoveryRole(__instance); if (discoveryRole == 0) { return; } string discoveryLink = GetDiscoveryLink(__instance); if (string.IsNullOrWhiteSpace(discoveryLink)) { return; } string text = string.Empty; if (Instance.IsDiscoveryUnlocked(discoveryLink)) { text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryUnlockedHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryUnlockedHoverText; } } else { switch (discoveryRole) { case 1: text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryLockedHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryLockedHoverText; } break; case 2: text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryRemoteHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryRemoteHoverText; } break; } } if (!string.IsNullOrWhiteSpace(text)) { __result = __result + "\n<color=orange>" + text + "</color>"; } } } [HarmonyPatch(typeof(TeleportWorld), "TargetFound")] private static class TeleportWorldTargetFoundPatch { private static void Postfix(TeleportWorld __instance, ref bool __result) { if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { __result = false; SetTargetFound(__instance, value: false); } } } [HarmonyPatch(typeof(TeleportWorld), "HaveTarget")] private static class TeleportWorldHaveTargetPatch { private static void Postfix(TeleportWorld __instance, ref bool __result) { if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { __result = false; } } } [HarmonyPatch(typeof(TeleportWorld), "Update")] private static class TeleportWorldVisualPatch { private static void Postfix(TeleportWorld __instance) { if (!((Object)(object)__instance == (Object)null)) { PortalLimitDiscoveryVisual portalLimitDiscoveryVisual = ((Component)__instance).GetComponent<PortalLimitDiscoveryVisual>(); if ((Object)(object)portalLimitDiscoveryVisual == (Object)null) { portalLimitDiscoveryVisual = ((Component)__instance).gameObject.AddComponent<PortalLimitDiscoveryVisual>(); } portalLimitDiscoveryVisual.Refresh(__instance); } } } private class PortalLimitDiscoveryVisual : MonoBehaviour { private GameObject markerRoot; private TextMesh markerText; private Renderer[] portalRenderers; private ParticleSystem[] portalParticles; private Light[] portalLights; private readonly Dictionary<Renderer, Color> originalColors = new Dictionary<Renderer, Color>(); private readonly Dictionary<ParticleSystem, bool> originalParticleStates = new Dictionary<ParticleSystem, bool>(); private readonly Dictionary<Light, bool> originalLightStates = new Dictionary<Light, bool>(); internal void Refresh(TeleportWorld portal) { //IL_0052: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance == (Object)null) && !((Object)(object)portal == (Object)null)) { bool flag = Instance.ShouldShowDiscoveryWorldMarker(portal); bool enabled = Instance.ShouldTintDiscoveryPortal(portal); bool suppress = Instance.ShouldSuppressLockedPortalGlow(portal); Color discoveryVisualColor = Instance.GetDiscoveryVisualColor(portal); EnsureMarker(); markerRoot.SetActive(flag); if (flag) { SetMarkerWorldPose(portal); SetMarkerText(Instance.GetDiscoveryMarkerDisplayText(portal)); SetMarkerColor(discoveryVisualColor); } UpdatePortalTint(enabled, discoveryVisualColor); UpdatePortalEffects(suppress); } } private void EnsureMarker() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)markerRoot != (Object)null)) { markerRoot = new GameObject("PortalLimit_DiscoveryMarker"); markerRoot.transform.SetParent(((Component)this).transform, false); markerRoot.transform.localPosition = new Vector3(0f, 1.55f, 0f); markerRoot.transform.localRotation = Quaternion.identity; markerRoot.transform.localScale = Vector3.one; markerText = markerRoot.AddComponent<TextMesh>(); markerText.text = "UNLOCK ON OTHER SIDE"; markerText.anchor = (TextAnchor)4; markerText.alignment = (TextAlignment)1; markerText.fontSize = 96; markerText.characterSize = 0.01f; markerText.richText = false; SetMarkerColor(LockedOrange); markerRoot.SetActive(false); } } private void SetMarkerText(string text) { if (!((Object)(object)markerText == (Object)null)) { markerText.text = text; if (string.Equals(text, "X", StringComparison.Ordinal)) { markerText.fontSize = 128; markerText.characterSize = 0.03f; } else if (string.Equals(text, "LOCKED", StringComparison.Ordinal)) { markerText.fontSize = 96; markerText.characterSize = 0.018f; } else { markerText.fontSize = 96; markerText.characterSize = 0.01f; } } } private void SetMarkerColor(Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)markerText != (Object)null) { markerText.color = color; } } private void SetMarkerWorldPose(TeleportWorld portal) { //IL_002d: 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_003c: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0069: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)markerRoot == (Object)null || (Object)(object)portal == (Object)null) { return; } Vector3 val = ((Component)portal).transform.position + Vector3.up * 1.55f; if ((Object)(object)Camera.main != (Object)null) { Vector3 val2 = ((Component)Camera.main).transform.position - val; if (((Vector3)(ref val2)).sqrMagnitude > 0.001f) { markerRoot.transform.position = val + ((Vector3)(ref val2)).normalized * 0.45f; markerRoot.transform.rotation = Quaternion.LookRotation(-((Vector3)(ref val2)).normalized, Vector3.up); return; } } markerRoot.transform.position = val; markerRoot.transform.rotation = ((Component)portal).transform.rotation; } private void UpdatePortalTint(bool enabled, Color color) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (portalRenderers == null) { portalRenderers = ((Component)this).GetComponentsInChildren<Renderer>(true); } Renderer[] array = portalRenderers; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Component)val).transform.IsChildOf(markerRoot.transform)) { if (!originalColors.ContainsKey(val)) { originalColors[val] = (val.material.HasProperty("_Color") ? val.material.color : Color.white); } if (val.material.HasProperty("_Color")) { val.material.color = (enabled ? Color.Lerp(originalColors[val], color, 0.45f) : originalColors[val]); } } } } private void UpdatePortalEffects(bool suppress) { ParticleSystem[] array; if (portalParticles == null) { portalParticles = ((Component)this).GetComponentsInChildren<ParticleSystem>(true); array = portalParticles; foreach (ParticleSystem val in array) { if ((Object)(object)val != (Object)null) { originalParticleStates[val] = ((Component)val).gameObject.activeSelf; } } } Light[] array2; if (portalLights == null) { portalLights = ((Component)this).GetComponentsInChildren<Light>(true); array2 = portalLights; foreach (Light val2 in array2) { if ((Object)(object)val2 != (Object)null) { originalLightStates[val2] = ((Behaviour)val2).enabled; } } } array = portalParticles; foreach (ParticleSystem val in array) { if (!((Object)(object)val == (Object)null) && !((Component)val).transform.IsChildOf(markerRoot.transform)) { if (!originalParticleStates.TryGetValue(val, out var value)) { value = true; } ((Component)val).gameObject.SetActive(!suppress && value); if (!suppress && value && !val.isPlaying) { val.Play(true); } } } array2 = portalLights; foreach (Light val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Component)val2).transform.IsChildOf(markerRoot.transform)) { if (!originalLightStates.TryGetValue(val2, out var value2)) { value2 = true; } ((Behaviour)val2).enabled = !suppress && value2; } } } } public const string PluginGuid = "keith.valheim.portallimit.client"; public const string PluginName = "Portal Limit and Discovery Client"; public const string PluginVersion = "0.1.4"; private const string RpcConfigRequest = "keith.valheim.portallimit.config_request"; private const string RpcConfigResponse = "keith.valheim.portallimit.config_response"; private const string RpcConfigUpdate = "keith.valheim.portallimit.config_update"; private const string RpcCountRequest = "keith.valheim.portallimit.count_request"; private const string RpcCountResponse = "keith.valheim.portallimit.count_response"; private const string RpcNotice = "keith.valheim.portallimit.notice"; private const string RpcDiscoveryMarkRequest = "keith.valheim.portallimit.discovery_mark_request"; private const string RpcDiscoveryUnlockRequest = "keith.valheim.portallimit.discovery_unlock_request"; private const string RpcDiscoveryRelockRequest = "keith.valheim.portallimit.discovery_relock_request"; private const string RpcDiscoveryUnlockListRequest = "keith.valheim.portallimit.discovery_unlock_list_request"; private const string RpcDiscoveryUnlockListResponse = "keith.valheim.portallimit.discovery_unlock_list_response"; private const string RpcAdminReportRequest = "keith.valheim.portallimit.admin_report_request"; private const string RpcAdminReportResponse = "keith.valheim.portallimit.admin_report_response"; private const string RpcPortalMetadataUpdate = "keith.valheim.portallimit.portal_metadata_update"; private const string DiscoveryRoleKey = "PortalLimit_DiscoveryRole"; private const string DiscoveryLinkKey = "PortalLimit_DiscoveryLink"; private const string DiscoveryColorKey = "PortalLimit_DiscoveryColor"; private const string DiscoveryMarkerTextKey = "PortalLimit_DiscoveryMarkerText"; private const string DiscoveryShowMarkerKey = "PortalLimit_DiscoveryShowMarker"; private const string DiscoverySuppressGlowKey = "PortalLimit_DiscoverySuppressGlow"; private const string DiscoveryLockedHoverTextKey = "PortalLimit_DiscoveryLockedHoverText"; private const string DiscoveryRemoteHoverTextKey = "PortalLimit_DiscoveryRemoteHoverText"; private const string DiscoveryUnlockedHoverTextKey = "PortalLimit_DiscoveryUnlockedHoverText"; private const string PortalBuiltUtcKey = "PortalLimit_BuiltUtc"; private const int DiscoveryRoleNone = 0; private const int DiscoveryRoleLocked = 1; private const int DiscoveryRoleRemote = 2; internal static PortalLimitClientPlugin Instance; internal static ManualLogSource Log; private static readonly FieldInfo AllPiecesField = AccessTools.Field(typeof(Piece), "s_allPieces"); private static readonly FieldInfo TeleportWorldTargetFoundField = AccessTools.Field(typeof(TeleportWorld), "m_target_found"); private static readonly MethodInfo GetPlayerIdMethod = AccessTools.Method(typeof(Player), "GetPlayerID", (Type[])null, (Type[])null); private static readonly MethodInfo GetPrefabNameMethod = AccessTools.Method(typeof(ZNetView), "GetPrefabName", (Type[])null, (Type[])null); private static readonly Color LockedOrange = new Color(1f, 0.6235294f, 0.1019608f, 1f); private static readonly string[] MarkerColorLabels = new string[8] { "RED", "ORANGE", "YELLOW", "GREEN", "BLUE", "PURPLE", "WHITE", "BLACK" }; private static readonly string[] MarkerColorValues = new string[8] { "#ff3030", "#ff9f1a", "#ffd84a", "#42ff68", "#38a6ff", "#b05cff", "#ffffff", "#000000" }; private static readonly string[] PortalRoleChoiceLabels = new string[3] { "NORMAL PORTAL", "LOCKED ENTRANCE", "UNLOCKED ENTRANCE" }; private static readonly string[] MarkerTextLabels = new string[3] { "UNLOCK ON OTHER SIDE", "LOCKED", "X" }; private static readonly string[] MarkerTextValues = new string[3] { "UnlockOnOtherSide", "Locked", "X" }; private Harmony harmony; private bool rpcRegistered; private bool configRequested; private bool showCountMessageOnNextResponse; private bool showPlacementCountOnNextResponse; private bool openAdminUiAfterPermissionCheck; private bool adminStatusKnown; private bool isAdmin; private bool adminBypass = true; private bool enforceOnServer = true; private int maxPortalsPerPlayer = 10; private string portalPrefabNames = "portal_wood,portal_stone"; private bool discoveryEnabled = true; private bool discoveryAdminBypass = true; private bool adminHoldEToEdit = true; private bool showDiscoveryHoverText = true; private string discoveryLockedHoverText = "Locked: find the other end first."; private string discoveryRemoteHoverText = "Discovery portal: use this side to unlock the route."; private string discoveryUnlockedHoverText = "Discovery route unlocked."; private string discoveryLockedMessage = "This portal is locked. Find and enter the other end first."; private string discoveryUnlockMessage = "Discovery portal unlocked."; private bool discoveryShowWorldMarker = true; private bool discoveryTintPortalModel; private bool discoverySuppressLockedGlow; private string discoveryLockedColor = "#ff9f1a"; private string discoveryRemoteColor = "#38a6ff"; private string discoveryUnlockedColor = "#42ff68"; private readonly HashSet<string> unlockedDiscoveryLinks = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private int serverPortalCount; private Rect adminWindow = new Rect(120f, 60f, 700f, 720f); private Vector2 adminScroll; private Vector2 portalInfoThisScroll; private Vector2 portalInfoWorldScroll; private bool showAdminWindow; private int adminTab; private string openDropdown = string.Empty; private bool portalInfoShowThis; private bool portalInfoShowWorld; private string portalInfoThisText = "Open this tab while editing a portal."; private string portalInfoWorldText = "Click Refresh to load world portal information."; private string portalInfoRequestedPortalKey = string.Empty; private int selectedPortalRole; private string loadedPortalKey = string.Empty; private TeleportWorld selectedPortal; private string maxText = "10"; private string portalNamesText = "portal_wood,portal_stone"; private string discoveryLinkText = string.Empty; private string selectedPortalColorText = "#ff9f1a"; private int selectedPortalColorIndex; private string selectedPortalMarkerText = "UNLOCK ON OTHER SIDE"; private bool selectedPortalShowMarker = true; private bool selectedPortalSuppressGlow; private string selectedLockedHoverText = string.Empty; private string selectedRemoteHoverText = string.Empty; private string selectedUnlockedHoverText = string.Empty; private string discoveryLockedHoverTextField = "Locked: find the other end first."; private string discoveryRemoteHoverTextField = "Discovery portal: use this side to unlock the route."; private string discoveryUnlockedHoverTextField = "Discovery route unlocked."; private string discoveryLockedMessageField = "This portal is locked. Find and enter the other end first."; private string discoveryUnlockMessageField = "Discovery portal unlocked."; private int selectedPortalMarkerTextIndex; private TeleportWorld holdInteractPortal; private float holdInteractStartedAt; private bool holdInteractOpened; private bool replayingVanillaPortalInteract; private string discoveryLockedColorField = "#ff9f1a"; private string discoveryRemoteColorField = "#38a6ff"; private string discoveryUnlockedColorField = "#42ff68"; private string statusMessage = "Use /portallimit to load server settings."; private bool adminStylesReady; private Texture2D adminWindowTexture; private Texture2D adminHeaderTexture; private Texture2D adminSectionTexture; private Texture2D adminInputTexture; private Texture2D adminButtonTexture; private Texture2D adminButtonHoverTexture; private Texture2D adminTabTexture; private Texture2D adminTabSelectedTexture; private GUIStyle adminWindowStyle; private GUIStyle adminTitleStyle; private GUIStyle adminLabelStyle; private GUIStyle adminHelpStyle; private GUIStyle adminSectionStyle; private GUIStyle adminButtonStyle; private GUIStyle adminTabStyle; private GUIStyle adminTabSelectedStyle; private GUIStyle adminTextFieldStyle; private GUIStyle adminBoxStyle; private ConfigEntry<KeyCode> toggleAdminUiKey; private void Awake() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (IsDedicatedServerProcess()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Portal Limit Client disabled on the dedicated server process."); ((Behaviour)this).enabled = false; return; } Instance = this; Log = ((BaseUnityPlugin)this).Logger; toggleAdminUiKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ToggleAdminUIKey", (KeyCode)291, "Key used to open the portal limit admin UI."); harmony = new Harmony("keith.valheim.portallimit.client"); harmony.PatchAll(); RegisterConsoleCommands(); ((MonoBehaviour)this).InvokeRepeating("TryRegisterRpcs", 1f, 1f); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } DestroyAdminTexture(adminWindowTexture); DestroyAdminTexture(adminHeaderTexture); DestroyAdminTexture(adminSectionTexture); DestroyAdminTexture(adminInputTexture); DestroyAdminTexture(adminButtonTexture); DestroyAdminTexture(adminButtonHoverTexture); DestroyAdminTexture(adminTabTexture); DestroyAdminTexture(adminTabSelectedTexture); } private static bool IsDedicatedServerProcess() { string processName = Process.GetCurrentProcess().ProcessName; return processName.StartsWith("valheim_server", StringComparison.OrdinalIgnoreCase); } private void TryRegisterRpcs() { if (!rpcRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.config_response", (Action<long, string>)OnConfigResponse); ZRoutedRpc.instance.Register<int, int, bool, string>("keith.valheim.portallimit.count_response", (Method<int, int, bool, string>)OnCountResponse); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.notice", (Action<long, string>)OnNotice); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.discovery_unlock_list_response", (Action<long, string>)OnDiscoveryUnlockListResponse); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.admin_report_response", (Action<long, string>)OnAdminReportResponse); rpcRegistered = true; ((MonoBehaviour)this).CancelInvoke("TryRegisterRpcs"); } } private static void RegisterConsoleCommands() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("portallimit", "Portal Limit commands. Use: portallimit, portallimit count, portallimit counts, portallimit portals, portallimit export", new ConsoleEvent(OnConsolePortalLimit), false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void OnConsolePortalLimit(ConsoleEventArgs args) { if ((Object)(object)Instance == (Object)null) { Terminal.Log((object)"Portal Limit client is not ready."); return; } string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "help"); if (text == "help") { Terminal.Log((object)"Portal Limit F5 commands:"); Terminal.Log((object)" portallimit count - show your portal count"); Terminal.Log((object)" portallimit counts - admin: show counts for all players"); Terminal.Log((object)" portallimit portals - admin: list known portals with names and coordinates"); Terminal.Log((object)" portallimit export - admin: rewrite report files on the server"); Terminal.Log((object)"Regular players can also type /portals in normal chat."); } else if (text == "count") { Instance.showCountMessageOnNextResponse = true; Instance.RequestCount(); Terminal.Log((object)"Portal Limit: checking your portal count..."); } else if (text != "counts" && text != "portals" && text != "export") { Terminal.Log((object)"Unknown Portal Limit command. Use: portallimit"); } else if (ZRoutedRpc.instance == null) { Terminal.Log((object)"Portal Limit server RPC is not ready yet."); } else { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.admin_report_request", new object[1] { text }); Terminal.Log((object)("Portal Limit: requesting " + text + " report...")); } } private void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (rpcRegistered && !((Object)(object)ZNet.instance == (Object)null)) { if (!configRequested && (Object)(object)Player.m_localPlayer != (Object)null) { RequestConfig(openUi: false); } if (Input.GetKeyDown(toggleAdminUiKey.Value)) { ToggleAdminWindow(); } UpdateHoldInteractAdminOpen(); } } private void UpdateHoldInteractAdminOpen() { if (!isAdmin || !adminHoldEToEdit || showAdminWindow || (Object)(object)Player.m_localPlayer == (Object)null) { ResetHoldInteract(); } else if ((Object)(object)holdInteractPortal == (Object)null) { TeleportWorld hoveredPortal = GetHoveredPortal(); if ((Object)(object)hoveredPortal != (Object)null && Input.GetKey((KeyCode)101)) { BeginDelayedPortalInteract(hoveredPortal); } } else if (!Input.GetKey((KeyCode)101)) { TeleportWorld val = holdInteractPortal; bool flag = !holdInteractOpened && Time.unscaledTime - holdInteractStartedAt < 0.45f; ResetHoldInteract(); if (flag && (Object)(object)val != (Object)null) { ReplayVanillaPortalInteract(val); } } else if (!holdInteractOpened && Time.unscaledTime - holdInteractStartedAt >= 0.45f) { holdInteractOpened = true; OpenAdminWindowForPortal(holdInteractPortal); } } private void BeginDelayedPortalInteract(TeleportWorld portal) { holdInteractPortal = portal; holdInteractStartedAt = Time.unscaledTime; holdInteractOpened = false; } private void ResetHoldInteract() { holdInteractPortal = null; holdInteractStartedAt = 0f; holdInteractOpened = false; } private void ReplayVanillaPortalInteract(TeleportWorld portal) { if ((Object)(object)portal == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } replayingVanillaPortalInteract = true; try { portal.Interact((Humanoid)(object)Player.m_localPlayer, false, false); } finally { replayingVanillaPortalInteract = false; } } private void OnGUI() { //IL_0025: 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_0045: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (showAdminWindow) { EnsureAdminStyles(); CenterAdminWindowIfNeeded(); adminWindow = GUI.Window(((Object)this).GetInstanceID(), adminWindow, new WindowFunction(DrawAdminWindow), GUIContent.none, GUIStyle.none); } } private void CenterAdminWindowIfNeeded() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(760f, (float)Screen.width - 40f); float num2 = Mathf.Min(680f, (float)Screen.height - 40f); if (Math.Abs(((Rect)(ref adminWindow)).width - num) > 0.1f || Math.Abs(((Rect)(ref adminWindow)).height - num2) > 0.1f) { adminWindow = new Rect(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2); } } private void DrawAdminWindow(int id) { //IL_0028: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) EnsureAdminStyles(); GUI.Box(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, ((Rect)(ref adminWindow)).height), GUIContent.none, adminWindowStyle); GUI.Box(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, 42f), GUIContent.none, adminSectionStyle); GUI.Label(new Rect(18f, 9f, ((Rect)(ref adminWindow)).width - 36f, 28f), "Portal Limit Admin", adminTitleStyle); if (GUI.Button(new Rect(((Rect)(ref adminWindow)).width - 38f, 8f, 28f, 26f), "X", adminButtonStyle)) { showAdminWindow = false; return; } GUILayout.BeginArea(new Rect(16f, 48f, ((Rect)(ref adminWindow)).width - 32f, ((Rect)(ref adminWindow)).height - 62f)); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(statusMessage, adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (isAdmin) { DrawAdminTabs(); adminScroll = GUILayout.BeginScrollView(adminScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(Math.Max(220f, ((Rect)(ref adminWindow)).height - 145f)) }); if (adminTab == 0) { DrawServerSettingsTab(); } else if (adminTab == 1) { DrawPortalSettingsTab(); } else { DrawPortalInformationTab(); } GUILayout.EndScrollView(); if (adminTab == 2) { DrawInformationFooter(); } else { DrawAdminFooter(); } } else { GUILayout.Label("You need to be on the Valheim admin list to edit this.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } } GUILayout.EndVertical(); GUILayout.EndArea(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, 42f)); } private void EnsureAdminStyles() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Expected O, but got Unknown //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Expected O, but got Unknown //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Expected O, but got Unknown //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Expected O, but got Unknown //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Expected O, but got Unknown //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Expected O, but got Unknown //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Expected O, but got Unknown //IL_0539: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Expected O, but got Unknown //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0579: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_05a8: Expected O, but got Unknown //IL_05b4: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Expected O, but got Unknown //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Expected O, but got Unknown //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Expected O, but got Unknown //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_0614: Expected O, but got Unknown if (!adminStylesReady) { adminWindowTexture = MakeAdminTexture(new Color(0.03f, 0.026f, 0.022f, 0.98f)); adminHeaderTexture = MakeAdminTexture(new Color(0.18f, 0.115f, 0.065f, 0.98f)); adminSectionTexture = MakeAdminTexture(new Color(0.13f, 0.085f, 0.052f, 0.96f)); adminInputTexture = MakeAdminBorderTexture(new Color(0.12f, 0.105f, 0.08f, 1f), new Color(1f, 0.78f, 0.26f, 1f)); adminButtonTexture = MakeAdminTexture(new Color(0.25f, 0.24f, 0.21f, 0.98f)); adminButtonHoverTexture = MakeAdminTexture(new Color(0.36f, 0.31f, 0.23f, 0.98f)); adminTabTexture = MakeAdminTexture(new Color(0.16f, 0.14f, 0.12f, 0.98f)); adminTabSelectedTexture = MakeAdminTexture(new Color(0.45f, 0.31f, 0.14f, 0.98f)); adminWindowStyle = new GUIStyle(GUI.skin.box); adminWindowStyle.normal.background = adminWindowTexture; adminWindowStyle.border = new RectOffset(8, 8, 8, 8); adminWindowStyle.padding = new RectOffset(14, 14, 14, 14); adminTitleStyle = new GUIStyle(GUI.skin.label); adminTitleStyle.fontSize = 18; adminTitleStyle.fontStyle = (FontStyle)1; adminTitleStyle.alignment = (TextAnchor)4; adminTitleStyle.normal.textColor = new Color(0.95f, 0.83f, 0.55f, 1f); adminLabelStyle = new GUIStyle(GUI.skin.label); adminLabelStyle.fontSize = 14; adminLabelStyle.wordWrap = true; adminLabelStyle.normal.textColor = new Color(0.88f, 0.84f, 0.74f, 1f); adminHelpStyle = new GUIStyle(adminLabelStyle); adminHelpStyle.fontSize = 13; adminHelpStyle.normal.textColor = new Color(0.67f, 0.64f, 0.56f, 1f); adminSectionStyle = new GUIStyle(GUI.skin.box); adminSectionStyle.normal.background = adminSectionTexture; adminSectionStyle.border = new RectOffset(4, 4, 4, 4); adminSectionStyle.padding = new RectOffset(8, 8, 4, 4); adminSectionStyle.normal.textColor = new Color(0.98f, 0.82f, 0.43f, 1f); adminSectionStyle.alignment = (TextAnchor)3; adminSectionStyle.fontStyle = (FontStyle)1; adminSectionStyle.fontSize = 15; adminButtonStyle = new GUIStyle(GUI.skin.button); adminButtonStyle.normal.background = adminButtonTexture; adminButtonStyle.hover.background = adminButtonHoverTexture; adminButtonStyle.active.background = adminTabSelectedTexture; adminButtonStyle.normal.textColor = new Color(0.9f, 0.86f, 0.76f, 1f); adminButtonStyle.hover.textColor = new Color(1f, 0.9f, 0.58f, 1f); adminButtonStyle.active.textColor = Color.white; adminButtonStyle.fontSize = 13; adminButtonStyle.padding = new RectOffset(8, 8, 5, 5); adminButtonStyle.margin = new RectOffset(3, 3, 3, 3); adminTabStyle = new GUIStyle(adminButtonStyle); adminTabStyle.normal.background = adminTabTexture; adminTabStyle.fontStyle = (FontStyle)1; adminTabSelectedStyle = new GUIStyle(adminButtonStyle); adminTabSelectedStyle.normal.background = adminTabSelectedTexture; adminTabSelectedStyle.normal.textColor = Color.white; adminTabSelectedStyle.fontStyle = (FontStyle)1; adminTextFieldStyle = new GUIStyle(GUI.skin.textField); adminTextFieldStyle.normal.background = adminInputTexture; adminTextFieldStyle.focused.background = adminInputTexture; adminTextFieldStyle.hover.background = adminInputTexture; adminTextFieldStyle.border = new RectOffset(4, 4, 4, 4); adminTextFieldStyle.normal.textColor = new Color(1f, 0.98f, 0.86f, 1f); adminTextFieldStyle.focused.textColor = Color.white; adminTextFieldStyle.fontSize = 15; adminTextFieldStyle.padding = new RectOffset(12, 12, 8, 8); adminTextFieldStyle.margin = new RectOffset(3, 3, 5, 10); adminBoxStyle = new GUIStyle(GUI.skin.box); adminBoxStyle.normal.background = adminHeaderTexture; adminBoxStyle.padding = new RectOffset(6, 6, 6, 6); adminBoxStyle.margin = new RectOffset(0, 0, 2, 8); adminStylesReady = true; } } private static Texture2D MakeAdminTexture(Color color) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, color); val.Apply(); return val; } private static Texture2D MakeAdminBorderTexture(Color fill, Color border) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0037: 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) Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { bool flag = j < 2 || i < 2 || j > 13 || i > 13; val.SetPixel(j, i, flag ? border : fill); } } val.Apply(); return val; } private static void DestroyAdminTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } private void DrawAdminTabs() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Server Settings", (adminTab == 0) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 0; openDropdown = string.Empty; } if (GUILayout.Button("This Portal", (adminTab == 1) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 1; openDropdown = string.Empty; } if (GUILayout.Button("Portal Information", (adminTab == 2) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 2; openDropdown = string.Empty; RequestPortalInformation(showStatus: false); } GUILayout.EndHorizontal(); } private void DrawSectionHeader(string text) { GUILayout.Box(text, adminSectionStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(30f) }); } private void DrawServerSettingsTab() { GUILayout.Space(8f); DrawSectionHeader("Portal Limit"); GUILayout.Label("How many counted portals may each non-admin player own? Use 0 for no limit.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); maxText = GUILayout.TextField(maxText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); adminBypass = DrawBoolDropdown("adminBypass", "Admin portal limit bypass", adminBypass, "Allowed", "Not allowed"); enforceOnServer = DrawBoolDropdown("enforceOnServer", "Server removes extra portals over the limit", enforceOnServer, "Enabled", "Disabled"); GUILayout.Label("Which portal types count toward the limit?", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Default covers normal wood and stone portals. Empty means every portal-like object.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); portalNamesText = GUILayout.TextField(portalNamesText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Your current portal count: " + serverPortalCount + " / " + maxPortalsPerPlayer, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(12f); DrawSectionHeader("Discovery Portals"); GUILayout.Label("These settings apply to every locked discovery portal pair.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryEnabled = DrawBoolDropdown("discoveryEnabled", "Locked discovery portals", discoveryEnabled, "Enabled", "Disabled"); discoveryAdminBypass = DrawBoolDropdown("discoveryAdminBypass", "Admin bypass for locked discovery portals", discoveryAdminBypass, "Allowed", "Not allowed"); adminHoldEToEdit = DrawBoolDropdown("adminHoldEToEdit", "Admin hold E portal editor", adminHoldEToEdit, "Enabled", "Disabled"); GUILayout.Label("When enabled, admins can hold E on a portal to edit that portal. Tap E still opens Valheim's normal Set Tag box.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); showDiscoveryHoverText = DrawBoolDropdown("showDiscoveryHoverText", "Lock/unlock hover text", showDiscoveryHoverText, "Shown", "Hidden"); GUILayout.Space(12f); DrawSectionHeader("Default Player-Facing Hover Text"); GUILayout.Label("These are the server defaults. A locked portal can override them on its own This Portal tab.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Locked entrance text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryLockedHoverTextField = GUILayout.TextField(discoveryLockedHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Unlocked entrance text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryRemoteHoverTextField = GUILayout.TextField(discoveryRemoteHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("After unlocked text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryUnlockedHoverTextField = GUILayout.TextField(discoveryUnlockedHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } private void DrawPortalSettingsTab() { GUILayout.Space(8f); TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { DrawSectionHeader("This Portal"); GUILayout.Label("No portal was opened.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Look at a portal and hold E to open settings for that exact portal.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); return; } int discoveryRole = GetDiscoveryRole(val); string portalTagForUi = GetPortalTagForUi(val); GUILayout.Label("Portal tag", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Use the same tag on both portals, for example: Bog Witch.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (CanEditPortalTag(val)) { discoveryLinkText = GUILayout.TextField(discoveryLinkText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else { GUILayout.Label(discoveryLinkText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("This portal was built by another player. Admins can edit Portal Limit settings, but the portal tag stays protected.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Space(8f); DrawSectionHeader("This portal"); GUILayout.Label("Current: " + GetPortalRoleLabel(discoveryRole).ToUpperInvariant() + " | Tag: " + (string.IsNullOrWhiteSpace(portalTagForUi) ? "(NONE)" : portalTagForUi), adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedPortalRole = DrawInlineChoice("selectedPortalRole", selectedPortalRole, PortalRoleChoiceLabels); int selectedPortalRoleValue = GetSelectedPortalRoleValue(); if (selectedPortalRoleValue != 0) { GUILayout.Space(10f); DrawSectionHeader("Relock Portal Tag"); GUILayout.Label("For this portal tag, make every player discover the unlocked entrance again.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); bool flag2 = (GUI.enabled = !string.IsNullOrWhiteSpace(discoveryLinkText)); if (GUILayout.Button("Relock this portal tag for players", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RelockSelectedDiscoveryPortal(); } GUI.enabled = true; if (!flag2) { GUILayout.Label("Enter a portal tag before relocking players.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } switch (selectedPortalRoleValue) { case 1: { GUILayout.Space(10f); DrawSectionHeader("Locked Entrance Options"); selectedPortalShowMarker = DrawBoolInline("Unlock message marker", selectedPortalShowMarker, "SHOWN", "HIDDEN"); selectedPortalSuppressGlow = !DrawBoolInline("Orange glow while locked", !selectedPortalSuppressGlow, "SHOWN", "HIDDEN"); GUILayout.Space(8f); GUILayout.Label("Marker color", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); int num = selectedPortalColorIndex; selectedPortalColorIndex = DrawInlineChoice("selectedPortalColor", selectedPortalColorIndex, MarkerColorLabels); if (num != selectedPortalColorIndex) { selectedPortalColorText = MarkerColorValues[Mathf.Clamp(selectedPortalColorIndex, 0, MarkerColorValues.Length - 1)]; } selectedPortalColorText = GUILayout.TextField(selectedPortalColorText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(8f); GUILayout.Label("Marker text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); int num2 = selectedPortalMarkerTextIndex; selectedPortalMarkerTextIndex = DrawInlineChoice("selectedPortalMarkerText", selectedPortalMarkerTextIndex, MarkerTextLabels); if (num2 != selectedPortalMarkerTextIndex) { selectedPortalMarkerText = MarkerTextLabels[Mathf.Clamp(selectedPortalMarkerTextIndex, 0, MarkerTextLabels.Length - 1)]; } selectedPortalMarkerText = GUILayout.TextField(selectedPortalMarkerText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(8f); GUILayout.Label("Player-facing hover text for this portal", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedLockedHoverText = GUILayout.TextField(selectedLockedHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); break; } case 2: GUILayout.Space(10f); DrawSectionHeader("Unlocked Entrance Options"); GUILayout.Label("Player-facing hover text for this portal", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedRemoteHoverText = GUILayout.TextField(selectedRemoteHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); break; } if (selectedPortalRoleValue != 0) { GUILayout.Space(10f); DrawSectionHeader("Unlocked Message"); GUILayout.Label("Text players see after they have unlocked this portal tag. Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedUnlockedHoverText = GUILayout.TextField(selectedUnlockedHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } private void DrawPortalInformationTab() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(8f); TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { DrawSectionHeader("Portal Information"); GUILayout.Label("No portal was opened.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Look at a portal and hold E to open settings for that exact portal.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); return; } if (GUILayout.Button("Refresh portal information", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RequestPortalInformation(showStatus: true); } portalInfoShowThis = DrawCollapseHeader(portalInfoShowThis, "THIS PORTAL"); if (portalInfoShowThis) { portalInfoThisScroll = GUILayout.BeginScrollView(portalInfoThisScroll, adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(220f) }); GUILayout.TextArea(portalInfoThisText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(GetTextAreaHeight(portalInfoThisText, 170f)) }); GUILayout.EndScrollView(); } portalInfoShowWorld = DrawCollapseHeader(portalInfoShowWorld, "WORLD PORTALS"); if (portalInfoShowWorld) { portalInfoWorldScroll = GUILayout.BeginScrollView(portalInfoWorldScroll, adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(260f) }); GUILayout.TextArea(portalInfoWorldText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(GetTextAreaHeight(portalInfoWorldText, 220f)) }); GUILayout.EndScrollView(); } } private static float GetTextAreaHeight(string text, float minimum) { int num = 1; if (!string.IsNullOrEmpty(text)) { num = text.Split(new char[1] { '\n' }).Length; } return Math.Max(minimum, 22f + (float)num * 20f); } private bool DrawCollapseHeader(bool expanded, string label) { GUILayout.Space(8f); if (GUILayout.Button((expanded ? "v " : "> ") + label, adminTabSelectedStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { expanded = !expanded; } return expanded; } private bool DrawBoolInline(string label, bool value, string trueLabel, string falseLabel) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(label, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) }); if (GUILayout.Button((value ? "> " : string.Empty) + trueLabel, value ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { value = true; } if (GUILayout.Button(((!value) ? "> " : string.Empty) + falseLabel, (!value) ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { value = false; } GUILayout.EndHorizontal(); return value; } private int DrawInlineChoice(string id, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { if (GUILayout.Button(((i == selected) ? "> " : string.Empty) + labels[i], (i == selected) ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndHorizontal(); return selected; } private bool DrawBoolDropdown(string id, string label, bool value, string trueLabel, string falseLabel) { int selected = ((!value) ? 1 : 0); selected = DrawChoiceDropdown(id, label, selected, new string[2] { trueLabel, falseLabel }); return selected == 0; } private int DrawChoiceDropdown(string id, int selected, string[] labels) { return DrawChoiceDropdown(id, string.Empty, selected, labels); } private int DrawChoiceDropdown(string id, string label, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (!string.IsNullOrWhiteSpace(label)) { GUILayout.Label(label, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(330f) }); } string text = labels[selected] + " v"; if (GUILayout.Button(text, adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(190f) })) { openDropdown = ((openDropdown == id) ? string.Empty : id); } GUILayout.EndHorizontal(); if (openDropdown == id) { GUILayout.BeginVertical(adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { string text2 = ((i == selected) ? "> " : " "); if (GUILayout.Button(text2 + labels[i], adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndVertical(); } return selected; } private int DrawChoiceList(string id, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginVertical(adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { string text = ((i == selected) ? "> " : " "); if (GUILayout.Button(text + labels[i], adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndVertical(); return selected; } private void DrawAdminFooter() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Apply", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { ApplyActiveTab(closeAfterApply: false); } if (GUILayout.Button("Apply & Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { ApplyActiveTab(closeAfterApply: true); } if (GUILayout.Button("Close Without Applying", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } GUILayout.EndHorizontal(); } private void DrawInformationFooter() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Refresh", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RequestPortalInformation(showStatus: true); } if (GUILayout.Button("Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } GUILayout.EndHorizontal(); } private void ApplyActiveTab(bool closeAfterApply) { if (adminTab == 0) { SaveConfigFromUi(); } else { MarkSelectedDiscoveryPortal(GetSelectedPortalRoleValue()); } if (closeAfterApply) { showAdminWindow = false; } } private void ToggleAdminWindow() { if (!adminStatusKnown) { openAdminUiAfterPermissionCheck = true; RequestConfig(openUi: false); ShowMessage("Checking portal limit permissions..."); return; } if (!isAdmin) { showAdminWindow = false; RequestCountForChat(); return; } showAdminWindow = !showAdminWindow; openDropdown = string.Empty; if (showAdminWindow) { RequestConfig(openUi: true); RequestCount(); CenterAdminWindowIfNeeded(); } } private void OpenAdminWindowForPortal(TeleportWorld portal) { SelectPortalForEditing(portal, showStatus: false); showAdminWindow = true; openDropdown = string.Empty; adminTab = 1; statusMessage = "Portal selected. Choose what this portal should do, then Apply or Apply & Close."; CenterAdminWindowIfNeeded(); RequestConfig(openUi: true); RequestCount(); } private void SaveConfigFromUi() { if (!int.TryParse(maxText, out var result)) { statusMessage = "Max portals must be a whole number."; return; } string text = "max=" + Math.Max(0, result) + "\nadminBypass=" + adminBypass + "\nenforceOnServer=" + enforceOnServer + "\nportalPrefabNames=" + Escape(portalNamesText) + "\ndiscoveryEnabled=" + discoveryEnabled + "\ndiscoveryAdminBypass=" + discoveryAdminBypass + "\nadminHoldEToEdit=" + adminHoldEToEdit + "\nshowDiscoveryHoverText=" + showDiscoveryHoverText + "\ndiscoveryLockedHoverText=" + Escape(discoveryLockedHoverTextField) + "\ndiscoveryRemoteHoverText=" + Escape(discoveryRemoteHoverTextField) + "\ndiscoveryUnlockedHoverText=" + Escape(discoveryUnlockedHoverTextField) + "\ndiscoveryLockedMessage=" + Escape(discoveryLockedMessageField) + "\ndiscoveryUnlockMessage=" + Escape(discoveryUnlockMessageField) + "\ndiscoveryShowWorldMarker=" + discoveryShowWorldMarker + "\ndiscoveryTintPortalModel=" + discoveryTintPortalModel + "\ndiscoverySuppressLockedGlow=" + discoverySuppressLockedGlow + "\ndiscoveryLockedColor=" + Escape(discoveryLockedColorField) + "\ndiscoveryRemoteColor=" + Escape(discoveryRemoteColorField) + "\ndiscoveryUnlockedColor=" + Escape(discoveryUnlockedColorField); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.config_update", new object[1] { text }); statusMessage = "Saving portal limit settings..."; } private void RequestConfig(bool openUi) { configRequested = true; if (openUi) { statusMessage = "Loading portal limit settings..."; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.config_request", new object[1] { (openUi ? string.Empty : "[silent]") + GetPlayerName() }); RequestUnlockList(); } private void RequestCount() { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.count_request", new object[1] { localPlayerId }); } } private void RequestCountForChat() { showCountMessageOnNextResponse = true; RequestCount(); ShowMessage("Checking portal count..."); } private void RequestPlacementCountSoon() { ((MonoBehaviour)this).StartCoroutine(RequestPlacementCountNextFrame()); } private IEnumerator RequestPlacementCountNextFrame() { yield return (object)new WaitForSeconds(0.35f); long playerId = GetLocalPlayerId(); int count = CountPortals(playerId); string maxText = ((maxPortalsPerPlayer > 0) ? maxPortalsPerPlayer.ToString() : "unlimited"); serverPortalCount = count; ShowMessage("Portals placed: " + count + " / " + maxText); RequestCount(); } private void RequestUnlockList() { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_unlock_list_request", new object[1] { localPlayerId }); } } private void RequestPortalInformation(bool showStatus) { TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { portalInfoThisText = "No portal was opened."; portalInfoWorldText = "Open this tab while editing a portal."; return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); ZDO val2 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); portalInfoRequestedPortalKey = ((val2 != null) ? ((object)(ZDOID)(ref val2.m_uid)).ToString() : GetPortalKey(val)); portalInfoThisText = "Loading authoritative portal information from the server..."; string portalTagForUi = GetPortalTagForUi(val); if (ZRoutedRpc.instance == null) { portalInfoWorldText = "Portal Limit server RPC is not ready yet."; return; } if (showStatus) { statusMessage = "Loading portal information..."; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.admin_report_request", new object[1] { "portalinfo|" + Escape(portalTagForUi) + "|" + Escape(portalInfoRequestedPortalKey) }); } private static void OnConfigResponse(long sender, string payload) { Instance.ApplyConfigPayload(payload); } private static void OnCountResponse(long sender, int count, int max, bool limitReached, string payload) { Instance.serverPortalCount = count; Instance.maxPortalsPerPlayer = max; Instance.ApplyConfigPayload(payload); if (Instance.showPlacementCountOnNextResponse) { Instance.showPlacementCountOnNextResponse = false; string text = ((max > 0) ? max.ToString() : "unlimited"); Instance.ShowMessage("Portals placed: " + count + " / " + text); } else if (Instance.showCountMessageOnNextResponse) { Instance.showCountMessageOnNextResponse = false; string text = ((max > 0) ? max.ToString() : "unlimited"); Instance.ShowMessage("Portals: " + count + " / " + text); } } private static void OnNotice(long sender, string message) { Instance.ShowMessage(message); } private static void OnDiscoveryUnlockListResponse(long sender, string payload) { Instance.ApplyUnlockPayload(payload); } private static void OnAdminReportResponse(long sender, string payload) { if (string.IsNullOrWhiteSpace(payload)) { Terminal.Log((object)"Portal Limit: empty report."); return; } if ((Object)(object)Instance != (Object)null && payload.StartsWith("PortalInfoResponse\n", StringComparison.Ordinal)) { Instance.ApplyPortalInformationPayload(payload); return; } string[] array = payload.Split(new char[1] { '\n' }); foreach (string text in array) { Terminal.Log((object)text); } if ((Object)(object)Instance != (Object)null) { Instance.ShowMessage("Portal Limit report written to F5 console."); } } private void ApplyPortalInformationPayload(string payload) { string text = payload.Substring("PortalInfoResponse\n".Length); string[] array = text.Split(new string[1] { "\n---WORLD---\n" }, StringSplitOptions.None); if (array.Length > 0 && !string.IsNullOrWhiteSpace(array[0])) { portalInfoThisText = array[0].Trim(); } portalInfoWorldText = ((array.Length > 1) ? array[1].Trim() : text.Trim()); statusMessage = "Portal information loaded."; } private void ApplyConfigPayload(string payload) { Dictionary<string, string> dictionary = ParsePayload(payload); if (dictionary.TryGetValue("isAdmin", out var value) && bool.TryParse(value, out var result)) { isAdmin = result; adminStatusKnown = true; if (!isAdmin) { showAdminWindow = false; } if (openAdminUiAfterPermissionCheck) { openAdminUiAfterPermissionCheck = false; if (isAdmin) { showAdminWindow = true; openDropdown = string.Empty; CenterAdminWindowIfNeeded(); RequestConfig(openUi: true); RequestCount(); } else { RequestCountForChat(); } } } if (dictionary.TryGetValue("max", out value) && int.TryParse(value, out var result2)) { maxPortalsPerPlayer = result2; maxText = result2.ToString(); } if (dictionary.TryGetValue("adminBypass", out value) && bool.TryParse(value, out result)) { adminBypass = result; } if (dictionary.TryGetValue("enforceOnServer", out value) && bool.TryParse(value, out result)) { enforceOnServer = result; } if (dictionary.TryGetValue("portalPrefabNames", out value)) { portalPrefabNames = value; portalNamesText = value; } if (dictionary.TryGetValue("discoveryEnabled", out value) && bool.TryParse(value, out result)) { discoveryEnabled = result; } if (dictionary.TryGetValue("discoveryAdminBypass", out value) && bool.TryParse(value, out result)) { discoveryAdminBypass = result; } if (dictionary.TryGetValue("adminHoldEToEdit", out value) && bool.TryParse(value, out result)) { adminHoldEToEdit = result; } if (dictionary.TryGetValue("showDiscoveryHoverText", out value) && bool.TryParse(value, out result)) { showDiscoveryHoverText = result; } if (dictionary.TryGetValue("discoveryLockedHoverText", out value)) { discoveryLockedHoverText = value; discoveryLockedHoverTextField = value; } if (dictionary.TryGetValue("discoveryRemoteHoverText", out value)) { discoveryRemoteHoverText = value; discoveryRemoteHoverTextField = value; } if (dictionary.TryGetValue("discoveryUnlockedHoverText", out value)) { discoveryUnlockedHoverText = value; discoveryUnlockedHoverTextField = value; } if (dictionary.TryGetValue("discoveryLockedMessage", out value)) { discoveryLockedMessage = value; discoveryLockedMessageField = value; } if (dictionary.TryGetValue("discoveryUnlockMessage", out value)) { discoveryUnlockMessage = value; discoveryUnlockMessageField = value; } if (dictionary.TryGetValue("discoveryShowWorldMarker", out value) && bool.TryParse(value, out result)) { discoveryShowWorldMarker = result; } if (dictionary.TryGetValue("discoveryTintPortalModel", out value) && bool.TryParse(value, out result)) { discoveryTintPortalModel = result; } if (dictionary.TryGetValue("discoverySuppressLockedGlow", out value) && bool.TryParse(value, out result)) { discoverySuppressLockedGlow = result; } if (dictionary.TryGetValue("discoveryLockedColor", out value)) { discoveryLockedColor = value; discoveryLockedColorField = value; } if (dictionary.TryGetValue("discoveryRemoteColor", out value)) { discoveryRemoteColor = value; discoveryRemoteColorField = value; } if (dictionary.TryGetValue("discoveryUnlockedColor", out value)) { discoveryUnlockedColor = value; discoveryUnlockedColorField = value; } if (dictionary.TryGetValue("message", out value) && !string.IsNullOrWhiteSpace(value)) { statusMessage = value; ShowMessage(value); } } private void ApplyUnlockPayload(string payload) { Dictionary<string, string> dictionary = ParsePayload(payload); unlockedDiscoveryLinks.Clear(); if (dictionary.TryGetValue("links", out var value)) { string[] array = value.Split(new char[1] { ';' }); foreach (string text in array) { string text2 = text.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { unlockedDiscoveryLinks.Add(text2); } } } if (dictionary.TryGetValue("message", out var value2) && !string.IsNullOrWhiteSpace(value2)) { ShowMessage(value2); } } private void MarkSelectedDiscoveryPortal(int role) { //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { statusMessage = "No portal selected. Look at a portal and click Select first."; return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { statusMessage = "That portal has no valid network view."; return; } string text = discoveryLinkText.Trim(); bool flag = CanEditPortalTag(val); if (!flag) { text = GetPortalTagForUi(val).Trim(); } if (role != 0 && string.IsNullOrWhiteSpace(text)) { statusMessage = "Enter a portal tag first."; return; } discoveryLinkText = text; if (flag) { SetPortalTag(val, text); } string text2 = ((role == 0) ? string.Empty : text); string normalized = string.Empty; string text3 = string.Empty; if (role != 0) { if (!TryNormalizeHexColor(selectedPortalColorText, out normalized)) { statusMessage = "Enter a color like #ff3030."; return; } selectedPortalColorText = normalized; text3 = NormalizeMarkerTextValue(selectedPortalMarkerText); } string text4 = "role=" + role + "\nlink=" + Escape(text2) + "\nmarkerColor=" + Escape(normalized) + "\nmarkerText=" + Escape(text3) + "\nshowMarker=" + selectedPortalShowMarker + "\nsuppressGlow=" + selectedPortalSuppressGlow + "\nlockedHoverText=" + Escape(selectedLockedHoverText) + "\nremoteHoverText=" + Escape(selectedRemoteHoverText) + "\nunlockedHoverText=" + Escape(selectedUnlockedHoverText); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_mark_request", new object[2] { component.GetZDO().m_uid, text4 }); ApplyLocalPortalMarker(val, role, text2, normalized, text3, selectedPortalShowMarker, selectedPortalSuppressGlow, selectedLockedHoverText, selectedRemoteHoverText, selectedUnlockedHoverText); statusMessage = "Portal settings saved."; Log.LogInfo((object)("Sent discovery portal marker request role=" + role + " tag='" + text + "' portal=" + component.GetZDO().m_uid)); } private void RelockSelectedDiscoveryPortal() { RelockDiscoveryPortalTag(discoveryLinkText); } private void RelockDiscoveryPortalTag(string portalTagText) { string text = (portalTagText ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { statusMessage = "Enter a portal tag first."; return; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_relock_request", new object[1] { text }); unlockedDiscoveryLinks.Remove(text); statusMessage = "Relock request sent for portal tag '" + text + "'."; } private void ReadSelectedPortalSettings() { TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { statusMessage = "No portal selected. Look at a portal and click Select first."; } else { LoadPortalSettings(val, showStatus: true); } } private string BuildLocalPortalInformation(TeleportWorld portal) { if ((Object)(object)portal == (Object)null) { return "THIS PORTAL\nNo portal selected."; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); string text = ((val != null) ? val.GetString("PortalLimit_BuiltUtc", string.Empty) : string.Empty); string text2 = GetPortalCreatorName(portal); if (string.IsNullOrWhiteSpace(text2)) { text2 = "unknown"; } string text3 = GetPortalTagForUi(portal); if (string.IsNullOrWhiteSpace(text3)) { text3 = "(none)"; } string text4 = (string.IsNullOrWhiteSpace(text) ? "unknown for older portals" : text); return "THIS PORTAL\nPortal Tag: " + text3 + "\nPlayer Who Built the Portal: " + text2 + "\nDate the portal was built: " + text4 + "\nPortal role: " + GetPortalRoleLabel(GetDiscoveryRole(portal)) + "\nPortal id: " + ((val != null) ? ((object)(ZDOID)(ref val.m_uid)).ToString() : "unknown"); } private void SelectPortalForEditing(TeleportWorld portal, bool showStatus) { if ((Object)(object)portal == (Object)null) { if (showStatus) { statusMessage = "Look directly at a portal first."; } } else { selectedPortal = portal; LoadPortalSettings(portal, showStatus); } } private TeleportWorld GetSelectedPortal() { if ((Object)(object)selectedPortal != (Object)null) { ZNetView component = ((Component)selectedPortal).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { return selectedPortal; } } selectedPortal = null; loadedPortalKey = string.Empty; return null; } private void LoadPortalSettings(TeleportWorld portal, bool showStatus) { selectedPortalRole = GetDiscoveryRole(portal) switch { 2 => 2, 1 => 1, _ => 0, }; string discoveryLink = GetDiscoveryLink(portal); if (!string.IsNullOrWhiteSpace(discoveryLink)) { discoveryLinkText = discoveryLink; } else { string portalTag = GetPortalTag(portal); if (!string.IsNullOrWhiteSpace(portalTag)) { discoveryLinkText = portalTag; } } loadedPortalKey = GetPortalKey(portal); selectedPortalColorText = GetDiscoveryColor(portal); if (string.IsNullOrWhiteSpace(selectedPortalColorText)) { selectedPortalColorText = MarkerColorValues[0]; } selectedPortalColorIndex = GetMarkerColorIndex(selectedPortalColorText); selectedPortalMarkerText = GetDiscoveryMarkerText(portal); selectedPortalMarkerTextIndex = GetMarkerTextIndex(selectedPortalMarkerText); selectedPortalShowMarker = GetDiscoveryShowMarker(portal); selectedPortalSuppressGlow = GetDiscoverySuppressGlow(portal); selectedLockedHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryLockedHoverText"); selectedRemoteHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryRemoteHoverText"); selectedUnlockedHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryUnlockedHoverText"); if (showStatus) { statusMessage = "Selected portal loaded. Choose what this portal does, then Apply."; } } private static void ApplyLocalPortalMarker(TeleportWorld portal, int role, string link, string markerColor, string markerText, bool showMarker, bool suppressGlow, string lockedHoverText, string remoteHoverText, string unlockedHoverText) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 != null) { val2.Set("PortalLimit_DiscoveryRole", role); val2.Set("PortalLimit_DiscoveryLink", (role == 0) ? string.Empty : link); val2.Set("PortalLimit_DiscoveryColor", (role == 0) ? string.Empty : markerColor); val2.Set("PortalLimit_DiscoveryMarkerText", (role == 0) ? string.Empty : NormalizeMarkerTextValue(markerText)); val2.Set("PortalLimit_DiscoveryShowMarker", (role != 0) ? (showMarker ? 1 : 0) : 0); val2.Set("PortalLimit_DiscoverySuppressGlow", (role != 0) ? (suppressGlow ? 1 : 0) : 0); val2.Set("PortalLimit_DiscoveryLockedHoverText", (role == 0) ? string.Empty : (lockedHoverText ?? string.Empty).Trim()); val2.Set("PortalLimit_DiscoveryRemoteHoverText", (role == 0) ? string.Empty : (remoteHoverText ?? string.Empty).Trim()); val2.Set("PortalLimit_DiscoveryUnlockedHoverText", (role == 0) ? string.Empty : (unlockedHoverText ?? string.Empty).Trim()); } } private int GetSelectedPortalRoleValue() { if (selectedPortalRole == 1) { return 1; } if (selectedPortalRole == 2) { return 2; } return 0; } private static string GetPortalRoleLabel(int role) { return role switch { 1 => "Locked entrance", 2 => "Unlocked entrance", _ => "Normal portal", }; } private static TeleportWorld GetHoveredPortal() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return null; } GameObject hoverObject = ((Humanoid)Player.m_localPlayer).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return null; } TeleportWorld val = hoverObject.GetComponent<TeleportWorld>(); if ((Object)(object)val == (Object)null) { val = hoverObject.GetComponentInParent<TeleportWorld>(); } return val; } private static string GetPortalKey(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? ((object)(ZDOID)(ref val2.m_uid)).ToString() : string.Empty; } private static string GetPortalCreatorName(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 == null) { return string.Empty; } string @string = val2.GetString(ZDOVars.s_creatorName, string.Empty); return @string ?? string.Empty; } private static bool CanEditPortalTag(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || (Object)(object)portal == (Object)null) { return false; } Piece val = ((Component)portal).GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = ((Component)portal).GetComponentInParent<Piece>(); } if ((Object)(object)val == (Object)null) { return true; } long creator = val.GetCreator(); long localPlayerId = GetLocalPlayerId(); return creator == 0 || creator == localPlayerId; } private static string GetPortalTag(TeleportWorld portal) { MethodInfo methodInfo = AccessTools.Method(typeof(TeleportWorld), "GetText", (Type[])null, (Type[])null); if ((Object)(object)portal != (Object)null && methodInfo != null) { object obj = methodInfo.Invoke(portal, null); if (obj != null) { return obj.ToString(); } } return string.Empty; } private static string GetPortalTagForUi(TeleportWorld portal) { string discoveryLink = GetDiscoveryLink(portal); if (!string.IsNullOrWhiteSpace(discoveryLink)) { return discoveryLink; } return GetPortalTag(portal); } private static void SetPortalTag(TeleportWorld portal, string tag) { if ((Object)(object)portal == (Object)null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(TeleportWorld), "SetText", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(portal, new object[1] { tag ?? string.Empty }); return; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val != null) { val.Set("tag", tag ?? string.Empty); } } private static void SetTargetFound(TeleportWorld portal, bool value) { if ((Object)(object)portal != (Object)null && TeleportWorldTargetFoundField != null) { TeleportWorldTargetFoundField.SetValue(portal, value); } } private static int GetDiscoveryRole(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetInt("PortalLimit_DiscoveryRole", 0) : 0; } private static string GetDiscoveryLink(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString("PortalLimit_DiscoveryLink", string.Empty) : string.Empty; } private static string GetDiscoveryColor(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString("PortalLimit_DiscoveryColor", string.Empty) : string.Empty; } private static string GetDiscoveryMarkerText(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? NormalizeMarkerTextValue(val2.GetString("PortalLimit_DiscoveryMarkerText", string.Empty)) : MarkerTextValues[0]; } private bool GetDiscoveryShowMarker(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? (val2.GetInt("PortalLimit_DiscoveryShowMarker", discoveryShowWorldMarker ? 1 : 0) != 0) : discoveryShowWorldMarker; } private bool GetDiscoverySuppressGlow(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? (val2.GetInt("PortalLimit_DiscoverySuppressGlow", discoverySuppressLockedGlow ? 1 : 0) != 0) : discoverySuppressLockedGlow; } private static string GetDiscoveryHoverOverride(TeleportWorld portal, string key) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString(key, string.Empty) : string.Empty; } private Color GetDiscoveryVisualColor(TeleportWorld portal) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0090: 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_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_0082: Unknown result type (might be due to invalid IL or missing references) string discoveryColor = GetDiscoveryColor(portal); if (!string.IsNullOrWhiteSpace(discoveryColor)) { return ParseHexColor(discoveryColor, LockedOrange); } int discoveryRole = GetDiscoveryRole(portal); string discoveryLink = GetDiscoveryLink(portal); if (discoveryRole != 0 && !string.IsNullOrWhiteSpace(discoveryLink) && IsDiscoveryUnlocked(discoveryLink)) { return ParseHexColor(discoveryUnlockedColor, Color.green); } if (discoveryRole == 2) { return ParseHexColor(discoveryRemoteColor, Color.cyan); } return ParseHexColor(discoveryLockedColor, LockedOrange); } private bool ShouldShowDiscoveryWorldMarker(TeleportWorld portal) { return discoveryEnabled && GetDiscoveryShowMarker(portal) && ShouldShowLockedEntranceX(portal); } private string GetDiscoveryMarkerDisplayText(TeleportWorld portal) { string discoveryMarkerText = GetDiscoveryMarkerText(portal); if (string.Equals(discoveryMarkerText, "Locked", StringComparison.OrdinalIgnoreCase)) { return "LOCKED"; } if (string.Equals(discoveryMarkerText, "X", StringComparison.OrdinalIgnoreCase)) { return "X"; } if (string.Equals(discoveryMarkerText, "UnlockOnOtherSide", StringComparison.OrdinalIgnoreCase)) { return "UNLOCK ON OTHER SIDE"; } return string.IsNullOrWhiteSpace(discoveryMarkerText) ? "UNLOCK ON OTHER SIDE" : discoveryMarkerText; } private bool ShouldShowLockedEntranceX(TeleportWorld portal) { if (GetDiscoveryRole(portal) != 1) { return false; } string discoveryLink = GetDiscoveryLink(portal); return !string.IsNullOrWhiteSpace(discoveryLink) && !IsDiscoveryUnlocked(discoveryLink); } private bool ShouldTintDiscoveryPortal(TeleportWorld portal) { return false; } private bool ShouldSuppressLockedPortalGlow(TeleportWorld portal) { if (!discoveryEnabled || !GetDiscoverySuppressGlow(portal) || GetDiscoveryRole(portal) != 1) { return false; } string discoveryLink = GetDiscoveryLink(portal); return !string.IsNullOrWhiteSpace(discoveryLink) && !IsDiscoveryUnlocked(discoveryLink); } private static Color ParseHexColor(string text, Color fallback) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00bb: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(text)) { return fallback; } string text2 = text.Trim(); if (text2.StartsWith("#", StringComparison.Ordinal)) { text2 = text2.Substring(1); } if (text2.Length == 6 && int.TryParse(text2.Substring(0, 2), NumberStyles.HexNumber, null, out var result) && int.TryParse(text2.Substring(2, 2), NumberStyles.HexNumber, null, out var result2) && int.TryParse(text2.Substring(4, 2), NumberStyles.HexNumber, null, out var result3)) { return new Color((float)result / 255f, (float)result2 / 255f, (float)result3 / 255f, 1f); } return fallback; } private static string NormalizeHexColor(string text, string fallback) { string text2 = (text ?? string.Empty).Trim(); if (!text2.StartsWith("#", StringComparison.Ordinal)) { text2 = "#" + text2; } Color val = default(Color); return ColorUtility.TryParseHtmlString(text2, ref val) ? text2 : fallback; } private static bool TryNormalizeHexColor(string text, out string normalized) { normalized = (text ?? string.Empty).Trim(); if (!normalized.StartsWith("#", StringComparison.Ordinal)) { normalized = "#" + normalized; } Color val = default(Color); if (normalized.Length == 7 && ColorUtility.TryParseHtmlString(normalized, ref val)) { return true; } normalized = string.Empty; return false; } private static int GetMarkerColorIndex(string color) { string a = NormalizeHexColor(color, MarkerColorValues[0]); for (int i = 0; i < MarkerColorValues.Length; i++) { if (string.Equals(a, MarkerColorValues[i], StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } private static string NormalizeMarkerTextValue(string value) { string text = (value ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { return MarkerTextLabels[0]; } for (int i = 0; i < MarkerTextValues.Length; i++) { if (string.Equals(text, MarkerTextValues[i], StringComparison.OrdinalIgnoreCase) || string.Equals(text, MarkerTextLabels[i], StringComparison.OrdinalIgnoreCase)) { return MarkerTextLabels[i]; } } return text; } private static int GetMarkerTextIndex(string value) { string a = NormalizeMarkerTextValue(value); for (int i = 0; i < MarkerTextValues.Length; i++) { if (string.Equals(a, MarkerTextValues[i], StringComparison.OrdinalIgnoreCase) || string.Equals(a, MarkerTextLabels[i], StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } private bool IsDiscoveryUnlocked(string link) { if (string.IsNullOrWhiteSpace(link)) { return false; } return unlockedDiscoveryLinks.Contains(link); } private void UnlockDiscoveryLink(string link, TeleportWorld portal) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(link)) { unlockedDiscoveryLinks.Add(link); long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0 && ZRoutedRpc.instance != null) { Vector3 val = (((Object)(object)portal != (Object)null) ? ((Component)portal).transform.position : Vector3.zero); ZNetView val2 = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDOID val3 = (((Object)(object)val2 != (Object)null && val2.IsValid()) ? val2.GetZDO().m_uid : ZDOID.None); string text = "link=" + Escape(link.Trim()) + "\nplayerName=" + Escape(GetPlayerName()) + "\nportalId=" + Escape(((object)(ZDOID)(ref val3)).ToString()) + "\nx=" + val.x.ToString("F1") + "\ny=" + val.y.ToString("F1") + "\nz=" + val.z.ToString("F1"); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_unlock_request", new object[2] { localPlayerId, text }); } } } private static bool ShouldBlockPortalUse(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || !Instance.discoveryEnabled || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } int discoveryRole = GetDiscoveryRole(portal); if (discoveryRole == 0) { return false; } string discoveryLink = GetDiscoveryLink(portal); if (string.IsNullOrWhiteSpace(discoveryLink)) { return false; } if (Instance.discoveryAdminBypass && Instance.isAdmin) { return false; } switch (discoveryRole) { case 2: if (!Instance.IsDiscoveryUnlocked(discoveryLink)) { Instance.UnlockDiscoveryLink(discoveryLink, portal); Instance.ShowMessage(Instance.discoveryUnlockMessage); } return false; case 1: if (!Instance.IsDiscoveryUnlocked(discoveryLink)) { Instance.ShowMessage(Instance.discoveryLockedMessage); Instance.RequestUnlockList(); return true; } break; } return false; } private static bool ShouldBlockBlankPortalUse(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || (Object)(object)portal == (Object)null) { return false; } if (string.IsNullOrWhiteSpace(GetPortalTag(portal))) { Instance.ShowMessage("Set a portal tag first."); return true; } return false; } internal static bool WouldExceedPortalLimit(Piece piece) { PortalLimitClientPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)piece == (Object)null || !instance.IsLimitedPortal(piece)) { return false; } if (instance.maxPortalsPerPlayer <= 0) { return false; } if (instance.adminBypass && instance.isAdmin) { return false; } long localPlayerId = GetLocalPlayerId(); int num = instance.CountPortals(localPlayerId); return num >= instance.maxPortalsPerPlayer; } private bool IsLimitedPortal(Piece piece) { if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<TeleportWorld>() == (Object)null) { return false; } HashSet<string> portalPrefabNameSet = GetPortalPrefabNameSet(); if (portalPrefabNameSet.Count == 0) { return true; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); string prefabName = GetPrefabName(component, piece); return portalPrefabNameSet.Contains(prefabName); } private void ReportPortalMetadata(Piece piece, string action) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null) && IsLimitedPortal(piece) && ZRoutedRpc.instance != null) { ZNetView component = ((Component)piece).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val != null) { Vector3 position = ((Component)piece).transform.position; string text = "action=" + Escape(action) + "\nportalId=" + Escape(((object)(ZDOID)(ref val.m_uid)).ToString()) + "\nplayerId=" + GetLocalPlayerId() + "\nplayerName=" + Escape(GetPlayerName()) + "\nx=" + position.x.ToString("F1") + "\ny=" + position.y.ToString("F1") + "\nz=" + position.z.ToString("F1"); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.portal_metadata_update", new object[1] { text }); } } } private void ReportPortalMetadata(TeleportWorld portal, string action) { if (!((Object)(object)portal == (Object)null)) { Piece val = ((Component)portal).GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = ((Component)portal).GetComponentInParent<Piece>(); } ReportPortalMetadata(val, action); } } private static string GetPrefabName(ZNetView nview, Piece piece) { if ((Object)(object)nview != (Object)null && GetPrefabNameMethod != null) { object obj = GetPrefabNameMethod.Invoke(nview, null); if (obj != null) { return obj.ToString(); } } return ((Object)(object)piece != (Object)null) ? ((Object)piece).name.Replace("(Clone)", string.Empty) : string.Empty; } private int CountPortals(long creatorId) { if (creatorId == 0 || AllPiecesField == null) { return serverPortalCount; } int num = 0; if (!(AllPiecesField.GetValue(null) is IEnumerable enumerable)) { return serverPortalCount; } foreach (object item in enumerable) { Piece val = (Piece)((item is Piece) ? item : null); if ((Object)(object)val != (Object)null && val.GetCreator() == creatorId && IsLimitedPortal(val)) { num++; } } return num; } private HashSet<string> GetPortalPrefabNameSet() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = portalPrefabNames.Split(new char[1] { ',' }); foreach (string text in array) { string text2 = text.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { hashSet.Add(text2); } } return hashSet; } private static long GetLocalPlayerId() { try { if ((Object)(object)Player.m_localPlayer != (Object)null && GetPlayerIdMethod != null) { object obj = GetPlayerIdMethod.Invoke(Player.m_localPlayer, null); if (obj != null && obj.GetType() == typeof(long)) { return (long)obj; } } } catch (Exception ex) { Log.LogWarning((object)("Could not read local player ID: " + ex.Message)); } return 0L; } private static string GetPlayerName() { return ((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "unknown-player"; } internal void ShowMessage(string message) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false); } else { Log.LogMessage((object)message); } } private static Dictionary<string, string> ParsePayload(string payload) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(payload)) { return dictionary; } string[] array = payload.Split(new char[1] { '\n' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { dictionary[text.Substring(0, num)] = Unescape(text.Substring(num + 1)); } } return dictionary; } private static string Escape(string value) { return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\n", "\\n").Replace("=", "\\e"); } private static string Unescape(string value) { return (value ?? string.Empty).Replace("\\e", "=").Replace("\\n", "\n").Replace("\\\\", "\\"); } }
BepInEx\plugins\PortalLimitClient.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace PortalLimit.Client; [BepInPlugin("keith.valheim.portallimit.client", "Portal Limit and Discovery Client", "0.1.4")] public class PortalLimitClientPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(Chat), "InputText")] private static class ChatInputPatch { private static bool Prefix(Chat __instance) { string a = (((Object)(object)((Terminal)__instance).m_input != (Object)null) ? ((TMP_InputField)((Terminal)__instance).m_input).text : string.Empty); if (string.Equals(a, "/portals", StringComparison.OrdinalIgnoreCase)) { if ((Object)(object)Instance != (Object)null) { Instance.RequestCountForChat(); } if ((Object)(object)((Terminal)__instance).m_input != (Object)null) { ((TMP_InputField)((Terminal)__instance).m_input).text = string.Empty; } __instance.Hide(); return false; } if (!string.Equals(a, "/portallimit", StringComparison.OrdinalIgnoreCase)) { return true; } if ((Object)(object)Instance != (Object)null) { Instance.ToggleAdminWindow(); } if ((Object)(object)((Terminal)__instance).m_input != (Object)null) { ((TMP_InputField)((Terminal)__instance).m_input).text = string.Empty; } __instance.Hide(); return false; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class PlacePiecePatch { private static bool Prefix(Piece piece, ref bool __result) { if (!WouldExceedPortalLimit(piece)) { return true; } __result = false; Instance.ShowMessage("Portal limit reached: " + Instance.maxPortalsPerPlayer + " portal(s) per player."); Instance.RequestCount(); return false; } private static void Postfix(Piece piece, bool __result) { if (__result && (Object)(object)Instance != (Object)null && (Object)(object)piece != (Object)null && Instance.IsLimitedPortal(piece)) { Instance.ReportPortalMetadata(piece, "placed"); Instance.RequestPlacementCountSoon(); } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] private static class PieceCanBeRemovedPatch { private static void Postfix(Piece __instance, ref bool __result) { if (__result && !((Object)(object)Instance == (Object)null) && !((Object)(object)__instance == (Object)null) && Instance.IsLimitedPortal(__instance)) { long creator = __instance.GetCreator(); long localPlayerId = GetLocalPlayerId(); if (!Instance.isAdmin && creator != 0 && creator != localPlayerId) { __result = false; Instance.ShowMessage("Only the builder or an admin can remove this portal."); } } } } [HarmonyPatch(typeof(TeleportWorld), "Interact")] private static class TeleportWorldInteractPatch { private static bool Prefix(TeleportWorld __instance, Humanoid human, bool hold, ref bool __result) { if ((Object)(object)Instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)human != (Object)(object)Player.m_localPlayer) { return true; } if (Instance.replayingVanillaPortalInteract) { return true; } if (Instance.isAdmin && Instance.adminHoldEToEdit && !hold) { Instance.BeginDelayedPortalInteract(__instance); __result = false; return false; } if (hold && Instance.isAdmin && Instance.adminHoldEToEdit) { Instance.OpenAdminWindowForPortal(__instance); Instance.ResetHoldInteract(); __result = false; return false; } if (!hold && ShouldBlockPortalUse(__instance)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] private static class TeleportWorldTeleportPatch { private static bool Prefix(TeleportWorld __instance, Player player) { if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } bool flag = !ShouldBlockBlankPortalUse(__instance) && !ShouldBlockPortalUse(__instance); if (flag && (Object)(object)Instance != (Object)null) { Instance.ReportPortalMetadata(__instance, "used"); } return flag; } } [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] private static class TeleportWorldHoverTextPatch { private static void Postfix(TeleportWorld __instance, ref string __result) { if ((Object)(object)Instance == (Object)null) { return; } if (string.IsNullOrWhiteSpace(GetPortalTag(__instance)) && !string.IsNullOrEmpty(__result)) { __result = __result.Replace(" [CONNECTED]", string.Empty).Replace("[CONNECTED]", string.Empty); } if (Instance.isAdmin) { if (Instance.adminHoldEToEdit) { __result += "\n<color=yellow>Hold E: Portal Limit settings</color>"; } string portalCreatorName = GetPortalCreatorName(__instance); if (!string.IsNullOrWhiteSpace(portalCreatorName)) { __result = __result + "\n<color=#ffd27a>Built by: " + portalCreatorName + "</color>"; } } if (!Instance.discoveryEnabled || (!Instance.showDiscoveryHoverText && !Instance.isAdmin)) { return; } int discoveryRole = GetDiscoveryRole(__instance); if (discoveryRole == 0) { return; } string discoveryLink = GetDiscoveryLink(__instance); if (string.IsNullOrWhiteSpace(discoveryLink)) { return; } string text = string.Empty; if (Instance.IsDiscoveryUnlocked(discoveryLink)) { text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryUnlockedHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryUnlockedHoverText; } } else { switch (discoveryRole) { case 1: text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryLockedHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryLockedHoverText; } break; case 2: text = GetDiscoveryHoverOverride(__instance, "PortalLimit_DiscoveryRemoteHoverText"); if (string.IsNullOrWhiteSpace(text)) { text = Instance.discoveryRemoteHoverText; } break; } } if (!string.IsNullOrWhiteSpace(text)) { __result = __result + "\n<color=orange>" + text + "</color>"; } } } [HarmonyPatch(typeof(TeleportWorld), "TargetFound")] private static class TeleportWorldTargetFoundPatch { private static void Postfix(TeleportWorld __instance, ref bool __result) { if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { __result = false; SetTargetFound(__instance, value: false); } } } [HarmonyPatch(typeof(TeleportWorld), "HaveTarget")] private static class TeleportWorldHaveTargetPatch { private static void Postfix(TeleportWorld __instance, ref bool __result) { if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { __result = false; } } } [HarmonyPatch(typeof(TeleportWorld), "Update")] private static class TeleportWorldVisualPatch { private static void Postfix(TeleportWorld __instance) { if (!((Object)(object)__instance == (Object)null)) { PortalLimitDiscoveryVisual portalLimitDiscoveryVisual = ((Component)__instance).GetComponent<PortalLimitDiscoveryVisual>(); if ((Object)(object)portalLimitDiscoveryVisual == (Object)null) { portalLimitDiscoveryVisual = ((Component)__instance).gameObject.AddComponent<PortalLimitDiscoveryVisual>(); } portalLimitDiscoveryVisual.Refresh(__instance); } } } private class PortalLimitDiscoveryVisual : MonoBehaviour { private GameObject markerRoot; private TextMesh markerText; private Renderer[] portalRenderers; private ParticleSystem[] portalParticles; private Light[] portalLights; private readonly Dictionary<Renderer, Color> originalColors = new Dictionary<Renderer, Color>(); private readonly Dictionary<ParticleSystem, bool> originalParticleStates = new Dictionary<ParticleSystem, bool>(); private readonly Dictionary<Light, bool> originalLightStates = new Dictionary<Light, bool>(); internal void Refresh(TeleportWorld portal) { //IL_0052: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Instance == (Object)null) && !((Object)(object)portal == (Object)null)) { bool flag = Instance.ShouldShowDiscoveryWorldMarker(portal); bool enabled = Instance.ShouldTintDiscoveryPortal(portal); bool suppress = Instance.ShouldSuppressLockedPortalGlow(portal); Color discoveryVisualColor = Instance.GetDiscoveryVisualColor(portal); EnsureMarker(); markerRoot.SetActive(flag); if (flag) { SetMarkerWorldPose(portal); SetMarkerText(Instance.GetDiscoveryMarkerDisplayText(portal)); SetMarkerColor(discoveryVisualColor); } UpdatePortalTint(enabled, discoveryVisualColor); UpdatePortalEffects(suppress); } } private void EnsureMarker() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)markerRoot != (Object)null)) { markerRoot = new GameObject("PortalLimit_DiscoveryMarker"); markerRoot.transform.SetParent(((Component)this).transform, false); markerRoot.transform.localPosition = new Vector3(0f, 1.55f, 0f); markerRoot.transform.localRotation = Quaternion.identity; markerRoot.transform.localScale = Vector3.one; markerText = markerRoot.AddComponent<TextMesh>(); markerText.text = "UNLOCK ON OTHER SIDE"; markerText.anchor = (TextAnchor)4; markerText.alignment = (TextAlignment)1; markerText.fontSize = 96; markerText.characterSize = 0.01f; markerText.richText = false; SetMarkerColor(LockedOrange); markerRoot.SetActive(false); } } private void SetMarkerText(string text) { if (!((Object)(object)markerText == (Object)null)) { markerText.text = text; if (string.Equals(text, "X", StringComparison.Ordinal)) { markerText.fontSize = 128; markerText.characterSize = 0.03f; } else if (string.Equals(text, "LOCKED", StringComparison.Ordinal)) { markerText.fontSize = 96; markerText.characterSize = 0.018f; } else { markerText.fontSize = 96; markerText.characterSize = 0.01f; } } } private void SetMarkerColor(Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)markerText != (Object)null) { markerText.color = color; } } private void SetMarkerWorldPose(TeleportWorld portal) { //IL_002d: 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_003c: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0069: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)markerRoot == (Object)null || (Object)(object)portal == (Object)null) { return; } Vector3 val = ((Component)portal).transform.position + Vector3.up * 1.55f; if ((Object)(object)Camera.main != (Object)null) { Vector3 val2 = ((Component)Camera.main).transform.position - val; if (((Vector3)(ref val2)).sqrMagnitude > 0.001f) { markerRoot.transform.position = val + ((Vector3)(ref val2)).normalized * 0.45f; markerRoot.transform.rotation = Quaternion.LookRotation(-((Vector3)(ref val2)).normalized, Vector3.up); return; } } markerRoot.transform.position = val; markerRoot.transform.rotation = ((Component)portal).transform.rotation; } private void UpdatePortalTint(bool enabled, Color color) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (portalRenderers == null) { portalRenderers = ((Component)this).GetComponentsInChildren<Renderer>(true); } Renderer[] array = portalRenderers; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Component)val).transform.IsChildOf(markerRoot.transform)) { if (!originalColors.ContainsKey(val)) { originalColors[val] = (val.material.HasProperty("_Color") ? val.material.color : Color.white); } if (val.material.HasProperty("_Color")) { val.material.color = (enabled ? Color.Lerp(originalColors[val], color, 0.45f) : originalColors[val]); } } } } private void UpdatePortalEffects(bool suppress) { ParticleSystem[] array; if (portalParticles == null) { portalParticles = ((Component)this).GetComponentsInChildren<ParticleSystem>(true); array = portalParticles; foreach (ParticleSystem val in array) { if ((Object)(object)val != (Object)null) { originalParticleStates[val] = ((Component)val).gameObject.activeSelf; } } } Light[] array2; if (portalLights == null) { portalLights = ((Component)this).GetComponentsInChildren<Light>(true); array2 = portalLights; foreach (Light val2 in array2) { if ((Object)(object)val2 != (Object)null) { originalLightStates[val2] = ((Behaviour)val2).enabled; } } } array = portalParticles; foreach (ParticleSystem val in array) { if (!((Object)(object)val == (Object)null) && !((Component)val).transform.IsChildOf(markerRoot.transform)) { if (!originalParticleStates.TryGetValue(val, out var value)) { value = true; } ((Component)val).gameObject.SetActive(!suppress && value); if (!suppress && value && !val.isPlaying) { val.Play(true); } } } array2 = portalLights; foreach (Light val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Component)val2).transform.IsChildOf(markerRoot.transform)) { if (!originalLightStates.TryGetValue(val2, out var value2)) { value2 = true; } ((Behaviour)val2).enabled = !suppress && value2; } } } } public const string PluginGuid = "keith.valheim.portallimit.client"; public const string PluginName = "Portal Limit and Discovery Client"; public const string PluginVersion = "0.1.4"; private const string RpcConfigRequest = "keith.valheim.portallimit.config_request"; private const string RpcConfigResponse = "keith.valheim.portallimit.config_response"; private const string RpcConfigUpdate = "keith.valheim.portallimit.config_update"; private const string RpcCountRequest = "keith.valheim.portallimit.count_request"; private const string RpcCountResponse = "keith.valheim.portallimit.count_response"; private const string RpcNotice = "keith.valheim.portallimit.notice"; private const string RpcDiscoveryMarkRequest = "keith.valheim.portallimit.discovery_mark_request"; private const string RpcDiscoveryUnlockRequest = "keith.valheim.portallimit.discovery_unlock_request"; private const string RpcDiscoveryRelockRequest = "keith.valheim.portallimit.discovery_relock_request"; private const string RpcDiscoveryUnlockListRequest = "keith.valheim.portallimit.discovery_unlock_list_request"; private const string RpcDiscoveryUnlockListResponse = "keith.valheim.portallimit.discovery_unlock_list_response"; private const string RpcAdminReportRequest = "keith.valheim.portallimit.admin_report_request"; private const string RpcAdminReportResponse = "keith.valheim.portallimit.admin_report_response"; private const string RpcPortalMetadataUpdate = "keith.valheim.portallimit.portal_metadata_update"; private const string DiscoveryRoleKey = "PortalLimit_DiscoveryRole"; private const string DiscoveryLinkKey = "PortalLimit_DiscoveryLink"; private const string DiscoveryColorKey = "PortalLimit_DiscoveryColor"; private const string DiscoveryMarkerTextKey = "PortalLimit_DiscoveryMarkerText"; private const string DiscoveryShowMarkerKey = "PortalLimit_DiscoveryShowMarker"; private const string DiscoverySuppressGlowKey = "PortalLimit_DiscoverySuppressGlow"; private const string DiscoveryLockedHoverTextKey = "PortalLimit_DiscoveryLockedHoverText"; private const string DiscoveryRemoteHoverTextKey = "PortalLimit_DiscoveryRemoteHoverText"; private const string DiscoveryUnlockedHoverTextKey = "PortalLimit_DiscoveryUnlockedHoverText"; private const string PortalBuiltUtcKey = "PortalLimit_BuiltUtc"; private const int DiscoveryRoleNone = 0; private const int DiscoveryRoleLocked = 1; private const int DiscoveryRoleRemote = 2; internal static PortalLimitClientPlugin Instance; internal static ManualLogSource Log; private static readonly FieldInfo AllPiecesField = AccessTools.Field(typeof(Piece), "s_allPieces"); private static readonly FieldInfo TeleportWorldTargetFoundField = AccessTools.Field(typeof(TeleportWorld), "m_target_found"); private static readonly MethodInfo GetPlayerIdMethod = AccessTools.Method(typeof(Player), "GetPlayerID", (Type[])null, (Type[])null); private static readonly MethodInfo GetPrefabNameMethod = AccessTools.Method(typeof(ZNetView), "GetPrefabName", (Type[])null, (Type[])null); private static readonly Color LockedOrange = new Color(1f, 0.6235294f, 0.1019608f, 1f); private static readonly string[] MarkerColorLabels = new string[8] { "RED", "ORANGE", "YELLOW", "GREEN", "BLUE", "PURPLE", "WHITE", "BLACK" }; private static readonly string[] MarkerColorValues = new string[8] { "#ff3030", "#ff9f1a", "#ffd84a", "#42ff68", "#38a6ff", "#b05cff", "#ffffff", "#000000" }; private static readonly string[] PortalRoleChoiceLabels = new string[3] { "NORMAL PORTAL", "LOCKED ENTRANCE", "UNLOCKED ENTRANCE" }; private static readonly string[] MarkerTextLabels = new string[3] { "UNLOCK ON OTHER SIDE", "LOCKED", "X" }; private static readonly string[] MarkerTextValues = new string[3] { "UnlockOnOtherSide", "Locked", "X" }; private Harmony harmony; private bool rpcRegistered; private bool configRequested; private bool showCountMessageOnNextResponse; private bool showPlacementCountOnNextResponse; private bool openAdminUiAfterPermissionCheck; private bool adminStatusKnown; private bool isAdmin; private bool adminBypass = true; private bool enforceOnServer = true; private int maxPortalsPerPlayer = 10; private string portalPrefabNames = "portal_wood,portal_stone"; private bool discoveryEnabled = true; private bool discoveryAdminBypass = true; private bool adminHoldEToEdit = true; private bool showDiscoveryHoverText = true; private string discoveryLockedHoverText = "Locked: find the other end first."; private string discoveryRemoteHoverText = "Discovery portal: use this side to unlock the route."; private string discoveryUnlockedHoverText = "Discovery route unlocked."; private string discoveryLockedMessage = "This portal is locked. Find and enter the other end first."; private string discoveryUnlockMessage = "Discovery portal unlocked."; private bool discoveryShowWorldMarker = true; private bool discoveryTintPortalModel; private bool discoverySuppressLockedGlow; private string discoveryLockedColor = "#ff9f1a"; private string discoveryRemoteColor = "#38a6ff"; private string discoveryUnlockedColor = "#42ff68"; private readonly HashSet<string> unlockedDiscoveryLinks = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private int serverPortalCount; private Rect adminWindow = new Rect(120f, 60f, 700f, 720f); private Vector2 adminScroll; private Vector2 portalInfoThisScroll; private Vector2 portalInfoWorldScroll; private bool showAdminWindow; private int adminTab; private string openDropdown = string.Empty; private bool portalInfoShowThis; private bool portalInfoShowWorld; private string portalInfoThisText = "Open this tab while editing a portal."; private string portalInfoWorldText = "Click Refresh to load world portal information."; private string portalInfoRequestedPortalKey = string.Empty; private int selectedPortalRole; private string loadedPortalKey = string.Empty; private TeleportWorld selectedPortal; private string maxText = "10"; private string portalNamesText = "portal_wood,portal_stone"; private string discoveryLinkText = string.Empty; private string selectedPortalColorText = "#ff9f1a"; private int selectedPortalColorIndex; private string selectedPortalMarkerText = "UNLOCK ON OTHER SIDE"; private bool selectedPortalShowMarker = true; private bool selectedPortalSuppressGlow; private string selectedLockedHoverText = string.Empty; private string selectedRemoteHoverText = string.Empty; private string selectedUnlockedHoverText = string.Empty; private string discoveryLockedHoverTextField = "Locked: find the other end first."; private string discoveryRemoteHoverTextField = "Discovery portal: use this side to unlock the route."; private string discoveryUnlockedHoverTextField = "Discovery route unlocked."; private string discoveryLockedMessageField = "This portal is locked. Find and enter the other end first."; private string discoveryUnlockMessageField = "Discovery portal unlocked."; private int selectedPortalMarkerTextIndex; private TeleportWorld holdInteractPortal; private float holdInteractStartedAt; private bool holdInteractOpened; private bool replayingVanillaPortalInteract; private string discoveryLockedColorField = "#ff9f1a"; private string discoveryRemoteColorField = "#38a6ff"; private string discoveryUnlockedColorField = "#42ff68"; private string statusMessage = "Use /portallimit to load server settings."; private bool adminStylesReady; private Texture2D adminWindowTexture; private Texture2D adminHeaderTexture; private Texture2D adminSectionTexture; private Texture2D adminInputTexture; private Texture2D adminButtonTexture; private Texture2D adminButtonHoverTexture; private Texture2D adminTabTexture; private Texture2D adminTabSelectedTexture; private GUIStyle adminWindowStyle; private GUIStyle adminTitleStyle; private GUIStyle adminLabelStyle; private GUIStyle adminHelpStyle; private GUIStyle adminSectionStyle; private GUIStyle adminButtonStyle; private GUIStyle adminTabStyle; private GUIStyle adminTabSelectedStyle; private GUIStyle adminTextFieldStyle; private GUIStyle adminBoxStyle; private ConfigEntry<KeyCode> toggleAdminUiKey; private void Awake() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (IsDedicatedServerProcess()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Portal Limit Client disabled on the dedicated server process."); ((Behaviour)this).enabled = false; return; } Instance = this; Log = ((BaseUnityPlugin)this).Logger; toggleAdminUiKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ToggleAdminUIKey", (KeyCode)291, "Key used to open the portal limit admin UI."); harmony = new Harmony("keith.valheim.portallimit.client"); harmony.PatchAll(); RegisterConsoleCommands(); ((MonoBehaviour)this).InvokeRepeating("TryRegisterRpcs", 1f, 1f); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } DestroyAdminTexture(adminWindowTexture); DestroyAdminTexture(adminHeaderTexture); DestroyAdminTexture(adminSectionTexture); DestroyAdminTexture(adminInputTexture); DestroyAdminTexture(adminButtonTexture); DestroyAdminTexture(adminButtonHoverTexture); DestroyAdminTexture(adminTabTexture); DestroyAdminTexture(adminTabSelectedTexture); } private static bool IsDedicatedServerProcess() { string processName = Process.GetCurrentProcess().ProcessName; return processName.StartsWith("valheim_server", StringComparison.OrdinalIgnoreCase); } private void TryRegisterRpcs() { if (!rpcRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.config_response", (Action<long, string>)OnConfigResponse); ZRoutedRpc.instance.Register<int, int, bool, string>("keith.valheim.portallimit.count_response", (Method<int, int, bool, string>)OnCountResponse); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.notice", (Action<long, string>)OnNotice); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.discovery_unlock_list_response", (Action<long, string>)OnDiscoveryUnlockListResponse); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.admin_report_response", (Action<long, string>)OnAdminReportResponse); rpcRegistered = true; ((MonoBehaviour)this).CancelInvoke("TryRegisterRpcs"); } } private static void RegisterConsoleCommands() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("portallimit", "Portal Limit commands. Use: portallimit, portallimit count, portallimit counts, portallimit portals, portallimit export", new ConsoleEvent(OnConsolePortalLimit), false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void OnConsolePortalLimit(ConsoleEventArgs args) { if ((Object)(object)Instance == (Object)null) { Terminal.Log((object)"Portal Limit client is not ready."); return; } string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "help"); if (text == "help") { Terminal.Log((object)"Portal Limit F5 commands:"); Terminal.Log((object)" portallimit count - show your portal count"); Terminal.Log((object)" portallimit counts - admin: show counts for all players"); Terminal.Log((object)" portallimit portals - admin: list known portals with names and coordinates"); Terminal.Log((object)" portallimit export - admin: rewrite report files on the server"); Terminal.Log((object)"Regular players can also type /portals in normal chat."); } else if (text == "count") { Instance.showCountMessageOnNextResponse = true; Instance.RequestCount(); Terminal.Log((object)"Portal Limit: checking your portal count..."); } else if (text != "counts" && text != "portals" && text != "export") { Terminal.Log((object)"Unknown Portal Limit command. Use: portallimit"); } else if (ZRoutedRpc.instance == null) { Terminal.Log((object)"Portal Limit server RPC is not ready yet."); } else { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.admin_report_request", new object[1] { text }); Terminal.Log((object)("Portal Limit: requesting " + text + " report...")); } } private void Update() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (rpcRegistered && !((Object)(object)ZNet.instance == (Object)null)) { if (!configRequested && (Object)(object)Player.m_localPlayer != (Object)null) { RequestConfig(openUi: false); } if (Input.GetKeyDown(toggleAdminUiKey.Value)) { ToggleAdminWindow(); } UpdateHoldInteractAdminOpen(); } } private void UpdateHoldInteractAdminOpen() { if (!isAdmin || !adminHoldEToEdit || showAdminWindow || (Object)(object)Player.m_localPlayer == (Object)null) { ResetHoldInteract(); } else if ((Object)(object)holdInteractPortal == (Object)null) { TeleportWorld hoveredPortal = GetHoveredPortal(); if ((Object)(object)hoveredPortal != (Object)null && Input.GetKey((KeyCode)101)) { BeginDelayedPortalInteract(hoveredPortal); } } else if (!Input.GetKey((KeyCode)101)) { TeleportWorld val = holdInteractPortal; bool flag = !holdInteractOpened && Time.unscaledTime - holdInteractStartedAt < 0.45f; ResetHoldInteract(); if (flag && (Object)(object)val != (Object)null) { ReplayVanillaPortalInteract(val); } } else if (!holdInteractOpened && Time.unscaledTime - holdInteractStartedAt >= 0.45f) { holdInteractOpened = true; OpenAdminWindowForPortal(holdInteractPortal); } } private void BeginDelayedPortalInteract(TeleportWorld portal) { holdInteractPortal = portal; holdInteractStartedAt = Time.unscaledTime; holdInteractOpened = false; } private void ResetHoldInteract() { holdInteractPortal = null; holdInteractStartedAt = 0f; holdInteractOpened = false; } private void ReplayVanillaPortalInteract(TeleportWorld portal) { if ((Object)(object)portal == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } replayingVanillaPortalInteract = true; try { portal.Interact((Humanoid)(object)Player.m_localPlayer, false, false); } finally { replayingVanillaPortalInteract = false; } } private void OnGUI() { //IL_0025: 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_0045: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (showAdminWindow) { EnsureAdminStyles(); CenterAdminWindowIfNeeded(); adminWindow = GUI.Window(((Object)this).GetInstanceID(), adminWindow, new WindowFunction(DrawAdminWindow), GUIContent.none, GUIStyle.none); } } private void CenterAdminWindowIfNeeded() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(760f, (float)Screen.width - 40f); float num2 = Mathf.Min(680f, (float)Screen.height - 40f); if (Math.Abs(((Rect)(ref adminWindow)).width - num) > 0.1f || Math.Abs(((Rect)(ref adminWindow)).height - num2) > 0.1f) { adminWindow = new Rect(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2); } } private void DrawAdminWindow(int id) { //IL_0028: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) EnsureAdminStyles(); GUI.Box(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, ((Rect)(ref adminWindow)).height), GUIContent.none, adminWindowStyle); GUI.Box(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, 42f), GUIContent.none, adminSectionStyle); GUI.Label(new Rect(18f, 9f, ((Rect)(ref adminWindow)).width - 36f, 28f), "Portal Limit Admin", adminTitleStyle); if (GUI.Button(new Rect(((Rect)(ref adminWindow)).width - 38f, 8f, 28f, 26f), "X", adminButtonStyle)) { showAdminWindow = false; return; } GUILayout.BeginArea(new Rect(16f, 48f, ((Rect)(ref adminWindow)).width - 32f, ((Rect)(ref adminWindow)).height - 62f)); GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(statusMessage, adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (isAdmin) { DrawAdminTabs(); adminScroll = GUILayout.BeginScrollView(adminScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(Math.Max(220f, ((Rect)(ref adminWindow)).height - 145f)) }); if (adminTab == 0) { DrawServerSettingsTab(); } else if (adminTab == 1) { DrawPortalSettingsTab(); } else { DrawPortalInformationTab(); } GUILayout.EndScrollView(); if (adminTab == 2) { DrawInformationFooter(); } else { DrawAdminFooter(); } } else { GUILayout.Label("You need to be on the Valheim admin list to edit this.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } } GUILayout.EndVertical(); GUILayout.EndArea(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref adminWindow)).width, 42f)); } private void EnsureAdminStyles() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Expected O, but got Unknown //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Expected O, but got Unknown //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Expected O, but got Unknown //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Expected O, but got Unknown //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Expected O, but got Unknown //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Expected O, but got Unknown //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown //IL_04bd: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Expected O, but got Unknown //IL_0539: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Expected O, but got Unknown //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0579: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_05a8: Expected O, but got Unknown //IL_05b4: Unknown result type (might be due to invalid IL or missing references) //IL_05be: Expected O, but got Unknown //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Expected O, but got Unknown //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Expected O, but got Unknown //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_0614: Expected O, but got Unknown if (!adminStylesReady) { adminWindowTexture = MakeAdminTexture(new Color(0.03f, 0.026f, 0.022f, 0.98f)); adminHeaderTexture = MakeAdminTexture(new Color(0.18f, 0.115f, 0.065f, 0.98f)); adminSectionTexture = MakeAdminTexture(new Color(0.13f, 0.085f, 0.052f, 0.96f)); adminInputTexture = MakeAdminBorderTexture(new Color(0.12f, 0.105f, 0.08f, 1f), new Color(1f, 0.78f, 0.26f, 1f)); adminButtonTexture = MakeAdminTexture(new Color(0.25f, 0.24f, 0.21f, 0.98f)); adminButtonHoverTexture = MakeAdminTexture(new Color(0.36f, 0.31f, 0.23f, 0.98f)); adminTabTexture = MakeAdminTexture(new Color(0.16f, 0.14f, 0.12f, 0.98f)); adminTabSelectedTexture = MakeAdminTexture(new Color(0.45f, 0.31f, 0.14f, 0.98f)); adminWindowStyle = new GUIStyle(GUI.skin.box); adminWindowStyle.normal.background = adminWindowTexture; adminWindowStyle.border = new RectOffset(8, 8, 8, 8); adminWindowStyle.padding = new RectOffset(14, 14, 14, 14); adminTitleStyle = new GUIStyle(GUI.skin.label); adminTitleStyle.fontSize = 18; adminTitleStyle.fontStyle = (FontStyle)1; adminTitleStyle.alignment = (TextAnchor)4; adminTitleStyle.normal.textColor = new Color(0.95f, 0.83f, 0.55f, 1f); adminLabelStyle = new GUIStyle(GUI.skin.label); adminLabelStyle.fontSize = 14; adminLabelStyle.wordWrap = true; adminLabelStyle.normal.textColor = new Color(0.88f, 0.84f, 0.74f, 1f); adminHelpStyle = new GUIStyle(adminLabelStyle); adminHelpStyle.fontSize = 13; adminHelpStyle.normal.textColor = new Color(0.67f, 0.64f, 0.56f, 1f); adminSectionStyle = new GUIStyle(GUI.skin.box); adminSectionStyle.normal.background = adminSectionTexture; adminSectionStyle.border = new RectOffset(4, 4, 4, 4); adminSectionStyle.padding = new RectOffset(8, 8, 4, 4); adminSectionStyle.normal.textColor = new Color(0.98f, 0.82f, 0.43f, 1f); adminSectionStyle.alignment = (TextAnchor)3; adminSectionStyle.fontStyle = (FontStyle)1; adminSectionStyle.fontSize = 15; adminButtonStyle = new GUIStyle(GUI.skin.button); adminButtonStyle.normal.background = adminButtonTexture; adminButtonStyle.hover.background = adminButtonHoverTexture; adminButtonStyle.active.background = adminTabSelectedTexture; adminButtonStyle.normal.textColor = new Color(0.9f, 0.86f, 0.76f, 1f); adminButtonStyle.hover.textColor = new Color(1f, 0.9f, 0.58f, 1f); adminButtonStyle.active.textColor = Color.white; adminButtonStyle.fontSize = 13; adminButtonStyle.padding = new RectOffset(8, 8, 5, 5); adminButtonStyle.margin = new RectOffset(3, 3, 3, 3); adminTabStyle = new GUIStyle(adminButtonStyle); adminTabStyle.normal.background = adminTabTexture; adminTabStyle.fontStyle = (FontStyle)1; adminTabSelectedStyle = new GUIStyle(adminButtonStyle); adminTabSelectedStyle.normal.background = adminTabSelectedTexture; adminTabSelectedStyle.normal.textColor = Color.white; adminTabSelectedStyle.fontStyle = (FontStyle)1; adminTextFieldStyle = new GUIStyle(GUI.skin.textField); adminTextFieldStyle.normal.background = adminInputTexture; adminTextFieldStyle.focused.background = adminInputTexture; adminTextFieldStyle.hover.background = adminInputTexture; adminTextFieldStyle.border = new RectOffset(4, 4, 4, 4); adminTextFieldStyle.normal.textColor = new Color(1f, 0.98f, 0.86f, 1f); adminTextFieldStyle.focused.textColor = Color.white; adminTextFieldStyle.fontSize = 15; adminTextFieldStyle.padding = new RectOffset(12, 12, 8, 8); adminTextFieldStyle.margin = new RectOffset(3, 3, 5, 10); adminBoxStyle = new GUIStyle(GUI.skin.box); adminBoxStyle.normal.background = adminHeaderTexture; adminBoxStyle.padding = new RectOffset(6, 6, 6, 6); adminBoxStyle.margin = new RectOffset(0, 0, 2, 8); adminStylesReady = true; } } private static Texture2D MakeAdminTexture(Color color) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false); val.SetPixel(0, 0, color); val.Apply(); return val; } private static Texture2D MakeAdminBorderTexture(Color fill, Color border) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0037: 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) Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false); for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { bool flag = j < 2 || i < 2 || j > 13 || i > 13; val.SetPixel(j, i, flag ? border : fill); } } val.Apply(); return val; } private static void DestroyAdminTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } private void DrawAdminTabs() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Server Settings", (adminTab == 0) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 0; openDropdown = string.Empty; } if (GUILayout.Button("This Portal", (adminTab == 1) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 1; openDropdown = string.Empty; } if (GUILayout.Button("Portal Information", (adminTab == 2) ? adminTabSelectedStyle : adminTabStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { adminTab = 2; openDropdown = string.Empty; RequestPortalInformation(showStatus: false); } GUILayout.EndHorizontal(); } private void DrawSectionHeader(string text) { GUILayout.Box(text, adminSectionStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(30f) }); } private void DrawServerSettingsTab() { GUILayout.Space(8f); DrawSectionHeader("Portal Limit"); GUILayout.Label("How many counted portals may each non-admin player own? Use 0 for no limit.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); maxText = GUILayout.TextField(maxText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); adminBypass = DrawBoolDropdown("adminBypass", "Admin portal limit bypass", adminBypass, "Allowed", "Not allowed"); enforceOnServer = DrawBoolDropdown("enforceOnServer", "Server removes extra portals over the limit", enforceOnServer, "Enabled", "Disabled"); GUILayout.Label("Which portal types count toward the limit?", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Default covers normal wood and stone portals. Empty means every portal-like object.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); portalNamesText = GUILayout.TextField(portalNamesText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Your current portal count: " + serverPortalCount + " / " + maxPortalsPerPlayer, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(12f); DrawSectionHeader("Discovery Portals"); GUILayout.Label("These settings apply to every locked discovery portal pair.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryEnabled = DrawBoolDropdown("discoveryEnabled", "Locked discovery portals", discoveryEnabled, "Enabled", "Disabled"); discoveryAdminBypass = DrawBoolDropdown("discoveryAdminBypass", "Admin bypass for locked discovery portals", discoveryAdminBypass, "Allowed", "Not allowed"); adminHoldEToEdit = DrawBoolDropdown("adminHoldEToEdit", "Admin hold E portal editor", adminHoldEToEdit, "Enabled", "Disabled"); GUILayout.Label("When enabled, admins can hold E on a portal to edit that portal. Tap E still opens Valheim's normal Set Tag box.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); showDiscoveryHoverText = DrawBoolDropdown("showDiscoveryHoverText", "Lock/unlock hover text", showDiscoveryHoverText, "Shown", "Hidden"); GUILayout.Space(12f); DrawSectionHeader("Default Player-Facing Hover Text"); GUILayout.Label("These are the server defaults. A locked portal can override them on its own This Portal tab.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Locked entrance text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryLockedHoverTextField = GUILayout.TextField(discoveryLockedHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Unlocked entrance text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryRemoteHoverTextField = GUILayout.TextField(discoveryRemoteHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("After unlocked text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); discoveryUnlockedHoverTextField = GUILayout.TextField(discoveryUnlockedHoverTextField, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } private void DrawPortalSettingsTab() { GUILayout.Space(8f); TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { DrawSectionHeader("This Portal"); GUILayout.Label("No portal was opened.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Look at a portal and hold E to open settings for that exact portal.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); return; } int discoveryRole = GetDiscoveryRole(val); string portalTagForUi = GetPortalTagForUi(val); GUILayout.Label("Portal tag", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Use the same tag on both portals, for example: Bog Witch.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); if (CanEditPortalTag(val)) { discoveryLinkText = GUILayout.TextField(discoveryLinkText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } else { GUILayout.Label(discoveryLinkText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("This portal was built by another player. Admins can edit Portal Limit settings, but the portal tag stays protected.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } GUILayout.Space(8f); DrawSectionHeader("This portal"); GUILayout.Label("Current: " + GetPortalRoleLabel(discoveryRole).ToUpperInvariant() + " | Tag: " + (string.IsNullOrWhiteSpace(portalTagForUi) ? "(NONE)" : portalTagForUi), adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedPortalRole = DrawInlineChoice("selectedPortalRole", selectedPortalRole, PortalRoleChoiceLabels); int selectedPortalRoleValue = GetSelectedPortalRoleValue(); if (selectedPortalRoleValue != 0) { GUILayout.Space(10f); DrawSectionHeader("Relock Portal Tag"); GUILayout.Label("For this portal tag, make every player discover the unlocked entrance again.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); bool flag2 = (GUI.enabled = !string.IsNullOrWhiteSpace(discoveryLinkText)); if (GUILayout.Button("Relock this portal tag for players", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RelockSelectedDiscoveryPortal(); } GUI.enabled = true; if (!flag2) { GUILayout.Label("Enter a portal tag before relocking players.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } switch (selectedPortalRoleValue) { case 1: { GUILayout.Space(10f); DrawSectionHeader("Locked Entrance Options"); selectedPortalShowMarker = DrawBoolInline("Unlock message marker", selectedPortalShowMarker, "SHOWN", "HIDDEN"); selectedPortalSuppressGlow = !DrawBoolInline("Orange glow while locked", !selectedPortalSuppressGlow, "SHOWN", "HIDDEN"); GUILayout.Space(8f); GUILayout.Label("Marker color", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); int num = selectedPortalColorIndex; selectedPortalColorIndex = DrawInlineChoice("selectedPortalColor", selectedPortalColorIndex, MarkerColorLabels); if (num != selectedPortalColorIndex) { selectedPortalColorText = MarkerColorValues[Mathf.Clamp(selectedPortalColorIndex, 0, MarkerColorValues.Length - 1)]; } selectedPortalColorText = GUILayout.TextField(selectedPortalColorText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(8f); GUILayout.Label("Marker text", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); int num2 = selectedPortalMarkerTextIndex; selectedPortalMarkerTextIndex = DrawInlineChoice("selectedPortalMarkerText", selectedPortalMarkerTextIndex, MarkerTextLabels); if (num2 != selectedPortalMarkerTextIndex) { selectedPortalMarkerText = MarkerTextLabels[Mathf.Clamp(selectedPortalMarkerTextIndex, 0, MarkerTextLabels.Length - 1)]; } selectedPortalMarkerText = GUILayout.TextField(selectedPortalMarkerText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Space(8f); GUILayout.Label("Player-facing hover text for this portal", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedLockedHoverText = GUILayout.TextField(selectedLockedHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); break; } case 2: GUILayout.Space(10f); DrawSectionHeader("Unlocked Entrance Options"); GUILayout.Label("Player-facing hover text for this portal", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedRemoteHoverText = GUILayout.TextField(selectedRemoteHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); break; } if (selectedPortalRoleValue != 0) { GUILayout.Space(10f); DrawSectionHeader("Unlocked Message"); GUILayout.Label("Text players see after they have unlocked this portal tag. Leave blank to use the server default.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); selectedUnlockedHoverText = GUILayout.TextField(selectedUnlockedHoverText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); } } private void DrawPortalInformationTab() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(8f); TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { DrawSectionHeader("Portal Information"); GUILayout.Label("No portal was opened.", adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label("Look at a portal and hold E to open settings for that exact portal.", adminHelpStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); return; } if (GUILayout.Button("Refresh portal information", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RequestPortalInformation(showStatus: true); } portalInfoShowThis = DrawCollapseHeader(portalInfoShowThis, "THIS PORTAL"); if (portalInfoShowThis) { portalInfoThisScroll = GUILayout.BeginScrollView(portalInfoThisScroll, adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(220f) }); GUILayout.TextArea(portalInfoThisText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(GetTextAreaHeight(portalInfoThisText, 170f)) }); GUILayout.EndScrollView(); } portalInfoShowWorld = DrawCollapseHeader(portalInfoShowWorld, "WORLD PORTALS"); if (portalInfoShowWorld) { portalInfoWorldScroll = GUILayout.BeginScrollView(portalInfoWorldScroll, adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(260f) }); GUILayout.TextArea(portalInfoWorldText, adminTextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(GetTextAreaHeight(portalInfoWorldText, 220f)) }); GUILayout.EndScrollView(); } } private static float GetTextAreaHeight(string text, float minimum) { int num = 1; if (!string.IsNullOrEmpty(text)) { num = text.Split(new char[1] { '\n' }).Length; } return Math.Max(minimum, 22f + (float)num * 20f); } private bool DrawCollapseHeader(bool expanded, string label) { GUILayout.Space(8f); if (GUILayout.Button((expanded ? "v " : "> ") + label, adminTabSelectedStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { expanded = !expanded; } return expanded; } private bool DrawBoolInline(string label, bool value, string trueLabel, string falseLabel) { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); GUILayout.Label(label, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) }); if (GUILayout.Button((value ? "> " : string.Empty) + trueLabel, value ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { value = true; } if (GUILayout.Button(((!value) ? "> " : string.Empty) + falseLabel, (!value) ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { value = false; } GUILayout.EndHorizontal(); return value; } private int DrawInlineChoice(string id, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { if (GUILayout.Button(((i == selected) ? "> " : string.Empty) + labels[i], (i == selected) ? adminTabSelectedStyle : adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndHorizontal(); return selected; } private bool DrawBoolDropdown(string id, string label, bool value, string trueLabel, string falseLabel) { int selected = ((!value) ? 1 : 0); selected = DrawChoiceDropdown(id, label, selected, new string[2] { trueLabel, falseLabel }); return selected == 0; } private int DrawChoiceDropdown(string id, int selected, string[] labels) { return DrawChoiceDropdown(id, string.Empty, selected, labels); } private int DrawChoiceDropdown(string id, string label, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (!string.IsNullOrWhiteSpace(label)) { GUILayout.Label(label, adminLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(330f) }); } string text = labels[selected] + " v"; if (GUILayout.Button(text, adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(190f) })) { openDropdown = ((openDropdown == id) ? string.Empty : id); } GUILayout.EndHorizontal(); if (openDropdown == id) { GUILayout.BeginVertical(adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { string text2 = ((i == selected) ? "> " : " "); if (GUILayout.Button(text2 + labels[i], adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndVertical(); } return selected; } private int DrawChoiceList(string id, int selected, string[] labels) { if (labels == null || labels.Length == 0) { return selected; } selected = Mathf.Clamp(selected, 0, labels.Length - 1); GUILayout.BeginVertical(adminBoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]); for (int i = 0; i < labels.Length; i++) { string text = ((i == selected) ? "> " : " "); if (GUILayout.Button(text + labels[i], adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { selected = i; openDropdown = string.Empty; } } GUILayout.EndVertical(); return selected; } private void DrawAdminFooter() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Apply", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { ApplyActiveTab(closeAfterApply: false); } if (GUILayout.Button("Apply & Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { ApplyActiveTab(closeAfterApply: true); } if (GUILayout.Button("Close Without Applying", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } GUILayout.EndHorizontal(); } private void DrawInformationFooter() { GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]); if (GUILayout.Button("Refresh", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { RequestPortalInformation(showStatus: true); } if (GUILayout.Button("Close", adminButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[0])) { showAdminWindow = false; } GUILayout.EndHorizontal(); } private void ApplyActiveTab(bool closeAfterApply) { if (adminTab == 0) { SaveConfigFromUi(); } else { MarkSelectedDiscoveryPortal(GetSelectedPortalRoleValue()); } if (closeAfterApply) { showAdminWindow = false; } } private void ToggleAdminWindow() { if (!adminStatusKnown) { openAdminUiAfterPermissionCheck = true; RequestConfig(openUi: false); ShowMessage("Checking portal limit permissions..."); return; } if (!isAdmin) { showAdminWindow = false; RequestCountForChat(); return; } showAdminWindow = !showAdminWindow; openDropdown = string.Empty; if (showAdminWindow) { RequestConfig(openUi: true); RequestCount(); CenterAdminWindowIfNeeded(); } } private void OpenAdminWindowForPortal(TeleportWorld portal) { SelectPortalForEditing(portal, showStatus: false); showAdminWindow = true; openDropdown = string.Empty; adminTab = 1; statusMessage = "Portal selected. Choose what this portal should do, then Apply or Apply & Close."; CenterAdminWindowIfNeeded(); RequestConfig(openUi: true); RequestCount(); } private void SaveConfigFromUi() { if (!int.TryParse(maxText, out var result)) { statusMessage = "Max portals must be a whole number."; return; } string text = "max=" + Math.Max(0, result) + "\nadminBypass=" + adminBypass + "\nenforceOnServer=" + enforceOnServer + "\nportalPrefabNames=" + Escape(portalNamesText) + "\ndiscoveryEnabled=" + discoveryEnabled + "\ndiscoveryAdminBypass=" + discoveryAdminBypass + "\nadminHoldEToEdit=" + adminHoldEToEdit + "\nshowDiscoveryHoverText=" + showDiscoveryHoverText + "\ndiscoveryLockedHoverText=" + Escape(discoveryLockedHoverTextField) + "\ndiscoveryRemoteHoverText=" + Escape(discoveryRemoteHoverTextField) + "\ndiscoveryUnlockedHoverText=" + Escape(discoveryUnlockedHoverTextField) + "\ndiscoveryLockedMessage=" + Escape(discoveryLockedMessageField) + "\ndiscoveryUnlockMessage=" + Escape(discoveryUnlockMessageField) + "\ndiscoveryShowWorldMarker=" + discoveryShowWorldMarker + "\ndiscoveryTintPortalModel=" + discoveryTintPortalModel + "\ndiscoverySuppressLockedGlow=" + discoverySuppressLockedGlow + "\ndiscoveryLockedColor=" + Escape(discoveryLockedColorField) + "\ndiscoveryRemoteColor=" + Escape(discoveryRemoteColorField) + "\ndiscoveryUnlockedColor=" + Escape(discoveryUnlockedColorField); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.config_update", new object[1] { text }); statusMessage = "Saving portal limit settings..."; } private void RequestConfig(bool openUi) { configRequested = true; if (openUi) { statusMessage = "Loading portal limit settings..."; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.config_request", new object[1] { (openUi ? string.Empty : "[silent]") + GetPlayerName() }); RequestUnlockList(); } private void RequestCount() { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.count_request", new object[1] { localPlayerId }); } } private void RequestCountForChat() { showCountMessageOnNextResponse = true; RequestCount(); ShowMessage("Checking portal count..."); } private void RequestPlacementCountSoon() { ((MonoBehaviour)this).StartCoroutine(RequestPlacementCountNextFrame()); } private IEnumerator RequestPlacementCountNextFrame() { yield return (object)new WaitForSeconds(0.35f); long playerId = GetLocalPlayerId(); int count = CountPortals(playerId); string maxText = ((maxPortalsPerPlayer > 0) ? maxPortalsPerPlayer.ToString() : "unlimited"); serverPortalCount = count; ShowMessage("Portals placed: " + count + " / " + maxText); RequestCount(); } private void RequestUnlockList() { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_unlock_list_request", new object[1] { localPlayerId }); } } private void RequestPortalInformation(bool showStatus) { TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { portalInfoThisText = "No portal was opened."; portalInfoWorldText = "Open this tab while editing a portal."; return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); ZDO val2 = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); portalInfoRequestedPortalKey = ((val2 != null) ? ((object)(ZDOID)(ref val2.m_uid)).ToString() : GetPortalKey(val)); portalInfoThisText = "Loading authoritative portal information from the server..."; string portalTagForUi = GetPortalTagForUi(val); if (ZRoutedRpc.instance == null) { portalInfoWorldText = "Portal Limit server RPC is not ready yet."; return; } if (showStatus) { statusMessage = "Loading portal information..."; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.admin_report_request", new object[1] { "portalinfo|" + Escape(portalTagForUi) + "|" + Escape(portalInfoRequestedPortalKey) }); } private static void OnConfigResponse(long sender, string payload) { Instance.ApplyConfigPayload(payload); } private static void OnCountResponse(long sender, int count, int max, bool limitReached, string payload) { Instance.serverPortalCount = count; Instance.maxPortalsPerPlayer = max; Instance.ApplyConfigPayload(payload); if (Instance.showPlacementCountOnNextResponse) { Instance.showPlacementCountOnNextResponse = false; string text = ((max > 0) ? max.ToString() : "unlimited"); Instance.ShowMessage("Portals placed: " + count + " / " + text); } else if (Instance.showCountMessageOnNextResponse) { Instance.showCountMessageOnNextResponse = false; string text = ((max > 0) ? max.ToString() : "unlimited"); Instance.ShowMessage("Portals: " + count + " / " + text); } } private static void OnNotice(long sender, string message) { Instance.ShowMessage(message); } private static void OnDiscoveryUnlockListResponse(long sender, string payload) { Instance.ApplyUnlockPayload(payload); } private static void OnAdminReportResponse(long sender, string payload) { if (string.IsNullOrWhiteSpace(payload)) { Terminal.Log((object)"Portal Limit: empty report."); return; } if ((Object)(object)Instance != (Object)null && payload.StartsWith("PortalInfoResponse\n", StringComparison.Ordinal)) { Instance.ApplyPortalInformationPayload(payload); return; } string[] array = payload.Split(new char[1] { '\n' }); foreach (string text in array) { Terminal.Log((object)text); } if ((Object)(object)Instance != (Object)null) { Instance.ShowMessage("Portal Limit report written to F5 console."); } } private void ApplyPortalInformationPayload(string payload) { string text = payload.Substring("PortalInfoResponse\n".Length); string[] array = text.Split(new string[1] { "\n---WORLD---\n" }, StringSplitOptions.None); if (array.Length > 0 && !string.IsNullOrWhiteSpace(array[0])) { portalInfoThisText = array[0].Trim(); } portalInfoWorldText = ((array.Length > 1) ? array[1].Trim() : text.Trim()); statusMessage = "Portal information loaded."; } private void ApplyConfigPayload(string payload) { Dictionary<string, string> dictionary = ParsePayload(payload); if (dictionary.TryGetValue("isAdmin", out var value) && bool.TryParse(value, out var result)) { isAdmin = result; adminStatusKnown = true; if (!isAdmin) { showAdminWindow = false; } if (openAdminUiAfterPermissionCheck) { openAdminUiAfterPermissionCheck = false; if (isAdmin) { showAdminWindow = true; openDropdown = string.Empty; CenterAdminWindowIfNeeded(); RequestConfig(openUi: true); RequestCount(); } else { RequestCountForChat(); } } } if (dictionary.TryGetValue("max", out value) && int.TryParse(value, out var result2)) { maxPortalsPerPlayer = result2; maxText = result2.ToString(); } if (dictionary.TryGetValue("adminBypass", out value) && bool.TryParse(value, out result)) { adminBypass = result; } if (dictionary.TryGetValue("enforceOnServer", out value) && bool.TryParse(value, out result)) { enforceOnServer = result; } if (dictionary.TryGetValue("portalPrefabNames", out value)) { portalPrefabNames = value; portalNamesText = value; } if (dictionary.TryGetValue("discoveryEnabled", out value) && bool.TryParse(value, out result)) { discoveryEnabled = result; } if (dictionary.TryGetValue("discoveryAdminBypass", out value) && bool.TryParse(value, out result)) { discoveryAdminBypass = result; } if (dictionary.TryGetValue("adminHoldEToEdit", out value) && bool.TryParse(value, out result)) { adminHoldEToEdit = result; } if (dictionary.TryGetValue("showDiscoveryHoverText", out value) && bool.TryParse(value, out result)) { showDiscoveryHoverText = result; } if (dictionary.TryGetValue("discoveryLockedHoverText", out value)) { discoveryLockedHoverText = value; discoveryLockedHoverTextField = value; } if (dictionary.TryGetValue("discoveryRemoteHoverText", out value)) { discoveryRemoteHoverText = value; discoveryRemoteHoverTextField = value; } if (dictionary.TryGetValue("discoveryUnlockedHoverText", out value)) { discoveryUnlockedHoverText = value; discoveryUnlockedHoverTextField = value; } if (dictionary.TryGetValue("discoveryLockedMessage", out value)) { discoveryLockedMessage = value; discoveryLockedMessageField = value; } if (dictionary.TryGetValue("discoveryUnlockMessage", out value)) { discoveryUnlockMessage = value; discoveryUnlockMessageField = value; } if (dictionary.TryGetValue("discoveryShowWorldMarker", out value) && bool.TryParse(value, out result)) { discoveryShowWorldMarker = result; } if (dictionary.TryGetValue("discoveryTintPortalModel", out value) && bool.TryParse(value, out result)) { discoveryTintPortalModel = result; } if (dictionary.TryGetValue("discoverySuppressLockedGlow", out value) && bool.TryParse(value, out result)) { discoverySuppressLockedGlow = result; } if (dictionary.TryGetValue("discoveryLockedColor", out value)) { discoveryLockedColor = value; discoveryLockedColorField = value; } if (dictionary.TryGetValue("discoveryRemoteColor", out value)) { discoveryRemoteColor = value; discoveryRemoteColorField = value; } if (dictionary.TryGetValue("discoveryUnlockedColor", out value)) { discoveryUnlockedColor = value; discoveryUnlockedColorField = value; } if (dictionary.TryGetValue("message", out value) && !string.IsNullOrWhiteSpace(value)) { statusMessage = value; ShowMessage(value); } } private void ApplyUnlockPayload(string payload) { Dictionary<string, string> dictionary = ParsePayload(payload); unlockedDiscoveryLinks.Clear(); if (dictionary.TryGetValue("links", out var value)) { string[] array = value.Split(new char[1] { ';' }); foreach (string text in array) { string text2 = text.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { unlockedDiscoveryLinks.Add(text2); } } } if (dictionary.TryGetValue("message", out var value2) && !string.IsNullOrWhiteSpace(value2)) { ShowMessage(value2); } } private void MarkSelectedDiscoveryPortal(int role) { //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { statusMessage = "No portal selected. Look at a portal and click Select first."; return; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { statusMessage = "That portal has no valid network view."; return; } string text = discoveryLinkText.Trim(); bool flag = CanEditPortalTag(val); if (!flag) { text = GetPortalTagForUi(val).Trim(); } if (role != 0 && string.IsNullOrWhiteSpace(text)) { statusMessage = "Enter a portal tag first."; return; } discoveryLinkText = text; if (flag) { SetPortalTag(val, text); } string text2 = ((role == 0) ? string.Empty : text); string normalized = string.Empty; string text3 = string.Empty; if (role != 0) { if (!TryNormalizeHexColor(selectedPortalColorText, out normalized)) { statusMessage = "Enter a color like #ff3030."; return; } selectedPortalColorText = normalized; text3 = NormalizeMarkerTextValue(selectedPortalMarkerText); } string text4 = "role=" + role + "\nlink=" + Escape(text2) + "\nmarkerColor=" + Escape(normalized) + "\nmarkerText=" + Escape(text3) + "\nshowMarker=" + selectedPortalShowMarker + "\nsuppressGlow=" + selectedPortalSuppressGlow + "\nlockedHoverText=" + Escape(selectedLockedHoverText) + "\nremoteHoverText=" + Escape(selectedRemoteHoverText) + "\nunlockedHoverText=" + Escape(selectedUnlockedHoverText); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_mark_request", new object[2] { component.GetZDO().m_uid, text4 }); ApplyLocalPortalMarker(val, role, text2, normalized, text3, selectedPortalShowMarker, selectedPortalSuppressGlow, selectedLockedHoverText, selectedRemoteHoverText, selectedUnlockedHoverText); statusMessage = "Portal settings saved."; Log.LogInfo((object)("Sent discovery portal marker request role=" + role + " tag='" + text + "' portal=" + component.GetZDO().m_uid)); } private void RelockSelectedDiscoveryPortal() { RelockDiscoveryPortalTag(discoveryLinkText); } private void RelockDiscoveryPortalTag(string portalTagText) { string text = (portalTagText ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { statusMessage = "Enter a portal tag first."; return; } ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_relock_request", new object[1] { text }); unlockedDiscoveryLinks.Remove(text); statusMessage = "Relock request sent for portal tag '" + text + "'."; } private void ReadSelectedPortalSettings() { TeleportWorld val = GetSelectedPortal(); if ((Object)(object)val == (Object)null) { statusMessage = "No portal selected. Look at a portal and click Select first."; } else { LoadPortalSettings(val, showStatus: true); } } private string BuildLocalPortalInformation(TeleportWorld portal) { if ((Object)(object)portal == (Object)null) { return "THIS PORTAL\nNo portal selected."; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); string text = ((val != null) ? val.GetString("PortalLimit_BuiltUtc", string.Empty) : string.Empty); string text2 = GetPortalCreatorName(portal); if (string.IsNullOrWhiteSpace(text2)) { text2 = "unknown"; } string text3 = GetPortalTagForUi(portal); if (string.IsNullOrWhiteSpace(text3)) { text3 = "(none)"; } string text4 = (string.IsNullOrWhiteSpace(text) ? "unknown for older portals" : text); return "THIS PORTAL\nPortal Tag: " + text3 + "\nPlayer Who Built the Portal: " + text2 + "\nDate the portal was built: " + text4 + "\nPortal role: " + GetPortalRoleLabel(GetDiscoveryRole(portal)) + "\nPortal id: " + ((val != null) ? ((object)(ZDOID)(ref val.m_uid)).ToString() : "unknown"); } private void SelectPortalForEditing(TeleportWorld portal, bool showStatus) { if ((Object)(object)portal == (Object)null) { if (showStatus) { statusMessage = "Look directly at a portal first."; } } else { selectedPortal = portal; LoadPortalSettings(portal, showStatus); } } private TeleportWorld GetSelectedPortal() { if ((Object)(object)selectedPortal != (Object)null) { ZNetView component = ((Component)selectedPortal).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { return selectedPortal; } } selectedPortal = null; loadedPortalKey = string.Empty; return null; } private void LoadPortalSettings(TeleportWorld portal, bool showStatus) { selectedPortalRole = GetDiscoveryRole(portal) switch { 2 => 2, 1 => 1, _ => 0, }; string discoveryLink = GetDiscoveryLink(portal); if (!string.IsNullOrWhiteSpace(discoveryLink)) { discoveryLinkText = discoveryLink; } else { string portalTag = GetPortalTag(portal); if (!string.IsNullOrWhiteSpace(portalTag)) { discoveryLinkText = portalTag; } } loadedPortalKey = GetPortalKey(portal); selectedPortalColorText = GetDiscoveryColor(portal); if (string.IsNullOrWhiteSpace(selectedPortalColorText)) { selectedPortalColorText = MarkerColorValues[0]; } selectedPortalColorIndex = GetMarkerColorIndex(selectedPortalColorText); selectedPortalMarkerText = GetDiscoveryMarkerText(portal); selectedPortalMarkerTextIndex = GetMarkerTextIndex(selectedPortalMarkerText); selectedPortalShowMarker = GetDiscoveryShowMarker(portal); selectedPortalSuppressGlow = GetDiscoverySuppressGlow(portal); selectedLockedHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryLockedHoverText"); selectedRemoteHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryRemoteHoverText"); selectedUnlockedHoverText = GetDiscoveryHoverOverride(portal, "PortalLimit_DiscoveryUnlockedHoverText"); if (showStatus) { statusMessage = "Selected portal loaded. Choose what this portal does, then Apply."; } } private static void ApplyLocalPortalMarker(TeleportWorld portal, int role, string link, string markerColor, string markerText, bool showMarker, bool suppressGlow, string lockedHoverText, string remoteHoverText, string unlockedHoverText) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 != null) { val2.Set("PortalLimit_DiscoveryRole", role); val2.Set("PortalLimit_DiscoveryLink", (role == 0) ? string.Empty : link); val2.Set("PortalLimit_DiscoveryColor", (role == 0) ? string.Empty : markerColor); val2.Set("PortalLimit_DiscoveryMarkerText", (role == 0) ? string.Empty : NormalizeMarkerTextValue(markerText)); val2.Set("PortalLimit_DiscoveryShowMarker", (role != 0) ? (showMarker ? 1 : 0) : 0); val2.Set("PortalLimit_DiscoverySuppressGlow", (role != 0) ? (suppressGlow ? 1 : 0) : 0); val2.Set("PortalLimit_DiscoveryLockedHoverText", (role == 0) ? string.Empty : (lockedHoverText ?? string.Empty).Trim()); val2.Set("PortalLimit_DiscoveryRemoteHoverText", (role == 0) ? string.Empty : (remoteHoverText ?? string.Empty).Trim()); val2.Set("PortalLimit_DiscoveryUnlockedHoverText", (role == 0) ? string.Empty : (unlockedHoverText ?? string.Empty).Trim()); } } private int GetSelectedPortalRoleValue() { if (selectedPortalRole == 1) { return 1; } if (selectedPortalRole == 2) { return 2; } return 0; } private static string GetPortalRoleLabel(int role) { return role switch { 1 => "Locked entrance", 2 => "Unlocked entrance", _ => "Normal portal", }; } private static TeleportWorld GetHoveredPortal() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return null; } GameObject hoverObject = ((Humanoid)Player.m_localPlayer).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return null; } TeleportWorld val = hoverObject.GetComponent<TeleportWorld>(); if ((Object)(object)val == (Object)null) { val = hoverObject.GetComponentInParent<TeleportWorld>(); } return val; } private static string GetPortalKey(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? ((object)(ZDOID)(ref val2.m_uid)).ToString() : string.Empty; } private static string GetPortalCreatorName(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 == null) { return string.Empty; } string @string = val2.GetString(ZDOVars.s_creatorName, string.Empty); return @string ?? string.Empty; } private static bool CanEditPortalTag(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || (Object)(object)portal == (Object)null) { return false; } Piece val = ((Component)portal).GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = ((Component)portal).GetComponentInParent<Piece>(); } if ((Object)(object)val == (Object)null) { return true; } long creator = val.GetCreator(); long localPlayerId = GetLocalPlayerId(); return creator == 0 || creator == localPlayerId; } private static string GetPortalTag(TeleportWorld portal) { MethodInfo methodInfo = AccessTools.Method(typeof(TeleportWorld), "GetText", (Type[])null, (Type[])null); if ((Object)(object)portal != (Object)null && methodInfo != null) { object obj = methodInfo.Invoke(portal, null); if (obj != null) { return obj.ToString(); } } return string.Empty; } private static string GetPortalTagForUi(TeleportWorld portal) { string discoveryLink = GetDiscoveryLink(portal); if (!string.IsNullOrWhiteSpace(discoveryLink)) { return discoveryLink; } return GetPortalTag(portal); } private static void SetPortalTag(TeleportWorld portal, string tag) { if ((Object)(object)portal == (Object)null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(TeleportWorld), "SetText", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(portal, new object[1] { tag ?? string.Empty }); return; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val != null) { val.Set("tag", tag ?? string.Empty); } } private static void SetTargetFound(TeleportWorld portal, bool value) { if ((Object)(object)portal != (Object)null && TeleportWorldTargetFoundField != null) { TeleportWorldTargetFoundField.SetValue(portal, value); } } private static int GetDiscoveryRole(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetInt("PortalLimit_DiscoveryRole", 0) : 0; } private static string GetDiscoveryLink(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString("PortalLimit_DiscoveryLink", string.Empty) : string.Empty; } private static string GetDiscoveryColor(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString("PortalLimit_DiscoveryColor", string.Empty) : string.Empty; } private static string GetDiscoveryMarkerText(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? NormalizeMarkerTextValue(val2.GetString("PortalLimit_DiscoveryMarkerText", string.Empty)) : MarkerTextValues[0]; } private bool GetDiscoveryShowMarker(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? (val2.GetInt("PortalLimit_DiscoveryShowMarker", discoveryShowWorldMarker ? 1 : 0) != 0) : discoveryShowWorldMarker; } private bool GetDiscoverySuppressGlow(TeleportWorld portal) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? (val2.GetInt("PortalLimit_DiscoverySuppressGlow", discoverySuppressLockedGlow ? 1 : 0) != 0) : discoverySuppressLockedGlow; } private static string GetDiscoveryHoverOverride(TeleportWorld portal, string key) { ZNetView val = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); return (val2 != null) ? val2.GetString(key, string.Empty) : string.Empty; } private Color GetDiscoveryVisualColor(TeleportWorld portal) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0090: 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_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_0082: Unknown result type (might be due to invalid IL or missing references) string discoveryColor = GetDiscoveryColor(portal); if (!string.IsNullOrWhiteSpace(discoveryColor)) { return ParseHexColor(discoveryColor, LockedOrange); } int discoveryRole = GetDiscoveryRole(portal); string discoveryLink = GetDiscoveryLink(portal); if (discoveryRole != 0 && !string.IsNullOrWhiteSpace(discoveryLink) && IsDiscoveryUnlocked(discoveryLink)) { return ParseHexColor(discoveryUnlockedColor, Color.green); } if (discoveryRole == 2) { return ParseHexColor(discoveryRemoteColor, Color.cyan); } return ParseHexColor(discoveryLockedColor, LockedOrange); } private bool ShouldShowDiscoveryWorldMarker(TeleportWorld portal) { return discoveryEnabled && GetDiscoveryShowMarker(portal) && ShouldShowLockedEntranceX(portal); } private string GetDiscoveryMarkerDisplayText(TeleportWorld portal) { string discoveryMarkerText = GetDiscoveryMarkerText(portal); if (string.Equals(discoveryMarkerText, "Locked", StringComparison.OrdinalIgnoreCase)) { return "LOCKED"; } if (string.Equals(discoveryMarkerText, "X", StringComparison.OrdinalIgnoreCase)) { return "X"; } if (string.Equals(discoveryMarkerText, "UnlockOnOtherSide", StringComparison.OrdinalIgnoreCase)) { return "UNLOCK ON OTHER SIDE"; } return string.IsNullOrWhiteSpace(discoveryMarkerText) ? "UNLOCK ON OTHER SIDE" : discoveryMarkerText; } private bool ShouldShowLockedEntranceX(TeleportWorld portal) { if (GetDiscoveryRole(portal) != 1) { return false; } string discoveryLink = GetDiscoveryLink(portal); return !string.IsNullOrWhiteSpace(discoveryLink) && !IsDiscoveryUnlocked(discoveryLink); } private bool ShouldTintDiscoveryPortal(TeleportWorld portal) { return false; } private bool ShouldSuppressLockedPortalGlow(TeleportWorld portal) { if (!discoveryEnabled || !GetDiscoverySuppressGlow(portal) || GetDiscoveryRole(portal) != 1) { return false; } string discoveryLink = GetDiscoveryLink(portal); return !string.IsNullOrWhiteSpace(discoveryLink) && !IsDiscoveryUnlocked(discoveryLink); } private static Color ParseHexColor(string text, Color fallback) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00bb: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(text)) { return fallback; } string text2 = text.Trim(); if (text2.StartsWith("#", StringComparison.Ordinal)) { text2 = text2.Substring(1); } if (text2.Length == 6 && int.TryParse(text2.Substring(0, 2), NumberStyles.HexNumber, null, out var result) && int.TryParse(text2.Substring(2, 2), NumberStyles.HexNumber, null, out var result2) && int.TryParse(text2.Substring(4, 2), NumberStyles.HexNumber, null, out var result3)) { return new Color((float)result / 255f, (float)result2 / 255f, (float)result3 / 255f, 1f); } return fallback; } private static string NormalizeHexColor(string text, string fallback) { string text2 = (text ?? string.Empty).Trim(); if (!text2.StartsWith("#", StringComparison.Ordinal)) { text2 = "#" + text2; } Color val = default(Color); return ColorUtility.TryParseHtmlString(text2, ref val) ? text2 : fallback; } private static bool TryNormalizeHexColor(string text, out string normalized) { normalized = (text ?? string.Empty).Trim(); if (!normalized.StartsWith("#", StringComparison.Ordinal)) { normalized = "#" + normalized; } Color val = default(Color); if (normalized.Length == 7 && ColorUtility.TryParseHtmlString(normalized, ref val)) { return true; } normalized = string.Empty; return false; } private static int GetMarkerColorIndex(string color) { string a = NormalizeHexColor(color, MarkerColorValues[0]); for (int i = 0; i < MarkerColorValues.Length; i++) { if (string.Equals(a, MarkerColorValues[i], StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } private static string NormalizeMarkerTextValue(string value) { string text = (value ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { return MarkerTextLabels[0]; } for (int i = 0; i < MarkerTextValues.Length; i++) { if (string.Equals(text, MarkerTextValues[i], StringComparison.OrdinalIgnoreCase) || string.Equals(text, MarkerTextLabels[i], StringComparison.OrdinalIgnoreCase)) { return MarkerTextLabels[i]; } } return text; } private static int GetMarkerTextIndex(string value) { string a = NormalizeMarkerTextValue(value); for (int i = 0; i < MarkerTextValues.Length; i++) { if (string.Equals(a, MarkerTextValues[i], StringComparison.OrdinalIgnoreCase) || string.Equals(a, MarkerTextLabels[i], StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } private bool IsDiscoveryUnlocked(string link) { if (string.IsNullOrWhiteSpace(link)) { return false; } return unlockedDiscoveryLinks.Contains(link); } private void UnlockDiscoveryLink(string link, TeleportWorld portal) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrWhiteSpace(link)) { unlockedDiscoveryLinks.Add(link); long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0 && ZRoutedRpc.instance != null) { Vector3 val = (((Object)(object)portal != (Object)null) ? ((Component)portal).transform.position : Vector3.zero); ZNetView val2 = (((Object)(object)portal != (Object)null) ? ((Component)portal).GetComponent<ZNetView>() : null); ZDOID val3 = (((Object)(object)val2 != (Object)null && val2.IsValid()) ? val2.GetZDO().m_uid : ZDOID.None); string text = "link=" + Escape(link.Trim()) + "\nplayerName=" + Escape(GetPlayerName()) + "\nportalId=" + Escape(((object)(ZDOID)(ref val3)).ToString()) + "\nx=" + val.x.ToString("F1") + "\ny=" + val.y.ToString("F1") + "\nz=" + val.z.ToString("F1"); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.discovery_unlock_request", new object[2] { localPlayerId, text }); } } } private static bool ShouldBlockPortalUse(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || !Instance.discoveryEnabled || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } int discoveryRole = GetDiscoveryRole(portal); if (discoveryRole == 0) { return false; } string discoveryLink = GetDiscoveryLink(portal); if (string.IsNullOrWhiteSpace(discoveryLink)) { return false; } if (Instance.discoveryAdminBypass && Instance.isAdmin) { return false; } switch (discoveryRole) { case 2: if (!Instance.IsDiscoveryUnlocked(discoveryLink)) { Instance.UnlockDiscoveryLink(discoveryLink, portal); Instance.ShowMessage(Instance.discoveryUnlockMessage); } return false; case 1: if (!Instance.IsDiscoveryUnlocked(discoveryLink)) { Instance.ShowMessage(Instance.discoveryLockedMessage); Instance.RequestUnlockList(); return true; } break; } return false; } private static bool ShouldBlockBlankPortalUse(TeleportWorld portal) { if ((Object)(object)Instance == (Object)null || (Object)(object)portal == (Object)null) { return false; } if (string.IsNullOrWhiteSpace(GetPortalTag(portal))) { Instance.ShowMessage("Set a portal tag first."); return true; } return false; } internal static bool WouldExceedPortalLimit(Piece piece) { PortalLimitClientPlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)piece == (Object)null || !instance.IsLimitedPortal(piece)) { return false; } if (instance.maxPortalsPerPlayer <= 0) { return false; } if (instance.adminBypass && instance.isAdmin) { return false; } long localPlayerId = GetLocalPlayerId(); int num = instance.CountPortals(localPlayerId); return num >= instance.maxPortalsPerPlayer; } private bool IsLimitedPortal(Piece piece) { if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<TeleportWorld>() == (Object)null) { return false; } HashSet<string> portalPrefabNameSet = GetPortalPrefabNameSet(); if (portalPrefabNameSet.Count == 0) { return true; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); string prefabName = GetPrefabName(component, piece); return portalPrefabNameSet.Contains(prefabName); } private void ReportPortalMetadata(Piece piece, string action) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)piece == (Object)null) && IsLimitedPortal(piece) && ZRoutedRpc.instance != null) { ZNetView component = ((Component)piece).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val != null) { Vector3 position = ((Component)piece).transform.position; string text = "action=" + Escape(action) + "\nportalId=" + Escape(((object)(ZDOID)(ref val.m_uid)).ToString()) + "\nplayerId=" + GetLocalPlayerId() + "\nplayerName=" + Escape(GetPlayerName()) + "\nx=" + position.x.ToString("F1") + "\ny=" + position.y.ToString("F1") + "\nz=" + position.z.ToString("F1"); ZRoutedRpc.instance.InvokeRoutedRPC("keith.valheim.portallimit.portal_metadata_update", new object[1] { text }); } } } private void ReportPortalMetadata(TeleportWorld portal, string action) { if (!((Object)(object)portal == (Object)null)) { Piece val = ((Component)portal).GetComponent<Piece>(); if ((Object)(object)val == (Object)null) { val = ((Component)portal).GetComponentInParent<Piece>(); } ReportPortalMetadata(val, action); } } private static string GetPrefabName(ZNetView nview, Piece piece) { if ((Object)(object)nview != (Object)null && GetPrefabNameMethod != null) { object obj = GetPrefabNameMethod.Invoke(nview, null); if (obj != null) { return obj.ToString(); } } return ((Object)(object)piece != (Object)null) ? ((Object)piece).name.Replace("(Clone)", string.Empty) : string.Empty; } private int CountPortals(long creatorId) { if (creatorId == 0 || AllPiecesField == null) { return serverPortalCount; } int num = 0; if (!(AllPiecesField.GetValue(null) is IEnumerable enumerable)) { return serverPortalCount; } foreach (object item in enumerable) { Piece val = (Piece)((item is Piece) ? item : null); if ((Object)(object)val != (Object)null && val.GetCreator() == creatorId && IsLimitedPortal(val)) { num++; } } return num; } private HashSet<string> GetPortalPrefabNameSet() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = portalPrefabNames.Split(new char[1] { ',' }); foreach (string text in array) { string text2 = text.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { hashSet.Add(text2); } } return hashSet; } private static long GetLocalPlayerId() { try { if ((Object)(object)Player.m_localPlayer != (Object)null && GetPlayerIdMethod != null) { object obj = GetPlayerIdMethod.Invoke(Player.m_localPlayer, null); if (obj != null && obj.GetType() == typeof(long)) { return (long)obj; } } } catch (Exception ex) { Log.LogWarning((object)("Could not read local player ID: " + ex.Message)); } return 0L; } private static string GetPlayerName() { return ((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerName() : "unknown-player"; } internal void ShowMessage(string message) { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false); } else { Log.LogMessage((object)message); } } private static Dictionary<string, string> ParsePayload(string payload) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(payload)) { return dictionary; } string[] array = payload.Split(new char[1] { '\n' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { dictionary[text.Substring(0, num)] = Unescape(text.Substring(num + 1)); } } return dictionary; } private static string Escape(string value) { return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\n", "\\n").Replace("=", "\\e"); } private static string Unescape(string value) { return (value ?? string.Empty).Replace("\\e", "=").Replace("\\n", "\n").Replace("\\\\", "\\"); } }
BepInEx\plugins\PortalLimitServer.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace PortalLimit.Server; [BepInPlugin("keith.valheim.portallimit.server", "Portal Limit and Discovery Server", "0.1.4")] public class PortalLimitServerPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(TeleportWorld), "SetConnectedPortal")] private static class TeleportWorldSetConnectedPortalPatch { private static void Prefix(TeleportWorld __instance, ref ZDOID targetID) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { targetID = ZDOID.None; } } } [HarmonyPatch(typeof(TeleportWorld), "RPC_SetConnected")] private static class TeleportWorldRpcSetConnectedPatch { private static void Prefix(TeleportWorld __instance, ref ZDOID portalID) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null && string.IsNullOrWhiteSpace(GetPortalTag(__instance))) { portalID = ZDOID.None; } } } [HarmonyPatch(typeof(Piece), "OnPlaced")] private static class PieceOnPlacedPatch { private static void Postfix(Piece __instance) { EnforceIfNeeded(__instance); } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] private static class WearNTearRemovePatch { private static bool Prefix(WearNTear __instance, long sender) { if ((Object)(object)Instance == (Object)null || (Object)(object)__instance == (Object)null) { return true; } Piece component = ((Component)__instance).GetComponent<Piece>(); if (!Instance.IsLimitedPortal(component)) { return true; } long creator = component.GetCreator(); if (sender == creator || Instance.IsSenderAdmin(sender)) { return true; } if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.notice", new object[1] { "Only the builder or an admin can remove this portal." }); } Log.LogWarning((object)("Blocked portal remove request sender=" + sender + " creator=" + creator + ".")); return false; } } public const string PluginGuid = "keith.valheim.portallimit.server"; public const string PluginName = "Portal Limit and Discovery Server"; public const string PluginVersion = "0.1.4"; private const string RpcConfigRequest = "keith.valheim.portallimit.config_request"; private const string RpcConfigResponse = "keith.valheim.portallimit.config_response"; private const string RpcConfigUpdate = "keith.valheim.portallimit.config_update"; private const string RpcCountRequest = "keith.valheim.portallimit.count_request"; private const string RpcCountResponse = "keith.valheim.portallimit.count_response"; private const string RpcNotice = "keith.valheim.portallimit.notice"; private const string RpcDiscoveryMarkRequest = "keith.valheim.portallimit.discovery_mark_request"; private const string RpcDiscoveryUnlockRequest = "keith.valheim.portallimit.discovery_unlock_request"; private const string RpcDiscoveryRelockRequest = "keith.valheim.portallimit.discovery_relock_request"; private const string RpcDiscoveryUnlockListRequest = "keith.valheim.portallimit.discovery_unlock_list_request"; private const string RpcDiscoveryUnlockListResponse = "keith.valheim.portallimit.discovery_unlock_list_response"; private const string RpcAdminReportRequest = "keith.valheim.portallimit.admin_report_request"; private const string RpcAdminReportResponse = "keith.valheim.portallimit.admin_report_response"; private const string RpcPortalMetadataUpdate = "keith.valheim.portallimit.portal_metadata_update"; private const string DiscoveryRoleKey = "PortalLimit_DiscoveryRole"; private const string DiscoveryLinkKey = "PortalLimit_DiscoveryLink"; private const string DiscoveryColorKey = "PortalLimit_DiscoveryColor"; private const string DiscoveryMarkerTextKey = "PortalLimit_DiscoveryMarkerText"; private const string DiscoveryShowMarkerKey = "PortalLimit_DiscoveryShowMarker"; private const string DiscoverySuppressGlowKey = "PortalLimit_DiscoverySuppressGlow"; private const string DiscoveryLockedHoverTextKey = "PortalLimit_DiscoveryLockedHoverText"; private const string DiscoveryRemoteHoverTextKey = "PortalLimit_DiscoveryRemoteHoverText"; private const string DiscoveryUnlockedHoverTextKey = "PortalLimit_DiscoveryUnlockedHoverText"; private const string PortalBuiltUtcKey = "PortalLimit_BuiltUtc"; private const string PortalBuilderNameKey = "PortalLimit_BuilderName"; private const string PortalBuilderIdKey = "PortalLimit_BuilderId"; private const string PortalLastUsedUtcKey = "PortalLimit_LastUsedUtc"; private const string PortalLastUsedNameKey = "PortalLimit_LastUsedName"; private const string PortalLastUsedIdKey = "PortalLimit_LastUsedId"; private const int DiscoveryRoleNone = 0; private const int DiscoveryRoleLocked = 1; private const int DiscoveryRoleRemote = 2; internal static PortalLimitServerPlugin Instance; internal static ManualLogSource Log; private static readonly FieldInfo AllPiecesField = AccessTools.Field(typeof(Piece), "s_allPieces"); private static readonly FieldInfo PeerSocketField = AccessTools.Field(typeof(ZNetPeer), "m_socket"); private static readonly FieldInfo OnZdoDestroyedField = AccessTools.Field(typeof(ZDOMan), "m_onZDODestroyed"); private static readonly FieldInfo NetScenePrefabsField = AccessTools.Field(typeof(ZNetScene), "m_prefabs"); private static readonly MethodInfo GetPrefabNameMethod = AccessTools.Method(typeof(ZNetView), "GetPrefabName", (Type[])null, (Type[])null); private static readonly MethodInfo GetPortalTextMethod = AccessTools.Method(typeof(TeleportWorld), "GetText", (Type[])null, (Type[])null); private Harmony harmony; private bool rpcRegistered; private bool portalIndexBuilt; private bool zdoDestroyedHooked; private string dataDirectory; private string unlockFilePath; private string unlockHistoryFilePath; private string portalCountsFilePath; private string portalPlacementLogFilePath; private readonly Dictionary<long, HashSet<string>> unlockedLinksByPlayer = new Dictionary<long, HashSet<string>>(); private readonly Dictionary<long, HashSet<ZDOID>> portalIdsByCreator = new Dictionary<long, HashSet<ZDOID>>(); private readonly Dictionary<ZDOID, long> creatorByPortalId = new Dictionary<ZDOID, long>(); private readonly Dictionary<long, string> creatorNamesByCreator = new Dictionary<long, string>(); private ConfigEntry<int> maxPortalsPerPlayer; private ConfigEntry<bool> adminBypass; private ConfigEntry<bool> enforceOnServer; private ConfigEntry<string> portalPrefabNames; private ConfigEntry<bool> discoveryPortalsEnabled; private ConfigEntry<bool> discoveryAdminBypass; private ConfigEntry<bool> adminHoldEToEdit; private ConfigEntry<bool> showDiscoveryHoverText; private ConfigEntry<string> discoveryLockedHoverText; private ConfigEntry<string> discoveryRemoteHoverText; private ConfigEntry<string> discoveryUnlockedHoverText; private ConfigEntry<string> discoveryLockedMessage; private ConfigEntry<string> discoveryUnlockMessage; private ConfigEntry<bool> discoveryShowWorldMarker; private ConfigEntry<bool> discoveryTintPortalModel; private ConfigEntry<bool> discoverySuppressLockedGlow; private ConfigEntry<string> discoveryLockedColor; private ConfigEntry<string> discoveryRemoteColor; private ConfigEntry<string> discoveryUnlockedColor; private void Awake() { //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; maxPortalsPerPlayer = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPortalsPerPlayer", 10, "Maximum number of matching portals each player may own. Set to 0 or below to disable the limit."); adminBypass = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AdminBypass", true, "Allow Valheim admins to exceed the portal limit."); enforceOnServer = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnforceOnServer", true, "Delete newly placed portals on the server when they exceed the limit. Keep this enabled for real enforcement."); portalPrefabNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PortalPrefabNames", "portal_wood,portal_stone", "Comma-separated portal prefab names to limit. Leave empty to limit every piece with a TeleportWorld component."); discoveryPortalsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "Enabled", true, "Enable per-player discovery-gated portals."); discoveryAdminBypass = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "AdminBypass", true, "Allow Valheim admins to use locked discovery portals without unlocking them."); adminHoldEToEdit = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "AdminHoldEToEdit", true, "Allow admins with the client plugin to hold E on a portal to open the Portal Limit editor."); showDiscoveryHoverText = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "ShowHoverText", true, "Show discovery portal status lines in portal hover text for clients with the plugin."); discoveryLockedHoverText = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "LockedHoverText", "Locked: find the other end first.", "Hover text shown for locked discovery portals before a player unlocks the link."); discoveryRemoteHoverText = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "RemoteHoverText", "Discovery portal: use this side to unlock the route.", "Hover text shown for the discovery side of a locked route."); discoveryUnlockedHoverText = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "UnlockedHoverText", "Discovery route unlocked.", "Hover text shown after the player unlocks the route."); discoveryLockedMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "LockedMessage", "This portal is locked. Find and enter the other end first.", "Message shown when a player tries to use a locked discovery portal."); discoveryUnlockMessage = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "UnlockMessage", "Discovery portal unlocked.", "Message shown when a player unlocks a discovery portal route."); discoveryShowWorldMarker = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "ShowWorldMarker", true, "Show a visible marker on marked discovery portals for clients with the plugin."); discoveryTintPortalModel = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "TintPortalModel", false, "Tint the portal model color for clients with the plugin."); discoverySuppressLockedGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Discovery Portals", "SuppressLockedGlow", false, "Hide connected portal glow and particle effects on locked portals before the route is unlocked."); discoveryLockedColor = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "LockedColor", "#ff9f1a", "Hex color for locked portals before the route is unlocked."); discoveryRemoteColor = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "RemoteColor", "#38a6ff", "Hex color for the far-side portal that unlocks the route."); discoveryUnlockedColor = ((BaseUnityPlugin)this).Config.Bind<string>("Discovery Portals", "UnlockedColor", "#42ff68", "Hex color for portals after the player has unlocked the route."); dataDirectory = Path.Combine(Paths.ConfigPath, "PortalLimit"); unlockFilePath = Path.Combine(dataDirectory, "discovery_unlocks.txt"); unlockHistoryFilePath = Path.Combine(dataDirectory, "discovery_unlock_history.tsv"); portalCountsFilePath = Path.Combine(dataDirectory, "portal_counts.tsv"); portalPlacementLogFilePath = Path.Combine(dataDirectory, "portal_placements.tsv"); Directory.CreateDirectory(dataDirectory); EnsurePlacementLogHeader(); EnsureUnlockHistoryHeader(); LoadUnlocks(); harmony = new Harmony("keith.valheim.portallimit.server"); harmony.PatchAll(); ((MonoBehaviour)this).InvokeRepeating("TryRegisterRpcs", 1f, 1f); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Portal Limit server component loaded for dedicated or local-host server use."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } UnhookZdoDestroyed(); } private static bool IsDedicatedServerProcess() { string processName = Process.GetCurrentProcess().ProcessName; return processName.StartsWith("valheim_server", StringComparison.OrdinalIgnoreCase); } private void TryRegisterRpcs() { if (!rpcRegistered && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.config_request", (Action<long, string>)OnConfigRequest); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.config_update", (Action<long, string>)OnConfigUpdate); ZRoutedRpc.instance.Register<long>("keith.valheim.portallimit.count_request", (Action<long, long>)OnCountRequest); ZRoutedRpc.instance.Register<ZDOID, string>("keith.valheim.portallimit.discovery_mark_request", (Action<long, ZDOID, string>)OnDiscoveryMarkRequest); ZRoutedRpc.instance.Register<long, string>("keith.valheim.portallimit.discovery_unlock_request", (Action<long, long, string>)OnDiscoveryUnlockRequest); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.discovery_relock_request", (Action<long, string>)OnDiscoveryRelockRequest); ZRoutedRpc.instance.Register<long>("keith.valheim.portallimit.discovery_unlock_list_request", (Action<long, long>)OnDiscoveryUnlockListRequest); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.admin_report_request", (Action<long, string>)OnAdminReportRequest); ZRoutedRpc.instance.Register<string>("keith.valheim.portallimit.portal_metadata_update", (Action<long, string>)OnPortalMetadataUpdate); rpcRegistered = true; ((MonoBehaviour)this).CancelInvoke("TryRegisterRpcs"); HookZdoDestroyed(); Log.LogInfo((object)"Registered portal limit server RPC handlers."); } } private void OnConfigRequest(long sender, string playerName) { if (IsDedicatedOrHostServer()) { bool flag = false; if (!string.IsNullOrEmpty(playerName) && playerName.StartsWith("[silent]", StringComparison.Ordinal)) { flag = true; playerName = playerName.Substring("[silent]".Length); } bool flag2 = IsSenderAdmin(sender); string message = (flag ? string.Empty : (flag2 ? "Portal limit settings loaded." : "Only admins can change portal limit settings.")); string text = BuildConfigPayload(flag2, message); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { text }); Log.LogInfo((object)("Config request from " + playerName + " admin=" + flag2)); } } private void OnConfigUpdate(long sender, string payload) { if (!IsDedicatedOrHostServer()) { return; } if (!IsSenderAdmin(sender)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: false, "Only admins can change portal limit settings.") }); return; } Dictionary<string, string> dictionary = ParsePayload(payload); if (dictionary.TryGetValue("max", out var value) && int.TryParse(value, out var result)) { maxPortalsPerPlayer.Value = Math.Max(0, result); } if (dictionary.TryGetValue("adminBypass", out value) && bool.TryParse(value, out var result2)) { adminBypass.Value = result2; } if (dictionary.TryGetValue("enforceOnServer", out value) && bool.TryParse(value, out result2)) { enforceOnServer.Value = result2; } if (dictionary.TryGetValue("portalPrefabNames", out value)) { portalPrefabNames.Value = value.Trim(); portalIndexBuilt = false; } if (dictionary.TryGetValue("discoveryEnabled", out value) && bool.TryParse(value, out result2)) { discoveryPortalsEnabled.Value = result2; } if (dictionary.TryGetValue("discoveryAdminBypass", out value) && bool.TryParse(value, out result2)) { discoveryAdminBypass.Value = result2; } if (dictionary.TryGetValue("adminHoldEToEdit", out value) && bool.TryParse(value, out result2)) { adminHoldEToEdit.Value = result2; } if (dictionary.TryGetValue("showDiscoveryHoverText", out value) && bool.TryParse(value, out result2)) { showDiscoveryHoverText.Value = result2; } if (dictionary.TryGetValue("discoveryLockedHoverText", out value)) { discoveryLockedHoverText.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryRemoteHoverText", out value)) { discoveryRemoteHoverText.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryUnlockedHoverText", out value)) { discoveryUnlockedHoverText.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryLockedMessage", out value)) { discoveryLockedMessage.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryUnlockMessage", out value)) { discoveryUnlockMessage.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryShowWorldMarker", out value) && bool.TryParse(value, out result2)) { discoveryShowWorldMarker.Value = result2; } if (dictionary.TryGetValue("discoveryTintPortalModel", out value) && bool.TryParse(value, out result2)) { discoveryTintPortalModel.Value = result2; } if (dictionary.TryGetValue("discoverySuppressLockedGlow", out value) && bool.TryParse(value, out result2)) { discoverySuppressLockedGlow.Value = result2; } if (dictionary.TryGetValue("discoveryLockedColor", out value)) { discoveryLockedColor.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryRemoteColor", out value)) { discoveryRemoteColor.Value = value.Trim(); } if (dictionary.TryGetValue("discoveryUnlockedColor", out value)) { discoveryUnlockedColor.Value = value.Trim(); } ((BaseUnityPlugin)this).Config.Save(); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Portal limit settings saved.") }); Log.LogInfo((object)("Portal limit config updated by peer " + sender + ".")); } private void OnCountRequest(long sender, long creatorId) { if (IsDedicatedOrHostServer()) { EnsurePortalIndexBuilt(); bool flag = IsSenderAdmin(sender); long creatorId2 = (flag ? creatorId : sender); int num = CountPortals(creatorId2); int value = maxPortalsPerPlayer.Value; bool flag2 = value > 0 && num >= value; ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.count_response", new object[4] { num, value, flag2, BuildConfigPayload(flag, string.Empty) }); } } private void OnAdminReportRequest(long sender, string command) { if (IsDedicatedOrHostServer()) { if (!IsSenderAdmin(sender)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.admin_report_response", new object[1] { "Portal Limit: only admins can use server-wide F5 reports." }); } else { string text = BuildAdminReport(command); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.admin_report_response", new object[1] { text }); } } } private void OnDiscoveryMarkRequest(long sender, ZDOID portalId, string payload) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) if (!IsDedicatedOrHostServer()) { return; } if (!IsSenderAdmin(sender)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: false, "Only admins can mark discovery portals.") }); return; } if (ZDOMan.instance == null || ((ZDOID)(ref portalId)).IsNone()) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "No valid portal was targeted.") }); return; } ZDO zDO = ZDOMan.instance.GetZDO(portalId); if (zDO == null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Could not find that portal on the server.") }); return; } Dictionary<string, string> dictionary = ParsePayload(payload); int.TryParse(dictionary.TryGetValue("role", out var value) ? value : "0", out var result); bool.TryParse(dictionary.TryGetValue("showMarker", out value) ? value : discoveryShowWorldMarker.Value.ToString(), out var result2); bool.TryParse(dictionary.TryGetValue("suppressGlow", out value) ? value : discoverySuppressLockedGlow.Value.ToString(), out var result3); int num = ((result == 1 || result == 2) ? result : 0); string text = (dictionary.TryGetValue("link", out value) ? value.Trim() : string.Empty); string normalized = (dictionary.TryGetValue("markerColor", out value) ? value.Trim() : string.Empty); string text2 = NormalizeMarkerTextValue(dictionary.TryGetValue("markerText", out value) ? value : string.Empty); string text3 = (dictionary.TryGetValue("lockedHoverText", out value) ? value.Trim() : string.Empty); string text4 = (dictionary.TryGetValue("remoteHoverText", out value) ? value.Trim() : string.Empty); string text5 = (dictionary.TryGetValue("unlockedHoverText", out value) ? value.Trim() : string.Empty); if (num != 0 && string.IsNullOrWhiteSpace(text)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Enter a portal tag first.") }); return; } if (num != 0) { if (!TryNormalizeHexColor(normalized, out normalized)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Enter a marker color like #ff3030.") }); return; } if (TryFindDiscoveryEndpointConflict(portalId, num, text, out var conflictId)) { string text6 = ((num == 1) ? "locked entrance" : "unlocked entrance"); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "A " + text6 + " already exists for portal tag '" + text + "'.") }); Log.LogWarning((object)string.Concat("Rejected duplicate discovery ", text6, " for link '", text, "' existing=", conflictId, " attempted=", portalId)); return; } } zDO.Set("PortalLimit_DiscoveryRole", num); zDO.Set("PortalLimit_DiscoveryLink", (num == 0) ? string.Empty : text); zDO.Set("PortalLimit_DiscoveryColor", (num == 0) ? string.Empty : normalized); zDO.Set("PortalLimit_DiscoveryMarkerText", (num == 0) ? string.Empty : text2); zDO.Set("PortalLimit_DiscoveryShowMarker", (num != 0) ? (result2 ? 1 : 0) : 0); zDO.Set("PortalLimit_DiscoverySuppressGlow", (num != 0) ? (result3 ? 1 : 0) : 0); zDO.Set("PortalLimit_DiscoveryLockedHoverText", (num == 0) ? string.Empty : text3); zDO.Set("PortalLimit_DiscoveryRemoteHoverText", (num == 0) ? string.Empty : text4); zDO.Set("PortalLimit_DiscoveryUnlockedHoverText", (num == 0) ? string.Empty : text5); ZDOMan.instance.ForceSendZDO(portalId); string text7 = ((num == 0) ? "Portal settings saved." : "Portal settings saved."); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, text7) }); Log.LogInfo((object)(text7 + " zdo=" + portalId)); } private void OnDiscoveryRelockRequest(long sender, string link) { if (!IsDedicatedOrHostServer()) { return; } if (!IsSenderAdmin(sender)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: false, "Only admins can relock discovery portals.") }); return; } string text = (link ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Enter a portal tag first.") }); return; } int num = 0; foreach (HashSet<string> value in unlockedLinksByPlayer.Values) { if (value.Remove(text)) { num++; } } SaveUnlocks(); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.config_response", new object[1] { BuildConfigPayload(isAdmin: true, "Relocked portal tag '" + text + "' for " + num + " player record(s).") }); Log.LogInfo((object)("Relocked discovery portal link '" + text + "' by admin sender " + sender + ".")); } private bool TryFindDiscoveryEndpointConflict(ZDOID currentPortalId, int role, string link, out ZDOID conflictId) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) conflictId = ZDOID.None; if (ZDOMan.instance == null || string.IsNullOrWhiteSpace(link)) { return false; } EnsurePortalIndexBuilt(); foreach (ZDOID item in new List<ZDOID>(creatorByPortalId.Keys)) { ZDO zDO = ZDOMan.instance.GetZDO(item); if (zDO == null || ((ZDOID)(ref zDO.m_uid)).Equals(currentPortalId) || zDO.GetInt("PortalLimit_DiscoveryRole", 0) != role || !string.Equals(zDO.GetString("PortalLimit_DiscoveryLink", string.Empty), link, StringComparison.OrdinalIgnoreCase)) { continue; } conflictId = zDO.m_uid; return true; } return false; } private void OnDiscoveryUnlockRequest(long sender, long playerId, string link) { if (!IsDedicatedOrHostServer()) { return; } long num = (IsSenderAdmin(sender) ? playerId : sender); Dictionary<string, string> dictionary = ParsePayload(link); string value; string text = ((dictionary.Count > 0 && dictionary.TryGetValue("link", out value)) ? value.Trim() : (link ?? string.Empty).Trim()); string playerName = (dictionary.TryGetValue("playerName", out value) ? value.Trim() : string.Empty); string portalId = (dictionary.TryGetValue("portalId", out value) ? value.Trim() : string.Empty); string x = (dictionary.TryGetValue("x", out value) ? value.Trim() : string.Empty); string y = (dictionary.TryGetValue("y", out value) ? value.Trim() : string.Empty); string z = (dictionary.TryGetValue("z", out value) ? value.Trim() : string.Empty); if (discoveryPortalsEnabled.Value && num != 0 && !string.IsNullOrWhiteSpace(text)) { HashSet<string> orCreateUnlockSet = GetOrCreateUnlockSet(num); bool flag = orCreateUnlockSet.Add(text); if (flag) { SaveUnlocks(); AppendUnlockHistoryLog(num, playerName, text, portalId, x, y, z); Log.LogInfo((object)("Unlocked discovery portal link '" + text + "' for player " + num + ".")); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.discovery_unlock_list_response", new object[1] { BuildUnlockPayload(num, flag ? discoveryUnlockMessage.Value : string.Empty) }); } } private void OnDiscoveryUnlockListRequest(long sender, long playerId) { if (IsDedicatedOrHostServer()) { long playerId2 = (IsSenderAdmin(sender) ? playerId : sender); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "keith.valheim.portallimit.discovery_unlock_list_response", new object[1] { BuildUnlockPayload(playerId2, string.Empty) }); } } private void OnPortalMetadataUpdate(long sender, string payload) { //IL_0269: Unknown result type (might be due to invalid IL or missing references) if (!IsDedicatedOrHostServer()) { return; } Dictionary<string, string> dictionary = ParsePayload(payload); string value; string a = (dictionary.TryGetValue("action", out value) ? value.Trim() : string.Empty); string portalKey = (dictionary.TryGetValue("portalId", out value) ? value.Trim() : string.Empty); string text = (dictionary.TryGetValue("playerName", out value) ? value.Trim() : string.Empty); if (!dictionary.TryGetValue("playerId", out value) || !long.TryParse(value, out var result)) { result = sender; } if (result == 0) { result = sender; } ZDO val = FindPortalZdoByKey(portalKey); if (val == null) { return; } bool flag = IsSenderAdmin(sender); long @long = val.GetLong(ZDOVars.s_creator, 0L); bool flag2 = @long == 0 || @long == sender || @long == result; if (!flag && !flag2 && !string.Equals(a, "used", StringComparison.OrdinalIgnoreCase)) { return; } if (!string.IsNullOrWhiteSpace(text)) { creatorNamesByCreator[result] = text; } if (string.Equals(a, "placed", StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrWhiteSpace(val.GetString("PortalLimit_BuiltUtc", string.Empty))) { val.Set("PortalLimit_BuiltUtc", DateTime.UtcNow.ToString("o")); } if (!string.IsNullOrWhiteSpace(text)) { val.Set("PortalLimit_BuilderName", text); } if (result != 0) { val.Set("PortalLimit_BuilderId", result); TrackPortal(val, result); } } else if (string.Equals(a, "used", StringComparison.OrdinalIgnoreCase)) { val.Set("PortalLimit_LastUsedUtc", DateTime.UtcNow.ToString("o")); if (!string.IsNullOrWhiteSpace(text)) { val.Set("PortalLimit_LastUsedName", text); } if (result != 0) { val.Set("PortalLimit_LastUsedId", result); } } if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(val.m_uid); } } internal static void EnforceIfNeeded(Piece piece) { if ((Object)(object)Instance == (Object)null || !Instance.enforceOnServer.Value || !IsDedicatedOrHostServer() || !Instance.IsLimitedPortal(piece)) { return; } long creator = piece.GetCreator(); if (creator == 0) { ((MonoBehaviour)Instance).StartCoroutine(Instance.EnforceNextFrame(piece)); return; } Instance.EnsurePortalIndexBuilt(); Instance.TrackPortal(piece, creator); int num = Instance.CountPortals(creator); int value = Instance.maxPortalsPerPlayer.Value; if (Instance.adminBypass.Value && Instance.IsCreatorAdmin(creator)) { Instance.SavePortalCounts(); Instance.AppendPortalPlacementLog(piece, creator, "PLACED_ADMIN_BYPASS"); Instance.SendPortalCountNotice(creator, num, value); } else if (value <= 0) { Instance.SavePortalCounts(); Instance.AppendPortalPlacementLog(piece, creator, "PLACED"); Instance.SendPortalCountNotice(creator, num, value); } else if (num <= Instance.maxPortalsPerPlayer.Value) { Instance.SavePortalCounts(); Instance.AppendPortalPlacementLog(piece, creator, "PLACED"); Instance.SendPortalCountNotice(creator, num, value); } else { ((MonoBehaviour)Instance).StartCoroutine(Instance.RemoveExcessPortalNextFrame(piece, creator, num)); } } private IEnumerator EnforceNextFrame(Piece piece) { yield return null; if (!((Object)(object)piece == (Object)null)) { long creatorId = piece.GetCreator(); if (creatorId == 0) { Log.LogWarning((object)"Could not enforce portal limit because placed portal has no creator id."); } else { EnforceIfNeeded(piece); } } } private IEnumerator RemoveExcessPortalNextFrame(Piece piece, long creatorId, int count) { yield return null; if (!((Object)(object)piece == (Object)null)) { Log.LogInfo((object)("Removing portal from creator " + creatorId + " because they have " + count + "/" + maxPortalsPerPlayer.Value + ".")); AppendPortalPlacementLog(piece, creatorId, "REMOVED_OVER_LIMIT"); UntrackPortal(piece); RemovePiece(piece); if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(creatorId, "keith.valheim.portallimit.notice", new object[1] { "Portal limit reached: " + maxPortalsPerPlayer.Value + " portal(s) per player." }); } SavePortalCounts(); } } private void SendPortalCountNotice(long creatorId, int count, int max) { if (ZRoutedRpc.instance != null && creatorId != 0) { string text = ((max > 0) ? max.ToString() : "unlimited"); ZRoutedRpc.instance.InvokeRoutedRPC(creatorId, "keith.valheim.portallimit.notice", new object[1] { "Portals placed: " + count + " / " + text }); } } private void RemovePiece(Piece piece) { WearNTear component = ((Component)piece).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.Remove(true); return; } ZNetView component2 = ((Component)piece).GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { component2.Destroy(); } } private bool IsLimitedPortal(Piece piece) { if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<TeleportWorld>() == (Object)null) { return false; } HashSet<string> portalPrefabNameSet = GetPortalPrefabNameSet(); if (portalPrefabNameSet.Count == 0) { return true; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); string prefabName = GetPrefabName(component, piece); return portalPrefabNameSet.Contains(prefabName); } private static string GetPrefabName(ZNetView nview, Piece piece) { if ((Object)(object)nview != (Object)null && GetPrefabNameMethod != null) { object obj = GetPrefabNameMethod.Invoke(nview, null); if (obj != null) { return obj.ToString(); } } return ((Object)(object)piece != (Object)null) ? ((Object)piece).name.Replace("(Clone)", string.Empty) : string.Empty; } private int CountPortals(long creatorId) { if (creatorId == 0) { return 0; } EnsurePortalIndexBuilt(); HashSet<ZDOID> value; return portalIdsByCreator.TryGetValue(creatorId, out value) ? value.Count : 0; } private void EnsurePortalIndexBuilt() { if (!portalIndexBuilt && ZDOMan.instance != null) { RebuildPortalIndex(); } } private void RebuildPortalIndex() { portalIdsByCreator.Clear(); creatorByPortalId.Clear(); creatorNamesByCreator.Clear(); if (ZDOMan.instance == null) { return; } HashSet<string> strictPortalPrefabNameSet = GetStrictPortalPrefabNameSet(); foreach (string item in strictPortalPrefabNameSet) { int num = 0; List<ZDO> list = new List<ZDO>(); while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(item, list, ref num)) { } foreach (ZDO item2 in list) { TrackPortal(item2); } } portalIndexBuilt = true; SavePortalCounts(); Log.LogInfo((object)("Built global portal index with " + creatorByPortalId.Count + " portal(s) across " + portalIdsByCreator.Count + " creator(s).")); } private HashSet<string> GetStrictPortalPrefabNameSet() { HashSet<string> portalPrefabNameSet = GetPortalPrefabNameSet(); if (portalPrefabNameSet.Count > 0) { return portalPrefabNameSet; } if ((Object)(object)ZNetScene.instance == (Object)null || NetScenePrefabsField == null) { return portalPrefabNameSet; } if (!(NetScenePrefabsField.GetValue(ZNetScene.instance) is IEnumerable enumerable)) { return portalPrefabNameSet; } foreach (object item in enumerable) { GameObject val = (GameObject)((item is GameObject) ? item : null); if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<TeleportWorld>() != (Object)null) { portalPrefabNameSet.Add(((Object)val).name.Replace("(Clone)", string.Empty)); } } return portalPrefabNameSet; } private void TrackPortal(Piece piece, long creatorId) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (((Object)(object)piece != (Object)null) ? ((Component)piece).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 != null && string.IsNullOrWhiteSpace(val2.GetString("PortalLimit_BuiltUtc", string.Empty))) { val2.Set("PortalLimit_BuiltUtc", DateTime.UtcNow.ToString("o")); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(val2.m_uid); } } TrackPortal(val2, creatorId); } private void TrackPortal(ZDO zdo) { TrackPortal(zdo, (zdo != null) ? zdo.GetLong(ZDOVars.s_creator, 0L) : 0); } private void TrackPortal(ZDO zdo, long creatorId) { //IL_001d: 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_005c: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (zdo != null && creatorId != 0) { ZDOID uid = zdo.m_uid; string @string = zdo.GetString("PortalLimit_BuilderName", string.Empty); if (string.IsNullOrWhiteSpace(@string)) { @string = zdo.GetString(ZDOVars.s_creatorName, string.Empty); } if (creatorByPortalId.TryGetValue(uid, out var value) && value != creatorId) { RemovePortalIdFromCreator(value, uid); } creatorByPortalId[uid] = creatorId; if (!string.IsNullOrWhiteSpace(@string)) { creatorNamesByCreator[creatorId] = @string; } if (!portalIdsByCreator.TryGetValue(creatorId, out var value2)) { value2 = new HashSet<ZDOID>(); portalIdsByCreator[creatorId] = value2; } value2.Add(uid); } } private void UntrackPortal(Piece piece) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (((Object)(object)piece != (Object)null) ? ((Component)piece).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 != null) { UntrackPortal(val2.m_uid); } } private void UntrackPortal(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (creatorByPortalId.TryGetValue(id, out var value)) { creatorByPortalId.Remove(id); RemovePortalIdFromCreator(value, id); } } private void RemovePortalIdFromCreator(long creatorId, ZDOID id) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (portalIdsByCreator.TryGetValue(creatorId, out var value)) { value.Remove(id); if (value.Count == 0) { portalIdsByCreator.Remove(creatorId); creatorNamesByCreator.Remove(creatorId); } } } private void HookZdoDestroyed() { if (!zdoDestroyedHooked && ZDOMan.instance != null && !(OnZdoDestroyedField == null)) { Action<ZDO> a = OnZdoDestroyedField.GetValue(ZDOMan.instance) as Action<ZDO>; a = (Action<ZDO>)Delegate.Combine(a, new Action<ZDO>(OnZdoDestroyed)); OnZdoDestroyedField.SetValue(ZDOMan.instance, a); zdoDestroyedHooked = true; } } private void UnhookZdoDestroyed() { if (zdoDestroyedHooked && ZDOMan.instance != null && !(OnZdoDestroyedField == null)) { Action<ZDO> source = OnZdoDestroyedField.GetValue(ZDOMan.instance) as Action<ZDO>; source = (Action<ZDO>)Delegate.Remove(source, new Action<ZDO>(OnZdoDestroyed)); OnZdoDestroyedField.SetValue(ZDOMan.instance, source); zdoDestroyedHooked = false; } } private void OnZdoDestroyed(ZDO zdo) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (zdo != null) { UntrackPortal(zdo.m_uid); SavePortalCounts(); } } private HashSet<string> GetPortalPrefabNameSet() { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = portalPrefabNames.Value.Split(new char[1] { ',' }); foreach (string text in array) { string text2 = text.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { hashSet.Add(text2); } } return hashSet; } private bool IsCreatorAdmin(long creatorId) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return false; } ZNetPeer peer = instance.GetPeer(creatorId); if (peer != null) { return IsPeerAdmin(peer); } return instance.IsServer() && !IsDedicatedServerProcess(); } private bool IsSenderAdmin(long sender) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return false; } ZNetPeer peer = instance.GetPeer(sender); if (peer != null) { return IsPeerAdmin(peer); } return instance.IsServer() && !IsDedicatedServerProcess(); } private bool IsPeerAdmin(ZNetPeer peer) { try { ISocket val = (ISocket)((PeerSocketField != null) ? /*isinst with value type is only supported in some contexts*/: null); string text = ((val != null) ? val.GetHostName() : string.Empty); return !string.IsNullOrWhiteSpace(text) && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsAdmin(text); } catch (Exception ex) { Log.LogWarning((object)("Could not check admin status: " + ex.Message)); return false; } } private string BuildConfigPayload(bool isAdmin, string message) { return "isAdmin=" + isAdmin + "\nmax=" + maxPortalsPerPlayer.Value + "\nadminBypass=" + adminBypass.Value + "\nenforceOnServer=" + enforceOnServer.Value + "\nportalPrefabNames=" + Escape(portalPrefabNames.Value) + "\ndiscoveryEnabled=" + discoveryPortalsEnabled.Value + "\ndiscoveryAdminBypass=" + discoveryAdminBypass.Value + "\nadminHoldEToEdit=" + adminHoldEToEdit.Value + "\nshowDiscoveryHoverText=" + showDiscoveryHoverText.Value + "\ndiscoveryLockedHoverText=" + Escape(discoveryLockedHoverText.Value) + "\ndiscoveryRemoteHoverText=" + Escape(discoveryRemoteHoverText.Value) + "\ndiscoveryUnlockedHoverText=" + Escape(discoveryUnlockedHoverText.Value) + "\ndiscoveryLockedMessage=" + Escape(discoveryLockedMessage.Value) + "\ndiscoveryUnlockMessage=" + Escape(discoveryUnlockMessage.Value) + "\ndiscoveryShowWorldMarker=" + discoveryShowWorldMarker.Value + "\ndiscoveryTintPortalModel=" + discoveryTintPortalModel.Value + "\ndiscoverySuppressLockedGlow=" + discoverySuppressLockedGlow.Value + "\ndiscoveryLockedColor=" + Escape(discoveryLockedColor.Value) + "\ndiscoveryRemoteColor=" + Escape(discoveryRemoteColor.Value) + "\ndiscoveryUnlockedColor=" + Escape(discoveryUnlockedColor.Value) + "\nmessage=" + Escape(message); } private string BuildUnlockPayload(long playerId, string message) { HashSet<string> orCreateUnlockSet = GetOrCreateUnlockSet(playerId); return "links=" + Escape(string.Join(";", new List<string>(orCreateUnlockSet).ToArray())) + "\nmessage=" + Escape(message); } private HashSet<string> GetOrCreateUnlockSet(long playerId) { if (!unlockedLinksByPlayer.TryGetValue(playerId, out var value)) { value = new HashSet<string>(StringComparer.OrdinalIgnoreCase); unlockedLinksByPlayer[playerId] = value; } return value; } private void LoadUnlocks() { unlockedLinksByPlayer.Clear(); if (!File.Exists(unlockFilePath)) { return; } string[] array = File.ReadAllLines(unlockFilePath); foreach (string text in array) { if (string.IsNullOrWhiteSpace(text) || text.TrimStart(new char[0]).StartsWith("#", StringComparison.Ordinal)) { continue; } string[] array2 = text.Split(new char[1] { '|' }); if (array2.Length >= 2 && long.TryParse(array2[0].Trim(), out var result)) { string text2 = array2[1].Trim(); if (!string.IsNullOrWhiteSpace(text2)) { GetOrCreateUnlockSet(result).Add(text2); } } } } private void SaveUnlocks() { List<string> list = new List<string>(); list.Add("# player id | discovery link id"); foreach (KeyValuePair<long, HashSet<string>> item in unlockedLinksByPlayer) { foreach (string item2 in item.Value) { list.Add(item.Key + " | " + item2); } } File.WriteAllLines(unlockFilePath, list.ToArray()); } private string BuildAdminReport(string command) { string text = (command ?? string.Empty).Trim().ToLowerInvariant(); EnsurePortalIndexBuilt(); if (text.StartsWith("portalinfo|", StringComparison.Ordinal)) { return BuildPortalInformationReport(command); } if (text == "export") { SavePortalCounts(); EnsurePlacementLogHeader(); EnsureUnlockHistoryHeader(); return "Portal Limit export refreshed.\nportal_counts.tsv: " + portalCountsFilePath + "\nportal_placements.tsv: " + portalPlacementLogFilePath + "\ndiscovery_unlock_history.tsv: " + unlockHistoryFilePath; } if (text == "portals") { return BuildPortalListReport(); } return BuildPlayerCountReport(); } private string BuildPlayerCountReport() { StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (HashSet<ZDOID> value in portalIdsByCreator.Values) { num += value.Count; } stringBuilder.AppendLine("Portal Limit server counts"); stringBuilder.AppendLine("Total counted portals: " + num); stringBuilder.AppendLine("Player limit: " + ((maxPortalsPerPlayer.Value > 0) ? maxPortalsPerPlayer.Value.ToString() : "unlimited")); List<long> list = new List<long>(portalIdsByCreator.Keys); list.Sort((long left, long right) => CountPortals(right).CompareTo(CountPortals(left))); foreach (long item in list) { int num2 = CountPortals(item); string creatorName = GetCreatorName(item); string text = ((maxPortalsPerPlayer.Value > 0 && num2 > maxPortalsPerPlayer.Value) ? " OVER LIMIT" : string.Empty); stringBuilder.AppendLine(num2 + " / " + ((maxPortalsPerPlayer.Value > 0) ? maxPortalsPerPlayer.Value.ToString() : "unlimited") + " - " + creatorName + " (" + item + ")" + text); } return stringBuilder.ToString().TrimEnd(new char[0]); } private string BuildPortalListReport() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Portal Limit portal list"); stringBuilder.AppendLine("playerName | playerId | prefab | tag | role | x,y,z | zdoId"); List<ZDOID> list = new List<ZDOID>(creatorByPortalId.Keys); list.Sort((ZDOID left, ZDOID right) => ((object)(ZDOID)(ref left)).ToString().CompareTo(((object)(ZDOID)(ref right)).ToString())); foreach (ZDOID item in list) { ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(item) : null); if (val != null) { long @long = val.GetLong(ZDOVars.s_creator, 0L); Vector3 position = val.GetPosition(); stringBuilder.AppendLine(GetCreatorName(@long) + " | " + @long + " | " + GetPrefabName(val) + " | " + GetPortalTag(val) + " | " + GetDiscoveryRoleName(val.GetInt("PortalLimit_DiscoveryRole", 0)) + " | " + FormatPosition(position) + " | " + val.m_uid); } } return stringBuilder.ToString().TrimEnd(new char[0]); } private string BuildPortalInformationReport(string command) { //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) string[] array = (command ?? string.Empty).Split(new char[1] { '|' }); string fallbackTag = ((array.Length > 1) ? Unescape(array[1]).Trim() : string.Empty); string portalKey = ((array.Length > 2) ? Unescape(array[2]).Trim() : string.Empty); ZDO zdo = FindPortalZdoByKey(portalKey); string text = ResolvePortalInformationTag(zdo, fallbackTag); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(BuildServerPortalIdentity(zdo, text)); stringBuilder.AppendLine(); stringBuilder.AppendLine("Players who unlocked this portal tag:"); List<string> list = BuildUnlockLinesForTag(text); if (list.Count == 0) { stringBuilder.AppendLine("No recorded unlocks yet."); } else { foreach (string item in list) { stringBuilder.AppendLine(item); } } StringBuilder stringBuilder2 = new StringBuilder(); int num = 0; foreach (HashSet<ZDOID> value in portalIdsByCreator.Values) { num += value.Count; } int num2 = 0; int num3 = 0; int num4 = 0; foreach (ZDOID key in creatorByPortalId.Keys) { ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(key) : null); switch ((val != null) ? val.GetInt("PortalLimit_DiscoveryRole", 0) : 0) { case 1: num2++; break; case 2: num3++; break; default: num4++; break; } } stringBuilder2.AppendLine("Count of all portals built in world: " + num); stringBuilder2.AppendLine("Normal portals: " + num4); stringBuilder2.AppendLine("Locked entrances: " + num2); stringBuilder2.AppendLine("Unlocked entrances: " + num3); stringBuilder2.AppendLine("Known portal builders: " + portalIdsByCreator.Count); stringBuilder2.AppendLine("Player limit: " + ((maxPortalsPerPlayer.Value > 0) ? maxPortalsPerPlayer.Value.ToString() : "unlimited")); stringBuilder2.AppendLine("Tip: blank-tag portals are kept unconnected so players do not get fake teleport links."); stringBuilder2.AppendLine("Tip: duplicate locked or unlocked discovery endpoints with the same tag are rejected."); return "PortalInfoResponse\n" + stringBuilder.ToString().TrimEnd(new char[0]) + "\n---WORLD---\n" + stringBuilder2.ToString().TrimEnd(new char[0]); } private ZDO FindPortalZdoByKey(string portalKey) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(portalKey) || ZDOMan.instance == null) { return null; } EnsurePortalIndexBuilt(); foreach (ZDOID key in creatorByPortalId.Keys) { ZDOID current = key; if (!string.Equals(((object)(ZDOID)(ref current)).ToString(), portalKey, StringComparison.Ordinal)) { continue; } return ZDOMan.instance.GetZDO(current); } HashSet<string> strictPortalPrefabNameSet = GetStrictPortalPrefabNameSet(); foreach (string item in strictPortalPrefabNameSet) { int num = 0; List<ZDO> list = new List<ZDO>(); while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative(item, list, ref num)) { } foreach (ZDO item2 in list) { if (item2 != null && string.Equals(((object)(ZDOID)(ref item2.m_uid)).ToString(), portalKey, StringComparison.Ordinal)) { TrackPortal(item2); return item2; } } } return null; } private static string ResolvePortalInformationTag(ZDO zdo, string fallbackTag) { string text = ((zdo != null) ? zdo.GetString("PortalLimit_DiscoveryLink", string.Empty) : string.Empty); if (string.IsNullOrWhiteSpace(text)) { text = GetPortalTag(zdo); } if (string.IsNullOrWhiteSpace(text)) { text = fallbackTag; } return string.IsNullOrWhiteSpace(text) ? string.Empty : text.Trim(); } private string BuildServerPortalIdentity(ZDO zdo, string fallbackTag) { //IL_01f9: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return "Portal Tag: " + (string.IsNullOrWhiteSpace(fallbackTag) ? "(none)" : fallbackTag) + "\nPlayer Who Built the Portal: unknown\nDate the portal was built: unknown\nLast time this portal was used: unknown\nPortal role: unknown\nPortal id: unknown"; } long num = zdo.GetLong(ZDOVars.s_creator, 0L); long @long = zdo.GetLong("PortalLimit_BuilderId", 0L); if (@long != 0) { num = @long; } string text = zdo.GetString("PortalLimit_BuilderName", string.Empty); if (string.IsNullOrWhiteSpace(text)) { text = zdo.GetString(ZDOVars.s_creatorName, string.Empty); } if (string.IsNullOrWhiteSpace(text)) { text = GetCreatorName(num); } string text2 = zdo.GetString("PortalLimit_DiscoveryLink", string.Empty); if (string.IsNullOrWhiteSpace(text2)) { text2 = GetPortalTag(zdo); } if (string.IsNullOrWhiteSpace(text2)) { text2 = (string.IsNullOrWhiteSpace(fallbackTag) ? "(none)" : fallbackTag); } string text3 = zdo.GetString("PortalLimit_BuiltUtc", string.Empty); if (string.IsNullOrWhiteSpace(text3)) { text3 = FindPortalBuiltUtcFromPlacementLog(((object)(ZDOID)(ref zdo.m_uid)).ToString()); } string text4 = FormatDateOnly(text3); if (string.IsNullOrWhiteSpace(text4)) { text4 = "unknown"; } string text5 = BuildLastUsedText(zdo); string text6 = ((num != 0) ? num.ToString() : "unknown"); return "Portal Tag: " + text2 + "\nPlayer Who Built the Portal: " + text + ", Steam ID: " + text6 + "\nDate the portal was built: " + text4 + "\nLast time this portal was used: " + text5 + "\nPortal role: " + GetDiscoveryRoleName(zdo.GetInt("PortalLimit_DiscoveryRole", 0)) + "\nPortal id: " + zdo.m_uid; } private string BuildLastUsedText(ZDO zdo) { if (zdo == null) { return "unknown"; } string text = FormatDateTimeText(zdo.GetString("PortalLimit_LastUsedUtc", string.Empty)); if (string.IsNullOrWhiteSpace(text)) { return "unknown"; } string text2 = zdo.GetString("PortalLimit_LastUsedName", string.Empty); long @long = zdo.GetLong("PortalLimit_LastUsedId", 0L); if (string.IsNullOrWhiteSpace(text2) && @long != 0) { text2 = GetCreatorName(@long); } string text3 = (string.IsNullOrWhiteSpace(text2) ? "unknown" : text2); string text4 = ((@long != 0) ? @long.ToString() : "unknown"); return text + ", by " + text3 + ", Steam ID: " + text4; } private List<string> BuildUnlockLinesForTag(string tag) { List<string> list = new List<string>(); HashSet<long> hashSet = new HashSet<long>(); if (!string.IsNullOrWhiteSpace(tag)) { foreach (KeyValuePair<long, HashSet<string>> item in unlockedLinksByPlayer) { if (item.Value.Contains(tag)) { hashSet.Add(item.Key); } } } HashSet<long> hashSet2 = new HashSet<long>(); if (File.Exists(unlockHistoryFilePath)) { string[] array = File.ReadAllLines(unlockHistoryFilePath); foreach (string text in array) { if (string.IsNullOrWhiteSpace(text) || text.StartsWith("timeUtc\t", StringComparison.OrdinalIgnoreCase)) { continue; } string[] array2 = text.Split(new char[1] { '\t' }); if (array2.Length >= 4 && string.Equals(array2[3], tag, StringComparison.OrdinalIgnoreCase)) { if (!long.TryParse(array2[2], out var result)) { result = 0L; } hashSet2.Add(result); string text2 = (string.IsNullOrWhiteSpace(array2[1]) ? GetCreatorName(result) : array2[1]); string text3 = FormatDateOnly(array2[0]); string text4 = FormatTimeOnly(array2[0]); list.Add(text2 + ", " + text3 + ", " + text4 + ", " + result); } } } foreach (long item2 in hashSet) { if (!hashSet2.Contains(item2)) { list.Add(GetCreatorName(item2) + ", unknown date, unknown time, " + item2); } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } private void EnsurePlacementLogHeader() { if (!string.IsNullOrEmpty(portalPlacementLogFilePath) && !File.Exists(portalPlacementLogFilePath)) { File.WriteAllText(portalPlacementLogFilePath, "timeUtc\tresult\tplayerName\tplayerId\tprefab\tportalTag\trole\tx\ty\tz\tzdoId" + Environment.NewLine); } } private void EnsureUnlockHistoryHeader() { if (!string.IsNullOrEmpty(unlockHistoryFilePath) && !File.Exists(unlockHistoryFilePath)) { File.WriteAllText(unlockHistoryFilePath, "timeUtc\tplayerName\tplayerId\tportalTag\tunlockPortalId\tx\ty\tz" + Environment.NewLine); } } private string FindPortalBuiltUtcFromPlacementLog(string portalId) { if (string.IsNullOrWhiteSpace(portalId) || !File.Exists(portalPlacementLogFilePath)) { return string.Empty; } string[] array = File.ReadAllLines(portalPlacementLogFilePath); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("timeUtc\t", StringComparison.OrdinalIgnoreCase)) { string[] array2 = text.Split(new char[1] { '\t' }); if (array2.Length >= 11 && string.Equals(array2[10], portalId, StringComparison.Ordinal) && string.Equals(array2[1], "PLACED", StringComparison.OrdinalIgnoreCase)) { return array2[0]; } } } return string.Empty; } private static string FormatDateOnly(string isoDate) { if (DateTime.TryParse(isoDate, null, DateTimeStyles.AdjustToUniversal, out var result)) { return result.ToUniversalTime().ToString("MM/dd/yyyy"); } return "unknown date"; } private static string FormatTimeOnly(string isoDate) { if (DateTime.TryParse(isoDate, null, DateTimeStyles.AdjustToUniversal, out var result)) { return result.ToUniversalTime().ToString("HH:mm:ss"); } return "unknown time"; } private static string FormatDateTimeText(string isoDate) { if (DateTime.TryParse(isoDate, null, DateTimeStyles.AdjustToUniversal, out var result)) { return result.ToUniversalTime().ToString("MM/dd/yyyy, HH:mm:ss"); } return string.Empty; } private void AppendUnlockHistoryLog(long playerId, string playerName, string link, string portalId, string x, string y, string z) { EnsureUnlockHistoryHeader(); string value = (string.IsNullOrWhiteSpace(playerName) ? GetCreatorName(playerId) : playerName); string text = DateTime.UtcNow.ToString("o") + "\t" + EscapeReportField(value) + "\t" + playerId + "\t" + EscapeReportField(link) + "\t" + EscapeReportField(portalId) + "\t" + EscapeReportField(x) + "\t" + EscapeReportField(y) + "\t" + EscapeReportField(z); File.AppendAllText(unlockHistoryFilePath, text + Environment.NewLine); } private void AppendPortalPlacementLog(Piece piece, long creatorId, string result) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (((Object)(object)piece != (Object)null) ? ((Component)piece).GetComponent<ZNetView>() : null); ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null); if (val2 != null) { EnsurePlacementLogHeader(); Vector3 position = val2.GetPosition(); string text = DateTime.UtcNow.ToString("o") + "\t" + EscapeReportField(result) + "\t" + EscapeReportField(GetCreatorName(creatorId)) + "\t" + creatorId + "\t" + EscapeReportField(GetPrefabName(val2)) + "\t" + EscapeReportField(GetPortalTag(val2)) + "\t" + EscapeReportField(GetDiscoveryRoleName(val2.GetInt("PortalLimit_DiscoveryRole", 0))) + "\t" + position.x.ToString("F1") + "\t" + position.y.ToString("F1") + "\t" + position.z.ToString("F1") + "\t" + val2.m_uid; File.AppendAllText(portalPlacementLogFilePath, text + Environment.NewLine); } } private string GetCreatorName(long creatorId) { string value; return (creatorNamesByCreator.TryGetValue(creatorId, out value) && !string.IsNullOrWhiteSpace(value)) ? value : "unknown"; } private static string GetPrefabName(ZDO zdo) { if (zdo == null || (Object)(object)ZNetScene.instance == (Object)null) { return "unknown"; } GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); return ((Object)(object)prefab != (Object)null) ? ((Object)prefab).name : zdo.GetPrefab().ToString(); } private static string GetPortalTag(ZDO zdo) { return (zdo != null) ? zdo.GetString("tag", string.Empty) : string.Empty; } private static string FormatPosition(Vector3 position) { return position.x.ToString("F1") + "," + position.y.ToString("F1") + "," + position.z.ToString("F1"); } private static string GetDiscoveryRoleName(int role) { return role switch { 1 => "LOCKED ENTRANCE", 2 => "UNLOCKED ENTRANCE", _ => "NORMAL PORTAL", }; } private void SavePortalCounts() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(portalCountsFilePath)) { return; } List<string> list = new List<string>(); list.Add("# PortalLimit global portal count export"); list.Add("# Generated from saved Valheim portal ZDO creator data. The world save remains authoritative."); list.Add("creatorId\tcreatorName\tportalCount\tportalZdoIds"); List<long> list2 = new List<long>(portalIdsByCreator.Keys); list2.Sort(); foreach (long item in list2) { if (!portalIdsByCreator.TryGetValue(item, out var value)) { continue; } List<string> list3 = new List<string>(); foreach (ZDOID item2 in value) { ZDOID current2 = item2; list3.Add(((object)(ZDOID)(ref current2)).ToString()); } list3.Sort(StringComparer.Ordinal); creatorNamesByCreator.TryGetValue(item, out var value2); list.Add(item + "\t" + EscapeReportField(value2) + "\t" + value.Count + "\t" + EscapeReportField(string.Join(",", list3.ToArray()))); } File.WriteAllLines(portalCountsFilePath, list.ToArray()); } private static string EscapeReportField(string value) { return (value ?? string.Empty).Replace("\t", " ").Replace("\r", " ").Replace("\n", " "); } private static Dictionary<string, string> ParsePayload(string payload) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(payload)) { return dictionary; } string[] array = payload.Split(new char[1] { '\n' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { dictionary[text.Substring(0, num)] = Unescape(text.Substring(num + 1)); } } return dictionary; } private static string Escape(string value) { return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\n", "\\n").Replace("=", "\\e"); } private static string NormalizeMarkerTextValue(string value) { string text = (value ?? string.Empty).Trim(); if (string.IsNullOrWhiteSpace(text)) { return "UNLOCK ON OTHER SIDE"; } if (string.Equals(text, "Locked", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "LOCKED", StringComparison.OrdinalIgnoreCase)) { return "LOCKED"; } if (string.Equals(text, "X", StringComparison.OrdinalIgnoreCase)) { return "X"; } if (string.Equals(text, "UnlockOnOtherSide", StringComparison.OrdinalIgnoreCase) || string.Equals(text, "UNLOCK ON OTHER SIDE", StringComparison.OrdinalIgnoreCase)) { return "UNLOCK ON OTHER SIDE"; } return text; } private static bool TryNormalizeHexColor(string text, out string normalized) { normalized = (text ?? string.Empty).Trim(); if (!normalized.StartsWith("#", StringComparison.Ordinal)) { normalized = "#" + normalized; } Color val = default(Color); if (normalized.Length == 7 && ColorUtility.TryParseHtmlString(normalized, ref val)) { return true; } normalized = string.Empty; return false; } private static string GetPortalTag(TeleportWorld portal) { if ((Object)(object)portal == (Object)null) { return string.Empty; } try { if (GetPortalTextMethod != null) { object obj = GetPortalTextMethod.Invoke(portal, null); return (obj != null) ? obj.ToString() : string.Empty; } } catch (Exception ex) { Log.LogWarning((object)("Could not read portal tag: " + ex.Message)); } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); return (val != null) ? val.GetString("tag", string.Empty) : string.Empty; } private static string Unescape(string value) { return (value ?? string.Empty).Replace("\\e", "=").Replace("\\n", "\n").Replace("\\\\", "\\"); } private static bool IsDedicatedOrHostServer() { return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer(); } }