Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of XpandedPortal v1.0.0
XpandedPortal.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Microsoft.CodeAnalysis; using PortalTweaks.Configuration; using PortalTweaks.Data; using PortalTweaks.Energy; using PortalTweaks.Patches; using PortalTweaks.StatusEffects; using PortalTweaks.UI; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("XpandedPortal Contributors")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("XpandedPortal")] [assembly: AssemblyTitle("XpandedPortal")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PortalTweaks { [BepInPlugin("com.user.xpandedportal", "XpandedPortal", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PortalTweaksPlugin : BaseUnityPlugin { public const string ModGuid = "com.user.xpandedportal"; public const string ModName = "XpandedPortal"; public const string ModVersion = "1.0.0"; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"XpandedPortal v1.0.0 initializing..."); ModConfig.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.user.xpandedportal"); _harmony.PatchAll(); Log.LogInfo((object)"XpandedPortal v1.0.0 loaded successfully."); if (Chainloader.PluginInfos.ContainsKey("com.jotunn.jotunn")) { HookJotunnSync(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void HookJotunnSync() { SynchronizationManager.OnConfigurationSynchronized += delegate { Log.LogInfo((object)"Server configuration synchronized successfully."); }; } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace PortalTweaks.UI { public class PortalConfigPanel : MonoBehaviour { private GameObject? _rootPanel; private RectTransform? _rootRect; private TeleportWorld? _currentPortal; private Text? _titleText; private Text? _tagLabel; private InputField? _tagInput; private Text? _passLabel; private InputField? _passwordInput; private Text? _targetLabel; private Dropdown? _targetDropdown; private Text? _outPassLabel; private InputField? _outboundPasswordInput; private Text? _distanceText; private Text? _energyText; private Text? _weightText; private Text? _statusText; private float _uiUpdateTimer; private Button? _saveButton; private Button? _cancelButton; private List<PortalInfo> _availablePortals = new List<PortalInfo>(); public static PortalConfigPanel? Instance { get; private set; } public static void Initialize() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null) && !((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("PortalTweaks_UIHandler"); val.transform.SetParent(GUIManager.CustomGUIFront.transform, false); Instance = val.AddComponent<PortalConfigPanel>(); } } private void Awake() { Instance = this; BuildUI(); } private void Update() { if (!((Object)(object)_rootPanel != (Object)null) || !_rootPanel.activeSelf) { return; } if (Input.GetKeyDown((KeyCode)27)) { Hide(); return; } _uiUpdateTimer += Time.deltaTime; if (_uiUpdateTimer >= 0.25f) { _uiUpdateTimer = 0f; UpdateStatus(); } } private void BuildUI() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_057c: Unknown result type (might be due to invalid IL or missing references) //IL_058b: Unknown result type (might be due to invalid IL or missing references) //IL_059a: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05d9: Expected O, but got Unknown //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_0607: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_064b: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Expected O, but got Unknown if (GUIManager.Instance != null && !((Object)(object)GUIManager.CustomGUIFront == (Object)null)) { _rootPanel = GUIManager.Instance.CreateWoodpanel(((Component)this).transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 580f, 360f, true); ((Object)_rootPanel).name = "PortalTweaks_ConfigPanel"; _rootRect = _rootPanel.GetComponent<RectTransform>(); GameObject val = GUIManager.Instance.CreateText("PORTAL CONFIGURATION", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -25f), GUIManager.Instance.AveriaSerifBold, 19, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 28f, false); _titleText = val.GetComponent<Text>(); _titleText.alignment = (TextAnchor)4; _tagLabel = CreateTextElement("Portal Tag", new Vector2(-140f, -55f), 250f); GameObject val2 = GUIManager.Instance.CreateInputField(_rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(-140f, -85f), (ContentType)0, "Enter portal tag...", 15, 250f, 32f); _tagInput = val2.GetComponent<InputField>(); _passLabel = CreateTextElement("Portal Password", new Vector2(140f, -55f), 250f); GameObject val3 = GUIManager.Instance.CreateInputField(_rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(140f, -85f), (ContentType)0, "None (Unprotected)", 15, 250f, 32f); _passwordInput = val3.GetComponent<InputField>(); _targetLabel = CreateTextElement("Outbound Destination", new Vector2(-140f, -125f), 250f); GameObject val4 = GUIManager.Instance.CreateDropDown(_rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(-140f, -155f), 14, 250f, 32f); _targetDropdown = val4.GetComponent<Dropdown>(); ((UnityEvent<int>)(object)_targetDropdown.onValueChanged).AddListener((UnityAction<int>)delegate { UpdateStatus(); }); _outPassLabel = CreateTextElement("Destination Password", new Vector2(140f, -125f), 250f); GameObject val5 = GUIManager.Instance.CreateInputField(_rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(140f, -155f), (ContentType)0, "Password for target...", 15, 250f, 32f); _outboundPasswordInput = val5.GetComponent<InputField>(); ((UnityEvent<string>)(object)_outboundPasswordInput.onValueChanged).AddListener((UnityAction<string>)delegate { UpdateStatus(); }); GameObject val6 = GUIManager.Instance.CreateText("", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -198f), GUIManager.Instance.AveriaSerif, 14, Color.white, true, Color.black, 520f, 22f, false); _distanceText = val6.GetComponent<Text>(); _distanceText.alignment = (TextAnchor)4; GameObject val7 = GUIManager.Instance.CreateText("", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -220f), GUIManager.Instance.AveriaSerif, 14, Color.white, true, Color.black, 520f, 22f, false); _energyText = val7.GetComponent<Text>(); _energyText.alignment = (TextAnchor)4; GameObject val8 = GUIManager.Instance.CreateText("", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -220f), GUIManager.Instance.AveriaSerif, 14, Color.white, true, Color.black, 520f, 22f, false); _weightText = val8.GetComponent<Text>(); _weightText.alignment = (TextAnchor)4; GameObject val9 = GUIManager.Instance.CreateText("", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -244f), GUIManager.Instance.AveriaSerif, 14, Color.yellow, true, Color.black, 520f, 22f, false); _statusText = val9.GetComponent<Text>(); _statusText.alignment = (TextAnchor)4; GameObject val10 = GUIManager.Instance.CreateButton("Save & Connect", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(-80f, -288f), 140f, 36f); _saveButton = val10.GetComponent<Button>(); ((UnityEvent)_saveButton.onClick).AddListener(new UnityAction(OnSaveClicked)); GameObject val11 = GUIManager.Instance.CreateButton("Cancel", _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(80f, -288f), 140f, 36f); _cancelButton = val11.GetComponent<Button>(); ((UnityEvent)_cancelButton.onClick).AddListener(new UnityAction(Hide)); _rootPanel.SetActive(false); } } private Text CreateTextElement(string text, Vector2 pos, float width) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) Text component = GUIManager.Instance.CreateText(text, _rootPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), pos, GUIManager.Instance.AveriaSerif, 14, Color.white, true, Color.black, width, 24f, false).GetComponent<Text>(); component.alignment = (TextAnchor)3; return component; } public void Show(TeleportWorld portal) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_055b: Unknown result type (might be due to invalid IL or missing references) //IL_0560: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_059d: Expected O, but got Unknown //IL_05bb: Unknown result type (might be due to invalid IL or missing references) //IL_05c2: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_0610: Expected O, but got Unknown //IL_0611: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_0623: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_rootPanel == (Object)null) { BuildUI(); } _currentPortal = portal; if ((Object)(object)_currentPortal == (Object)null || (Object)(object)_rootPanel == (Object)null || (Object)(object)_rootRect == (Object)null) { return; } ZNetView component = ((Component)_currentPortal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } PortalInfo portalInfo = PortalDataManager.FromZDO(component.GetZDO()); if (portalInfo == null) { return; } if ((Object)(object)_titleText != (Object)null) { _titleText.text = (ModConfig.IsStonePortal(_currentPortal) ? "STONE PORTAL CONFIGURATION" : "PORTAL CONFIGURATION"); } bool value = ModConfig.EnablePasswordSystem.Value; bool value2 = ModConfig.EnableTargetSelectionUI.Value; float num; float num2; float width; if (value) { num = 580f; num2 = -140f; width = 250f; } else { num = 380f; num2 = 0f; width = 290f; } Text? tagLabel = _tagLabel; SetPosAndSize((tagLabel != null) ? ((Graphic)tagLabel).rectTransform : null, new Vector2(num2, -55f), width, 24f); InputField? tagInput = _tagInput; SetPosAndSize((tagInput != null) ? ((Component)tagInput).GetComponent<RectTransform>() : null, new Vector2(num2, -85f), width, 32f); Text? passLabel = _passLabel; if (passLabel != null) { ((Component)passLabel).gameObject.SetActive(value); } InputField? passwordInput = _passwordInput; if (passwordInput != null) { ((Component)passwordInput).gameObject.SetActive(value); } if (value) { Text? passLabel2 = _passLabel; SetPosAndSize((passLabel2 != null) ? ((Graphic)passLabel2).rectTransform : null, new Vector2(140f, -55f), 250f, 24f); InputField? passwordInput2 = _passwordInput; SetPosAndSize((passwordInput2 != null) ? ((Component)passwordInput2).GetComponent<RectTransform>() : null, new Vector2(140f, -85f), 250f, 32f); } Text? targetLabel = _targetLabel; if (targetLabel != null) { ((Component)targetLabel).gameObject.SetActive(value2); } Dropdown? targetDropdown = _targetDropdown; if (targetDropdown != null) { ((Component)targetDropdown).gameObject.SetActive(value2); } if (value2) { Text? targetLabel2 = _targetLabel; SetPosAndSize((targetLabel2 != null) ? ((Graphic)targetLabel2).rectTransform : null, new Vector2(num2, -125f), width, 24f); Dropdown? targetDropdown2 = _targetDropdown; SetPosAndSize((targetDropdown2 != null) ? ((Component)targetDropdown2).GetComponent<RectTransform>() : null, new Vector2(num2, -155f), width, 32f); } bool flag = value && value2; Text? outPassLabel = _outPassLabel; if (outPassLabel != null) { ((Component)outPassLabel).gameObject.SetActive(flag); } InputField? outboundPasswordInput = _outboundPasswordInput; if (outboundPasswordInput != null) { ((Component)outboundPasswordInput).gameObject.SetActive(flag); } if (flag) { Text? outPassLabel2 = _outPassLabel; SetPosAndSize((outPassLabel2 != null) ? ((Graphic)outPassLabel2).rectTransform : null, new Vector2(140f, -125f), 250f, 24f); InputField? outboundPasswordInput2 = _outboundPasswordInput; SetPosAndSize((outboundPasswordInput2 != null) ? ((Component)outboundPasswordInput2).GetComponent<RectTransform>() : null, new Vector2(140f, -155f), 250f, 32f); } float num3 = (value2 ? (-198f) : (-128f)); Text? distanceText = _distanceText; if (distanceText != null) { ((Component)distanceText).gameObject.SetActive(value2); } if (value2 && (Object)(object)_distanceText != (Object)null) { SetPosAndSize(((Graphic)_distanceText).rectTransform, new Vector2(0f, num3), num - 40f, 22f); num3 -= 22f; } bool value3 = ModConfig.EnableEnergySystem.Value; Text? energyText = _energyText; if (energyText != null) { ((Component)energyText).gameObject.SetActive(value3); } if (value3 && (Object)(object)_energyText != (Object)null) { SetPosAndSize(((Graphic)_energyText).rectTransform, new Vector2(0f, num3), num - 40f, 22f); num3 -= 22f; } if ((Object)(object)_weightText != (Object)null) { SetPosAndSize(((Graphic)_weightText).rectTransform, new Vector2(0f, num3), num - 40f, 22f); num3 -= 22f; } if ((Object)(object)_statusText != (Object)null) { SetPosAndSize(((Graphic)_statusText).rectTransform, new Vector2(0f, num3), num - 40f, 22f); num3 -= 32f; } Button? saveButton = _saveButton; SetPosAndSize((saveButton != null) ? ((Component)saveButton).GetComponent<RectTransform>() : null, new Vector2(-80f, num3), 140f, 36f); Button? cancelButton = _cancelButton; SetPosAndSize((cancelButton != null) ? ((Component)cancelButton).GetComponent<RectTransform>() : null, new Vector2(80f, num3), 140f, 36f); float num4 = Mathf.Abs(num3) + 55f; _rootRect.sizeDelta = new Vector2(num, num4); if ((Object)(object)_tagInput != (Object)null) { _tagInput.text = portalInfo.Tag; } if ((Object)(object)_passwordInput != (Object)null) { _passwordInput.text = portalInfo.Password; } if ((Object)(object)_outboundPasswordInput != (Object)null) { _outboundPasswordInput.text = portalInfo.OutboundPassword; } if (value2 && (Object)(object)_targetDropdown != (Object)null) { _availablePortals = PortalDataManager.GetAllPortals(portalInfo.Id); Vector3 myPos = ((Component)_currentPortal).transform.position; _availablePortals.Sort((PortalInfo a, PortalInfo b) => Utils.DistanceXZ(myPos, a.Position).CompareTo(Utils.DistanceXZ(myPos, b.Position))); _targetDropdown.ClearOptions(); List<OptionData> list = new List<OptionData> { new OptionData("[ None / Unconnected ]") }; int value4 = 0; for (int num5 = 0; num5 < _availablePortals.Count; num5++) { PortalInfo portalInfo2 = _availablePortals[num5]; float num6 = Utils.DistanceXZ(myPos, portalInfo2.Position); string arg = ((!string.IsNullOrEmpty(portalInfo2.Password)) ? " [Locked]" : ""); list.Add(new OptionData($"{portalInfo2.DisplayName}{arg} ({num6:F0}m)")); if (portalInfo.OutboundTarget != ZDOID.None && portalInfo.OutboundTarget == portalInfo2.Id) { value4 = num5 + 1; } } _targetDropdown.AddOptions(list); _targetDropdown.value = value4; } UpdateStatus(); _rootPanel.SetActive(true); GUIManager.BlockInput(true); } private static void SetPosAndSize(RectTransform? rt, Vector2 pos, float width, float height) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)rt == (Object)null)) { rt.anchorMin = new Vector2(0.5f, 1f); rt.anchorMax = new Vector2(0.5f, 1f); rt.anchoredPosition = pos; rt.sizeDelta = new Vector2(width, height); } } public void Hide() { if ((Object)(object)_rootPanel != (Object)null) { _rootPanel.SetActive(false); } GUIManager.BlockInput(false); _currentPortal = null; } private void UpdateStatus() { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentPortal == (Object)null) { return; } bool value = ModConfig.EnablePasswordSystem.Value; bool value2 = ModConfig.EnableTargetSelectionUI.Value; if ((Object)(object)_weightText != (Object)null) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && ((Humanoid)localPlayer).GetInventory() != null) { float totalWeight = ((Humanoid)localPlayer).GetInventory().GetTotalWeight(); float maxWeight = ModConfig.GetMaxWeight(_currentPortal); if (ModConfig.EnableMaxWeightLimit.Value && totalWeight > maxWeight) { _weightText.text = $"<color=red>Carry Weight: {totalWeight:F0} / {maxWeight:F0} lbs (Overweight)</color>"; } else { _weightText.text = $"<color=#cccccc>Carry Weight: {totalWeight:F0} / {maxWeight:F0} lbs</color>"; } } } bool interactable = true; string text = ""; float? overrideDistance = null; if (value2 && (Object)(object)_targetDropdown != (Object)null) { int value3 = _targetDropdown.value; if (value3 > 0 && value3 - 1 < _availablePortals.Count) { PortalInfo portalInfo = _availablePortals[value3 - 1]; float num = Utils.DistanceXZ(((Component)_currentPortal).transform.position, portalInfo.Position); overrideDistance = num; if ((Object)(object)_distanceText != (Object)null) { float maxDistance = ModConfig.GetMaxDistance(_currentPortal); float minDistance = ModConfig.GetMinDistance(_currentPortal); if (ModConfig.EnableDistanceLimit.Value && num > maxDistance) { _distanceText.text = $"<color=red>Distance: {num:F0}m (Exceeds {maxDistance:F0}m limit)</color>"; text = "Destination is too far away!"; interactable = false; } else if (ModConfig.EnableMinDistanceLimit.Value && num < minDistance) { _distanceText.text = $"<color=red>Distance: {num:F0}m (Below {minDistance:F0}m limit)</color>"; text = "Destination is too close!"; interactable = false; } else { _distanceText.text = $"<color=#80c0ff>Distance to target: {num:F0}m</color>"; } } if (value) { string suppliedOutboundPassword = (((Object)(object)_outboundPasswordInput != (Object)null) ? _outboundPasswordInput.text.Trim() : ""); if (!PortalDataManager.ValidatePasswordMatch(portalInfo.Password, suppliedOutboundPassword, out string _)) { text = "<color=red>Destination is password-protected! Incorrect password.</color>"; interactable = false; } else if (!string.IsNullOrEmpty(portalInfo.Password)) { text = "<color=#80ff80>Destination password matched.</color>"; } } } else if ((Object)(object)_distanceText != (Object)null) { _distanceText.text = "<color=#aaaaaa>No destination selected (Portal will be unlinked).</color>"; } } else if ((Object)(object)_distanceText != (Object)null) { _distanceText.text = ""; } if (ModConfig.EnableEnergySystem.Value && (Object)(object)_energyText != (Object)null && EnergyManager.GetCurrentEnergy(_currentPortal, out var currentEnergy, out var maxEnergy, out var rechargeRate)) { Player localPlayer2 = Player.m_localPlayer; float totalCost; string costBreakdown; float num2 = EnergyManager.CalculateTeleportCost(localPlayer2, _currentPortal, out totalCost, out costBreakdown, overrideDistance); if (currentEnergy >= num2) { _energyText.text = $"<color=#ffd700>Portal Energy: {currentEnergy:F0} / {maxEnergy:F0} (+{rechargeRate:F1}/s) | Jump Cost: {num2:F0} ({costBreakdown})</color>"; } else if (ModConfig.LowEnergyAction.Value == LowEnergyBehavior.ExtendSickness) { float num3 = EnergyManager.CalculateOverdraftExtraSickness(num2 - currentEnergy); if (num2 > maxEnergy) { string exceedsCapacityReason = EnergyManager.GetExceedsCapacityReason(localPlayer2, _currentPortal, maxEnergy, overrideDistance); _energyText.text = $"<color=#ffaa55>Portal Overdraft: {currentEnergy:F0} / {maxEnergy:F0} (Cost: {num2:F0} - {exceedsCapacityReason}) (+{num3:F0}s sickness)</color>"; } else { float rechargeTimeRemaining = EnergyManager.GetRechargeTimeRemaining(currentEnergy, num2, rechargeRate); _energyText.text = $"<color=#ffaa55>Portal Overdraft: {currentEnergy:F0} / {maxEnergy:F0} (+{num3:F0}s sickness! Ready in ~{rechargeTimeRemaining:F0}s)</color>"; } } else if (num2 > maxEnergy) { string exceedsCapacityReason2 = EnergyManager.GetExceedsCapacityReason(localPlayer2, _currentPortal, maxEnergy, overrideDistance); _energyText.text = $"<color=#ff8080>Portal Energy: {currentEnergy:F0} / {maxEnergy:F0} (Cost: {num2:F0} - {exceedsCapacityReason2})</color>"; } else { float rechargeTimeRemaining2 = EnergyManager.GetRechargeTimeRemaining(currentEnergy, num2, rechargeRate); _energyText.text = $"<color=#ff8080>Portal Energy: {currentEnergy:F0} / {maxEnergy:F0} (Cost: {num2:F0} - Recharging: ~{rechargeTimeRemaining2:F0}s)</color>"; } } if (TeleportPatch.HasProximityConflict(_currentPortal, out var closestDist)) { float value4 = ModConfig.MinDistanceBetweenPortals.Value; string text2 = $"<color=red>Interference: Portal is {closestDist:F0}m from another portal (min {value4:F0}m)!</color>"; text = (string.IsNullOrEmpty(text) ? text2 : (text + "\n" + text2)); } if (ModConfig.EnableTeleportSickness.Value && ModConfig.SicknessBlockTeleport.Value && TeleportSicknessManager.HasSickness(Player.m_localPlayer, out var remainingSeconds)) { string text3 = $"<color=red>Teleportation sickness active ({remainingSeconds:F0}s remaining)!</color>"; text = (string.IsNullOrEmpty(text) ? text3 : (text + "\n" + text3)); } if ((Object)(object)_statusText != (Object)null) { _statusText.text = text; } if ((Object)(object)_saveButton != (Object)null) { ((Selectable)_saveButton).interactable = interactable; } } private void OnSaveClicked() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_currentPortal == (Object)null) { Hide(); return; } string tag = (((Object)(object)_tagInput != (Object)null) ? _tagInput.text.Trim() : ""); string password = (((Object)(object)_passwordInput != (Object)null) ? _passwordInput.text.Trim() : ""); ZDOID val = ZDOID.None; string outboundPassword = (((Object)(object)_outboundPasswordInput != (Object)null) ? _outboundPasswordInput.text.Trim() : ""); bool value = ModConfig.EnableTargetSelectionUI.Value; if (value && (Object)(object)_targetDropdown != (Object)null) { int value2 = _targetDropdown.value; if (value2 > 0 && value2 - 1 < _availablePortals.Count) { val = _availablePortals[value2 - 1].Id; } } PortalDataManager.SavePortal(_currentPortal, tag, password, val, outboundPassword, value); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, (value && val != ZDOID.None) ? "Portal destination routed!" : "Portal configuration saved.", 0, (Sprite)null, false); } Hide(); } } } namespace PortalTweaks.StatusEffects { public class SE_TeleportSickness : SE_Stats { public const string EffectName = "SE_TeleportSickness"; public static readonly int EffectHash = StringExtensionMethods.GetStableHashCode("SE_TeleportSickness"); public SE_TeleportSickness() { ((Object)this).name = "SE_TeleportSickness"; ((StatusEffect)this).m_name = "Teleport Sickness"; ((StatusEffect)this).m_tooltip = "Suffering from spatial displacement disorientation."; } public override void Setup(Character character) { ((SE_Stats)this).Setup(character); ApplyConfigModifiers(); } public void ApplyConfigModifiers() { base.m_addMaxCarryWeight = 0f - Mathf.Max(0f, ModConfig.SicknessCarryWeightReduction.Value); float num = Mathf.Clamp(ModConfig.SicknessMovementSpeed.Value, 0f, 100f); base.m_speedModifier = num / 100f - 1f; base.m_healthRegenMultiplier = Mathf.Clamp(ModConfig.SicknessHealthRegen.Value, 0f, 100f) / 100f; base.m_staminaRegenMultiplier = Mathf.Clamp(ModConfig.SicknessStaminaRegen.Value, 0f, 100f) / 100f; base.m_eitrRegenMultiplier = Mathf.Clamp(ModConfig.SicknessEitrRegen.Value, 0f, 100f) / 100f; } public override string GetTooltipString() { List<string> list = new List<string>(); if (ModConfig.SicknessBlockTeleport.Value) { list.Add("<color=#ff6060>Unable to use portals</color>"); } if (ModConfig.SicknessCarryWeightReduction.Value > 0f) { list.Add($"Carry weight: -{ModConfig.SicknessCarryWeightReduction.Value:F0}"); } if (ModConfig.SicknessMovementSpeed.Value < 100f) { list.Add($"Movement speed: {ModConfig.SicknessMovementSpeed.Value:F0}%"); } if (ModConfig.SicknessHealthRegen.Value < 100f) { list.Add($"Health regen: {ModConfig.SicknessHealthRegen.Value:F0}%"); } if (ModConfig.SicknessStaminaRegen.Value < 100f) { list.Add($"Stamina regen: {ModConfig.SicknessStaminaRegen.Value:F0}%"); } if (ModConfig.SicknessEitrRegen.Value < 100f) { list.Add($"Eitr regen: {ModConfig.SicknessEitrRegen.Value:F0}%"); } return string.Join("\n", list); } public override string GetIconText() { float remaningTime = ((StatusEffect)this).GetRemaningTime(); if (!(remaningTime > 0f)) { return ""; } return remaningTime.ToString("F0") + "s"; } } public static class TeleportSicknessManager { private struct PendingSicknessData { public float JumpDistance; public bool IsStonePortal; public float OverdraftExtraSeconds; } private static SE_TeleportSickness? _templateEffect; private static readonly Dictionary<long, PendingSicknessData> _pendingSickness = new Dictionary<long, PendingSicknessData>(); public static void SchedulePendingSickness(Player? player, float jumpDist, bool isStonePortal = false, float overdraftExtraSeconds = 0f) { if (!((Object)(object)player == (Object)null)) { _pendingSickness[player.GetPlayerID()] = new PendingSicknessData { JumpDistance = jumpDist, IsStonePortal = isStonePortal, OverdraftExtraSeconds = overdraftExtraSeconds }; } } public static void ClearPendingSickness(Player? player) { if (!((Object)(object)player == (Object)null)) { _pendingSickness.Remove(player.GetPlayerID()); } } public static void ApplyPendingSickness(Player? player) { if ((Object)(object)player == (Object)null) { return; } long playerID = player.GetPlayerID(); if (!_pendingSickness.TryGetValue(playerID, out var value)) { return; } _pendingSickness.Remove(playerID); if (ModConfig.EnableTeleportSickness.Value) { ApplyDurabilityLoss(player, value.IsStonePortal); } float num = 0f; if (ModConfig.EnableTeleportSickness.Value) { num = CalculateDuration(value.JumpDistance, value.IsStonePortal); } float num2 = num + value.OverdraftExtraSeconds; if (num2 > 0.001f) { ApplySickness(player, num2); if (value.OverdraftExtraSeconds > 0.001f) { ((Character)player).Message((MessageType)2, $"Teleported via overdraft! Sickness extended (+{value.OverdraftExtraSeconds:F0}s)", 0, (Sprite)null, false); } } } public static float CalculateDuration(float distance, bool isStonePortal = false) { float sicknessBaseDuration = ModConfig.GetSicknessBaseDuration(isStonePortal); if (sicknessBaseDuration <= 0.001f) { return 0f; } float value = ModConfig.SicknessBaseDistance.Value; float value2 = ModConfig.SicknessDurationExponent.Value; if (distance <= 0f || value <= 0.001f) { return sicknessBaseDuration; } float num = Mathf.Max(0f, distance / value); float num2 = sicknessBaseDuration * Mathf.Pow(num, value2); return Mathf.Max(0f, num2); } public static void ApplyDurabilityLoss(Player? player, bool isStonePortal = false) { if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null) { return; } float num = Mathf.Clamp(ModConfig.GetSicknessDurabilityLossPercent(isStonePortal), 0f, 100f); if (num <= 0.001f) { return; } float num2 = num / 100f; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem?.m_shared != null && allItem.m_shared.m_useDurability) { float num3 = allItem.GetMaxDurability() * num2; allItem.m_durability = Mathf.Max(0f, allItem.m_durability - num3); } } } public static Sprite? GetSicknessIcon() { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab("portal_wood"); if ((Object)(object)prefab != (Object)null) { Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_icon != (Object)null) { return component.m_icon; } } } if ((Object)(object)ObjectDB.instance != (Object)null) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("Frost")); if ((Object)(object)statusEffect != (Object)null && (Object)(object)statusEffect.m_icon != (Object)null) { return statusEffect.m_icon; } } return null; } public static SE_TeleportSickness GetOrCreateTemplate() { if ((Object)(object)_templateEffect == (Object)null) { _templateEffect = ScriptableObject.CreateInstance<SE_TeleportSickness>(); ((Object)_templateEffect).name = "SE_TeleportSickness"; ((StatusEffect)_templateEffect).m_name = "Teleport Sickness"; ((StatusEffect)_templateEffect).m_icon = GetSicknessIcon(); } if ((Object)(object)((StatusEffect)_templateEffect).m_icon == (Object)null) { ((StatusEffect)_templateEffect).m_icon = GetSicknessIcon(); } return _templateEffect; } public static void ApplySickness(Player? player, float duration) { if (!((Object)(object)player == (Object)null) && !(duration <= 0.001f)) { SE_TeleportSickness orCreateTemplate = GetOrCreateTemplate(); orCreateTemplate.ApplyConfigModifiers(); ((StatusEffect)orCreateTemplate).m_ttl = duration; SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan != null) { sEMan.AddStatusEffect((StatusEffect)(object)orCreateTemplate, true, 0, 0f, (short)(-1)); } } } public static bool HasSickness(Player? player, out float remainingSeconds) { remainingSeconds = 0f; if ((Object)(object)player == (Object)null) { return false; } SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan == null || !sEMan.HaveStatusEffect(SE_TeleportSickness.EffectHash)) { return false; } StatusEffect statusEffect = sEMan.GetStatusEffect(SE_TeleportSickness.EffectHash); if ((Object)(object)statusEffect != (Object)null) { remainingSeconds = Mathf.Max(0f, statusEffect.GetRemaningTime()); return remainingSeconds > 0.001f; } return false; } } } namespace PortalTweaks.Patches { [HarmonyPatch] public static class TeleportPatch { public static bool IsOverWeightLimit(Player? player, TeleportWorld? portal, out float currentWeight, out float maxWeight) { currentWeight = 0f; maxWeight = ModConfig.GetMaxWeight(portal); if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null) { return false; } currentWeight = ((Humanoid)player).GetInventory().GetTotalWeight(); if (ModConfig.EnableMaxWeightLimit.Value) { return currentWeight > maxWeight; } return false; } public static bool IsOverWeightLimit(Player? player, bool isStone, out float currentWeight, out float maxWeight) { currentWeight = 0f; maxWeight = ModConfig.GetMaxWeight(isStone); if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null) { return false; } currentWeight = ((Humanoid)player).GetInventory().GetTotalWeight(); if (ModConfig.EnableMaxWeightLimit.Value) { return currentWeight > maxWeight; } return false; } public static bool IsOverWeightLimit(Player? player, out float currentWeight, out float maxWeight) { return IsOverWeightLimit(player, null, out currentWeight, out maxWeight); } public static bool CanTeleportItems(Player? player, TeleportWorld? portal, out string rejectionReason) { return CanTeleportItems(player, ModConfig.IsStonePortal(portal), out rejectionReason); } public static bool CanTeleportItems(Player? player, bool isStone, out string rejectionReason) { //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Invalid comparison between Unknown and I4 //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Invalid comparison between Unknown and I4 //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Invalid comparison between Unknown and I4 rejectionReason = string.Empty; if (!ModConfig.ModEnabled.Value) { return true; } ItemRestrictionTier restrictionTier = ModConfig.GetRestrictionTier(isStone); switch (restrictionTier) { case ItemRestrictionTier.NoTeleport: rejectionReason = "Portals are disabled"; return false; case ItemRestrictionTier.Unrestricted: return true; default: { if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null) { return true; } List<ItemData> allItems = ((Humanoid)player).GetInventory().GetAllItems(); switch (restrictionTier) { case ItemRestrictionTier.Naked: if (allItems.Count > 0) { rejectionReason = "Inventory must be empty"; return false; } break; case ItemRestrictionTier.EquippedOnly: foreach (ItemData item in allItems) { if (!item.m_equipped) { rejectionReason = "Only actively equipped items allowed"; return false; } } break; case ItemRestrictionTier.EquipmentOnly: foreach (ItemData item2 in allItems) { if (!item2.IsEquipable()) { rejectionReason = "Only equipment is allowed"; return false; } } break; case ItemRestrictionTier.GearAndProvisions: foreach (ItemData item3 in allItems) { bool num = item3.IsEquipable(); bool flag = item3.m_shared != null && (int)item3.m_shared.m_itemType == 2; bool flag2 = item3.m_shared != null && ((int)item3.m_shared.m_itemType == 9 || (int)item3.m_shared.m_itemType == 23); if (!num && !flag && !flag2) { rejectionReason = "Only equipment, food, and ammo allowed"; return false; } } break; case ItemRestrictionTier.Vanilla: foreach (ItemData item4 in allItems) { if (item4.m_shared != null && !item4.m_shared.m_teleportable) { rejectionReason = "Carrying non-teleportable items (ores/metals)"; return false; } } break; } return true; } } } public static bool CanTeleportItems(Player? player, out string rejectionReason) { return CanTeleportItems(player, isStone: false, out rejectionReason); } public static bool TryGetTargetPortalDistance(TeleportWorld portal, out float distance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) distance = 0f; if ((Object)(object)portal == (Object)null) { return false; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)1); if (connectionZDOID == ZDOID.None) { return false; } if (ZDOMan.instance == null) { return false; } ZDO zDO2 = ZDOMan.instance.GetZDO(connectionZDOID); if (zDO2 == null) { ZDOMan.instance.RequestZDO(connectionZDOID); return false; } Vector3 position = ((Component)portal).transform.position; Vector3 position2 = zDO2.GetPosition(); distance = Utils.DistanceXZ(position, position2); return true; } public static bool IsDistanceViolated(TeleportWorld portal, out float distance, out string rejectionReason) { distance = 0f; rejectionReason = string.Empty; if (!ModConfig.ModEnabled.Value || !ModConfig.EnableDistanceLimit.Value) { return false; } if (!TryGetTargetPortalDistance(portal, out distance)) { return false; } float maxDistance = ModConfig.GetMaxDistance(portal); if (distance > maxDistance) { rejectionReason = $"Portals are too far apart ({distance:F0}m / {maxDistance:F0}m)"; return true; } if (ModConfig.EnableMinDistanceLimit.Value) { float minDistance = ModConfig.GetMinDistance(portal); if (distance < minDistance) { rejectionReason = $"Portals are too close together ({distance:F0}m / {minDistance:F0}m)"; return true; } } return false; } public static bool IsPasswordMismatched(TeleportWorld portal, out string reason) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) reason = string.Empty; if (!ModConfig.ModEnabled.Value || !ModConfig.EnablePasswordSystem.Value) { return false; } if ((Object)(object)portal == (Object)null) { return false; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } ZDOID connectionZDOID = zDO.GetConnectionZDOID((ConnectionType)1); if (connectionZDOID == ZDOID.None || ZDOMan.instance == null) { return false; } ZDO zDO2 = ZDOMan.instance.GetZDO(connectionZDOID); if (zDO2 == null) { return false; } string text = zDO2.GetString("PortalTweaks_Password", string.Empty); if (ModConfig.EnableTargetSelectionUI.Value) { string suppliedOutboundPassword = zDO.GetString("PortalTweaks_OutboundPassword", string.Empty); if (!PortalDataManager.ValidatePasswordMatch(text, suppliedOutboundPassword, out reason)) { return true; } } else if (zDO.GetString("PortalTweaks_Password", string.Empty) != text) { reason = "Password mismatch between paired portals"; return true; } return false; } public static bool HasProximityConflict(Vector3 pos, ZDOID excludeId, out float closestDist, out Vector3 closestPos) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_0096: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) closestDist = float.MaxValue; closestPos = Vector3.zero; if (!ModConfig.ModEnabled.Value || !ModConfig.EnablePortalProximityLimit.Value) { return false; } float value = ModConfig.MinDistanceBetweenPortals.Value; if (value <= 0f) { return false; } if (ZDOMan.instance == null) { return false; } List<ZDO> portalList = ZDOMan.instance.GetPortalList(); if (portalList == null || portalList.Count == 0) { return false; } foreach (ZDO item in portalList) { if (item != null && !(item.m_uid == ZDOID.None) && !(item.m_uid == excludeId)) { float num = Utils.DistanceXZ(pos, item.GetPosition()); if (num < closestDist) { closestDist = num; closestPos = item.GetPosition(); } } } return closestDist < value; } public static bool HasProximityConflict(TeleportWorld portal, out float closestDist) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_004f: Unknown result type (might be due to invalid IL or missing references) closestDist = float.MaxValue; if ((Object)(object)portal == (Object)null) { return false; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDOID excludeId = component.GetZDO()?.m_uid ?? ZDOID.None; Vector3 closestPos; return HasProximityConflict(((Component)portal).transform.position, excludeId, out closestDist, out closestPos); } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] [HarmonyPostfix] private static void PostfixUpdatePlacementGhost(Player __instance, GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.ModEnabled.Value && ModConfig.EnablePortalProximityLimit.Value && !((Object)(object)___m_placementGhost == (Object)null) && !((Object)(object)___m_placementGhost.GetComponentInChildren<TeleportWorld>() == (Object)null) && HasProximityConflict(___m_placementGhost.transform.position, ZDOID.None, out var _, out var _)) { ___m_placementStatus = (PlacementStatus)1; Piece component = ___m_placementGhost.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.SetInvalidPlacementHeightlight(true); } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] [HarmonyPrefix] private static bool PrefixTryPlacePiece(Player __instance, Piece piece, GameObject ___m_placementGhost) { //IL_006e: 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_0073: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ModEnabled.Value || !ModConfig.EnablePortalProximityLimit.Value) { return true; } if ((Object)(object)piece == (Object)null) { return true; } if (!((Object)(object)((Component)piece).GetComponentInChildren<TeleportWorld>() != (Object)null) && (!((Object)(object)___m_placementGhost != (Object)null) || !((Object)(object)___m_placementGhost.GetComponentInChildren<TeleportWorld>() != (Object)null))) { return true; } if (HasProximityConflict(((Object)(object)___m_placementGhost != (Object)null) ? ___m_placementGhost.transform.position : ((Component)__instance).transform.position, ZDOID.None, out var closestDist, out var _)) { float value = ModConfig.MinDistanceBetweenPortals.Value; ((Character)__instance).Message((MessageType)2, $"Too close to another portal ({closestDist:F0}m / {value:F0}m)", 0, (Sprite)null, false); return false; } return true; } [HarmonyPatch(typeof(Player), "PlacePiece")] [HarmonyPrefix] private static bool PrefixPlacePiece(Player __instance, Piece piece, Vector3 pos) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.ModEnabled.Value || !ModConfig.EnablePortalProximityLimit.Value) { return true; } if ((Object)(object)piece != (Object)null && (Object)(object)((Component)piece).GetComponentInChildren<TeleportWorld>() != (Object)null && HasProximityConflict(pos, ZDOID.None, out var closestDist, out var _)) { float value = ModConfig.MinDistanceBetweenPortals.Value; ((Character)__instance).Message((MessageType)2, $"Too close to another portal ({closestDist:F0}m / {value:F0}m)", 0, (Sprite)null, false); return false; } return true; } [HarmonyPatch(typeof(TeleportWorld), "TargetFound")] [HarmonyPostfix] private static void PostfixTargetFound(TeleportWorld __instance, ref bool __result) { if (ModConfig.ModEnabled.Value && __result) { string rejectionReason; if (HasProximityConflict(__instance, out var closestDist)) { __result = false; } else if (IsDistanceViolated(__instance, out closestDist, out rejectionReason)) { __result = false; } else if (IsPasswordMismatched(__instance, out rejectionReason)) { __result = false; } } } [HarmonyPatch(typeof(TeleportWorld), "UpdatePortal")] [HarmonyPostfix] private static void PostfixUpdatePortal(TeleportWorld __instance) { if (!ModConfig.ModEnabled.Value) { return; } float currentEnergy; float rechargeRate; if (HasProximityConflict(__instance, out var closestDist)) { if ((Object)(object)__instance.m_target_found != (Object)null) { __instance.m_target_found.SetActive(false); } } else if (ModConfig.EnableEnergySystem.Value && ModConfig.DeactivateVortexWhenInsufficientEnergy && EnergyManager.GetCurrentEnergy(__instance, out currentEnergy, out closestDist, out rechargeRate)) { string costBreakdown; float num = EnergyManager.CalculateTeleportCost(Player.m_localPlayer, __instance, out rechargeRate, out costBreakdown); if (currentEnergy < num && (Object)(object)__instance.m_target_found != (Object)null) { __instance.m_target_found.SetActive(false); } } } [HarmonyPatch(typeof(TeleportWorld), "Update")] [HarmonyPostfix] private static void PostfixUpdate(TeleportWorld __instance) { //IL_0080: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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) if (ModConfig.ModEnabled.Value && ModConfig.EnableEnergySystem.Value && ModConfig.ScalePortalVfxWithEnergy.Value && !((Object)(object)__instance.m_model == (Object)null) && !((Object)(object)((Renderer)__instance.m_model).material == (Object)null) && EnergyManager.GetCurrentEnergy(__instance, out var currentEnergy, out var maxEnergy, out var _)) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); bool num = (Object)(object)component != (Object)null && component.IsValid() && component.GetZDO() != null && component.GetZDO().GetConnectionZDOID((ConnectionType)1) != ZDOID.None; float num2 = ((maxEnergy > 0.001f) ? Mathf.Clamp01(currentEnergy / maxEnergy) : 0f); Color colorUnconnected = __instance.m_colorUnconnected; Color val = (num ? __instance.m_colorTargetfound : colorUnconnected); Color val2 = Color.Lerp(colorUnconnected, val, num2); ((Renderer)__instance.m_model).material.SetColor("_EmissionColor", val2); } } [HarmonyPatch(typeof(Humanoid), "IsTeleportable")] [HarmonyPrefix] private static void PrefixIsTeleportable(ref bool allowAllItems) { if (ModConfig.ModEnabled.Value && ModConfig.GetRestrictionTier(allowAllItems) == ItemRestrictionTier.Unrestricted) { allowAllItems = true; } } [HarmonyPatch(typeof(Humanoid), "IsTeleportable")] [HarmonyPostfix] private static void PostfixIsTeleportable(Humanoid __instance, bool allowAllItems, ref bool __result) { if (!ModConfig.ModEnabled.Value) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { string rejectionReason; if (IsOverWeightLimit(val, allowAllItems, out var _, out var maxWeight)) { __result = false; } else if (!CanTeleportItems(val, allowAllItems, out rejectionReason)) { __result = false; } else if (ModConfig.EnableTeleportSickness.Value && ModConfig.SicknessBlockTeleport.Value && TeleportSicknessManager.HasSickness(val, out maxWeight)) { __result = false; } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] [HarmonyPrefix] private static bool OnTeleportPrefix(TeleportWorld __instance, Player player) { if (!ModConfig.ModEnabled.Value) { return true; } if (ModConfig.EnableTeleportSickness.Value && ModConfig.SicknessBlockTeleport.Value && TeleportSicknessManager.HasSickness(player, out var remainingSeconds)) { if (player != null) { ((Character)player).Message((MessageType)2, $"Cannot teleport: Teleportation sickness active ({remainingSeconds:F0}s remaining)", 0, (Sprite)null, false); } return false; } if (HasProximityConflict(__instance, out var closestDist)) { float value = ModConfig.MinDistanceBetweenPortals.Value; if (player != null) { ((Character)player).Message((MessageType)2, $"Cannot teleport: Portal interference (within {closestDist:F0}m of another portal, minimum {value:F0}m required)", 0, (Sprite)null, false); } return false; } if (IsPasswordMismatched(__instance, out string reason)) { if (player != null) { ((Character)player).Message((MessageType)2, "Cannot teleport: " + reason, 0, (Sprite)null, false); } return false; } if (IsDistanceViolated(__instance, out float distance, out string rejectionReason)) { if (player != null) { ((Character)player).Message((MessageType)2, "Cannot teleport: " + rejectionReason, 0, (Sprite)null, false); } return false; } if (IsOverWeightLimit(player, __instance, out var currentWeight, out var maxWeight)) { if (player != null) { ((Character)player).Message((MessageType)2, $"Too heavy for portal: {currentWeight:F0} / {maxWeight:F0}", 0, (Sprite)null, false); } return false; } if (!CanTeleportItems(player, __instance, out string rejectionReason2)) { if (player != null) { ((Character)player).Message((MessageType)2, "Cannot teleport: " + rejectionReason2, 0, (Sprite)null, false); } return false; } float num = 0f; if (ModConfig.EnableEnergySystem.Value) { EnergyManager.GetCurrentEnergy(__instance, out var currentEnergy, out var maxEnergy, out var rechargeRate); string costBreakdown; float num2 = EnergyManager.CalculateTeleportCost(player, __instance, out distance, out costBreakdown); if (currentEnergy < num2) { if (ModConfig.LowEnergyAction.Value == LowEnergyBehavior.RefuseTeleport) { if (num2 > maxEnergy) { string exceedsCapacityReason = EnergyManager.GetExceedsCapacityReason(player, __instance, maxEnergy); if (player != null) { ((Character)player).Message((MessageType)2, "Cannot teleport: Exceeds portal capacity (" + exceedsCapacityReason + ")", 0, (Sprite)null, false); } return false; } float rechargeTimeRemaining = EnergyManager.GetRechargeTimeRemaining(currentEnergy, num2, rechargeRate); if (player != null) { ((Character)player).Message((MessageType)2, $"Cannot teleport: Portal recharging ({currentEnergy:F0} / {num2:F0} energy, ~{rechargeTimeRemaining:F0}s)", 0, (Sprite)null, false); } return false; } float num3 = num2 - currentEnergy; EnergyManager.ConsumeEnergy(__instance, currentEnergy, out distance); num = EnergyManager.CalculateOverdraftExtraSickness(num3); if (ModConfig.LogPortalTeleports.Value) { PortalTweaksPlugin.Log.LogInfo((object)$"Portal [{__instance.GetText()}] overdrafted by {num3:F1} energy. Sickness extended by {num:F0}s."); } } else { EnergyManager.ConsumeEnergy(__instance, num2, out var remainingEnergy); if (ModConfig.LogPortalTeleports.Value) { PortalTweaksPlugin.Log.LogInfo((object)$"Portal [{__instance.GetText()}] consumed {num2:F1} energy ({costBreakdown}). Remaining: {remainingEnergy:F1}/{maxEnergy:F1}"); } } } if (ModConfig.LogPortalTeleports.Value && (Object)(object)player != (Object)null) { string text = __instance.GetText(); PortalTweaksPlugin.Log.LogInfo((object)("Player '" + player.GetPlayerName() + "' teleporting via portal [Tag: '" + text + "']")); } if ((ModConfig.EnableTeleportSickness.Value || num > 0f) && (Object)(object)player != (Object)null) { bool isStonePortal = ModConfig.IsStonePortal(__instance); TryGetTargetPortalDistance(__instance, out var distance2); TeleportSicknessManager.SchedulePendingSickness(player, distance2, isStonePortal, num); } return true; } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] [HarmonyPostfix] private static void OnTeleportPostfix(TeleportWorld __instance, Player player) { if ((Object)(object)player != (Object)null && !((Character)player).IsTeleporting()) { TeleportSicknessManager.ClearPendingSickness(player); } } [HarmonyPatch(typeof(TeleportWorld), "GetHoverText")] [HarmonyPostfix] private static void GetHoverTextPostfix(TeleportWorld __instance, ref string __result) { if (!ModConfig.ModEnabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if (ModConfig.EnableTeleportSickness.Value && ModConfig.SicknessBlockTeleport.Value && (Object)(object)localPlayer != (Object)null && TeleportSicknessManager.HasSickness(localPlayer, out var remainingSeconds)) { __result += $"\n<color=red>Cannot teleport: Teleportation sickness ({remainingSeconds:F0}s)</color>"; } if (HasProximityConflict(__instance, out var closestDist)) { float value = ModConfig.MinDistanceBetweenPortals.Value; __result += $"\n<color=red>Portal interference: Too close to another portal ({closestDist:F0}m / {value:F0}m)</color>"; } if (IsPasswordMismatched(__instance, out string reason)) { __result = __result + "\n<color=red>Cannot teleport: " + reason + "</color>"; } float distance2; if (TryGetTargetPortalDistance(__instance, out var distance)) { if (IsDistanceViolated(__instance, out distance2, out string rejectionReason)) { __result = __result + "\n<color=red>Cannot teleport: " + rejectionReason + "</color>"; } else if (ModConfig.ShowDistanceInHoverText.Value) { __result += $"\n<color=#80c0ff>Portal distance: {distance:F0}m</color>"; } } if ((Object)(object)localPlayer == (Object)null) { return; } if (ModConfig.ShowHoverWeightWarning.Value && IsOverWeightLimit(localPlayer, __instance, out var currentWeight, out var maxWeight)) { __result += $"\n<color=red>Too heavy to teleport: {currentWeight:F0} / {maxWeight:F0}</color>"; } if (ModConfig.ShowHoverItemWarning.Value && !CanTeleportItems(localPlayer, __instance, out string rejectionReason2)) { __result = __result + "\n<color=red>Cannot teleport: " + rejectionReason2 + "</color>"; } if (!ModConfig.EnableEnergySystem.Value || !ModConfig.ShowHoverEnergyInfo.Value || !EnergyManager.GetCurrentEnergy(__instance, out var currentEnergy, out var maxEnergy, out var rechargeRate)) { return; } string costBreakdown; float num = EnergyManager.CalculateTeleportCost(localPlayer, __instance, out distance2, out costBreakdown); if (currentEnergy >= num) { __result += $"\n<color=#ffd700>Portal Energy: {currentEnergy:F0} / {maxEnergy:F0} (Cost: {num:F0})</color>"; return; } if (num > maxEnergy && ModConfig.LowEnergyAction.Value == LowEnergyBehavior.RefuseTeleport) { string exceedsCapacityReason = EnergyManager.GetExceedsCapacityReason(localPlayer, __instance, maxEnergy); __result += $"\n<color=#ff8080>Portal Energy: {currentEnergy:F0} / {maxEnergy:F0} (Cost: {num:F0} - {exceedsCapacityReason})</color>"; return; } float rechargeTimeRemaining = EnergyManager.GetRechargeTimeRemaining(currentEnergy, num, rechargeRate); if (ModConfig.LowEnergyAction.Value == LowEnergyBehavior.RefuseTeleport) { __result += $"\n<color=#ff8080>Portal Recharging: {currentEnergy:F0} / {maxEnergy:F0} (Requires {num:F0}, ready in ~{rechargeTimeRemaining:F0}s)</color>"; } else { float num2 = EnergyManager.CalculateOverdraftExtraSickness(num - currentEnergy); __result += $"\n<color=#ffaa00>Portal Overdraft: {currentEnergy:F0} / {num:F0} (+{num2:F0}s sickness! Ready in ~{rechargeTimeRemaining:F0}s)</color>"; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPostfix] private static void PostfixObjectDBAwake(ObjectDB __instance) { RegisterCustomStatusEffects(__instance); } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPostfix] private static void PostfixCopyOtherDB(ObjectDB __instance) { RegisterCustomStatusEffects(__instance); } private static void RegisterCustomStatusEffects(ObjectDB db) { if (!((Object)(object)db == (Object)null) && db.m_StatusEffects != null) { SE_TeleportSickness orCreateTemplate = TeleportSicknessManager.GetOrCreateTemplate(); if (!db.m_StatusEffects.Contains((StatusEffect)(object)orCreateTemplate)) { db.m_StatusEffects.Add((StatusEffect)(object)orCreateTemplate); } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] [HarmonyPrefix] private static void PrefixUpdateTeleport(Player __instance, ref float dt, bool ___m_teleporting, out bool __state) { __state = ___m_teleporting; if (!ModConfig.ModEnabled.Value || !___m_teleporting) { return; } float value = ModConfig.PortalLoadTime.Value; if (!Mathf.Approximately(value, 8f)) { if (value <= 0.05f) { dt = Mathf.Max(dt, 8f); } else { dt *= 8f / value; } } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] [HarmonyPostfix] private static void PostfixUpdateTeleport(Player __instance, bool __state, bool ___m_teleporting) { if (__state && !___m_teleporting) { TeleportSicknessManager.ApplyPendingSickness(__instance); } } } [HarmonyPatch] public static class UIPatches { [HarmonyPatch(typeof(Game), "Awake")] [HarmonyPostfix] private static void OnGameAwake() { PortalConfigPanel.Initialize(); } [HarmonyPatch(typeof(TextInput), "RequestText")] [HarmonyPrefix] private static bool PrefixRequestText(TextReceiver sign) { if (!ModConfig.ModEnabled.Value) { return true; } if (ModConfig.EnableTargetSelectionUI.Value || ModConfig.EnablePasswordSystem.Value) { TeleportWorld val = (TeleportWorld)(object)((sign is TeleportWorld) ? sign : null); if (val != null) { if ((Object)(object)PortalConfigPanel.Instance == (Object)null) { PortalConfigPanel.Initialize(); } PortalConfigPanel.Instance?.Show(val); return false; } } return true; } [HarmonyPatch(typeof(Game), "ConnectPortals")] [HarmonyPrefix] private static bool PrefixConnectPortals() { if (ModConfig.ModEnabled.Value && ModConfig.EnableTargetSelectionUI.Value) { return false; } return true; } } } namespace PortalTweaks.Energy { public static class EnergyManager { public static bool GetCurrentEnergy(TeleportWorld? portal, out float currentEnergy, out float maxEnergy, out float rechargeRate) { maxEnergy = ModConfig.GetMaxEnergy(portal); rechargeRate = ModConfig.GetRechargeRate(portal); currentEnergy = maxEnergy; if ((Object)(object)portal == (Object)null) { return false; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } long num = zDO.GetLong("PortalTweaks_EnergyTime", 0L); double num2 = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : ((double)Time.time)); if (num == 0L) { float num3 = Mathf.Clamp(ModConfig.StartingEnergyPercentage.Value, 0f, 100f) / 100f; currentEnergy = maxEnergy * num3; if (!component.IsOwner()) { component.ClaimOwnership(); } zDO.Set("PortalTweaks_Energy", currentEnergy); zDO.Set("PortalTweaks_EnergyTime", BitConverter.DoubleToInt64Bits(num2)); return true; } double num4 = BitConverter.Int64BitsToDouble(num); float num5 = zDO.GetFloat("PortalTweaks_Energy", 0f); double num6 = num2 - num4; if (num6 < 0.0) { num6 = 0.0; } currentEnergy = Mathf.Min(maxEnergy, num5 + (float)(num6 * (double)rechargeRate)); currentEnergy = Mathf.Max(0f, currentEnergy); return true; } public static float CalculateTeleportCost(Player? player, TeleportWorld? portal, out float totalCost, out string costBreakdown, float? overrideDistance = null) { float baseCost = ModConfig.GetBaseCost(portal); float num = baseCost; List<string> list = new List<string> { $"Base: {baseCost:F0}" }; if ((Object)(object)player != (Object)null && ((Humanoid)player).GetInventory() != null) { if (ModConfig.EnableWeightCostScaling.Value) { float num2 = ((Humanoid)player).GetInventory().GetTotalWeight() * ModConfig.GetWeightCostFactor(portal); num += num2; if (num2 > 0.01f) { list.Add($"Weight: +{num2:F0}"); } } if (ModConfig.EnableOreCostScaling.Value) { float num3 = 0f; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem.m_shared != null && !allItem.m_shared.m_teleportable) { num3 += allItem.GetWeight(-1); } } if (num3 > 0f) { float num4 = num3 * ModConfig.GetOreCostFactor(portal); num += num4; list.Add($"Ore: +{num4:F0}"); } } } num = (totalCost = Mathf.Max(0f, num)); if (ModConfig.EnableDistanceCostScaling.Value) { float num5 = 0f; bool flag = false; float distance; if (overrideDistance.HasValue) { num5 = overrideDistance.Value; flag = true; } else if ((Object)(object)portal != (Object)null && TeleportPatch.TryGetTargetPortalDistance(portal, out distance)) { num5 = distance; flag = true; } if (flag) { float distanceCostBase = ModConfig.GetDistanceCostBase(portal); float distanceCostExponent = ModConfig.GetDistanceCostExponent(portal); float num6 = 1f; if (distanceCostBase > 0.001f) { num6 = Mathf.Pow(Mathf.Max(0f, num5 / distanceCostBase), distanceCostExponent); num6 = Mathf.Max(ModConfig.MinDistanceCostMultiplier.Value, num6); } totalCost = num * num6; list.Add($"Dist ({num5:F0}m): x{num6:F2}"); } } totalCost = Mathf.Max(0f, totalCost); costBreakdown = string.Join(", ", list); return totalCost; } public static void ConsumeEnergy(TeleportWorld? portal, float amount, out float remainingEnergy) { remainingEnergy = 0f; if ((Object)(object)portal == (Object)null) { return; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null) { GetCurrentEnergy(portal, out var currentEnergy, out var _, out var _); remainingEnergy = Mathf.Max(0f, currentEnergy - amount); if (!component.IsOwner()) { component.ClaimOwnership(); } double value = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : ((double)Time.time)); zDO.Set("PortalTweaks_Energy", remainingEnergy); zDO.Set("PortalTweaks_EnergyTime", BitConverter.DoubleToInt64Bits(value)); } } public static float GetRechargeTimeRemaining(float currentEnergy, float targetCost, float rechargeRate) { if (currentEnergy >= targetCost || rechargeRate <= 0.0001f) { return 0f; } return Mathf.Max(0f, (targetCost - currentEnergy) / rechargeRate); } public static string GetExceedsCapacityReason(Player? player, TeleportWorld? portal, float maxEnergy, float? overrideDistance = null) { float baseCost = ModConfig.GetBaseCost(portal); float num = 0f; float num2 = 0f; if ((Object)(object)player != (Object)null && ((Humanoid)player).GetInventory() != null) { if (ModConfig.EnableWeightCostScaling.Value) { num = ((Humanoid)player).GetInventory().GetTotalWeight() * ModConfig.GetWeightCostFactor(portal); } if (ModConfig.EnableOreCostScaling.Value) { float num3 = 0f; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem.m_shared != null && !allItem.m_shared.m_teleportable) { num3 += allItem.GetWeight(-1); } } num2 = num3 * ModConfig.GetOreCostFactor(portal); } } float num4 = baseCost + num + num2; float num5 = 1f; if (ModConfig.EnableDistanceCostScaling.Value) { float num6 = 0f; bool flag = false; float distance; if (overrideDistance.HasValue) { num6 = overrideDistance.Value; flag = true; } else if ((Object)(object)portal != (Object)null && TeleportPatch.TryGetTargetPortalDistance(portal, out distance)) { num6 = distance; flag = true; } float distanceCostBase = ModConfig.GetDistanceCostBase(portal); float distanceCostExponent = ModConfig.GetDistanceCostExponent(portal); if (flag && distanceCostBase > 0.001f) { num5 = Mathf.Pow(Mathf.Max(0f, num6 / distanceCostBase), distanceCostExponent); num5 = Mathf.Max(ModConfig.MinDistanceCostMultiplier.Value, num5); } } bool flag2 = num4 > maxEnergy; bool flag3 = baseCost * num5 > maxEnergy; if (flag2 && !flag3) { return "Carrying too much"; } if (flag3 && !flag2) { return "Portal is too far away"; } if (num5 > 1.8f && num + num2 <= baseCost) { return "Portal is too far away"; } if (num + num2 > baseCost * 2f && num5 <= 1.2f) { return "Carrying too much"; } return "Carrying too much or portal too far"; } public static float CalculateOverdraftExtraSickness(float deficit) { if (deficit <= 0f) { return 0f; } return Mathf.Max(0f, deficit * ModConfig.OverdraftSicknessSecondsPerEnergy.Value); } } } namespace PortalTweaks.Data { public class PortalInfo { public ZDOID Id { get; set; } public string Tag { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public Vector3 Position { get; set; } public ZDOID OutboundTarget { get; set; } = ZDOID.None; public string OutboundPassword { get; set; } = string.Empty; public string DisplayName { get { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(Tag)) { return Tag; } return $"[Unnamed Portal] ({Id})"; } } } public static class PortalDataManager { public const string KeyPassword = "PortalTweaks_Password"; public const string KeyOutboundTarget = "PortalTweaks_OutboundTarget"; public const string KeyOutboundPassword = "PortalTweaks_OutboundPassword"; public const string KeyEnergy = "PortalTweaks_Energy"; public const string KeyEnergyTime = "PortalTweaks_EnergyTime"; public static PortalInfo? FromZDO(ZDO? zdo) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || zdo.m_uid == ZDOID.None) { return null; } return new PortalInfo { Id = zdo.m_uid, Tag = zdo.GetString(ZDOVars.s_tag, string.Empty), Password = zdo.GetString("PortalTweaks_Password", string.Empty), Position = zdo.GetPosition(), OutboundTarget = zdo.GetZDOID("PortalTweaks_OutboundTarget"), OutboundPassword = zdo.GetString("PortalTweaks_OutboundPassword", string.Empty) }; } public static List<PortalInfo> GetAllPortals(ZDOID excludeId = default(ZDOID)) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_004b: Unknown result type (might be due to invalid IL or missing references) List<PortalInfo> list = new List<PortalInfo>(); if (ZDOMan.instance == null) { return list; } List<ZDO> portalList = ZDOMan.instance.GetPortalList(); if (portalList == null) { return list; } foreach (ZDO item in portalList) { if (item != null && !(item.m_uid == ZDOID.None) && !(item.m_uid == excludeId)) { PortalInfo portalInfo = FromZDO(item); if (portalInfo != null) { list.Add(portalInfo); } } } list.Sort((PortalInfo a, PortalInfo b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase)); return list; } public static void SavePortal(TeleportWorld portal, string tag, string password, ZDOID outboundTarget, string outboundPassword, bool updateTarget) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)portal == (Object)null) { return; } ZNetView component = ((Component)portal).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null) { if (tag != portal.GetText()) { portal.SetText(tag); } zDO.Set("PortalTweaks_Password", password ?? string.Empty); if (updateTarget) { zDO.Set("PortalTweaks_OutboundTarget", outboundTarget); zDO.Set("PortalTweaks_OutboundPassword", outboundPassword ?? string.Empty); zDO.SetConnection((ConnectionType)1, outboundTarget); } } } public static bool ValidatePasswordMatch(string targetPortalPassword, string suppliedOutboundPassword, out string error) { error = string.Empty; if (string.IsNullOrEmpty(targetPortalPassword)) { return true; } if (targetPortalPassword == suppliedOutboundPassword) { return true; } error = "Password mismatch: incorrect password for destination."; return false; } } } namespace PortalTweaks.Configuration { public class ConfigurationManagerAttributes { public bool? Browsable; public string? Category; public bool? DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string? Description; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public bool? IsAdminOnly; } public enum ItemRestrictionTier { NoTeleport, Naked, EquippedOnly, EquipmentOnly, GearAndProvisions, Vanilla, Unrestricted } public enum LowEnergyBehavior { RefuseTeleport, ExtendSickness } public static class ModConfig { public static ConfigEntry<bool> ModEnabled { get; private set; } public static ConfigEntry<float> PortalLoadTime { get; private set; } public static ConfigEntry<bool> EnableMaxWeightLimit { get; private set; } public static ConfigEntry<float> MaxPortalWeight { get; private set; } public static ConfigEntry<float> StoneMaxPortalWeight { get; private set; } public static ConfigEntry<bool> ShowHoverWeightWarning { get; private set; } public static ConfigEntry<ItemRestrictionTier> ItemRestrictionTierConfig { get; private set; } public static ConfigEntry<ItemRestrictionTier> StoneRestrictionTier { get; private set; } public static ConfigEntry<bool> ShowHoverItemWarning { get; private set; } public static ConfigEntry<bool> EnableDistanceLimit { get; private set; } public static ConfigEntry<float> MaxPortalDistance { get; private set; } public static ConfigEntry<float> StoneMaxPortalDistance { get; private set; } public static ConfigEntry<bool> EnableMinDistanceLimit { get; private set; } public static ConfigEntry<float> MinPortalDistance { get; private set; } public static ConfigEntry<float> StoneMinPortalDistance { get; private set; } public static ConfigEntry<bool> ShowDistanceInHoverText { get; private set; } public static ConfigEntry<bool> EnableTargetSelectionUI { get; private set; } public static ConfigEntry<bool> EnablePasswordSystem { get; private set; } public static ConfigEntry<bool> EnablePortalProximityLimit { get; private set; } public static ConfigEntry<float> MinDistanceBetweenPortals { get; private set; } public static ConfigEntry<bool> EnableEnergySystem { get; private set; } public static ConfigEntry<float> MaxPortalEnergy { get; private set; } public static ConfigEntry<float> StoneMaxPortalEnergy { get; private set; } public static ConfigEntry<float> EnergyRechargeRate { get; private set; } public static ConfigEntry<float> StoneEnergyRechargeRate { get; private set; } public static ConfigEntry<float> StartingEnergyPercentage { get; private set; } public static ConfigEntry<float> BaseTeleportCost { get; private set; } public static ConfigEntry<float> StoneBaseTeleportCost { get; private set; } public static ConfigEntry<bool> EnableWeightCostScaling { get; private set; } public static ConfigEntry<float> WeightCostFactor { get; private set; } public static ConfigEntry<float> StoneWeightCostFactor { get; private set; } public static ConfigEntry<bool> EnableOreCostScaling { get; private set; } public static ConfigEntry<float> OreCostFactor { get; private set; } public static ConfigEntry<float> StoneOreCostFactor { get; private set; } public static ConfigEntry<bool> EnableDistanceCostScaling { get; private set; } public static ConfigEntry<float> DistanceCostBase { get; private set; } public static ConfigEntry<float> StoneDistanceCostBase { get; private set; } public static ConfigEntry<float> DistanceCostExponent { get; private set; } public static ConfigEntry<float> StoneDistanceCostExponent { get; private set; } public static ConfigEntry<float> MinDistanceCostMultiplier { get; private set; } public static ConfigEntry<LowEnergyBehavior> LowEnergyAction { get; private set; } public static ConfigEntry<float> OverdraftSicknessSecondsPerEnergy { get; private set; } public static bool DeactivateVortexWhenInsufficientEnergy => LowEnergyAction.Value == LowEnergyBehavior.RefuseTeleport; public static ConfigEntry<bool> ScalePortalVfxWithEnergy { get; private set; } public static ConfigEntry<bool> ShowHoverEnergyInfo { get; private set; } public static ConfigEntry<bool> EnableTeleportSickness { get; private set; } public static ConfigEntry<float> SicknessBaseDuration { get; private set; } public static ConfigEntry<float> StoneSicknessBaseDuration { get; private set; } public static ConfigEntry<float> SicknessBaseDistance { get; private set; } public static ConfigEntry<float> SicknessDurationExponent { get; private set; } public static ConfigEntry<bool> SicknessBlockTeleport { get; private set; } public static ConfigEntry<float> SicknessDurabilityLossPercent { get; private set; } public static ConfigEntry<float> StoneSicknessDurabilityLossPercent { get; private set; } public static ConfigEntry<float> SicknessCarryWeightReduction { get; private set; } public static ConfigEntry<float> SicknessMovementSpeed { get; private set; } public static ConfigEntry<float> SicknessHealthRegen { get; private set; } public static ConfigEntry<float> SicknessStaminaRegen { get; private set; } public static ConfigEntry<float> SicknessEitrRegen { get; private set; } public static ConfigEntry<bool> LogPortalTeleports { get; private set; } public static void Init(ConfigFile config) { ModEnabled = Bind(config, "1 - General", "General", "Enabled", defaultValue: true, "Master switch to enable or disable all features of PortalTweaks.", 100); PortalLoadTime = Bind(config, "1 - General", "General", "PortalLoadTime", 8f, "Portal teleport load / transition screen duration in seconds. Vanilla default is 8.0 seconds.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 30f)); EnableTargetSelectionUI = Bind(config, "2 - Portal UI", "Portal UI", "EnableTargetSelectionUI", defaultValue: true, "If true, interacting with a portal displays a destination selection dropdown to pick outbound portals.", 100); EnablePasswordSystem = Bind(config, "2 - Portal UI", "Portal UI", "EnablePasswordSystem", defaultValue: false, "If true, enables portal passwords. Portals only connect if passwords match.", 90); EnablePortalProximityLimit = Bind(config, "3 - Portal Proximity", "Portal Proximity", "EnablePortalProximityLimit", defaultValue: false, "If true, enforces a minimum distance between any two portals to prevent portal stacking.", 100); MinDistanceBetweenPortals = Bind(config, "3 - Portal Proximity", "Portal Proximity", "MinDistanceBetweenPortals", 400f, "Minimum distance (in meters) required between any two portals in the world.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2000f)); ItemRestrictionTierConfig = Bind(config, "4 - Item Restrictions", "Item Restrictions", "RestrictionTier", ItemRestrictionTier.Vanilla, "Progressive item filtering tier for standard wood portals:\n- NoTeleport: Portals cannot be used at all.\n- Naked: Inventory must be 100% empty.\n- EquippedOnly: Only actively worn armor and wielded items allowed.\n- EquipmentOnly: Weapons, armor, and tools allowed (in bag or equipped), but no materials or food.\n- GearAndProvisions: Equipment + food, potions, and ammo allowed, but no raw materials or loot.\n- Vanilla: Standard Valheim rules (materials allowed, but ores/metals blocked).\n- Unrestricted: All items allowed, including ores and metals.", 100); StoneRestrictionTier = Bind(config, "4 - Item Restrictions", "Item Restrictions", "StoneRestrictionTier", ItemRestrictionTier.Unrestricted, "Progressive item filtering tier for Ashlands Stone Portals. Defaults to Unrestricted.", 90); ShowHoverItemWarning = Bind(config, "4 - Item Restrictions", "Item Restrictions", "ShowHoverItemWarning", defaultValue: true, "If true, displays a warning in the portal hover text when carrying items disallowed by the active tier.", 80, null, isAdminOnly: false); EnableMaxWeightLimit = Bind(config, "5 - Weight Limit", "Weight Limit", "EnableMaxWeightLimit", defaultValue: false, "If true, portals only allow players through if their total inventory weight is below MaxPortalWeight.", 100); MaxPortalWeight = Bind(config, "5 - Weight Limit", "Weight Limit", "MaxPortalWeight", 300f, "Maximum player inventory weight allowed to use wood portals.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2000f)); StoneMaxPortalWeight = Bind(config, "5 - Weight Limit", "Weight Limit", "StoneMaxPortalWeight", 600f, "Maximum player inventory weight allowed to use Stone Portals.", 85, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2000f)); ShowHoverWeightWarning = Bind(config, "5 - Weight Limit", "Weight Limit", "ShowHoverWeightWarning", defaultValue: true, "If true, displays a warning in the portal hover text when carrying too much weight.", 80, null, isAdminOnly: false); EnableDistanceLimit = Bind(config, "6 - Distance Limit", "Distance Limit", "EnableDistanceLimit", defaultValue: false, "If true, portals only connect and allow travel if the distance between them is within configured limits.", 100); MaxPortalDistance = Bind(config, "6 - Distance Limit", "Distance Limit", "MaxPortalDistance", 2000f, "Maximum distance (in meters) allowed between connected wood portals.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(50f, 20000f)); StoneMaxPortalDistance = Bind(config, "6 - Distance Limit", "Distance Limit", "StoneMaxPortalDistance", 4000f, "Maximum distance (in meters) allowed between connected Stone Portals.", 85, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(50f, 20000f)); EnableMinDistanceLimit = Bind(config, "6 - Distance Limit", "Distance Limit", "EnableMinDistanceLimit", defaultValue: false, "If true, portals also require a minimum distance between them to activate.", 80); MinPortalDistance = Bind(config, "6 - Distance Limit", "Distance Limit", "MinPortalDistance", 100f, "Minimum distance (in meters) required between connected wood portals.", 75, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2000f)); StoneMinPortalDistance = Bind(config, "6 - Distance Limit", "Distance Limit", "StoneMinPortalDistance", 100f, "Minimum distance (in meters) required between connected Stone Portals.", 70, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2000f)); ShowDistanceInHoverText = Bind(config, "6 - Distance Limit", "Distance Limit", "ShowDistanceInHoverText", defaultValue: true, "If true, displays the distance to the connected portal on the portal hover HUD text.", 60, null, isAdminOnly: false); EnableEnergySystem = Bind(config, "7 - Energy System", "Energy System", "EnableEnergySystem", defaultValue: false, "If true, portals require and consume energy to teleport players, recharging over time.", 100); MaxPortalEnergy = Bind(config, "7 - Energy System", "Energy System", "MaxPortalEnergy", 360f, "Maximum energy reserve a wood portal can store.", 95, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 3000f)); StoneMaxPortalEnergy = Bind(config, "7 - Energy System", "Energy System", "StoneMaxPortalEnergy", 1080f, "Maximum energy reserve a Stone Portal can store.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 3000f)); EnergyRechargeRate = Bind(config, "7 - Energy System", "Energy System", "EnergyRechargeRate", 0.1f, "Rate at which wood portal energy recharges per second.", 85, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 50f)); StoneEnergyRechargeRate = Bind(config, "7 - Energy System", "Energy System", "StoneEnergyRechargeRate", 0.2f, "Rate at which Stone Portal energy recharges per second.", 80, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 50f)); StartingEnergyPercentage = Bind(config, "7 - Energy System", "Energy System", "StartingEnergyPercentage", 0f, "Starting energy percentage (0-100%) when a portal is newly placed or first discovered. Defaults to 0%.", 75, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 100f)); BaseTeleportCost = Bind(config, "7 - Energy System", "Energy System", "BaseTeleportCost", 6f, "Base fixed energy cost deducted per wood portal teleport.", 70, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 500f)); StoneBaseTeleportCost = Bind(config, "7 - Energy System", "Energy System", "StoneBaseTeleportCost", 6f, "Base fixed energy cost deducted per teleport on Stone Portals.", 65, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 500f)); EnableWeightCostScaling = Bind(config, "7 - Energy System", "Energy System", "EnableWeightCostScaling", defaultValue: true, "If true, player inventory carry weight adds additional energy cost to the teleport.", 60); WeightCostFactor = Bind(config, "7 - Energy System", "Energy System", "WeightCostFactor", 0.1f, "Additional energy cost per unit of inventory weight carried on wood portals.", 55, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2f)); StoneWeightCostFactor = Bind(config, "7 - Energy System", "Energy System", "StoneWeightCostFactor", 0.1f, "Additional energy cost per unit of inventory weight carried on Stone Portals.", 50, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 2f)); EnableOreCostScaling = Bind(config, "7 - Energy System", "Energy System", "EnableOreCostScaling", defaultValue: true, "If true, carrying non-teleportable items (ores/metals) adds an additional energy surcharge per weight unit.", 45); OreCostFactor = Bind(config, "7 - Energy System", "Energy System", "OreCostFactor", 0.9f, "Extra energy cost per unit of non-teleportable ore/metal weight in inventory for wood portals.", 40, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 5f)); StoneOreCostFactor = Bind(config, "7 - Energy System", "Energy System", "StoneOreCostFactor", 0f, "Extra energy cost per unit of non-teleportable ore/metal weight on Stone Portals.", 35, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 5f)); EnableDistanceCostScaling = Bind(config, "7 - Energy System", "Energy System", "EnableDistanceCostScaling", defaultValue: true, "If true, scales the teleport energy cost based on the distance between portals.", 30); DistanceCostBase = Bind(config, "7 - Energy System", "Energy System", "DistanceCostBase", 1000f, "Base distance (in meters) for cost scaling on wood portals: mult(dist) = (dist / base)^exponent.", 25, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 20000f)); StoneDistanceCostBase = Bind(config, "7 - Energy System", "Energy System", "StoneDistanceCostBase", 1000f, "Base distance (in meters) for cost scaling on Stone Portals.", 22, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 20000f)); DistanceCostExponent = Bind(config, "7 - Energy System", "Energy System", "DistanceCostExponent", 1.5f, "Exponent for distance multiplier formula on wood portals: mult(dist) = (dist / base)^exponent.", 20, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 4f)); StoneDistanceCostExponent = Bind(config, "7 - Energy System", "Energy System", "StoneDistanceCostExponent", 1f, "Exponent for distance multiplier formula on Stone Portals.", 18, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 4f)); MinDistanceCostMultiplier = Bind(config, "7 - Energy System", "Energy System", "MinDistanceCostMultiplier", 0.25f, "Minimum floor for the distance cost multiplier. Defaults to 0.25.", 15, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 10f)); LowEnergyAction = Bind(config, "7 - Energy System", "Energy System", "LowEnergyAction", LowEnergyBehavior.RefuseTeleport, "Behavior when attempting to teleport through a portal with insufficient energy:\n- RefuseTeleport: Overdraft disabled; portal rejects the jump until recharged.\n- ExtendSickness: Overdraft enabled; drains energy to 0 and extends Teleportation Sickness duration.", 12); OverdraftSicknessSecondsPerEnergy = Bind(config, "7 - Energy System", "Energy System", "OverdraftSicknessSecondsPerEnergy", 10f, "Additional Teleportation Sickness seconds added per point of energy deficit when overdrafting.", 10, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 120f)); ScalePortalVfxWithEnergy = Bind(config, "7 - Energy System", "Energy System", "ScalePortalVfxWithEnergy", defaultValue: true, "If true, scales the emission brightness of the portal arch based on current energy reserve (dim when empty, glowing brighter as it recharges).", 5, null, isAdminOnly: false); ShowHoverEnergyInfo = Bind(config, "7 - Energy System", "Energy System", "ShowHoverEnergyInfo", defaultValue: true, "If true, displays portal energy reserve and recharge status on the portal hover HUD text.", 2, null, isAdminOnly: false); EnableTeleportSickness = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "EnableTeleportSickness", defaultValue: false, "If true, imposes a temporary debuff on players upon teleporting.", 100); SicknessBlockTeleport = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "SicknessBlockTeleport", defaultValue: true, "If true, prevents players from using portals while affected by teleportation sickness.", 95); SicknessBaseDuration = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "SicknessBaseDuration", 180f, "Base debuff duration (in seconds) at base distance for wood portals: duration(dist) = base_duration * (dist / base_dist)^exponent.", 90, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 600f)); StoneSicknessBaseDuration = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "StoneSicknessBaseDuration", 120f, "Base debuff duration (in seconds) at base distance for Stone Portals.", 85, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 600f)); SicknessBaseDistance = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "SicknessBaseDistance", 1000f, "Base distance (in meters) for sickness duration scaling.", 80, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 20000f)); SicknessDurationExponent = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "SicknessDurationExponent", 0.5f, "Exponent for sickness duration scaling: duration(dist) = base_duration * (dist / base_dist)^exponent.", 75, (AcceptableValueBase?)(object)new AcceptableValueRange<float>(0f, 5f)); SicknessDurabilityLossPercent = Bind(config, "8 - Teleportation Sickness", "Teleportation Sickness", "SicknessDurabilityLossPercent", 10f, "Instant percentage of max durability dama