using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; using Waystones; using YamlDotNet.Serialization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Waystones")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Waystones")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("1af3a9e7-99be-490a-a211-741aaff1aef2")] [assembly: AssemblyFileVersion("1.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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; } } } public class WaystoneSmall : MonoBehaviour, TextReceiver, Hoverable, Interactable { private class SacrificeHoverItem { public string itemName; public int amount; public int value; public int inventoryCount; public int totalCount; } [HarmonyPatch(typeof(TextsDialog), "UpdateTextsList")] public static class TextsDialog_UpdateTextsList_WaystoneSacrificeItems { private static void Postfix(TextsDialog __instance) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown string text = BuildConfiguredSacrificeItemsText(); if (text.Length != 0) { string waystoneTopic = Localization.instance.Localize("$ws_tutorial_waystone_label"); int num = __instance.m_texts.FindIndex((TextInfo info) => info != null && (info.m_topic == "$ws_tutorial_waystone_label" || info.m_topic == waystoneTopic || Localization.instance.Localize(info.m_topic) == waystoneTopic)); if (num >= 0) { __instance.m_texts.Insert(num + 1, new TextInfo("$ws_compendium_sacrifice_items_topic", text)); } } } } [HarmonyPatch(typeof(TextInput), "Update")] public static class TextInput_Update_HoldUseButton { private static void Postfix(TextInput __instance) { ((TMP_InputField)__instance.m_inputField).readOnly = false; if (__instance.m_queuedSign is WaystoneSmall && TextInput.IsVisible() && blockInputUntil > Time.time) { ((TMP_InputField)__instance.m_inputField).readOnly = true; } } } [CompilerGenerated] private sealed class d__24 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public WaystoneSmall <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__24(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitWhile((Func)(() => ZInput.GetButton("Use") || ZInput.GetButton("JoyUse"))); <>1__state = 1; return true; case 1: <>1__state = -1; if (TextInput.IsVisible()) { return false; } if (IsSearchAllowed(player, validateCharge: false) && global::Waystones.Waystones.CanCast()) { ((Character)player).Message((MessageType)2, "$ws_piece_waystone_activation", 0, (Sprite)null); WaystoneList.EnterSearchMode(<>4__this.m_nview.GetZDO()); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public GameObject m_activeObject; public EffectList m_activateEffect = new EffectList(); public EffectList m_deactivateEffect = new EffectList(); public static bool initial = false; public static StringBuilder sb = new StringBuilder(); public ZNetView m_nview; public static float blockInputUntil; public const float waystoneHoldSetTagDelay = 0.35f; private const float sacrificeHoverItemsUpdateInterval = 1f; private static float nextSacrificeHoverItemsUpdate; private static readonly List sacrificeHoverItems = new List(); public void Awake() { if (!initial) { m_activeObject = ((Component)((Component)this).transform.Find("WayEffect")).gameObject; m_activeObject.SetActive(false); m_nview = ((Component)this).GetComponent(); if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { ((MonoBehaviour)this).InvokeRepeating("UpdateStatus", 0f, 1f); m_nview.Register("RPC_SetTag", (Action)RPC_SetTag); m_nview.Register("ToggleActivated", (Action)RPC_ToggleActivated); m_nview.Register("RPC_AddCharge", (Action)RPC_AddCharge); } } } public void RPC_ToggleActivated(long uid, long playerID, string name) { if (m_nview.IsOwner()) { if (IsActivated(playerID)) { RemoveActivated(playerID); } else { AddActivated(playerID, name); } UpdateStatus(); } } public void RemoveActivated(long playerID) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) List> activatedPlayers = GetActivatedPlayers(); if (activatedPlayers.RemoveAll((KeyValuePair x) => x.Key == playerID) > 0) { SetActivatedPlayers(activatedPlayers); m_deactivateEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } public bool IsActivated(long playerID) { return IsWaystoneActivated(m_nview.GetZDO(), playerID); } public void AddActivated(long playerID, string playerName) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) List> activatedPlayers = GetActivatedPlayers(); foreach (KeyValuePair item in activatedPlayers) { if (item.Key == playerID) { return; } } activatedPlayers.Add(new KeyValuePair(playerID, playerName)); SetActivatedPlayers(activatedPlayers); m_activateEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } public void SetActivatedPlayers(List> users) { m_nview.GetZDO().Set(ZDOVars.s_permitted, users.Count, false); for (int i = 0; i < users.Count; i++) { KeyValuePair keyValuePair = users[i]; m_nview.GetZDO().Set("pu_id" + i, keyValuePair.Key); m_nview.GetZDO().Set("pu_name" + i, keyValuePair.Value); } } public List> GetActivatedPlayers() { return GetWaystoneActivatedPlayers(m_nview.GetZDO()); } public bool IsEnabled() { if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } return IsActivated(Player.m_localPlayer.GetPlayerID()); } public void UpdateStatus() { bool active = IsEnabled(); m_activeObject.SetActive(active); } public string GetHoverText() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (!m_nview.IsValid()) { return ""; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return ""; } if (((Character)Player.m_localPlayer).InInterior()) { return GetHoverName(); } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { return Localization.instance.Localize(GetHoverName() + "\n$piece_noaccess"); } sb.Clear(); sb.Append(GetHoverName()); string text = StringExtensionMethods.RemoveRichTextTags(GetText()); if (text.Length > 0) { sb.AppendFormat(" \"{0}\"", text); } sb.Append("\n[$KEY_Use] $ws_tooltip_start_search $ws_piece_waystone_settag"); string text2 = ((!ZInput.IsNonClassicFunctionality() || !ZInput.IsGamepadActive()) ? "$KEY_AltPlace" : "$KEY_JoyAltKeys"); sb.Append("\n[" + text2 + " + $KEY_Use] " + (IsActive() ? "$ws_piece_waystone_deactivate" : "$ws_piece_waystone_activate")); if (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Cooldown) { if (WorldData.IsOnCooldown()) { sb.Append("\n$hud_powernotready: " + WorldData.GetCooldownString() + ""); } } else if (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) { if (WaystoneList.IsPlayerChargeStorage()) { sb.Append($"\n$ws_tooltip_player_charge {WorldData.GetPlayerCharge()}"); } else { sb.Append($"\n$ws_tooltip_waystone_charge {WaystoneList.GetWaystoneCharge(m_nview.GetZDO())}"); } } AppendSacrificeItemsHoverText(Player.m_localPlayer); return Localization.instance.Localize(sb.ToString()); } public string GetHoverName() { return IsActive() ? "$ws_piece_waystone_activated" : "$ws_piece_waystone_name"; } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).InInterior() || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (hold) { if (ZInput.GetButtonPressedTimer("Use") + ZInput.GetButtonPressedTimer("JoyUse") > 0.35f && !TextInput.IsVisible()) { blockInputUntil = Time.time + 1f; ZInput.ResetButtonStatus("Use"); ZInput.ResetButtonStatus("JoyUse"); TextInput.instance.RequestText((TextReceiver)(object)this, "$ws_piece_waystone_tag", Math.Max(global::Waystones.Waystones.tagCharactersLimit.Value, 10)); } return false; } Player val = (Player)(object)((human is Player) ? human : null); if (alt) { m_nview.InvokeRPC("ToggleActivated", new object[2] { val.GetPlayerID(), val.GetPlayerName() }); return true; } ((MonoBehaviour)this).StartCoroutine(ActivationToggleRequested(val)); return true; } [IteratorStateMachine(typeof(d__24))] public IEnumerator ActivationToggleRequested(Player player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__24(0) { <>4__this = this, player = player }; } public bool UseItem(Humanoid user, ItemData item) { if (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Cooldown && global::Waystones.Waystones.itemSacrifitionReduceCooldown.Value) { int cooldown = 0; if (TryReduceCooldownOnItemSacrifice(user, item, item.m_shared.m_name, ref cooldown)) { ((Character)user).Message((MessageType)2, Localization.instance.Localize("$ws_piece_waystone_cooldown_reduced", new string[1] { cooldown.ToString() }), 0, (Sprite)null); if (WorldData.IsOnCooldown()) { ((Character)user).Message((MessageType)1, "$hud_powernotready: " + WorldData.GetCooldownString(), 0, (Sprite)null); } return true; } } if (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) { int charge = 0; if (TryChargeWaystoneOnItemSacrifice(user, item, item.m_shared.m_name, ref charge)) { ((Character)user).Message((MessageType)2, Localization.instance.Localize("$ws_piece_waystone_charge_added", new string[1] { charge.ToString() }), 0, (Sprite)null); return true; } } return false; } private bool TryReduceCooldownOnItemSacrifice(Humanoid user, ItemData item, string itemName, ref int cooldown) { if (itemName == null) { return false; } itemName = itemName.GetItemName(); if (global::Waystones.Waystones.itemsToReduceCooldown.Value.TryGetValue(itemName, out var value) && (cooldown = value) > 0) { return user.GetInventory().RemoveOneItem(item) && WorldData.TryReduceCooldown(value); } string text = global::Waystones.Waystones.itemsToReduceCooldown.Value.Keys.FirstOrDefault((string key) => key.StartsWith(itemName)); if (text != null && global::Waystones.Waystones.itemsToReduceCooldown.Value.TryGetValue(text, out var value2) && (cooldown = value2) > 0) { string[] array = text.Split(':'); int result; return array.Length > 1 && array[0] == itemName && int.TryParse(array[1], out result) && CountItems(user.GetInventory(), itemName) >= result && user.GetInventory().RemoveItem(item, result) && WorldData.TryReduceCooldown(value2); } return false; } private bool TryChargeWaystoneOnItemSacrifice(Humanoid user, ItemData item, string itemName, ref int charge) { if (itemName == null || !m_nview.IsValid()) { return false; } itemName = itemName.GetItemName(); if (global::Waystones.Waystones.itemsToReduceCooldown.Value.TryGetValue(itemName, out var value) && value > 0) { return TryConsumeChargeItem(user, item, itemName, value, 1, ref charge); } string text = global::Waystones.Waystones.itemsToReduceCooldown.Value.Keys.FirstOrDefault((string key) => key == itemName || key.StartsWith(itemName + ":")); if (text != null && global::Waystones.Waystones.itemsToReduceCooldown.Value.TryGetValue(text, out var value2) && value2 > 0) { string[] array = text.Split(':'); if (array.Length > 1 && array[0] == itemName && int.TryParse(array[1], out var result)) { return TryConsumeChargeItem(user, item, itemName, value2, result, ref charge); } } return false; } private bool TryConsumeChargeItem(Humanoid user, ItemData item, string itemName, int addCharge, int amount, ref int charge) { if (amount <= 0 || CountItems(user.GetInventory(), itemName) < amount) { return false; } charge = WaystoneList.GetPotentialChargeAdded(m_nview.GetZDO(), addCharge); if (charge <= 0) { return false; } if (!((amount == 1) ? user.GetInventory().RemoveOneItem(item) : user.GetInventory().RemoveItem(item, amount))) { return false; } AddCharge(addCharge); return true; } private void AddCharge(int amount) { if (m_nview.IsValid() && amount > 0) { if (WaystoneList.IsPlayerChargeStorage()) { WaystoneList.AddCharge(m_nview.GetZDO(), amount); return; } if (m_nview.IsOwner()) { WaystoneList.AddWaystoneCharge(m_nview.GetZDO(), amount); return; } m_nview.InvokeRPC("RPC_AddCharge", new object[1] { amount }); } } public void RPC_AddCharge(long sender, int amount) { if (m_nview.IsValid() && m_nview.IsOwner()) { WaystoneList.AddWaystoneCharge(m_nview.GetZDO(), amount); } } private int CountItems(Inventory inventory, string itemName) { return CountOwnInventoryItems(inventory, itemName); } private static int CountOwnInventoryItems(Inventory inventory, string itemName) { if (inventory == null) { return 0; } int num = 0; foreach (ItemData item in inventory.m_inventory) { if (item.m_shared.m_name.GetItemName() == itemName && item.m_worldLevel >= Game.m_worldLevel) { num += item.m_stack; } } return num; } private static int CountAvailableItems(Inventory inventory, string itemName) { if (inventory == null) { return 0; } return inventory.CountItems(itemName, -1, true); } private static void AppendSacrificeItemsHoverText(Player player) { if (!global::Waystones.Waystones.showSacrificeItemsInHover.Value || !ShouldShowSacrificeItems()) { return; } RefreshSacrificeHoverItems(player); if (sacrificeHoverItems.Count == 0) { return; } sb.Append("\n\n"); sb.Append((global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "$ws_tooltip_sacrifice_add_charge" : "$ws_tooltip_sacrifice_reduce_cooldown"); string text = ((global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "$ws_tooltip_charges" : "$ws_tooltip_seconds"); foreach (SacrificeHoverItem sacrificeHoverItem in sacrificeHoverItems) { sb.Append("\n - "); sb.Append("" + sacrificeHoverItem.itemName + ""); if (sacrificeHoverItem.amount > 1) { sb.Append($" x{sacrificeHoverItem.amount}"); } sb.Append(string.Format(" - {0}: {1}{2}. $settings_inventory: {3}", text, (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "+" : "-", sacrificeHoverItem.value, sacrificeHoverItem.inventoryCount)); if (sacrificeHoverItem.totalCount != sacrificeHoverItem.inventoryCount) { sb.Append($", $item_total: {sacrificeHoverItem.totalCount}"); } } } private static bool ShouldShowSacrificeItems() { return global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge || (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Cooldown && global::Waystones.Waystones.itemSacrifitionReduceCooldown.Value); } private static void RefreshSacrificeHoverItems(Player player) { if (Time.time < nextSacrificeHoverItemsUpdate) { return; } nextSacrificeHoverItemsUpdate = Time.time + 1f; sacrificeHoverItems.Clear(); if ((Object)(object)player == (Object)null) { return; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return; } foreach (KeyValuePair item in global::Waystones.Waystones.itemsToReduceCooldown.Value) { if (item.Value > 0 && TryParseSacrificeEntry(item.Key, out var itemName, out var amount)) { int num = CountOwnInventoryItems(inventory, itemName); int num2 = CountAvailableItems(inventory, itemName); if (num > 0 || num2 > 0) { sacrificeHoverItems.Add(new SacrificeHoverItem { itemName = itemName, amount = amount, value = item.Value, inventoryCount = num, totalCount = num2 }); } } } } private static bool TryParseSacrificeEntry(string key, out string itemName, out int amount) { itemName = key; amount = 1; if (string.IsNullOrWhiteSpace(key)) { return false; } string[] array = key.Split(':'); if (array.Length == 1) { return true; } if (array.Length != 2 || string.IsNullOrWhiteSpace(array[0]) || !int.TryParse(array[1], out amount) || amount <= 0) { return false; } itemName = array[0]; return true; } private static string BuildConfiguredSacrificeItemsText() { if (!ShouldShowSacrificeItems()) { return ""; } if (global::Waystones.Waystones.itemsToReduceCooldown.Value.Count == 0) { return ""; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append((global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "$ws_tooltip_sacrifice_add_charge" : "$ws_tooltip_sacrifice_reduce_cooldown"); string arg = ((global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "$ws_tooltip_charges" : "$ws_tooltip_seconds"); foreach (KeyValuePair item in global::Waystones.Waystones.itemsToReduceCooldown.Value) { if (item.Value > 0 && TryParseSacrificeEntry(item.Key, out var itemName, out var amount)) { stringBuilder.Append("\n - "); stringBuilder.Append(itemName); if (amount > 1) { stringBuilder.Append($" x{amount}"); } stringBuilder.Append(string.Format(" - {0}: {1}{2}", arg, (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge) ? "+" : "-", item.Value)); } } return stringBuilder.ToString(); } public bool IsActive() { return m_activeObject.activeSelf; } public string GetText() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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) ZDO zDO = m_nview.GetZDO(); if (zDO == null) { return ""; } string @string = zDO.GetString(ZDOVars.s_tagauthor, ""); PlatformUserID val = (PlatformUserID)(string.IsNullOrEmpty(@string) ? PlatformUserID.None : new PlatformUserID(@string)); return CensorShittyWords.FilterUGC(zDO.GetString(ZDOVars.s_tag, ""), (UGCType)4, val, 0L); } public void GetTagSignature(out string tagRaw, out string authorId) { ZDO zDO = m_nview.GetZDO(); tagRaw = zDO.GetString(ZDOVars.s_tag, ""); authorId = zDO.GetString(ZDOVars.s_tagauthor, ""); } public void SetText(string text) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (m_nview.IsValid()) { ZNetView nview = m_nview; object[] obj = new object[2] { text, null }; PlatformUserID platformUserID = ((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID; obj[1] = ((object)(PlatformUserID)(ref platformUserID)).ToString(); nview.InvokeRPC("RPC_SetTag", obj); } } public void RPC_SetTag(long sender, string tag, string authorId) { if (m_nview.IsValid() && m_nview.IsOwner()) { GetTagSignature(out var tagRaw, out var authorId2); if (!(tagRaw == tag) || !(authorId2 == authorId)) { ZDO zDO = m_nview.GetZDO(); zDO.Set(ZDOVars.s_tag, tag); zDO.Set(ZDOVars.s_tagauthor, authorId); } } } public static List> GetWaystoneActivatedPlayers(ZDO zdo) { List> list = new List>(); int @int = zdo.GetInt(ZDOVars.s_permitted, 0); for (int i = 0; i < @int; i++) { long @long = zdo.GetLong("pu_id" + i, 0L); string @string = zdo.GetString("pu_name" + i, ""); if (@long != 0) { list.Add(new KeyValuePair(@long, @string)); } } return list; } public static bool IsWaystoneActivated(ZDO zdo, long playerID) { if (zdo == null) { return false; } foreach (KeyValuePair waystoneActivatedPlayer in GetWaystoneActivatedPlayers(zdo)) { if (global::Waystones.Waystones.allowForEveryone.Value || waystoneActivatedPlayer.Key == playerID) { return true; } } return false; } internal static bool IsSearchAllowed(Player player, bool validateCharge = true) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if ((Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Cooldown && WorldData.IsOnCooldown()) { ((Character)player).Message((MessageType)2, "$hud_powernotready: " + WorldData.GetCooldownString(), 0, (Sprite)null); return false; } if (validateCharge && global::Waystones.Waystones.waystoneMode.Value == global::Waystones.Waystones.WaystoneMode.Charge && !WaystoneList.CanStartSearchWithCharge(WaystoneList.GetCurrentTravelCharge(player.GetPlayerID(), ((Component)player).transform.position))) { ((Character)player).Message((MessageType)2, "$ws_message_not_enough_charge", 0, (Sprite)null); return false; } if (IsNotInPosition(player)) { ((Character)player).Message((MessageType)2, "$msg_cart_incorrectposition", 0, (Sprite)null); return false; } if (!global::Waystones.Waystones.allowEncumbered.Value && ((Character)player).IsEncumbered()) { ((Character)player).Message((MessageType)2, "$se_encumbered_start", 0, (Sprite)null); return false; } if (!global::Waystones.Waystones.allowNonTeleportableItems.Value && !((Humanoid)player).IsTeleportable()) { ((Character)player).Message((MessageType)2, "$msg_noteleport", 0, (Sprite)null); return false; } if (!global::Waystones.Waystones.allowWet.Value && ((Character)player).GetSEMan().HaveStatusEffect(SEMan.s_statusEffectWet)) { ((Character)player).Message((MessageType)2, "$msg_bedwet", 0, (Sprite)null); return false; } if (!global::Waystones.Waystones.allowSensed.Value && player.IsSensed()) { ((Character)player).Message((MessageType)2, "$msg_bedenemiesnearby", 0, (Sprite)null); return false; } if (!global::Waystones.Waystones.allowNonSitting.Value && !((Character)player).IsSitting()) { ((Character)player).Message((MessageType)2, "$ws_piece_waystone_sit", 0, (Sprite)null); return false; } return true; } internal static bool IsNotInPosition(Player player) { return ((Character)player).IsAttachedToShip() || ((Character)player).IsAttached() || ((Character)player).IsDead() || ((Character)player).IsRiding() || player.IsSleeping() || ((Character)player).IsTeleporting() || ((Character)player).InPlaceMode() || ((Character)player).InBed() || ((Character)player).InCutscene() || ((Character)player).InInterior(); } } internal class CustomPrefabs { [HarmonyPatch(typeof(ZNetView), "Awake")] public static class ZNetView_Awake_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(ZSyncTransform), "Awake")] public static class ZSyncTransform_Awake_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(ZSyncTransform), "OnEnable")] public static class ZSyncTransform_OnEnable_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(ItemDrop), "Awake")] public static class ItemDrop_Awake_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(ItemDrop), "Start")] public static class ItemDrop_Start_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(Piece), "Awake")] public static class Piece_Awake_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(WearNTear), "Awake")] public static class WearNTear_Awake_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(WearNTear), "Start")] public static class WearNTear_Start_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } [HarmonyPatch(typeof(GuidePoint), "Start")] public static class GuidePoint_Start_AddPrefab { [HarmonyPriority(800)] private static bool Prefix() { return !prefabInit; } } private const string c_rootObjectName = "_shudnalRoot"; private const string c_rootPrefabsName = "Prefabs"; private static GameObject rootObject; private static GameObject rootPrefabs; public static bool prefabInit; private static void InitRootObject() { //IL_0023: 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_008c: Expected O, but got Unknown if ((Object)(object)rootObject == (Object)null) { rootObject = (GameObject)(((object)GameObject.Find("_shudnalRoot")) ?? ((object)new GameObject("_shudnalRoot"))); } Object.DontDestroyOnLoad((Object)(object)rootObject); if ((Object)(object)rootPrefabs == (Object)null) { Transform obj = rootObject.transform.Find("Prefabs"); rootPrefabs = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)rootPrefabs == (Object)null) { rootPrefabs = new GameObject("Prefabs"); rootPrefabs.transform.SetParent(rootObject.transform, false); rootPrefabs.SetActive(false); } } } internal static GameObject InitPrefabClone(GameObject prefabToClone, string prefabName) { InitRootObject(); if ((Object)(object)rootPrefabs.transform.Find(prefabName) != (Object)null) { return ((Component)rootPrefabs.transform.Find(prefabName)).gameObject; } prefabInit = true; GameObject val = Object.Instantiate(prefabToClone, rootPrefabs.transform, false); prefabInit = false; ((Object)val).name = prefabName; return val; } internal static Component AddComponent(GameObject gameObject, Type type) { prefabInit = true; Component result = gameObject.AddComponent(type); prefabInit = false; return result; } } namespace LocalizationManager { [PublicAPI] public class Localizer { [CompilerGenerated] private sealed class d__12 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__12(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitUntil((Func)(() => PlatformManager.DistributionPlatform != null && PlatformInitializer.PreferencesInitialized)); <>1__state = 1; return true; case 1: <>1__state = -1; if (string.IsNullOrEmpty(PlatformPrefs.GetString("language", ""))) { PlatformPrefs.SetString("language", "English"); } LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage()); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string defaultLanguage = "English"; private static readonly Dictionary>> PlaceholderProcessors; private static readonly Dictionary> loadedTexts; private static readonly ConditionalWeakTable localizationLanguage; private static readonly List> localizationObjects; private static BaseUnityPlugin? _plugin; private static readonly List fileExtensions; private static BaseUnityPlugin Plugin { get { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown if (_plugin == null) { IEnumerable source; try { source = Assembly.GetExecutingAssembly().DefinedTypes.ToList(); } catch (ReflectionTypeLoadException ex) { source = from t in ex.Types where t != null select t.GetTypeInfo(); } _plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); } return _plugin; } } private static void UpdatePlaceholderText(Localization localization, string key) { localizationLanguage.TryGetValue(localization, out string value); string text = loadedTexts[value][key]; if (PlaceholderProcessors.TryGetValue(key, out Dictionary> value2)) { text = value2.Aggregate(text, (string current, KeyValuePair> kv) => current.Replace("{" + kv.Key + "}", kv.Value())); } localization.AddWord(key, text); } public static void AddPlaceholder(string key, string placeholder, ConfigEntry config, Func? convertConfigValue = null) where T : notnull { string key2 = key; string placeholder2 = placeholder; Func convertConfigValue2 = convertConfigValue; ConfigEntry config2 = config; if (convertConfigValue2 == null) { convertConfigValue2 = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key2)) { PlaceholderProcessors[key2] = new Dictionary>(); } config2.SettingChanged += delegate { UpdatePlaceholder(); }; if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage())) { UpdatePlaceholder(); } void UpdatePlaceholder() { PlaceholderProcessors[key2][placeholder2] = () => convertConfigValue2(config2.Value); UpdatePlaceholderText(Localization.instance, key2); } } public static void AddText(string key, string text) { List> list = new List>(); foreach (WeakReference localizationObject in localizationObjects) { if (localizationObject.TryGetTarget(out var target)) { Dictionary dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)]; if (!target.m_translations.ContainsKey(key)) { dictionary[key] = text; target.AddWord(key, text); } } else { list.Add(localizationObject); } } foreach (WeakReference item in list) { localizationObjects.Remove(item); } } [IteratorStateMachine(typeof(d__12))] public static IEnumerator Load() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__12(0); } private static void LoadLocalization(Localization __instance, string language) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown if (!localizationLanguage.Remove(__instance)) { localizationObjects.Add(new WeakReference(__instance)); } localizationLanguage.Add(__instance, language); Dictionary localizationFiles = new Dictionary(); string[] prefixes = new string[2] { Plugin.Info.Metadata.Name + ".", Plugin.Info.Metadata.Name.Replace(" ", "") + "." }; Scan(Paths.ConfigPath, warn: true); Scan(Paths.PluginPath, warn: false); byte[] array = LoadTranslationFromAssembly("English"); if (array == null) { throw new Exception("Found no English localizations in mod " + Plugin.Info.Metadata.Name + ". Expected an embedded resource Translations/English.json or Translations/English.yml."); } Dictionary dictionary = ((BuilderSkeleton)new DeserializerBuilder()).IgnoreFields().Build().Deserialize>(Encoding.UTF8.GetString(array)); if (dictionary == null) { throw new Exception("Localization for mod " + Plugin.Info.Metadata.Name + " failed: Localization file was empty."); } string text = null; if (language != "English") { if (localizationFiles.ContainsKey(language)) { text = File.ReadAllText(localizationFiles[language]); } else { byte[] array2 = LoadTranslationFromAssembly(language); if (array2 != null) { text = Encoding.UTF8.GetString(array2); } } } if (text == null && localizationFiles.ContainsKey("English")) { text = File.ReadAllText(localizationFiles["English"]); } if (text != null) { Dictionary dictionary2; try { dictionary2 = ((BuilderSkeleton)new DeserializerBuilder()).IgnoreFields().Build().Deserialize>(text) ?? new Dictionary(); } catch (Exception arg) { global::Waystones.Waystones.LogInfo($"Failed to deserialize localization for language '{language}'. Using base localization only.\n{arg}"); dictionary2 = new Dictionary(); } foreach (KeyValuePair item in dictionary2) { dictionary[item.Key] = item.Value; } } loadedTexts[language] = dictionary; foreach (KeyValuePair item2 in dictionary) { UpdatePlaceholderText(__instance, item2.Key); } void Scan(string root, bool warn) { foreach (string item3 in from f in Directory.GetFiles(root, "*.*", SearchOption.AllDirectories) where fileExtensions.Contains(Path.GetExtension(f)) select f) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item3); string[] array3 = prefixes; foreach (string text2 in array3) { if (fileNameWithoutExtension.StartsWith(text2)) { string text3 = fileNameWithoutExtension.Substring(text2.Length); if (!string.IsNullOrWhiteSpace(text3)) { if (localizationFiles.ContainsKey(text3)) { if (warn) { global::Waystones.Waystones.LogInfo("Duplicate localization '" + text3 + "' for " + Plugin.Info.Metadata.Name + ". Skipping " + item3); } } else { localizationFiles[text3] = item3; } } break; } } } } } static Localizer() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown PlaceholderProcessors = new Dictionary>>(); loadedTexts = new Dictionary>(); localizationLanguage = new ConditionalWeakTable(); localizationObjects = new List>(); fileExtensions = new List { ".json", ".yml" }; Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static byte[]? LoadTranslationFromAssembly(string language) { foreach (string fileExtension in fileExtensions) { byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension); if (array != null) { return array; } } return null; } public static byte[]? ReadEmbeddedFileBytes(string resourceFileName, Assembly? containingAssembly = null) { string resourceFileName2 = resourceFileName; using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault((string str) => str.EndsWith(resourceFileName2, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } } namespace Waystones { internal static class CustomSyncedValuesSynchronizer { [CompilerGenerated] private sealed class d__6 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CustomSyncedValue syncedValue; public Func function; public bool assignIfChanged; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AssignAfterServerUpdate(syncedValue, function(), assignIfChanged); <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__7 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CustomSyncedValue syncedValue; public T value; public bool assignIfChanged; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (assignIfChanged && syncedValue.Value.Equals(value)) { return false; } <>2__current = waitForServerUpdate; <>1__state = 1; return true; case 1: <>1__state = -1; syncedValue.AssignLocalValue(value); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; coroutines.Dequeue(); goto IL_005c; } <>1__state = -1; goto IL_0081; IL_005c: if (coroutines.Count > 0) { <>2__current = ((MonoBehaviour)Waystones.instance).StartCoroutine(coroutines.Peek()); <>1__state = 1; return true; } if (coroutines.Count == 0) { return false; } goto IL_0081; IL_0081: bool flag = true; goto IL_005c; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Queue coroutines = new Queue(); private static readonly WaitWhile waitForServerUpdate = new WaitWhile((Func)(() => ConfigSync.ProcessingServerUpdate)); public static void AssignValueSafe(this CustomSyncedValue syncedValue, T value) { AddToQueue(AssignAfterServerUpdate(syncedValue, value, assignIfChanged: false)); } public static void AssignValueSafe(this CustomSyncedValue syncedValue, Func function) { AddToQueue(AssignAfterServerUpdate(syncedValue, function, assignIfChanged: false)); } public static void AssignValueIfChanged(this CustomSyncedValue syncedValue, T value) { AddToQueue(AssignAfterServerUpdate(syncedValue, value, assignIfChanged: true)); } public static void AssignValueIfChanged(this CustomSyncedValue syncedValue, Func function) { AddToQueue(AssignAfterServerUpdate(syncedValue, function, assignIfChanged: true)); } [IteratorStateMachine(typeof(d__6<>))] private static IEnumerator AssignAfterServerUpdate(CustomSyncedValue syncedValue, Func function, bool assignIfChanged) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(0) { syncedValue = syncedValue, function = function, assignIfChanged = assignIfChanged }; } [IteratorStateMachine(typeof(d__7<>))] private static IEnumerator AssignAfterServerUpdate(CustomSyncedValue syncedValue, T value, bool assignIfChanged) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(0) { syncedValue = syncedValue, value = value, assignIfChanged = assignIfChanged }; } private static void AddToQueue(IEnumerator coroutine) { coroutines.Enqueue(coroutine); if (coroutines.Count == 1) { ((MonoBehaviour)Waystones.instance).StartCoroutine(CoroutineCoordinator()); } } [IteratorStateMachine(typeof(d__9))] private static IEnumerator CoroutineCoordinator() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0); } } public static class DirectionSearch { public class Direction { public string name; public Vector3 position; public Quaternion rotation; public double cooldown; public int travelCost; public int arrivalCharge; private const int NoArrivalCharge = int.MinValue; private readonly WaystoneList.WaystoneData waystone; public static readonly StringBuilder _sb = new StringBuilder(5); public Direction(string name, Vector3 position) : this(name, position, Quaternion.identity, null) { }//IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) public Direction(string name, Vector3 position, Quaternion rotation) : this(name, position, rotation, null) { }//IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) internal Direction(string name, WaystoneList.WaystoneData waystone) : this(name, waystone.searchPosition, waystone.searchRotation, waystone) { }//IL_0003: 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) private Direction(string name, Vector3 position, Quaternion rotation, WaystoneList.WaystoneData waystone) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) this.name = name; this.position = position; this.rotation = rotation; this.waystone = waystone; cooldown = WorldData.GetCooldownTimeToTarget(position); travelCost = WorldData.GetTravelChargeCost(Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Component)Player.m_localPlayer).transform.position : Vector3.zero, position); arrivalCharge = waystone?.charge ?? int.MinValue; } public string GetHoverText() { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) _sb.Clear(); _sb.Append(name); if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Cooldown) { _sb.Append("\n[$KEY_Use] $ws_tooltip_moving_to"); _sb.Append("\n\n$ws_tooltip_cooldown_after " + WorldData.TimerString(cooldown) + ""); } else if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Charge) { _sb.Append("\n[$KEY_Use] $ws_tooltip_moving_to"); _sb.Append($"\n\n$ws_tooltip_travel_cost {travelCost}"); if (WaystoneList.IsPlayerChargeStorage()) { int playerCharge = WorldData.GetPlayerCharge(); _sb.Append($"\n$ws_tooltip_player_charge {playerCharge}"); _sb.Append($"\n$ws_tooltip_player_charge_after {playerCharge - travelCost}"); } else if (arrivalCharge != int.MinValue) { _sb.Append($"\n$ws_tooltip_arrival_charge {arrivalCharge}"); bool flag = WaystoneList.HasEnoughWaystoneCharge(arrivalCharge, travelCost, Waystones.allowWaystoneChargeOverdraft.Value); _sb.Append("\n$ws_tooltip_return_check " + (flag ? "$menu_yes" : "$menu_no") + ""); } } else { float value = Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, position); string text = FormatUnits(value, (Waystones.orientationDistanceUnit.Value == Waystones.DistanceUnit.Yards) ? " yd" : "m"); _sb.Append("\n$ws_tooltip_distance " + text + ""); } return Localization.instance.Localize(_sb.ToString()); } private static string FormatUnits(float value, string unit) { if (value < 1000f) { return $"{Mathf.RoundToInt(value)}{unit}"; } float num = value / 1000f; return (num >= 10f) ? $"{num:0}k{unit}" : $"{num:0.#}k{unit}"; } } [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] public static class Hud_UpdateCrosshair_HoverTextDirectionMode { private static void Postfix(Hud __instance) { //IL_0062: 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) if (activated && current != null) { ((TMP_Text)__instance.m_hoverName).SetText(current.GetHoverText()); ((Graphic)__instance.m_crosshair).color = (Color)((((TMP_Text)__instance.m_hoverName).text.Length > 0) ? Color.yellow : new Color(1f, 1f, 1f, 0.5f)); } } } [HarmonyPatch(typeof(Hud), "Awake")] public static class Hud_Awake_BlackPanelInit { private static void Postfix(Hud __instance) { GameObject val = Object.Instantiate(((Component)__instance.m_loadingScreen).gameObject, ((Component)__instance.m_loadingScreen).transform.parent); ((Object)val).name = "Waystones_DirectionSearchBlack"; val.transform.SetSiblingIndex(0); val.transform.Find("Loading/TopFade").SetParent(val.transform); val.transform.Find("Loading/BottomFade").SetParent(val.transform); for (int num = val.transform.childCount - 1; num >= 0; num--) { Transform child = val.transform.GetChild(num); switch (((Object)child).name) { case "Loading": case "Sleeping": case "Teleporting": case "Image": case "Tip": case "panel_separator": Object.Destroy((Object)(object)((Component)child).gameObject); break; } } GameObject prefab = ZNetScene.instance.GetPrefab("guard_stone"); if ((Object)(object)prefab != (Object)null) { GameObject val2 = Object.Instantiate(((Component)prefab.transform.Find("WayEffect/sfx")).gameObject, val.transform); ((Object)val2).name = "sfx"; val2.AddComponent(); val2.SetActive(true); screenBlackenerSfx = val2.GetComponent(); } screenBlackener = val.GetComponent(); ((Component)screenBlackener).gameObject.SetActive(false); Waystones.LogInfo("Blackener panel initialized"); } } [HarmonyPatch(typeof(Hud), "UpdateBlackScreen")] public static class Hud_UpdateBlackScreen_DirectionModeScreenEffect { private static void Postfix(float dt) { if (activated) { ((Component)screenBlackener).gameObject.SetActive(true); screenBlackener.alpha = Mathf.MoveTowards(screenBlackener.alpha, Mathf.Lerp(Waystones.fadeMin.Value, Waystones.fadeMax.Value, currentAngle / Mathf.Max(GetCurrentScreenSensivityThreshold(), GetCurrentSensivity())), dt); screenBlackenerSfx.volume = Mathf.MoveTowards(screenBlackenerSfx.volume, Mathf.Lerp(Waystones.sfxMax.Value, Waystones.sfxMin.Value, currentAngle / Mathf.Max(GetCurrentSfxSensivityThreshold(), GetCurrentSensivity())), dt * 3f); screenBlackenerSfx.pitch = Mathf.MoveTowards(screenBlackenerSfx.pitch, Mathf.Lerp(Waystones.sfxPitchMax.Value, Waystones.sfxPitchMin.Value, currentAngle / Mathf.Max(GetCurrentSfxSensivityThreshold(), GetCurrentSensivity())), dt); return; } screenBlackener.alpha = Mathf.MoveTowards(screenBlackener.alpha, 0f, dt / 2f); screenBlackenerSfx.volume = Mathf.MoveTowards(screenBlackenerSfx.volume, 0f, dt); screenBlackenerSfx.pitch = Mathf.MoveTowards(screenBlackenerSfx.pitch, 1f, dt); if (screenBlackener.alpha <= 0f) { ((Component)screenBlackener).gameObject.SetActive(false); } } } [HarmonyPatch] public static class JoyRightStick_SlowFactor { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZInput), "GetJoyRightStickX", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZInput), "GetJoyRightStickY", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] private static IEnumerable TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2); } private static void Postfix(ref float __result) { if (activated) { if (!Game.CanPause()) { __result /= 2f; } else if (Game.m_timeScale != 0f) { __result *= Mathf.Clamp(1f / Game.m_timeScale, 1f, 2f); } } } } [HarmonyPatch(typeof(ZInput), "GetMouseDelta")] public static class ZInput_GetMouseDelta_SlowFactor { private static void Postfix(ref Vector2 __result) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) if (activated) { __result *= Mathf.Clamp(((Vector2)(ref __result)).magnitude / Waystones.slowFactorLookDeceleration.Value, Waystones.slowFactorLookMinimum.Value, 1f); } } } [HarmonyPatch] public static class StopDirectionMode_Postfix { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Menu), "Show", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Menu), "Hide", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Game), "Unpause", (Type[])null, (Type[])null); <>1__state = 3; return true; case 3: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Game), "Pause", (Type[])null, (Type[])null); <>1__state = 4; return true; case 4: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZoneSystem), "Start", (Type[])null, (Type[])null); <>1__state = 5; return true; case 5: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZoneSystem), "OnDestroy", (Type[])null, (Type[])null); <>1__state = 6; return true; case 6: <>1__state = -1; <>2__current = AccessTools.Method(typeof(FejdStartup), "Start", (Type[])null, (Type[])null); <>1__state = 7; return true; case 7: <>1__state = -1; <>2__current = AccessTools.Method(typeof(FejdStartup), "OnDestroy", (Type[])null, (Type[])null); <>1__state = 8; return true; case 8: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Player), "SetSleeping", (Type[])null, (Type[])null); <>1__state = 9; return true; case 9: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Player), "UseHotbarItem", (Type[])null, (Type[])null); <>1__state = 10; return true; case 10: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Player), "StartGuardianPower", (Type[])null, (Type[])null); <>1__state = 11; return true; case 11: <>1__state = -1; <>2__current = AccessTools.Method(typeof(Player), "StopEmote", (Type[])null, (Type[])null); <>1__state = 12; return true; case 12: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] private static IEnumerable TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2); } private static void Postfix() { Exit(force: true); } } [HarmonyPatch(typeof(GameCamera), "Awake")] public static class GameCamera_Awake_SetDefaultPov { private static void Postfix(GameCamera __instance) { defaultFoV = ((__instance.m_fov == 0f) ? 65f : __instance.m_fov); } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] public static class GameCamera_UpdateCamera_BlockCameraDistance { private static void Prefix(GameCamera __instance, ref float __state) { if (activated) { __state = __instance.m_zoomSens; __instance.m_zoomSens = 0f; } } private static void Postfix(GameCamera __instance, float __state) { if (activated) { __instance.m_zoomSens = __state; } } } [HarmonyPatch(typeof(Player), "SetControls")] public static class Player_SetControls_SearchModeExit { private static void Postfix(Player __instance, Vector3 movedir, bool attack, bool secondaryAttack, bool block, bool jump, bool crouch, bool run, bool autoRun, bool dodge) { if (activated && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (((Vector3)(ref movedir)).magnitude > 0.05f || attack || secondaryAttack || block || jump || crouch || run || autoRun || dodge)) { Exit(force: true); } } } [HarmonyPatch(typeof(Player), "FindHoverObject")] public static class Player_FindHoverObject_SearchMode { private static bool Prefix(Player __instance, out GameObject hover, out Character hoverCreature) { hover = null; hoverCreature = null; if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if (!activated) { return true; } return false; } } [HarmonyPatch(typeof(Player), "GetHoverObject")] public static class Player_GetHoverObject_SearchMode { private static bool Prefix(Player __instance, ref GameObject __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if (!activated) { return true; } __result = null; return false; } } [HarmonyPatch(typeof(Minimap), "OnMapLeftDown")] public static class Minimap_ShowPinNameInput_BlockPinDialogInSearchMode { private static bool Prefix(Minimap __instance) { if (!IsActivated) { return true; } __instance.m_leftClickTime = Time.time; __instance.m_leftDownTime = Time.time; return false; } } private static List directions = new List(); private static Direction current; private static bool activated; private static readonly Direction placeOfMystery = new Direction("$ws_location_random_point", Vector3.zero); private static float currentAngle; private static WaystoneList.WaystoneData sourceWaystone; private static float defaultFoV; private static float targetFoV; public static CanvasGroup screenBlackener; public static AudioSource screenBlackenerSfx; public static bool IsActivated => activated; internal static void Toggle() { if (activated) { Exit(); } else if (Waystones.useShortcutToEnter.Value && Waystones.CanCast() && WaystoneSmall.IsSearchAllowed(Player.m_localPlayer, validateCharge: false)) { WaystoneList.EnterSearchMode(); } } internal static void Enter() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Waystones.CanCast() || !WaystoneSmall.IsSearchAllowed(localPlayer, validateCharge: false)) { return; } sourceWaystone = WaystoneList.GetSearchSourceWaystone() ?? WaystoneList.GetClosestActivatedWaystoneData(((Component)localPlayer).transform.position); if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Charge && !WaystoneList.HasEnoughTravelCharge(sourceWaystone, WorldData.MinWaystoneChargeCost, Waystones.allowWaystoneChargeOverdraft.Value)) { sourceWaystone = null; ((Character)localPlayer).Message((MessageType)2, "$ws_message_not_enough_charge", 0, (Sprite)null); return; } if (!activated) { Game.FadeTimeScale(Waystones.slowFactorTime.Value, 4f); targetFoV = defaultFoV; Waystones.LogInfo($"Search mode activated at {((Component)localPlayer).transform.position}"); } FillDirections(); activated = true; WaystoneList.UpdatePins(); } internal static void Exit(bool force = false) { if (!Waystones.CanCast() && !force) { return; } if (activated) { GameCamera.instance.m_fov = defaultFoV; if (Game.m_timeScale >= Waystones.slowFactorTime.Value) { Game.FadeTimeScale(1f, 1f); } if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Cooldown && !WorldData.IsOnCooldown()) { WorldData.SetCooldown(Waystones.cooldownSearchMode.Value); } Waystones.LogInfo("Search mode ended"); } activated = false; current = null; currentAngle = 0f; sourceWaystone = null; WaystoneList.UpdatePins(); } internal static void FillDirections() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) directions.Clear(); if (Waystones.locationShowCurrentSpawn.Value) { directions.Add(new Direction("$ws_location_spawn_point", GetSpawnPoint())); } ZoneSystem.instance.tempIconList.Clear(); ZoneSystem.instance.GetLocationIcons(ZoneSystem.instance.tempIconList); foreach (KeyValuePair tempIcon in ZoneSystem.instance.tempIconList) { if (tempIcon.Value == "StartTemple" && Waystones.locationShowStartTemple.Value) { directions.Add(new Direction("$ws_location_start_temple", tempIcon.Key)); } else if (tempIcon.Value == "Vendor_BlackForest" && Waystones.locationShowHaldor.Value) { directions.Add(new Direction("$npc_haldor", tempIcon.Key)); } else if (tempIcon.Value == "Hildir_camp" && Waystones.locationShowHildir.Value) { directions.Add(new Direction("$npc_hildir", tempIcon.Key)); } else if (tempIcon.Value == "BogWitch_Camp" && Waystones.locationShowBogWitch.Value) { directions.Add(new Direction("$npc_bogwitch", tempIcon.Key)); } } PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile.HaveDeathPoint() && Waystones.locationShowLastTombstone.Value) { directions.Add(new Direction("$ws_location_last_tombstone", playerProfile.GetDeathPoint())); } directions.AddRange(WorldData.GetSavedDirections()); CollectionExtensions.Do((IEnumerable)directions, (Action)delegate(Direction d) { //IL_0021: 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_004c: Unknown result type (might be due to invalid IL or missing references) Waystones.LogInfo(string.Format("{0} {1} {2} {3}", Localization.instance.Localize(d.name), d.position, WorldData.TimerString(d.cooldown), (Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, d.position) < 10f) ? "(filtered, too close)" : "")); }); directions.RemoveAll((Direction d) => Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, d.position) < 10f); if (Waystones.waystoneMode.Value != Waystones.WaystoneMode.Orientation) { return; } float maxDistance = Waystones.orientationWaystoneVisibilityDistance.Value; directions.RemoveAll(delegate(Direction d) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) float num = Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, d.position); if (num <= maxDistance) { return false; } string name = d.name; if (1 == 0) { } bool result = name switch { "$ws_location_spawn_point" => !Waystones.orientationShowDistantCurrentSpawn.Value, "$ws_location_last_tombstone" => !Waystones.orientationShowDistantLastTombstone.Value, "$ws_location_last_ship" => !Waystones.orientationShowDistantLastShip.Value, "$ws_location_last_location" => !Waystones.orientationShowDistantLastPoint.Value, "$ws_location_start_temple" => !Waystones.orientationShowDistantStartTemple.Value, "$npc_haldor" => !Waystones.orientationShowDistantHaldor.Value, "$npc_hildir" => !Waystones.orientationShowDistantHildir.Value, "$npc_bogwitch" => !Waystones.orientationShowDistantBogWitch.Value, _ => d.name.Contains("$ws_piece_waystone_name") && !Waystones.orientationShowDistantWaystones.Value, }; if (1 == 0) { } return result; }); } internal static Vector3 GetSpawnPoint() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile.HaveCustomSpawnPoint()) { return playerProfile.GetCustomSpawnPoint(); } return playerProfile.GetHomePoint(); } internal static void Update() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: 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_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = Waystones.shortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Toggle(); } else if (activated && (ZInput.GetButtonDown("Block") || ZInput.GetButtonDown("JoyButtonB"))) { Exit(); } if (current != null && (ZInput.GetButton("Use") || ZInput.GetButton("JoyUse")) && Waystones.CanCast()) { Direction direction = ((current == placeOfMystery) ? new Direction("$ws_location_random_point", GetRandomPoint()) : current); if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Orientation) { Exit(); return; } if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Charge && !WaystoneList.HasEnoughTravelCharge(sourceWaystone, direction.travelCost, Waystones.allowWaystoneChargeOverdraft.Value)) { MessageHud.instance.ShowMessage((MessageType)2, "$ws_message_not_enough_charge", 0, (Sprite)null, false); return; } Waystones.TeleportAttempt(direction.position, direction.rotation, direction.cooldown, direction.name, sourceWaystone, direction.travelCost); Exit(); } if (activated && !Waystones.CanCast()) { Exit(force: true); } if (!activated) { return; } current = null; targetFoV -= Mathf.Clamp(ZInput.GetMouseScrollWheel(), -1f, 1f); if (ZInput.GetButton("JoyAltKeys") && !Hud.InRadial()) { if (ZInput.GetButton("JoyCamZoomIn")) { targetFoV -= 1f; } else if (ZInput.GetButton("JoyCamZoomOut")) { targetFoV += 1f; } } targetFoV = Mathf.Clamp(targetFoV, defaultFoV - Waystones.fovDelta.Value, defaultFoV + Waystones.fovDelta.Value); GameCamera.instance.m_fov = Mathf.MoveTowards(GameCamera.instance.m_fov, targetFoV, Waystones.fovDelta.Value); Vector3 look = ((Character)Player.m_localPlayer).GetLookDir(); currentAngle = Vector3.Angle(look, Vector3.down); if (currentAngle < GetCurrentSensivity() && Waystones.locationShowRandomPoint.Value) { current = placeOfMystery; } else if (directions.Count != 0) { Vector3 pos = ((Character)Player.m_localPlayer).GetEyePoint(); directions = directions.OrderBy((Direction dir) => Vector3.Angle(look, dir.position - pos)).ToList(); currentAngle = Vector3.Angle(look, directions[0].position - pos); if (currentAngle < GetCurrentSensivity()) { current = directions[0]; } } } private static float GetCurrentSensivity() { return Waystones.directionSensitivity.Value * targetFoV / defaultFoV; } private static float GetCurrentScreenSensivityThreshold() { return Waystones.directionSensitivityThreshold.Value * targetFoV / defaultFoV; } private static float GetCurrentSfxSensivityThreshold() { return Waystones.sfxSensitivityThreshold.Value * targetFoV / defaultFoV; } private static Vector3 GetRandomPoint() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Vector3 zero = Vector3.zero; do { zero = GetRandomPointInRadius(Vector3.zero, 10000f); } while (!IsValidRandomPointForTeleport(ref zero)); return zero; } private static bool IsValidRandomPointForTeleport(ref Vector3 pos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Biome biome = WorldGenerator.instance.GetBiome(pos); if ((int)biome == 256 || (int)biome == 0 || !Player.m_localPlayer.m_knownBiome.Contains(biome)) { return false; } pos = new Vector3(pos.x, 31f, pos.z); return true; } public static Vector3 GetRandomPointInRadius(Vector3 center, float radius) { //IL_001f: 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_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_0042: Unknown result type (might be due to invalid IL or missing references) float num = Random.value * (float)Math.PI * 2f; float num2 = Random.Range(0f, radius); return center + new Vector3(Mathf.Sin(num) * num2, 0f, Mathf.Cos(num) * num2); } } public static class ItemNameTokens { [HarmonyPatch(typeof(Player), "Load")] private static class Player_Load_UpdateRegisters { private static void Prefix() { UpdateRegisters(); } } public static readonly Dictionary itemNames = new Dictionary(StringComparer.OrdinalIgnoreCase); public static void UpdateRegisters() { if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { return; } itemNames.Clear(); foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent(); if (component != null) { SharedData val = component.m_itemData?.m_shared; if (val != null && !string.IsNullOrWhiteSpace(val.m_name) && val.m_name.StartsWith("$")) { itemNames[((Object)item).name] = val.m_name; itemNames[val.m_name] = val.m_name; } } } Waystones.ReadInitialConfigs(); } public static string GetItemName(this string input) { string value; return itemNames.TryGetValue((input ?? "").Trim(), out value) ? value : input; } } internal static class WaystoneList { public class WaystoneData { public string tag; public Vector3 searchPosition; public Quaternion searchRotation; public Vector3 worldPosition; public int charge; } [HarmonyPatch(typeof(Minimap), "Start")] public static class WaystoneIconType { public static int pinType; private static void Postfix(Minimap __instance) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) pinType = __instance.m_visibleIconTypes.Length; bool[] array = new bool[pinType + 1]; Array.Copy(__instance.m_visibleIconTypes, array, pinType); __instance.m_visibleIconTypes = array; __instance.m_icons.Add(new SpriteData { m_name = (PinType)pinType, m_icon = iconWaystone }); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] public static class ZoneSystem_Start_WaystoneList { private static void Postfix() { RegisterRPCs(); } } [HarmonyPatch(typeof(ZoneSystem), "OnDestroy")] public static class ZoneSystem_OnDestroy_WaystoneList { private static void Postfix() { waystoneObjects.Clear(); activatedWaystones.Clear(); searchSourceWaystone = null; } } [HarmonyPatch(typeof(ZDOMan), "Load")] public static class ZDOMan_Load_WaystoneListInit { private static void Postfix(ZDOMan __instance) { foreach (KeyValuePair item in __instance.m_objectsByID) { if (item.Value.GetPrefab() == PieceWaystone.waystoneHash) { waystoneObjects.Add(item.Value); } } } } [HarmonyPatch(typeof(ZDOMan), "CreateNewZDO", new Type[] { typeof(ZDOID), typeof(Vector3), typeof(int) })] public static class ZDOMan_CreateNewZDO_WaystoneListAddNew { private static void Postfix(int prefabHashIn, ZDO __result) { if (((prefabHashIn != 0) ? prefabHashIn : __result.GetPrefab()) == PieceWaystone.waystoneHash) { waystoneObjects.Add(__result); } } } [HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")] public static class ZDOMan_HandleDestroyedZDO_WaystoneListRemove { private static void Prefix(ZDOMan __instance, ZDOID uid) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = __instance.GetZDO(uid); if (zDO != null && zDO.GetPrefab() == PieceWaystone.waystoneHash) { waystoneObjects.Remove(zDO); } } } [HarmonyPatch(typeof(ZDO), "Deserialize")] public static class ZDO_Deserialize_WaystoneListAdd { private static void Postfix(ZDO __instance) { if (__instance.GetPrefab() == PieceWaystone.waystoneHash) { waystoneObjects.Add(__instance); } } } public static Sprite iconWaystone; public static readonly List waystonePins = new List(); public static readonly List activatedWaystones = new List(); private static WaystoneData searchSourceWaystone; public static readonly HashSet waystoneObjects = new HashSet(); public const string customDataKey = "WaystoneList"; public const string chargeZdoKey = "WaystoneCharges"; private const float waystoneSearchPointOffset = 1f; private const float defaultWaystoneMatchDistance = 8f; private const string markedLocationRequestRpc = "MarkedLocationRequest"; private const string markedLocationResponseRpc = "MarkedLocationResponse"; private const string consumeWaystoneChargeRequestRpc = "ConsumeWaystoneChargeRequest"; public static void UpdatePins() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) foreach (PinData waystonePin in waystonePins) { Minimap.instance.RemovePin(waystonePin); } waystonePins.Clear(); if (!Waystones.locationWaystonesShowOnMap.Value || !DirectionSearch.IsActivated) { return; } foreach (WaystoneData activatedWaystone in activatedWaystones) { waystonePins.Add(Minimap.instance.AddPin(activatedWaystone.searchPosition, (PinType)WaystoneIconType.pinType, activatedWaystone.tag, false, false, Player.m_localPlayer.GetPlayerID(), default(PlatformUserID))); } } internal static void RegisterRPCs() { if (ZNet.instance.IsServer()) { ZRoutedRpc.instance.Register("MarkedLocationRequest", (Action)RPC_MarkedLocationRequest); ZRoutedRpc.instance.Register("ConsumeWaystoneChargeRequest", (Action)RPC_ConsumeWaystoneChargeRequest); } else { ZRoutedRpc.instance.Register("MarkedLocationResponse", (Action)RPC_MarkedLocationResponse); } } public static void EnterSearchMode(ZDO sourceZdo = null) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && !((Object)(object)ZNet.instance == (Object)null)) { if (!ZNet.instance.IsServer()) { MarkedLocationRequest(sourceZdo); return; } GetActivatedWaystones(localPlayer.GetPlayerID()); searchSourceWaystone = CreateSearchSourceWaystone(sourceZdo, ((Component)localPlayer).transform.position); DirectionSearch.Enter(); } } public static void MarkedLocationRequest(ZDO sourceZdo = null) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { Waystones.LogInfo("Marked location request"); ZPackage val = new ZPackage(); val.Write(localPlayer.GetPlayerID()); val.Write(((Component)localPlayer).transform.position); bool flag = sourceZdo != null; val.Write(flag ? 1 : 0); if (flag) { val.Write(sourceZdo.GetPosition()); } ZRoutedRpc.instance.InvokeRoutedRPC("MarkedLocationRequest", new object[1] { val }); } } public static List GetActivatedWaystones(long playerID) { activatedWaystones.Clear(); waystoneObjects.RemoveWhere((ZDO zdo) => zdo == null); foreach (ZDO waystoneObject in waystoneObjects) { if (WaystoneSmall.IsWaystoneActivated(waystoneObject, playerID)) { string @string = waystoneObject.GetString(ZDOVars.s_tag, ""); if (!string.IsNullOrWhiteSpace(@string)) { activatedWaystones.Add(CreateWaystoneData(waystoneObject, @string)); } } } return activatedWaystones; } private static WaystoneData CreateWaystoneData(ZDO zdo, string tag) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (zdo == null) { return null; } Vector3 position = zdo.GetPosition(); Quaternion rotation = zdo.GetRotation(); Vector3 val = rotation * Vector3.forward; return new WaystoneData { tag = tag, worldPosition = position, searchPosition = position + val * 1f + Vector3.up, searchRotation = rotation * Quaternion.Euler(0f, 180f, 0f), charge = GetWaystoneCharge(zdo) }; } private static WaystoneData CreateSearchSourceWaystone(ZDO sourceZdo, Vector3 playerPosition) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (sourceZdo == null) { sourceZdo = GetClosestWaystone(playerPosition); } return CreateWaystoneData(sourceZdo, (sourceZdo == null) ? "" : sourceZdo.GetString(ZDOVars.s_tag, "")); } public static WaystoneData GetSearchSourceWaystone() { return searchSourceWaystone; } public static WaystoneData GetClosestActivatedWaystoneData(Vector3 point, float maxDistance = 8f) { //IL_001c: 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) WaystoneData result = null; float num = maxDistance; foreach (WaystoneData activatedWaystone in activatedWaystones) { float num2 = Utils.DistanceXZ(point, activatedWaystone.worldPosition); if (num2 <= num) { num = num2; result = activatedWaystone; } } return result; } public static int GetClosestActivatedWaystoneCharge(long playerID, Vector3 point, float maxDistance = 8f) { //IL_0001: 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) WaystoneData closestActivatedWaystoneData = GetClosestActivatedWaystoneData(point, maxDistance); if (closestActivatedWaystoneData != null) { return closestActivatedWaystoneData.charge; } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ZDO closestWaystone = GetClosestWaystone(point, maxDistance); return (closestWaystone != null) ? GetWaystoneCharge(closestWaystone) : 0; } return 0; } public static bool IsPlayerChargeStorage() { return Waystones.waystoneChargeStorage.Value == Waystones.ChargeStorage.Player; } public static int GetDefaultWaystoneCharge() { return WorldData.GetDefaultCharge(); } public static int GetCurrentTravelCharge(long playerID, Vector3 point, float maxDistance = 8f) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) return IsPlayerChargeStorage() ? WorldData.GetPlayerCharge() : GetClosestActivatedWaystoneCharge(playerID, point, maxDistance); } public static int GetWaystoneCharge(ZDO zdo) { if (zdo == null) { return 0; } int @int = zdo.GetInt("WaystoneCharges", GetDefaultWaystoneCharge()); return Waystones.allowWaystoneChargeOverflow.Value ? @int : Mathf.Min(@int, WorldData.MaxWaystoneCharge); } public static int GetPotentialChargeAdded(ZDO zdo, int amount) { return IsPlayerChargeStorage() ? WorldData.GetPotentialPlayerChargeAdded(amount) : GetPotentialWaystoneChargeAdded(zdo, amount); } public static int GetPotentialWaystoneChargeAdded(ZDO zdo, int amount) { if (zdo == null || amount <= 0) { return 0; } int waystoneCharge = GetWaystoneCharge(zdo); int maxWaystoneCharge = WorldData.MaxWaystoneCharge; if (Waystones.allowWaystoneChargeOverflow.Value) { return (waystoneCharge < maxWaystoneCharge) ? amount : 0; } int num = Mathf.Min(waystoneCharge + amount, maxWaystoneCharge); return Mathf.Max(0, num - waystoneCharge); } public static bool CanStartSearchWithCharge(int current) { return HasEnoughCharge(current, WorldData.MinWaystoneChargeCost, Waystones.allowWaystoneChargeOverdraft.Value); } public static bool HasEnoughTravelCharge(WaystoneData sourceWaystone, int amount, bool allowOverdraftWhenPositive) { int current = (IsPlayerChargeStorage() ? WorldData.GetPlayerCharge() : (sourceWaystone?.charge ?? 0)); return HasEnoughCharge(current, amount, allowOverdraftWhenPositive); } public static bool HasEnoughWaystoneCharge(WaystoneData waystone, int amount, bool allowOverdraftWhenPositive) { return waystone != null && HasEnoughCharge(waystone.charge, amount, allowOverdraftWhenPositive); } public static bool HasEnoughWaystoneCharge(int current, int amount, bool allowOverdraftWhenPositive) { return HasEnoughCharge(current, amount, allowOverdraftWhenPositive); } public static bool TryConsumeTravelCharge(WaystoneData sourceWaystone, long playerID, int amount, bool allowOverdraftWhenPositive = false) { return IsPlayerChargeStorage() ? WorldData.TryConsumePlayerCharge(amount, allowOverdraftWhenPositive) : TryConsumeWaystoneCharge(sourceWaystone, playerID, amount, allowOverdraftWhenPositive); } public static bool TryConsumeWaystoneCharge(WaystoneData waystone, long playerID, int amount, bool allowOverdraftWhenPositive = false) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (waystone == null || amount <= 0) { return false; } if (!HasEnoughCharge(waystone.charge, amount, allowOverdraftWhenPositive)) { return false; } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ZDO closestWaystone = GetClosestWaystone(waystone.worldPosition, 2f); if (!TryConsumeWaystoneCharge(closestWaystone, amount, allowOverdraftWhenPositive)) { return false; } waystone.charge = GetWaystoneCharge(closestWaystone); return true; } waystone.charge -= amount; ConsumeWaystoneChargeRequest(playerID, waystone.worldPosition, amount, allowOverdraftWhenPositive); return true; } public static bool TryConsumeWaystoneCharge(ZDO zdo, int amount, bool allowOverdraftWhenPositive = false) { if (zdo == null || amount <= 0) { return false; } int waystoneCharge = GetWaystoneCharge(zdo); if (!HasEnoughCharge(waystoneCharge, amount, allowOverdraftWhenPositive)) { return false; } zdo.Set("WaystoneCharges", waystoneCharge - amount); return true; } private static bool HasEnoughCharge(int current, int amount, bool allowOverdraftWhenPositive) { return current >= amount || (allowOverdraftWhenPositive && current > 0); } public static int AddCharge(ZDO zdo, int amount) { return IsPlayerChargeStorage() ? WorldData.AddPlayerCharge(amount) : AddWaystoneCharge(zdo, amount); } public static int AddWaystoneCharge(ZDO zdo, int amount) { int potentialWaystoneChargeAdded = GetPotentialWaystoneChargeAdded(zdo, amount); if (potentialWaystoneChargeAdded <= 0) { return 0; } zdo.Set("WaystoneCharges", GetWaystoneCharge(zdo) + potentialWaystoneChargeAdded); return potentialWaystoneChargeAdded; } public static ZDO GetClosestActivatedWaystone(long playerID, Vector3 point, float maxDistance = 8f) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) ZDO result = null; float num = maxDistance; foreach (ZDO waystoneObject in waystoneObjects) { if (WaystoneSmall.IsWaystoneActivated(waystoneObject, playerID)) { float num2 = Utils.DistanceXZ(point, waystoneObject.GetPosition()); if (num2 <= num) { num = num2; result = waystoneObject; } } } return result; } public static ZDO GetClosestWaystone(Vector3 point, float maxDistance = 8f) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) ZDO result = null; float num = maxDistance; waystoneObjects.RemoveWhere((ZDO zdo) => zdo == null); foreach (ZDO waystoneObject in waystoneObjects) { float num2 = Utils.DistanceXZ(point, waystoneObject.GetPosition()); if (num2 <= num) { num = num2; result = waystoneObject; } } return result; } private static void ConsumeWaystoneChargeRequest(long playerID, Vector3 worldPosition, int amount, bool allowOverdraftWhenPositive) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0010: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(playerID); val.Write(worldPosition); val.Write(amount); val.Write(allowOverdraftWhenPositive ? 1 : 0); ZRoutedRpc.instance.InvokeRoutedRPC("ConsumeWaystoneChargeRequest", new object[1] { val }); } public static void RPC_ConsumeWaystoneChargeRequest(long sender, ZPackage pkg) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) long num = pkg.ReadLong(); Vector3 val = pkg.ReadVector3(); int num2 = pkg.ReadInt(); pkg.ReadInt(); bool value = Waystones.allowWaystoneChargeOverdraft.Value; ZDO closestWaystone = GetClosestWaystone(val, 2f); if (!TryConsumeWaystoneCharge(closestWaystone, num2, value)) { Waystones.LogInfo($"Rejected waystone charge consume request from {sender}. Player: {num}, amount: {num2}, position: {val}"); } } public static void RPC_MarkedLocationRequest(long sender, ZPackage request) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) long playerID = request.ReadLong(); Vector3 playerPosition = request.ReadVector3(); ZDO sourceZdo = null; if (request.ReadInt() != 0) { sourceZdo = GetClosestWaystone(request.ReadVector3(), 2f); } GetActivatedWaystones(playerID); WaystoneData waystoneData = CreateSearchSourceWaystone(sourceZdo, playerPosition); ZPackage val = new ZPackage(); val.Write(activatedWaystones.Count); foreach (WaystoneData activatedWaystone in activatedWaystones) { WriteWaystoneData(val, activatedWaystone); } val.Write((waystoneData != null) ? 1 : 0); if (waystoneData != null) { WriteWaystoneData(val, waystoneData); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "MarkedLocationResponse", new object[1] { val }); } public static void RPC_MarkedLocationResponse(long sender, ZPackage pkg) { Waystones.LogInfo("Server responded with activated location list"); activatedWaystones.Clear(); int num = pkg.ReadInt(); for (int i = 0; i < num; i++) { activatedWaystones.Add(ReadWaystoneData(pkg)); } searchSourceWaystone = ((pkg.ReadInt() != 0) ? ReadWaystoneData(pkg) : null); DirectionSearch.Enter(); } private static void WriteWaystoneData(ZPackage pkg, WaystoneData waystone) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) pkg.Write(waystone.tag ?? ""); pkg.Write(waystone.searchPosition); pkg.Write(waystone.searchRotation); pkg.Write(waystone.worldPosition); pkg.Write(waystone.charge); } private static WaystoneData ReadWaystoneData(ZPackage pkg) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) return new WaystoneData { tag = pkg.ReadString(), searchPosition = pkg.ReadVector3(), searchRotation = pkg.ReadQuaternion(), worldPosition = pkg.ReadVector3(), charge = pkg.ReadInt() }; } } internal class PieceWaystone { [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Awake_AddPiece { [HarmonyPriority(800)] private static void Postfix() { RegisterPiece(); } } public static Sprite itemWaystone; internal static GameObject waystonePrefab; internal const string waystoneName = "Waystone_small"; public static int waystoneHash = StringExtensionMethods.GetStableHashCode("Waystone_small"); public const string waystonePieceName = "$ws_piece_waystone_name"; public const string waystonePieceDescription = "$ws_piece_waystone_description"; public static void RegisterPiece() { //IL_0072: 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_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022d: 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_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Expected O, but got Unknown //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Expected O, but got Unknown //IL_051b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)waystonePrefab)) { WayStone val = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((WayStone ws) => ((Object)ws).name == "Waystone")); if ((Object)(object)val == (Object)null) { return; } waystonePrefab = CustomPrefabs.InitPrefabClone(((Component)val).gameObject, "Waystone_small"); Transform transform = waystonePrefab.transform; transform.localScale *= 0.15f; LODGroup component = waystonePrefab.GetComponent(); LOD[] lODs = component.GetLODs(); List list = lODs[0].renderers.Where((Renderer r) => ((Object)r).name == "model").ToList(); list.Add((Renderer)(object)((Component)waystonePrefab.transform.Find("WayEffect/Particle System sparcs")).GetComponent()); lODs[0].renderers = list.ToArray(); component.SetLODs(lODs); Object.Destroy((Object)(object)((Component)waystonePrefab.transform.Find("WayEffect/Particle System")).gameObject); Object.Destroy((Object)(object)((Component)waystonePrefab.transform.Find("WayEffect/sfx")).gameObject); Transform val2 = waystonePrefab.transform.Find("WayEffect/Particle System (1)"); val2.localScale *= 0.75f; MainModule main = ((Component)val2).GetComponent().main; ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.75f); ((MainModule)(ref main)).startSpeedMultiplier = 0.1f; ((MainModule)(ref main)).maxParticles = 75; ShapeModule shape = ((Component)val2).GetComponent().shape; ((ShapeModule)(ref shape)).radius = 0.005f; EmissionModule emission = ((Component)val2).GetComponent().emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(5f); Transform val3 = waystonePrefab.transform.Find("WayEffect/Particle System sparcs"); val3.localScale *= 0.4f; MainModule main2 = ((Component)val3).GetComponent().main; ((MainModule)(ref main2)).startSpeed = MinMaxCurve.op_Implicit(1f); ((MainModule)(ref main2)).maxParticles = 200; EmissionModule emission2 = ((Component)val3).GetComponent().emission; ((EmissionModule)(ref emission2)).rateOverTime = MinMaxCurve.op_Implicit(20f); ((Component)val3).gameObject.SetActive(!Waystones.disableWaystoneSparcs.Value); Light component2 = ((Component)waystonePrefab.transform.Find("WayEffect/Point light")).GetComponent(); component2.intensity = 1.1f; Light component3 = ((Component)waystonePrefab.transform.Find("Point light (1)")).GetComponent(); component3.intensity = 1.1f; ((Component)component3).gameObject.AddComponent().m_lightDistance = 50f; waystonePrefab.GetComponentInChildren().m_type = (Type)2; Component obj2 = CustomPrefabs.AddComponent(waystonePrefab, typeof(ZNetView)); ZNetView val4 = (ZNetView)(object)((obj2 is ZNetView) ? obj2 : null); val4.m_persistent = true; val4.m_distant = true; val4.m_type = (ObjectType)2; Component obj3 = CustomPrefabs.AddComponent(waystonePrefab, typeof(Piece)); Piece val5 = (Piece)(object)((obj3 is Piece) ? obj3 : null); val5.m_icon = itemWaystone; val5.m_name = "$ws_piece_waystone_name"; val5.m_description = "$ws_piece_waystone_description"; val5.m_clipGround = true; val5.m_clipEverything = true; val5.m_notOnTiltingSurface = true; val5.m_noClipping = false; ((StaticTarget)val5).m_randomTarget = false; Component obj4 = CustomPrefabs.AddComponent(waystonePrefab, typeof(WearNTear)); WearNTear val6 = (WearNTear)(object)((obj4 is WearNTear) ? obj4 : null); GameObject val7 = new GameObject("new"); val7.transform.SetParent(waystonePrefab.transform); val7.transform.SetSiblingIndex(0); waystonePrefab.transform.Find("model").SetParent(val7.transform); val6.m_new = val7; val6.m_worn = val7; val6.m_broken = val7; val6.m_noRoofWear = false; val6.m_noSupportWear = false; val6.m_burnable = false; val6.m_supports = false; val6.m_ashDamageResist = true; val6.m_staticPosition = true; val6.m_materialType = (MaterialType)1; val6.m_health = 1000f; val6.m_damages.m_pierce = (DamageModifier)1; val6.m_damages.m_chop = (DamageModifier)4; val6.m_damages.m_pickaxe = (DamageModifier)4; val6.m_damages.m_fire = (DamageModifier)1; val6.m_damages.m_frost = (DamageModifier)1; val6.m_damages.m_poison = (DamageModifier)3; val6.m_damages.m_spirit = (DamageModifier)3; WayStone component4 = waystonePrefab.GetComponent(); WaystoneSmall.initial = true; WaystoneSmall waystoneSmall = waystonePrefab.AddComponent(); WaystoneSmall.initial = false; Object.Destroy((Object)(object)component4); GameObject val8 = new GameObject("GuidePoint"); val8.transform.SetParent(waystonePrefab.transform); val8.transform.localPosition = new Vector3(-0.5f, 8.9f, -1.3f); Component obj5 = CustomPrefabs.AddComponent(val8, typeof(GuidePoint)); GuidePoint val9 = (GuidePoint)(object)((obj5 is GuidePoint) ? obj5 : null); val9.m_text.m_alwaysSpawn = false; val9.m_text.m_key = "ws_waystone"; val9.m_text.m_topic = "$ws_tutorial_waystone_topic"; val9.m_text.m_label = "$ws_tutorial_waystone_label"; val9.m_text.m_text = ((Waystones.waystoneMode.Value == Waystones.WaystoneMode.Orientation) ? "$ws_tutorial_waystone_text_orientation" : "$ws_tutorial_waystone_text"); Waystones.LogInfo("Waystone prefab added"); } if (!Object.op_Implicit((Object)(object)waystonePrefab)) { return; } GameObject prefab = ZNetScene.instance.GetPrefab("stone_pile"); if ((Object)(object)prefab != (Object)null) { waystonePrefab.GetComponent().m_placeEffect.m_effectPrefabs = prefab.GetComponent().m_placeEffect.m_effectPrefabs.ToArray(); waystonePrefab.GetComponent().m_destroyedEffect.m_effectPrefabs = prefab.GetComponent().m_destroyedEffect.m_effectPrefabs.ToArray(); waystonePrefab.GetComponent().m_hitEffect.m_effectPrefabs = prefab.GetComponent().m_hitEffect.m_effectPrefabs.ToArray(); } WaystoneSmall component5 = waystonePrefab.GetComponent(); WayStone val10 = ((IEnumerable)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((WayStone obj) => ((Object)obj).name == "Waystone")); if ((Object)(object)val10 != (Object)null) { component5.m_activateEffect.m_effectPrefabs = val10.m_activeEffect.m_effectPrefabs.ToArray(); } GameObject prefab2 = ZNetScene.instance.GetPrefab("guard_stone"); PrivateArea val11 = ((prefab2 != null) ? prefab2.GetComponent() : null); if ((Object)(object)val11 != (Object)null) { component5.m_deactivateEffect.m_effectPrefabs = val11.m_removedPermittedEffect.m_effectPrefabs.ToArray(); } GameObject prefab3 = ZNetScene.instance.GetPrefab("piece_workbench"); GuidePoint val12 = ((prefab3 != null) ? prefab3.GetComponentInChildren() : null); if ((Object)(object)val12 != (Object)null) { waystonePrefab.GetComponentInChildren().m_ravenPrefab = val12.m_ravenPrefab; } if (ZNetScene.instance.m_namedPrefabs.ContainsKey(waystoneHash)) { ZNetScene.instance.m_prefabs.Remove(ZNetScene.instance.m_namedPrefabs[waystoneHash]); ZNetScene.instance.m_namedPrefabs.Remove(waystoneHash); } ZNetScene.instance.m_prefabs.Add(waystonePrefab); ZNetScene.instance.m_namedPrefabs.Add(waystoneHash, waystonePrefab); SetPieceRequirements(); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); PieceTable val13 = ((itemPrefab == null) ? null : itemPrefab.GetComponent()?.m_itemData.m_shared.m_buildPieces); if (val13 != null) { val13.m_pieces.RemoveAll((GameObject piece) => ((Object)piece).name == "Waystone_small"); val13.m_pieces.Add(waystonePrefab); } } public static void SetPieceRequirements() { //IL_00ba: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown if ((Object)(object)waystonePrefab == (Object)null) { return; } Piece component = waystonePrefab.GetComponent(); List list = new List(); string[] array = Waystones.pieceRecipe.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length != 2) { continue; } int num = int.Parse(array2[1]); if (num > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(array2[0].Trim()); if (!((Object)(object)itemPrefab == (Object)null)) { list.Add(new Requirement { m_amount = num, m_resItem = itemPrefab.GetComponent(), m_recover = true }); } } } component.m_resources = list.ToArray(); } } internal class WaystoneTravelEffect : MonoBehaviour { private ZNetView m_nview; private float volume; private AudioSource sfx; private MainModule main; private Light light; public static readonly int progressHash = StringExtensionMethods.GetStableHashCode("TravelProgress"); public static bool initial = false; private void Awake() { if (!initial) { m_nview = ((Component)this).GetComponent(); } } private void Start() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) sfx = ((Component)((Component)this).transform.Find("Sfx")).GetComponent(); ((Behaviour)sfx).enabled = true; volume = sfx.volume; main = ((Component)((Component)this).transform.Find("Sparcs")).GetComponent().main; light = ((Component)((Component)this).transform.Find("Light")).GetComponent(); } private void Update() { //IL_0020: 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) float progress = GetProgress(m_nview); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(0.5f + 5.5f * progress); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(4f - 3.5f * progress); ((MainModule)(ref main)).simulationSpeed = 1f + progress; light.intensity = 1f + 2f * progress; light.range = 5f + 15f * progress; sfx.volume = volume * progress; } internal static void SetProgress(ZNetView netView, float progress) { if (!((Object)(object)netView == (Object)null) && netView.IsValid()) { netView.GetZDO().Set(progressHash, progress); } } internal static float GetProgress(ZNetView netView) { if ((Object)(object)netView == (Object)null || !netView.IsValid()) { return 0f; } return netView.GetZDO().GetFloat(progressHash, 0f); } } [Serializable] public class WorldData { [HarmonyPatch(typeof(Ship), "OnTriggerExit")] public static class Ship_OnTriggerExit_LastShipPosition { private static void Prefix(Ship __instance, Collider collider) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && (Object)(object)Player.m_localPlayer == (Object)(object)((Component)collider).GetComponent() && Ship.s_currentShips.Contains(__instance)) { saveNextGroundPositionAsShipLocation = true; } } } [HarmonyPatch(typeof(Player), "FixedUpdate")] public static class Player_FixedUpdate_SaveLastShipPosition { private static void Postfix(Player __instance) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && saveNextGroundPositionAsShipLocation && ((Character)__instance).IsOnGround() && !((Character)__instance).InWater() && (Object)(object)((Character)__instance).GetStandingOnShip() == (Object)null) { saveNextGroundPositionAsShipLocation = false; SaveLastShip(((Component)Player.m_localPlayer).transform.position); } } } [CompilerGenerated] private sealed class d__43 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private string input; public string <>3__input; private StringReader 5__1; private string 5__2; string IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__43(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__1 = null; 5__2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (input == null) { return false; } 5__1 = new StringReader(input); <>1__state = -3; break; case 1: <>1__state = -3; break; } if ((5__2 = 5__1.ReadLine()) != null) { <>2__current = 5__2; <>1__state = 1; return true; } 5__2 = null; <>m__Finally1(); 5__1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (5__1 != null) { ((IDisposable)5__1).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__43 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__43(0); } d__.input = <>3__input; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public long worldUID; public string globalTime; public double worldTime; public Vector3 lastShip = Vector3.zero; public Vector3 lastPosition = Vector3.zero; public bool playerChargeInitialized; public int playerCharge; public const string customDataKey = "Waystones"; public static bool saveNextGroundPositionAsShipLocation; public static int MaxWaystoneCharge => Mathf.Clamp(Waystones.maxWaystoneCharge.Value, 1, 100000); public static int MinWaystoneChargeCost => Mathf.Clamp(Waystones.chargeCostMinimum.Value, 1, 100000); public static int MaxWaystoneChargeCost => Mathf.Max(MinWaystoneChargeCost, Mathf.Clamp(Waystones.chargeCostMaximum.Value, 1, 100000)); public static int MinWaystoneChargeDistance => Mathf.Clamp(Waystones.chargeDistanceMinimum.Value, 1, 100000); public static int MaxWaystoneChargeDistance => Mathf.Max(MinWaystoneChargeDistance, Mathf.Clamp(Waystones.chargeDistanceMaximum.Value, 1, 100000)); public static List GetSavedDirections() { //IL_0033: 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_007b: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) List result = new List(); WorldData worldData = GetWorldData(GetState()); if (worldData == null) { return result; } _ = worldData.lastShip; if (worldData.lastShip != Vector3.zero && Waystones.locationShowLastShip.Value) { result.Add(new DirectionSearch.Direction("$ws_location_last_ship", worldData.lastShip)); } _ = worldData.lastPosition; if (worldData.lastPosition != Vector3.zero && Waystones.locationShowLastPoint.Value) { result.Add(new DirectionSearch.Direction("$ws_location_last_location", worldData.lastPosition)); } if (Waystones.locationShowWaystones.Value) { CollectionExtensions.Do((IEnumerable)WaystoneList.activatedWaystones, (Action)delegate(WaystoneList.WaystoneData waystone) { result.Add(new DirectionSearch.Direction("$ws_piece_waystone_name \"" + waystone.tag + "\"", waystone)); }); } return result; } public static void SaveLastPosition(Vector3 position) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) List state = GetState(); GetWorldData(state, createIfEmpty: true).lastPosition = position; Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Vector3 val = position; Waystones.LogInfo("Last teleport location saved: " + ((object)(Vector3)(ref val)).ToString()); } public static void SaveLastShip(Vector3 position) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) List state = GetState(); GetWorldData(state, createIfEmpty: true).lastShip = position; Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Vector3 val = position; Waystones.LogInfo("Last ship location saved: " + ((object)(Vector3)(ref val)).ToString()); } private double GetCooldownTime() { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0.0; } if (Waystones.cooldownTime.Value == Waystones.CooldownTime.WorldTime) { return (worldTime == 0.0) ? 0.0 : Math.Max(worldTime - ZNet.instance.GetTimeSeconds(), 0.0); } if (DateTime.TryParse(globalTime, CultureInfo.InvariantCulture, DateTimeStyles.None, out var result)) { return Math.Max((result - GetTime()).TotalSeconds, 0.0); } return 0.0; } private void SetCooldownTime(double cooldown) { if (Waystones.cooldownTime.Value == Waystones.CooldownTime.GlobalTime) { globalTime = GetTime().AddSeconds(cooldown).ToString(CultureInfo.InvariantCulture); } else { worldTime = ZNet.instance.GetTimeSeconds() + cooldown; } } public static double GetCooldownTimeToTarget(Vector3 target) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (target == Vector3.zero) { return Waystones.cooldownMinimum.Value; } float num = Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, target); if (num < (float)Waystones.cooldownDistanceMinimum.Value) { return Waystones.cooldownMinimum.Value; } if (num > (float)Waystones.cooldownDistanceMaximum.Value) { return Waystones.cooldownMaximum.Value; } return Mathf.Lerp((float)Waystones.cooldownMinimum.Value, (float)Waystones.cooldownMaximum.Value, (num - (float)Waystones.cooldownDistanceMinimum.Value) / (float)(Waystones.cooldownDistanceMaximum.Value - Waystones.cooldownDistanceMinimum.Value)); } public static int GetTravelChargeCost(Vector3 from, Vector3 target) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) int minWaystoneChargeCost = MinWaystoneChargeCost; int maxWaystoneChargeCost = MaxWaystoneChargeCost; if (target == Vector3.zero) { return minWaystoneChargeCost; } float num = Utils.DistanceXZ(from, target); int minWaystoneChargeDistance = MinWaystoneChargeDistance; int maxWaystoneChargeDistance = MaxWaystoneChargeDistance; if (num < (float)minWaystoneChargeDistance) { return minWaystoneChargeCost; } if (num > (float)maxWaystoneChargeDistance) { return maxWaystoneChargeCost; } if (maxWaystoneChargeDistance == minWaystoneChargeDistance) { return maxWaystoneChargeCost; } float num2 = (num - (float)minWaystoneChargeDistance) / (float)(maxWaystoneChargeDistance - minWaystoneChargeDistance); return Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp((float)minWaystoneChargeCost, (float)maxWaystoneChargeCost, num2)), minWaystoneChargeCost, maxWaystoneChargeCost); } public static int GetDefaultCharge() { return Waystones.defaultWaystoneChargeFull.Value ? MaxWaystoneCharge : 0; } private int GetStoredPlayerCharge() { return playerChargeInitialized ? playerCharge : GetDefaultCharge(); } private static int NormalizeStoredCharge(int charge) { return Waystones.allowWaystoneChargeOverflow.Value ? charge : Mathf.Min(charge, MaxWaystoneCharge); } public static int GetPlayerCharge() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return 0; } WorldData worldData = GetWorldData(GetState()); return (worldData == null) ? GetDefaultCharge() : NormalizeStoredCharge(worldData.GetStoredPlayerCharge()); } public static int GetPotentialPlayerChargeAdded(int amount) { if (amount <= 0) { return 0; } int num = GetPlayerCharge(); if (Waystones.allowWaystoneChargeOverflow.Value) { return amount; } int num2 = Mathf.Min(num + amount, MaxWaystoneCharge); return Mathf.Max(0, num2 - num); } public static int AddPlayerCharge(int amount) { int potentialPlayerChargeAdded = GetPotentialPlayerChargeAdded(amount); if (potentialPlayerChargeAdded <= 0 || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return 0; } List state = GetState(); WorldData worldData = GetWorldData(state, createIfEmpty: true); int num = NormalizeStoredCharge(worldData.GetStoredPlayerCharge()); worldData.playerChargeInitialized = true; worldData.playerCharge = num + potentialPlayerChargeAdded; Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Waystones.LogInfo($"Player waystone charge added: +{potentialPlayerChargeAdded}, current: {worldData.playerCharge}"); return potentialPlayerChargeAdded; } public static bool TryConsumePlayerCharge(int amount, bool allowOverdraftWhenPositive) { if (amount <= 0 || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } List state = GetState(); WorldData worldData = GetWorldData(state, createIfEmpty: true); int num = NormalizeStoredCharge(worldData.GetStoredPlayerCharge()); if (num < amount && (!allowOverdraftWhenPositive || num <= 0)) { return false; } worldData.playerChargeInitialized = true; worldData.playerCharge = num - amount; Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Waystones.LogInfo($"Player waystone charge consumed: -{amount}, current: {worldData.playerCharge}"); return true; } private static DateTime GetTime() { return DateTime.Now.ToUniversalTime(); } internal static WorldData GetWorldData(List state, bool createIfEmpty = false) { long uid = ZNet.instance.GetWorldUID(); WorldData worldData = state.Find((WorldData d) => d.worldUID == uid); if (createIfEmpty && worldData == null) { worldData = new WorldData { worldUID = uid }; state.Add(worldData); } return worldData; } public static void SetCooldown(double cooldown) { if (Object.op_Implicit((Object)(object)ZNet.instance)) { List state = GetState(); GetWorldData(state, createIfEmpty: true).SetCooldownTime(cooldown); Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Waystones.LogInfo("Cooldown set " + TimerString(cooldown)); } } public static bool TryReduceCooldown(int seconds) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } List state = GetState(); WorldData worldData = GetWorldData(state); if (worldData == null) { return false; } worldData.SetCooldownTime(Math.Max(worldData.GetCooldownTime() - (double)seconds, 0.0)); Player.m_localPlayer.m_customData["Waystones"] = SaveWorldDataList(state); Waystones.LogInfo("Cooldown set " + TimerString(worldData.GetCooldownTime())); return true; } internal static bool IsOnCooldown() { WorldData worldData = GetWorldData(GetState()); return worldData != null && worldData.GetCooldownTime() > 0.0; } internal static string GetCooldownString() { WorldData worldData = GetWorldData(GetState()); return (worldData == null) ? "" : TimerString(worldData.GetCooldownTime()); } public static string TimerString(double seconds) { if (seconds < 60.0) { return DateTime.FromBinary(599266080000000000L).AddSeconds(seconds).ToString("ss\\s"); } TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); if (timeSpan.Hours > 0) { return string.Format("{0}{1}", (int)timeSpan.TotalHours, new DateTime(timeSpan.Ticks).ToString("\\h mm\\m")); } if (timeSpan.Seconds == 0) { return new DateTime(timeSpan.Ticks).ToString("mm\\m"); } return new DateTime(timeSpan.Ticks).ToString("mm\\m ss\\s"); } private static List GetState() { string value; return Player.m_localPlayer.m_customData.TryGetValue("Waystones", out value) ? GetWorldDataList(value) : new List(); } private static List GetWorldDataList(string value) { List data = new List(); CollectionExtensions.Do(SplitToLines(value), (Action)delegate(string line) { data.Add(JsonUtility.FromJson(line)); }); return data; } private static string SaveWorldDataList(List list) { StringBuilder sb = new StringBuilder(); CollectionExtensions.Do((IEnumerable)list, (Action)delegate(WorldData data) { sb.AppendLine(JsonUtility.ToJson((object)data)); }); return sb.ToString(); } [IteratorStateMachine(typeof(d__43))] private static IEnumerable SplitToLines(string input) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__43(-2) { <>3__input = input }; } } [BepInPlugin("shudnal.Waystones", "Waystones", "1.1.0")] public class Waystones : BaseUnityPlugin { public enum CooldownTime { WorldTime, GlobalTime } public enum WaystoneMode { Cooldown, Charge, Orientation } public enum ChargeStorage { Waystone, Player } public enum DistanceUnit { Meters, Yards } [HarmonyPatch(typeof(ZInput), "GetMouseDelta")] public static class ZInput_GetMouseDelta_PreventMouseInput { [HarmonyPriority(0)] public static void Postfix(ref Vector2 __result) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (PreventPlayerInput()) { __result = Vector2.zero; } } } [HarmonyPatch] public static class JoyRightStick_SlowFactor { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZInput), "GetJoyRightStickX", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(ZInput), "GetJoyRightStickY", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0))] private static IEnumerable TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2); } private static void Postfix(ref float __result) { if (PreventPlayerInput()) { __result = 0f; } } } [HarmonyPatch(typeof(PlayerController), "TakeInput")] public static class PlayerController_TakeInput_PreventPlayerMovements { [HarmonyPriority(800)] public static bool Prefix() { return !PreventPlayerInput(); } } [HarmonyPatch(typeof(Player), "SetMouseLook")] public static class Player_SetMouseLook_PreventPlayerMovements { [HarmonyPriority(800)] public static void Prefix(Player __instance, ref Vector2 mouseLook) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (((Character)__instance).GetSEMan().HaveStatusEffect(SE_Waystone.statusEffectWaystonesHash)) { mouseLook = Vector2.zero; } } } [HarmonyPatch(typeof(Player), "ActivateGuardianPower")] public static class Player_ActivateGuardianPower_PreventGPowerUseWhenTeleporting { private static bool Prefix(Player __instance) { return !((Character)__instance).GetSEMan().HaveStatusEffect(SE_Waystone.statusEffectWaystonesHash); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] public static class ZoneSystem_Start_InitSeasonStateAndConfigWatcher { private static void Postfix() { SetupConfigWatcher(enabled: true); } } [HarmonyPatch(typeof(ZoneSystem), "OnDestroy")] public static class ZoneSystem_OnDestroy_DisableConfigWatcher { private static void Postfix() { SetupConfigWatcher(enabled: false); } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static EventHandler <>9__89_0; public static ConsoleEvent <>9__92_0; internal void b__89_0(object sender, EventArgs args) { PieceWaystone.SetPieceRequirements(); } internal void b__92_0(ConsoleEventArgs args) { WorldData.SetCooldown(args.TryParameterInt(1, 0)); } } public const string pluginID = "shudnal.Waystones"; public const string pluginName = "Waystones"; public const string pluginVersion = "1.1.0"; private readonly Harmony harmony = new Harmony("shudnal.Waystones"); internal static readonly ConfigSync configSync = new ConfigSync("shudnal.Waystones") { DisplayName = "Waystones", CurrentVersion = "1.1.0", MinimumRequiredVersion = "1.1.0" }; internal static Waystones instance; internal static ConfigEntry configLocked; internal static ConfigEntry loggingEnabled; internal static ConfigEntry shortcut; internal static ConfigEntry pieceRecipe; internal static ConfigEntry itemSacrifitionReduceCooldown; internal static ConfigEntry showSacrificeItemsInHover; internal static ConfigEntry disableWaystoneSparcs; internal static ConfigEntry locationWaystonesShowOnMap; internal static ConfigEntry locationShowCurrentSpawn; internal static ConfigEntry locationShowLastPoint; internal static ConfigEntry locationShowLastShip; internal static ConfigEntry locationShowLastTombstone; internal static ConfigEntry locationShowStartTemple; internal static ConfigEntry locationShowHaldor; internal static ConfigEntry locationShowHildir; internal static ConfigEntry locationShowBogWitch; internal static ConfigEntry locationShowWaystones; internal static ConfigEntry locationShowRandomPoint; internal static ConfigEntry useShortcutToEnter; internal static ConfigEntry allowEncumbered; internal static ConfigEntry allowNonTeleportableItems; internal static ConfigEntry emitNoiseOnTeleportation; internal static ConfigEntry allowWet; internal static ConfigEntry allowSensed; internal static ConfigEntry allowNonSitting; internal static ConfigEntry tagCharactersLimit; internal static ConfigEntry allowForEveryone; internal static ConfigEntry directionSensitivity; internal static ConfigEntry directionSensitivityThreshold; internal static ConfigEntry fadeMax; internal static ConfigEntry fadeMin; internal static ConfigEntry slowFactorTime; internal static ConfigEntry slowFactorLookDeceleration; internal static ConfigEntry slowFactorLookMinimum; internal static ConfigEntry fovDelta; internal static ConfigEntry sfxSensitivityThreshold; internal static ConfigEntry sfxMax; internal static ConfigEntry sfxMin; internal static ConfigEntry sfxPitchMax; internal static ConfigEntry sfxPitchMin; internal static ConfigEntry cooldownTime; internal static ConfigEntry cooldownMaximum; internal static ConfigEntry cooldownMinimum; internal static ConfigEntry cooldownDistanceMaximum; internal static ConfigEntry cooldownDistanceMinimum; internal static ConfigEntry cooldownShort; internal static ConfigEntry cooldownSearchMode; internal static ConfigEntry waystoneMode; internal static ConfigEntry maxWaystoneCharge; internal static ConfigEntry allowWaystoneChargeOverdraft; internal static ConfigEntry defaultWaystoneChargeFull; internal static ConfigEntry allowWaystoneChargeOverflow; internal static ConfigEntry waystoneChargeStorage; internal static ConfigEntry chargeCostMaximum; internal static ConfigEntry chargeCostMinimum; internal static ConfigEntry chargeDistanceMaximum; internal static ConfigEntry chargeDistanceMinimum; internal static ConfigEntry orientationWaystoneVisibilityDistance; internal static ConfigEntry orientationDistanceUnit; internal static ConfigEntry orientationShowDistantCurrentSpawn; internal static ConfigEntry orientationShowDistantLastPoint; internal static ConfigEntry orientationShowDistantLastShip; internal static ConfigEntry orientationShowDistantLastTombstone; internal static ConfigEntry orientationShowDistantStartTemple; internal static ConfigEntry orientationShowDistantHaldor; internal static ConfigEntry orientationShowDistantHildir; internal static ConfigEntry orientationShowDistantBogWitch; internal static ConfigEntry orientationShowDistantWaystones; internal static ConfigEntry particlesCollision; internal static ConfigEntry particlesMaxAmount; internal static ConfigEntry particlesMinRateOverTime; internal static ConfigEntry particlesMaxRateOverTime; internal static ConfigEntry particlesMinForceOverTime; internal static ConfigEntry particlesMaxForceOverTime; public static readonly CustomSyncedValue> itemsToReduceCooldown = new CustomSyncedValue>(configSync, "Items to reduce cooldowns", new Dictionary()); public static string configDirectory; internal static FileSystemWatcher configWatcher; private const string itemsToReduceCooldownFilter = "shudnal.Waystones.reduce_cooldowns.*"; private void Awake() { harmony.PatchAll(); instance = this; ConfigInit(); configSync.AddLockingConfigEntry(configLocked); Game.isModded = true; configDirectory = Path.Combine(Paths.ConfigPath, "shudnal.Waystones"); LoadIcons(); ((MonoBehaviour)this).StartCoroutine(Localizer.Load()); } public void ConfigInit() { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Expected O, but got Unknown //IL_0713: Unknown result type (might be due to invalid IL or missing references) //IL_071e: Expected O, but got Unknown config("General", "NexusID", 2832, "Nexus mod ID for updates", synchronizedSetting: false); configLocked = config("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only."); loggingEnabled = config("General", "Logging enabled", defaultValue: false, "Enable logging. [Not Synced with Server]", synchronizedSetting: false); pieceRecipe = config("General", "Recipe", "SurtlingCore:1,GreydwarfEye:5,Stone:5", "Piece recipe"); disableWaystoneSparcs = config("General", "Disable waystone sparcs", defaultValue: false, "Enable sacrifition of item from list to reduce waystone cooldown. Restart required. [Not Synced with Server]", synchronizedSetting: false); waystoneMode = config("General", "Waystone mode", WaystoneMode.Cooldown, "Cooldown - You will only be able to teleport again after the specified time has passed\nCharge - requires waystone to be charged to start teleportation, charges consumption depends on distance, no cooldown on teleportation\nOrientation - Use waystones only for navigation, not teleportation"); maxWaystoneCharge = config("General", "Max waystone charge", 100, new ConfigDescription("Maximum waystone charge for Charge mode.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100000), Array.Empty())); allowWaystoneChargeOverdraft = config("Charge mode", "Allow charge overdraft", defaultValue: true, "If enabled, teleportation can consume more charge than the source waystone currently has as long as its charge is positive. This may leave negative charge."); defaultWaystoneChargeFull = config("Charge mode", "Default charge is full", defaultValue: false, "If enabled, waystones without stored charge data start with maximum charge. If disabled, they start empty."); allowWaystoneChargeOverflow = config("Charge mode", "Allow charge above maximum", defaultValue: true, "If enabled, item sacrifices can increase stored charge above Max waystone charge, but only once."); waystoneChargeStorage = config("Charge mode", "Charge storage", ChargeStorage.Waystone, "Where charge is stored and consumed.\nWaystone - item sacrifices charge the interacted waystone, and travel consumes the source waystone charge.\nPlayer - item sacrifices charge the player in current world data, and travel consumes player charge."); pieceRecipe.SettingChanged += delegate { PieceWaystone.SetPieceRequirements(); }; itemSacrifitionReduceCooldown = config("Item sacrifition", "Sacrifice item from list to reduce cooldown", defaultValue: true, "Enable sacrifition of item from list to reduce waystone cooldown"); showSacrificeItemsInHover = config("Item sacrifition", "Show available sacrifice items in hover text", defaultValue: true, "Show sacrifice items available to the player in waystone hover text. [Not Synced with Server]", synchronizedSetting: false); locationWaystonesShowOnMap = config("Locations", "Show waystones on map", defaultValue: true, "Show waystone map pins"); locationShowCurrentSpawn = config("Locations", "Show current spawn", defaultValue: true, "Show current spawn point in search mode"); locationShowLastPoint = config("Locations", "Show last location", defaultValue: true, "Show last location from where you used fast travel last time in search mode"); locationShowLastShip = config("Locations", "Show last ship", defaultValue: true, "Show last ship position in search mode"); locationShowLastTombstone = config("Locations", "Show last tombstone", defaultValue: true, "Show last death position in search mode"); locationShowStartTemple = config("Locations", "Show sacrificial stones", defaultValue: true, "Show sacrificial stones positioin in search mode"); locationShowHaldor = config("Locations", "Show Haldor", defaultValue: true, "Show Haldor location in search mode"); locationShowHildir = config("Locations", "Show Hildir", defaultValue: true, "Show Hildir location in search mode"); locationShowBogWitch = config("Locations", "Show Bog Witch", defaultValue: true, "Show Bog Witch location in search mode"); locationShowWaystones = config("Locations", "Show waystones", defaultValue: true, "Show waystones network in search mode"); locationShowRandomPoint = config("Locations", "Show random point", defaultValue: true, "Show random point position in search mode"); emitNoiseOnTeleportation = config("Restrictions", "Emit noise on fast travelling", defaultValue: true, "If enabled then you will attract attention of nearby enemies on fast travelling start."); allowEncumbered = config("Restrictions", "Ignore encumbered to start search", defaultValue: false, "If enabled then encumbrance check before search start will be omitted."); allowNonTeleportableItems = config("Restrictions", "Ignore nonteleportable items to start search", defaultValue: false, "If enabled then inventory check before search start will be omitted."); allowWet = config("Restrictions", "Ignore wet status to start search", defaultValue: false, "If enabled then Wet status check before search start will be omitted."); allowSensed = config("Restrictions", "Ignore nearby enemies to start search", defaultValue: false, "If enabled then Sensed by nearby enemies check before search start will be omitted."); allowNonSitting = config("Restrictions", "Ignore sitting to start search", defaultValue: false, "If enabled then sitting position check before search start will be omitted."); useShortcutToEnter = config("Restrictions", "Use shortcut to toggle search mode", defaultValue: false, "If set you can enter direction search mode by pressing shortcut. If not set - you have to sit in front of the waystone to start search mode."); shortcut = config("Restrictions", "Shortcut", new KeyboardShortcut((KeyCode)121, Array.Empty()), "Enter/Exit direction search mode [Not Synced with Server]", synchronizedSetting: false); tagCharactersLimit = config("Restrictions", "Tag characters limit", 15, "Max length of waystone tag. Values less than 10 will be ignored."); allowForEveryone = config("Restrictions", "Allow all players to use activated waystones", defaultValue: false, "If enabled, any player can use a waystone once it has been activated by someone."); directionSensitivity = config("Search mode", "Target sensitivity threshold", 2f, "Angle between look direction and target direction for location to appear in search mode"); directionSensitivityThreshold = config("Search mode", "Screen sensitivity threshold", 6f, "Angle between look direction and target direction for location to start appearing in search mode"); fadeMax = config("Search mode", "Screen fade max", 0.98f, "Screen darkness when sensitivity threshold is not met."); fadeMin = config("Search mode", "Screen fade min", 0.88f, "Screen darkness when looking at target"); sfxSensitivityThreshold = config("Search mode", "Sound effect sensitivity threshold", 20f, "Angle between look direction and target direction for sound to start appearing in direction search mode"); sfxMax = config("Search mode", "Sound effect max volume", 1.1f, "Volume of sound effect played in direction mode when looking at a target [Not Synced with Server]", synchronizedSetting: false); sfxMin = config("Search mode", "Sound effect min volume", 0.4f, "Volume of sound effect played in direction mode when sensitivity threshold is not met [Not Synced with Server]", synchronizedSetting: false); sfxPitchMax = config("Search mode", "Sound effect max pitch", 1f, "Pitch of sound effect played in direction mode when looking at a target"); sfxPitchMin = config("Search mode", "Sound effect min pitch", 0.8f, "Pitch of sound effect played in direction mode when sensitivity threshold is not met."); slowFactorTime = config("Search mode", "Slow factor time", 0.25f, "Multiplier of speed \u200b\u200bof time (singleplayer)"); slowFactorLookDeceleration = config("Search mode", "Slow factor mouse deceleration", 40f, "Mouse camera sensitivity acceleration factor. [Not Synced with Server]\nIncrease to make mouse acceleration proportionally lower, decrease to make mouse movement faster ", synchronizedSetting: false); slowFactorLookMinimum = config("Search mode", "Slow factor mouse minimum", 0.08f, "Minimum mouse camera sensitivity factor in search mode. [Not Synced with Server]", synchronizedSetting: false); fovDelta = config("Search mode", "FoV delta", 40f, "How much camera FoV can be changed both sides using zoom"); cooldownTime = config("Travel cooldown", "Time", CooldownTime.WorldTime, "Time type to calculate cooldown.\nWorld time - calculate from time passed in game world\nGlobal time - calculate from real world time"); cooldownDistanceMaximum = config("Travel cooldown", "Fast travelling distance maximum", 5000, "If fast travelling distance is larger then that cooldown will be set to maximum. World radius is 10000."); cooldownDistanceMinimum = config("Travel cooldown", "Fast travelling distance minimum", 500, "If fast travelling distance is smaller then that cooldown will be set to minimum. World radius is 10000."); cooldownMaximum = config("Travel cooldown", "Fast travelling cooldown maximum", 7200, "Maximal cooldown to be set after successfull fast travelling"); cooldownMinimum = config("Travel cooldown", "Fast travelling cooldown minimum", 600, "Minimal cooldown to be set after successfull fast travelling"); cooldownShort = config("Travel cooldown", "Fast travelling interrupted cooldown", 60, "Cooldown to be set if fast travelling was interrupted"); cooldownSearchMode = config("Travel cooldown", "Search mode cooldown", 30, "Cooldown to be set on search mode exit"); chargeDistanceMaximum = config("Travel charge", "Fast travelling distance maximum", 5000, "If fast travelling distance is larger than that, charge cost will be set to maximum. World radius is 10000."); chargeDistanceMinimum = config("Travel charge", "Fast travelling distance minimum", 500, "If fast travelling distance is smaller than that, charge cost will be set to minimum. World radius is 10000."); chargeCostMaximum = config("Travel charge", "Fast travelling charge maximum", 50, new ConfigDescription("Maximum charge cost after successful fast travelling.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100000), Array.Empty())); chargeCostMinimum = config("Travel charge", "Fast travelling charge minimum", 20, new ConfigDescription("Minimum charge cost after successful fast travelling.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 100000), Array.Empty())); orientationWaystoneVisibilityDistance = config("Orientation mode", "Waystone visibility distance", 1000, "Maximum distance to show other waystones in orientation mode."); orientationDistanceUnit = config("Orientation mode", "Distance unit", DistanceUnit.Meters, "Displayed units for orientation mode distance."); orientationShowDistantCurrentSpawn = config("Orientation mode", "Show distant current spawn", defaultValue: true, "Show current spawn marker even if farther than orientation distance."); orientationShowDistantLastPoint = config("Orientation mode", "Show distant last location", defaultValue: true, "Show last location marker even if farther than orientation distance."); orientationShowDistantLastShip = config("Orientation mode", "Show distant last ship", defaultValue: true, "Show last ship marker even if farther than orientation distance."); orientationShowDistantLastTombstone = config("Orientation mode", "Show distant last tombstone", defaultValue: true, "Show last tombstone marker even if farther than orientation distance."); orientationShowDistantStartTemple = config("Orientation mode", "Show distant sacrificial stones", defaultValue: true, "Show sacrificial stones marker even if farther than orientation distance."); orientationShowDistantHaldor = config("Orientation mode", "Show distant Haldor", defaultValue: true, "Show Haldor marker even if farther than orientation distance."); orientationShowDistantHildir = config("Orientation mode", "Show distant Hildir", defaultValue: true, "Show Hildir marker even if farther than orientation distance."); orientationShowDistantBogWitch = config("Orientation mode", "Show distant Bog Witch", defaultValue: true, "Show Bog Witch marker even if farther than orientation distance."); orientationShowDistantWaystones = config("Orientation mode", "Show distant waystones", defaultValue: false, "Show player-built waystone markers even if farther than orientation distance."); particlesCollision = config("Travelling effect", "Particles physics collision", defaultValue: false, "Make particles emitted while fast travelling collide with objects. Restart required."); particlesMaxAmount = config("Travelling effect", "Particles amount maximum", 8000, "Maximum amount of particles emitted. Restart required."); particlesMaxRateOverTime = config("Travelling effect", "Particles rate over time maximum", 4000, "Maximum amount of particles emitted per second at the curve end. Restart required."); particlesMinRateOverTime = config("Travelling effect", "Particles rate over time minimum", 50, "Minimum amount of particles emitted per second at the curve start. Restart required."); particlesMaxForceOverTime = config("Travelling effect", "Particles force over time maximum", 10, "Maximum emission force of particles emitted at the curve end. Restart required."); particlesMinForceOverTime = config("Travelling effect", "Particles force over time minimum", 5, "Minimum emission force of particles emitted at the curve start. Restart required."); InitCommands(); } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); instance = null; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } public void LateUpdate() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType != 4 && !((Object)(object)Player.m_localPlayer == (Object)null)) { if (((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && Object.op_Implicit((Object)(object)TextViewer.instance) && !TextViewer.instance.IsVisible() && !((Character)Player.m_localPlayer).InCutscene() && ((Character)Player.m_localPlayer).GetSEMan().HaveStatusEffect(SE_Waystone.statusEffectWaystonesHash) && (ZInput.GetButtonDown("Block") || ZInput.GetButtonDown("JoyButtonB"))) { ZInput.ResetButtonStatus("Block"); ZInput.ResetButtonStatus("JoyButtonB"); ((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect(SE_Waystone.statusEffectWaystonesHash, false); } DirectionSearch.Update(); } } public static void InitCommands() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown object obj = <>c.<>9__92_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { WorldData.SetCooldown(args.TryParameterInt(1, 0)); }; <>c.<>9__92_0 = val; obj = (object)val; } new ConsoleCommand("setwaystonecooldown", "seconds", (ConsoleEvent)obj, true, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } public static void TeleportAttempt(Vector3 targetPoint, Quaternion targetRotation, double cooldown, string location) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) TeleportAttempt(targetPoint, targetRotation, cooldown, location, null, 0); } internal static void TeleportAttempt(Vector3 targetPoint, Quaternion targetRotation, double cooldown, string location, WaystoneList.WaystoneData sourceWaystone, int travelCost) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if (!CanCast()) { return; } if (!Utility.IsNullOrWhiteSpace(location)) { MessageHud.instance.ShowMessage((MessageType)1, "$ws_tooltip_moving_to " + location, 0, (Sprite)null, false); } SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan(); if (sEMan.HaveStatusEffect(SE_Waystone.statusEffectWaystonesHash)) { ((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect(SE_Waystone.statusEffectWaystonesHash, false); return; } bool validateCharge = waystoneMode.Value != WaystoneMode.Charge || travelCost <= 0; if (!WaystoneSmall.IsSearchAllowed(Player.m_localPlayer, validateCharge)) { return; } SE_Waystone sE_Waystone = ((Character)Player.m_localPlayer).GetSEMan().AddStatusEffect(SE_Waystone.statusEffectWaystonesHash, false, 0, 0f) as SE_Waystone; if ((Object)(object)sE_Waystone != (Object)null) { sE_Waystone.targetPoint = targetPoint; sE_Waystone.targetCooldown = cooldown; sE_Waystone.targetRotation = targetRotation; sE_Waystone.sourceWaystone = sourceWaystone; sE_Waystone.travelCost = travelCost; if (emitNoiseOnTeleportation.Value) { ((Character)Player.m_localPlayer).AddNoise(50f); BaseAI.DoProjectileHitNoise(((Component)Player.m_localPlayer).transform.position, 50f, (Character)(object)Player.m_localPlayer); } if (!Utility.IsNullOrWhiteSpace(location)) { MessageHud.instance.ShowMessage((MessageType)2, "$ws_message_travelling_to " + location, 0, (Sprite)null, false); ((StatusEffect)sE_Waystone).m_name = location; LogInfo($"Teleport initiated to {location} pos {targetPoint} cooldown {WorldData.TimerString(cooldown)}"); } } } public static bool CanCast() { Player localPlayer = Player.m_localPlayer; return !((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !((Character)localPlayer).InCutscene() && !((Character)localPlayer).IsTeleporting() && !((Character)localPlayer).InInterior() && ((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible() && (Object)(object)TextViewer.instance != (Object)null && !TextViewer.instance.IsVisible() && !TextInput.IsVisible() && !GameCamera.InFreeFly() && !StoreGui.IsVisible() && !InventoryGui.IsVisible(); } public static void LogInfo(object data) { if (loggingEnabled.Value) { ((BaseUnityPlugin)instance).Logger.LogInfo(data); } } private ConfigEntry config(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind(group, name, defaultValue, description); SyncedConfigEntry syncedConfigEntry = configSync.AddConfigEntry(val); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return val; } private ConfigEntry config(string group, string name, T defaultValue, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } private void LoadIcons() { LoadIcon("SE_Waystone.png", ref SE_Waystone.iconWaystones); LoadIcon("item_waystone.png", ref PieceWaystone.itemWaystone); LoadIcon("icon_waystone.png", ref WaystoneList.iconWaystone); } internal static void LoadIcon(string filename, ref Sprite icon) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Texture2D tex = new Texture2D(2, 2); if (LoadTexture(filename, ref tex)) { icon = Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), Vector2.zero); } } internal static bool LoadTexture(string filename, ref Texture2D tex) { string text = Path.Combine(configDirectory, filename); if (File.Exists(text)) { LogInfo("Loaded image: " + text); return ImageConversion.LoadImage(tex, File.ReadAllBytes(text)); } Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename)); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(name); byte[] array = new byte[manifestResourceStream.Length]; manifestResourceStream.Read(array, 0, array.Length); ((Object)tex).name = Path.GetFileNameWithoutExtension(filename); return ImageConversion.LoadImage(tex, array, true); } private static bool PreventPlayerInput() { return (Object)(object)Player.m_localPlayer != (Object)null && ((Character)Player.m_localPlayer).GetSEMan().HaveStatusEffect(SE_Waystone.statusEffectWaystonesHash); } public static void SetupConfigWatcher(bool enabled) { if (Directory.Exists(Paths.ConfigPath)) { if (enabled) { ReadInitialConfigs(); } if (configWatcher == null) { configWatcher = new FileSystemWatcher(Paths.ConfigPath, "shudnal.Waystones.reduce_cooldowns.*"); configWatcher.Changed += ReadConfigs; configWatcher.Created += ReadConfigs; configWatcher.Renamed += ReadConfigs; configWatcher.Deleted += ReadConfigs; configWatcher.IncludeSubdirectories = false; configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; } configWatcher.EnableRaisingEvents = enabled; } } internal static void ReadInitialConfigs() { FileInfo[] files = new DirectoryInfo(Paths.ConfigPath).GetFiles("shudnal.Waystones.reduce_cooldowns.*", SearchOption.AllDirectories); foreach (FileInfo fileInfo in files) { ReadConfigFile(fileInfo.Name, fileInfo.FullName); } } private static void ReadConfigs(object sender, FileSystemEventArgs eargs) { if (eargs is RenamedEventArgs) { ReadInitialConfigs(); } else { ReadConfigFile(eargs.Name, eargs.FullPath); } } private static void ReadConfigFile(string filename, string fullname) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Dictionary dictionary = new Dictionary(); try { string text = File.ReadAllText(fullname); if (text != null) { foreach (KeyValuePair item in ((BuilderSkeleton)new DeserializerBuilder()).IgnoreFields().Build().Deserialize>(text) ?? new Dictionary()) { if (item.Value > 0) { string text2 = NormalizeSacrificeItemKey(item.Key); if (!Utility.IsNullOrWhiteSpace(text2)) { dictionary[text2] = item.Value; } } } } } catch (Exception ex) { LogInfo("Error reading file (" + fullname + ")! Error: " + ex.Message); } itemsToReduceCooldown.AssignValueSafe(dictionary); LogInfo($"Loaded {dictionary.Count} items from file {filename}"); } private static string NormalizeSacrificeItemKey(string key) { if (Utility.IsNullOrWhiteSpace(key)) { return ""; } key = key.Trim(); int num = key.LastIndexOf(':'); if (num < 0) { return key.GetItemName(); } string text = key.Substring(0, num).Trim(); string text2 = key.Substring(num + 1).Trim(); if (Utility.IsNullOrWhiteSpace(text)) { return ""; } if (Utility.IsNullOrWhiteSpace(text2)) { return text.GetItemName(); } return text.GetItemName() + ":" + text2; } } public class SE_Waystone : SE_Stats { [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_AddStatusEffects { public static void AddCustomStatusEffects(ObjectDB odb) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00e5: Expected O, but got Unknown RegisterEffects(); if (odb.m_StatusEffects.Count > 0 && !odb.m_StatusEffects.Any((StatusEffect se) => ((Object)se).name == "WaystoneFastTravel")) { SE_Waystone sE_Waystone = ScriptableObject.CreateInstance(); ((Object)sE_Waystone).name = "WaystoneFastTravel"; ((StatusEffect)sE_Waystone).m_nameHash = statusEffectWaystonesHash; ((StatusEffect)sE_Waystone).m_icon = iconWaystones; ((SE_Stats)sE_Waystone).m_noiseModifier = 1f; ((SE_Stats)sE_Waystone).m_stealthModifier = -1f; ((SE_Stats)sE_Waystone).m_staminaDrainPerSec = 10f; ((StatusEffect)sE_Waystone).m_name = "$se_waystone_name"; ((StatusEffect)sE_Waystone).m_tooltip = "$se_waystone_tooltip"; ((StatusEffect)sE_Waystone).m_startEffects.m_effectPrefabs = (EffectData[])(object)new EffectData[1] { new EffectData { m_prefab = vfx_Waystones, m_enabled = true, m_inheritParentScale = true, m_attach = true } }; ((StatusEffect)sE_Waystone).m_ttl = 10f; odb.m_StatusEffects.Add((StatusEffect)(object)sE_Waystone); } } private static void Postfix(ObjectDB __instance) { AddCustomStatusEffects(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class ObjectDB_CopyOtherDB_AddStatusEffects { private static void Postfix(ObjectDB __instance) { ObjectDB_Awake_AddStatusEffects.AddCustomStatusEffects(__instance); } } [HarmonyPatch(typeof(Player), "ActivateGuardianPower")] public static class Player_ActivateGuardianPower_PreventGuardianPower { private static bool Prefix(Player __instance) { return !((Character)__instance).GetSEMan().HaveStatusEffect(statusEffectWaystonesHash) && !(blockGPTime > Time.time); } } public const string statusEffectWaystonesName = "WaystoneFastTravel"; public static readonly int statusEffectWaystonesHash = StringExtensionMethods.GetStableHashCode("WaystoneFastTravel"); public const string vfx_WaystonesName = "vfx_Waystones"; public static readonly int vfx_WaystonesHash = StringExtensionMethods.GetStableHashCode("vfx_Waystones"); public const string vfx_WaystonesParticles = "Sparcs"; public const string vfx_WaystonesSfx = "Sfx"; public const string vfx_WaystonesLight = "Light"; public const string statusEffectName = "$se_waystone_name"; public const string statusEffectTooltip = "$se_waystone_tooltip"; public static Sprite iconWaystones; public static GameObject vfx_Waystones; public static float blockGPTime; [NonSerialized] public Vector3 targetPoint = Vector3.zero; [NonSerialized] public Quaternion targetRotation = Quaternion.identity; [NonSerialized] public double targetCooldown = 0.0; [NonSerialized] internal WaystoneList.WaystoneData sourceWaystone; [NonSerialized] internal int travelCost; [NonSerialized] private bool lookDirTriggered; [NonSerialized] private bool teleportTriggered; [NonSerialized] private ZNetView effectNetView; public override void UpdateStatusEffect(float dt) { //IL_01b7: 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_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) ((SE_Stats)this).UpdateStatusEffect(dt); if (((StatusEffect)this).m_startEffectInstances == null) { return; } if ((Object)(object)effectNetView == (Object)null) { effectNetView = ((StatusEffect)this).m_startEffectInstances[0].GetComponent(); } WaystoneTravelEffect.SetProgress(effectNetView, ((StatusEffect)this).m_time / ((StatusEffect)this).m_ttl); if (ControlLocalPlayer()) { Player localPlayer = Player.m_localPlayer; if (!lookDirTriggered && targetPoint != Vector3.zero) { lookDirTriggered = true; ((Character)localPlayer).SetLookDir(targetPoint - ((Component)localPlayer).transform.position, 5f); blockGPTime = Time.time + ((StatusEffect)this).m_ttl + 1f; ((Character)localPlayer).GetZAnim().SetTrigger("gpower"); } if (((Character)localPlayer).m_lookTransitionTime > 0f) { ((Component)localPlayer).transform.rotation = ((Character)localPlayer).m_lookYaw; } localPlayer.SetMouseLookForward(false); localPlayer.m_lookPitch = Mathf.MoveTowards(localPlayer.m_lookPitch, 0f, dt * 10f); ((Character)localPlayer).GetZAnim().SetSpeed(0.125f); if (!teleportTriggered && ((StatusEffect)this).GetRemaningTime() < 0.75f && targetPoint != Vector3.zero) { ((Character)localPlayer).TeleportTo(targetPoint, (targetRotation == Quaternion.identity) ? ((Component)localPlayer).transform.rotation : targetRotation, true); WorldData.SaveLastPosition(((Component)localPlayer).transform.position); teleportTriggered = true; } } if (targetPoint != Vector3.zero) { Vector3 val = targetPoint - ((Component)((StatusEffect)this).m_character).transform.position; ((Vector3)(ref val)).Normalize(); ((StatusEffect)this).m_startEffectInstances[0].transform.rotation = Quaternion.LookRotation(val); ((StatusEffect)this).m_startEffectInstances[0].transform.localPosition = Vector3.MoveTowards(((StatusEffect)this).m_startEffectInstances[0].transform.localPosition, new Vector3(0f, 1.5f, -0.3f), dt / 10f); } } public override void Setup(Character character) { ((SE_Stats)this).Setup(character); character.StopEmote(); } public override void Stop() { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) ((StatusEffect)this).Stop(); if (!Object.op_Implicit((Object)(object)((StatusEffect)this).m_character)) { return; } ((StatusEffect)this).m_character.GetZAnim().SetSpeed(1f); ((StatusEffect)this).m_character.m_lookTransitionTime = 0f; if ((Object)(object)((StatusEffect)this).m_character == (Object)(object)Player.m_localPlayer) { if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Cooldown) { WorldData.SetCooldown(teleportTriggered ? targetCooldown : ((double)Waystones.cooldownShort.Value)); } else if (Waystones.waystoneMode.Value == Waystones.WaystoneMode.Charge && teleportTriggered && travelCost > 0 && !WaystoneList.TryConsumeTravelCharge(sourceWaystone, Player.m_localPlayer.GetPlayerID(), travelCost, Waystones.allowWaystoneChargeOverdraft.Value)) { Waystones.LogInfo($"Failed to consume travel charge after teleport. Cost: {travelCost}, storage: {Waystones.waystoneChargeStorage.Value}, source: {((sourceWaystone == null) ? Vector3.zero : sourceWaystone.worldPosition)}"); } } } public override void OnDamaged(HitData hit, Character attacker) { ((StatusEffect)this).OnDamaged(hit, attacker); if (!((Object)(object)attacker == (Object)null)) { ((StatusEffect)this).m_time = ((StatusEffect)this).m_time - 1f; blockGPTime += 1f; } } private bool ControlLocalPlayer() { return (Object)(object)((StatusEffect)this).m_character != (Object)null && (Object)(object)((StatusEffect)this).m_character == (Object)(object)Player.m_localPlayer; } public static void RegisterEffects() { //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_025d: 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_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { return; } if (!Object.op_Implicit((Object)(object)vfx_Waystones)) { WayStone val = Resources.FindObjectsOfTypeAll().FirstOrDefault(); if ((Object)(object)val == (Object)null) { return; } vfx_Waystones = CustomPrefabs.InitPrefabClone(ObjectDB.instance.GetStatusEffect(SEMan.s_statusEffectCold).m_startEffects.m_effectPrefabs[0].m_prefab, "vfx_Waystones"); for (int num = vfx_Waystones.transform.childCount - 1; num >= 0; num--) { Transform child = vfx_Waystones.transform.GetChild(num); child.parent = null; Object.Destroy((Object)(object)((Component)child).gameObject); } WaystoneTravelEffect.initial = true; vfx_Waystones.AddComponent(); WaystoneTravelEffect.initial = false; ZSyncTransform component = vfx_Waystones.GetComponent(); component.m_syncRotation = true; component.m_useGravity = false; component.m_syncScale = false; ((Object)Object.Instantiate(((Component)val).transform.Find("WayEffect/sfx"), vfx_Waystones.transform)).name = "Sfx"; GameObject gameObject = ((Component)Object.Instantiate(((Component)val).transform.Find("WayEffect/Point light"), vfx_Waystones.transform)).gameObject; ((Object)gameObject).name = "Light"; gameObject.transform.localPosition = new Vector3(0f, 0f, -0.2f); Light component2 = gameObject.GetComponent(); component2.cullingMask = -1; component2.shadows = (LightShadows)0; component2.intensity = 0f; GameObject gameObject2 = ((Component)Object.Instantiate(((Component)val).transform.Find("WayEffect/Particle System sparcs"), vfx_Waystones.transform)).gameObject; ((Object)gameObject2).name = "Sparcs"; gameObject2.transform.localPosition = new Vector3(0f, 0f, -0.1f); ParticleSystem component3 = gameObject2.GetComponent(); MainModule main = component3.main; ((MainModule)(ref main)).maxParticles = Waystones.particlesMaxAmount.Value; ((MainModule)(ref main)).duration = 20f; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).simulationSpeed = 1f; ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(1f); ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1f); EmissionModule emission = component3.emission; MinMaxCurve rateOverTime = ((EmissionModule)(ref emission)).rateOverTime; ((MinMaxCurve)(ref rateOverTime)).mode = (ParticleSystemCurveMode)1; ((MinMaxCurve)(ref rateOverTime)).curve = AnimationCurve.Linear(0f, (float)Waystones.particlesMinRateOverTime.Value, 1f, (float)Waystones.particlesMaxRateOverTime.Value); ((EmissionModule)(ref emission)).rateOverTime = rateOverTime; if (Waystones.particlesCollision.Value) { CollisionModule collision = component3.collision; ((CollisionModule)(ref collision)).enabled = true; ((CollisionModule)(ref collision)).type = (ParticleSystemCollisionType)1; } ForceOverLifetimeModule forceOverLifetime = component3.forceOverLifetime; ((ForceOverLifetimeModule)(ref forceOverLifetime)).enabled = true; MinMaxCurve z = ((ForceOverLifetimeModule)(ref forceOverLifetime)).z; ((MinMaxCurve)(ref z)).mode = (ParticleSystemCurveMode)1; ((MinMaxCurve)(ref z)).curve = AnimationCurve.Linear(0f, (float)Waystones.particlesMinForceOverTime.Value, 1f, (float)Waystones.particlesMaxForceOverTime.Value); ((ForceOverLifetimeModule)(ref forceOverLifetime)).z = z; ((ForceOverLifetimeModule)(ref forceOverLifetime)).zMultiplier = 3f; } if (Object.op_Implicit((Object)(object)vfx_Waystones)) { if (ZNetScene.instance.m_namedPrefabs.ContainsKey(vfx_WaystonesHash)) { ZNetScene.instance.m_prefabs.Remove(ZNetScene.instance.m_namedPrefabs[vfx_WaystonesHash]); ZNetScene.instance.m_namedPrefabs.Remove(vfx_WaystonesHash); } ZNetScene.instance.m_prefabs.Add(vfx_Waystones); ZNetScene.instance.m_namedPrefabs.Add(vfx_WaystonesHash, vfx_Waystones); } } } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 ServerSync { [PublicAPI] public abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] public class SyncedConfigEntry : OwnConfigEntryBase { public readonly ConfigEntry SourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public SyncedConfigEntry(ConfigEntry sourceConfig) { SourceConfig = sourceConfig; base..ctor(); } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } public abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly string Identifier; public readonly Type Type; private object? boxedValue; protected bool localIsOwner; public readonly int Priority; public object? BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action? ValueChanged; protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] public sealed class CustomSyncedValue : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] public class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })); }).ToList(); List nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList(); SendAdmin(nonAdminPeer, isAdmin: false); SendAdmin(adminPeer, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary configValues = new Dictionary(); public readonly Dictionary customValues = new Dictionary(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished = false; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(ref Dictionary? __state, ZNet __instance, ZRpc rpc) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend > 0) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { ZRpc rpc2 = rpc; ZNet __instance2 = __instance; Dictionary __state2 = __state; ZNetPeer peer; if (__instance2.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance2).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc2.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc2, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance2, new object[1] { rpc2 }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state2[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List entries = new List(); if (configSync.CurrentVersion != null) { entries.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); entries.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)listContainsId == null) ? ((object)adminList.Contains(rpc2.GetSocket().GetHostName())) : listContainsId.Invoke(ZNet.instance, new object[2] { adminList, rpc2.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, entries, partial: false); yield return ((MonoBehaviour)__instance2).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section = null; public string key = null; public Type type = null; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } private class InvalidDeserializationTypeException : Exception { public string expected = null; public string received = null; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired = false; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig = null; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0052; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag.GetValueOrDefault(); } if (!num) { goto IL_0052; } int result = ((!lockExempt) ? 1 : 0); goto IL_0053; IL_0053: return (byte)result != 0; IL_0052: result = 0; goto IL_0053; } set { forceConfigLocking = value; } } public bool IsAdmin => lockExempt || isSourceOfTruth; public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } = false; public event Action? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry(ConfigEntry configEntry) { ConfigEntry configEntry2 = configEntry; OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry2); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry2); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry2).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry2).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry2.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry2); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { CustomSyncedValueBase customValue2 = customValue; if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue2.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue2); allCustomValues = new HashSet(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue2.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue2); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(delegate(KeyValuePair kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2u) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out SortedDictionary value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4u) != 0) { byte[] buffer = package.ReadByteArray(); MemoryStream stream = new MemoryStream(buffer); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; val2.Save(); } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int i = 0; i < num; i++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { OwnConfigEntryBase config2 = config; ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config2)); if (configSync == null) { return true; } return configSync.IsSourceOfTruth || !config2.SynchronizedConfig || config2.LocalBaseValue == null || (!configSync.IsLocked && (config2 != configSync.lockedConfig || lockExempt)); } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZNetPeer peer2 = peer; ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer2.m_socket.IsConnected()) { ZPackage fragmentedPackage = new ZPackage(); fragmentedPackage.Write((byte)2); fragmentedPackage.Write(packageIdentifier); fragmentedPackage.Write(fragment); fragmentedPackage.Write(fragments); fragmentedPackage.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(fragmentedPackage); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer2.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer2.m_server ? 0 : peer2.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer2.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer2.m_uid} after 30 seconds config sending timeout"); peer2.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer2); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = (List)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where((ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { ZPackage package2 = package; if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] rawData = package2.GetArray(); if (rawData != null && rawData.LongLength > 10000) { ZPackage compressedPackage = new ZPackage(); compressedPackage.Write((byte)4); MemoryStream output = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(output, CompressionLevel.Optimal)) { deflateStream.Write(rawData, 0, rawData.Length); } compressedPackage.Write(output.ToArray()); package2 = compressedPackage; } List> writers = (from peer in peers where peer.IsReady() select peer into p select distributeConfigToPeers(p, package2)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private static OwnConfigEntryBase? configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } public static SyncedConfigEntry? ConfigData(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { return type.IsEnum ? Enum.GetUnderlyingType(type) : type; } private static ZPackage ConfigsToPackage(IEnumerable? configs = null, IEnumerable? customValues = null, IEnumerable? packageEntries = null, bool partial = true) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown List list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write((byte)(partial ? 1 : 0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, object? value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } [PublicAPI] [HarmonyPatch] internal class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { return minimumRequiredVersion ?? (ModRequired ? CurrentVersion : "0.0.0"); } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool flag = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion); bool flag2 = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion); return flag && flag2; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } return (new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion)) ? (DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + ".") : (DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."); } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { return (rpc == null) ? ErrorClient() : ErrorServer(rpc); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { ZRpc rpc2 = rpc; return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc2)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; foreach (VersionCheck versionCheck in array2) { Debug.LogWarning((object)versionCheck.Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy, string>((KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } }