

using 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("\\\\", "\\");
}
}using 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("\\\\", "\\");
}
}using 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();
}
}